Skip to content

Commit

Permalink
Add usdt support for ARM64
Browse files Browse the repository at this point in the history
Specifically the following argument patterns will be
supported:
```
   [-]<size>@<value>
   [-]<size>@<reg>
   [-]<size>@[<reg>]
   [-]<size>@[<reg>,<offset>]
```

I did not use std regex library as the old gcc (e.g. 4.8.5)
does not have a good support for it.

Signed-off-by: Yonghong Song <[email protected]>
  • Loading branch information
yonghong-song committed Oct 26, 2017
1 parent fbbe6d6 commit c2d9880
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 27 deletions.
30 changes: 27 additions & 3 deletions src/cc/usdt.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,26 +74,51 @@ class Argument {
const optional<int> deref_offset() const { return deref_offset_; }

friend class ArgumentParser;
friend class ArgumentParser_aarch64;
friend class ArgumentParser_powerpc64;
friend class ArgumentParser_x64;
};

class ArgumentParser {
protected:
protected:
const char *arg_;
ssize_t cur_pos_;

void skip_whitespace_from(size_t pos);
void skip_until_whitespace_from(size_t pos);
void print_error(ssize_t pos);
ssize_t parse_number(ssize_t pos, optional<int> *result) {
char *endp;
int number = strtol(arg_ + pos, &endp, 0);
if (endp > arg_ + pos)
*result = number;
return endp - arg_;
}
bool error_return(ssize_t error_start, ssize_t skip_start) {
print_error(error_start);
skip_until_whitespace_from(skip_start);
return false;
}

public:
public:
virtual bool parse(Argument *dest) = 0;
bool done() { return cur_pos_ < 0 || arg_[cur_pos_] == '\0'; }

ArgumentParser(const char *arg) : arg_(arg), cur_pos_(0) {}
};

class ArgumentParser_aarch64 : public ArgumentParser {
private:
bool parse_register(ssize_t pos, ssize_t &new_pos, optional<int> *reg_num);
bool parse_size(ssize_t pos, ssize_t &new_pos, optional<int> *arg_size);
bool parse_mem(ssize_t pos, ssize_t &new_pos, optional<int> *reg_num,
optional<int> *offset);

public:
bool parse(Argument *dest);
ArgumentParser_aarch64(const char *arg) : ArgumentParser(arg) {}
};

class ArgumentParser_powerpc64 : public ArgumentParser {
public:
bool parse(Argument *dest);
Expand Down Expand Up @@ -131,7 +156,6 @@ class ArgumentParser_x64 : public ArgumentParser {
bool normalize_register(std::string *reg, int *reg_size);
void reg_to_name(std::string *norm, Register reg);
ssize_t parse_register(ssize_t pos, std::string &name, int &size);
ssize_t parse_number(ssize_t pos, optional<int> *number);
ssize_t parse_identifier(ssize_t pos, optional<std::string> *ident);
ssize_t parse_base_register(ssize_t pos, Argument *dest);
ssize_t parse_index_register(ssize_t pos, Argument *dest);
Expand Down
4 changes: 3 additions & 1 deletion src/cc/usdt/usdt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
namespace USDT {

Location::Location(uint64_t addr, const char *arg_fmt) : address_(addr) {
#ifdef __powerpc64__
#ifdef __aarch64__
ArgumentParser_aarch64 parser(arg_fmt);
#elif __powerpc64__
ArgumentParser_powerpc64 parser(arg_fmt);
#else
ArgumentParser_x64 parser(arg_fmt);
Expand Down
114 changes: 96 additions & 18 deletions src/cc/usdt/usdt_args.cc
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,98 @@ void ArgumentParser::skip_until_whitespace_from(size_t pos) {
cur_pos_ = pos;
}

bool ArgumentParser_aarch64::parse_register(ssize_t pos, ssize_t &new_pos,
optional<int> *reg_num) {
new_pos = parse_number(pos, reg_num);
if (new_pos == pos || *reg_num < 0 || *reg_num > 31)
return error_return(pos, pos);
return true;
}

bool ArgumentParser_aarch64::parse_size(ssize_t pos, ssize_t &new_pos,
optional<int> *arg_size) {
int abs_arg_size;

new_pos = parse_number(pos, arg_size);
if (new_pos == pos)
return error_return(pos, pos);

abs_arg_size = abs(arg_size->value());
if (abs_arg_size != 1 && abs_arg_size != 2 && abs_arg_size != 4 &&
abs_arg_size != 8)
return error_return(pos, pos);
return true;
}

bool ArgumentParser_aarch64::parse_mem(ssize_t pos, ssize_t &new_pos,
optional<int> *reg_num,
optional<int> *offset) {
if (arg_[pos] != 'x')
return error_return(pos, pos);
if (parse_register(pos + 1, new_pos, reg_num) == false)
return false;

if (arg_[new_pos] == ',') {
pos = new_pos + 1;
new_pos = parse_number(pos, offset);
if (new_pos == pos)
return error_return(pos, pos);
}
if (arg_[new_pos] != ']')
return error_return(new_pos, new_pos);
new_pos++;
return true;
}

bool ArgumentParser_aarch64::parse(Argument *dest) {
if (done())
return false;

// Support the following argument patterns:
// [-]<size>@<value>, [-]<size>@<reg>, [-]<size>@[<reg>], or
// [-]<size>@[<reg>,<offset>]
ssize_t cur_pos = cur_pos_, new_pos;
optional<int> arg_size;

// Parse [-]<size>
if (parse_size(cur_pos, new_pos, &arg_size) == false)
return false;
dest->arg_size_ = arg_size;

// Make sure '@' present
if (arg_[new_pos] != '@')
return error_return(new_pos, new_pos);
cur_pos = new_pos + 1;

if (arg_[cur_pos] == 'x') {
// Parse ...@<reg>
optional<int> reg_num;
if (parse_register(cur_pos + 1, new_pos, &reg_num) == false)
return false;
cur_pos_ = new_pos;
dest->base_register_name_ = "regs[" + std::to_string(reg_num.value()) + "]";
} else if (arg_[cur_pos] == '[') {
// Parse ...@[<reg>] and ...@[<reg,<offset>]
optional<int> reg_num, offset = 0;
if (parse_mem(cur_pos + 1, new_pos, &reg_num, &offset) == false)
return false;
cur_pos_ = new_pos;
dest->base_register_name_ = "regs[" + std::to_string(reg_num.value()) + "]";
dest->deref_offset_ = offset;
} else {
// Parse ...@<value>
optional<int> val;
new_pos = parse_number(cur_pos, &val);
if (cur_pos == new_pos)
return error_return(cur_pos, cur_pos);
cur_pos_ = new_pos;
dest->constant_ = val;
}

skip_whitespace_from(cur_pos_);
return true;
}

bool ArgumentParser_powerpc64::parse(Argument *dest) {
if (done())
return false;
Expand Down Expand Up @@ -193,14 +285,6 @@ bool ArgumentParser_powerpc64::parse(Argument *dest) {
return true;
}

ssize_t ArgumentParser_x64::parse_number(ssize_t pos, optional<int> *result) {
char *endp;
int number = strtol(arg_ + pos, &endp, 0);
if (endp > arg_ + pos)
*result = number;
return endp - arg_;
}

ssize_t ArgumentParser_x64::parse_identifier(ssize_t pos,
optional<std::string> *result) {
if (isalpha(arg_[pos]) || arg_[pos] == '_') {
Expand Down Expand Up @@ -319,16 +403,10 @@ bool ArgumentParser_x64::parse(Argument *dest) {
return false;

ssize_t res = parse_1(cur_pos_, dest);
if (res < 0) {
print_error(-res);
skip_whitespace_from(-res + 1);
return false;
}
if (!isspace(arg_[res]) && arg_[res] != '\0') {
print_error(res);
skip_until_whitespace_from(res);
return false;
}
if (res < 0)
return error_return(-res, -res + 1);
if (!isspace(arg_[res]) && arg_[res] != '\0')
return error_return(res, res);
skip_whitespace_from(res);
return true;
}
Expand Down
12 changes: 10 additions & 2 deletions tests/cc/test_usdt_args.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ static void verify_register(USDT::ArgumentParser &parser, int arg_size,

TEST_CASE("test usdt argument parsing", "[usdt]") {
SECTION("parse failure") {
#ifdef __powerpc64__
#ifdef __aarch64__
USDT::ArgumentParser_aarch64 parser("4@[x32,200]");
#elif __powerpc64__
USDT::ArgumentParser_powerpc64 parser("4@-12(42)");
#elif defined(__x86_64__)
USDT::ArgumentParser_x64 parser("4@i%ra+1r");
Expand All @@ -69,7 +71,13 @@ TEST_CASE("test usdt argument parsing", "[usdt]") {
REQUIRE(i < 10);
}
SECTION("argument examples from the Python implementation") {
#ifdef __powerpc64__
#ifdef __aarch64__
USDT::ArgumentParser_aarch64 parser("-1@x0 4@5 8@[x12] -4@[x31,-40]");
verify_register(parser, -1, "regs[0]");
verify_register(parser, 4, 5);
verify_register(parser, 8, "regs[12]", 0);
verify_register(parser, -4, "regs[31]", -40);
#elif __powerpc64__
USDT::ArgumentParser_powerpc64 parser(
"-4@0 8@%r0 8@i0 4@0(%r0) -2@0(0) "
"1@0 -2@%r3 -8@i9 -1@0(%r4) -4@16(6) "
Expand Down
6 changes: 3 additions & 3 deletions tests/python/include/folly/tracing/StaticTracepoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

#pragma once

#if defined(__ELF__) && \
(defined(__powerpc64__) || defined(__powerpc__) || \
defined(__x86_64__) || defined(__i386__))
#if defined(__ELF__) && \
(defined(__powerpc64__) || defined(__powerpc__) || defined(__aarch64__) || \
defined(__x86_64__) || defined(__i386__))
#include <folly/tracing/StaticTracepoint-ELF.h>

#define FOLLY_SDT(provider, name, ...) \
Expand Down

0 comments on commit c2d9880

Please sign in to comment.