Commit 1f0f7b66 authored by Sandipan Das's avatar Sandipan Das

Add basic USDT probe support for powerpc64

This adds basic support for parsing USDT arguments having
operands in the powerpc64 format. The following operand
formats are supported for now:
  * iNUM or i-NUM
  * REG or %rREG
  * NUM(REG) or -NUM(REG) or NUM(%rREG) or -NUM(%rREG)
  * REG,REG or %rREG,%rREG

Where NUM represents a numeric constant and REG represents
a general-purpose register.
Signed-off-by: default avatarSandipan Das <sandipan@linux.vnet.ibm.com>
parent 899d3e92
...@@ -74,37 +74,34 @@ public: ...@@ -74,37 +74,34 @@ public:
const optional<int> deref_offset() const { return deref_offset_; } const optional<int> deref_offset() const { return deref_offset_; }
friend class ArgumentParser; friend class ArgumentParser;
friend class ArgumentParser_powerpc64;
friend class ArgumentParser_x64;
}; };
class ArgumentParser { class ArgumentParser {
protected:
const char *arg_; const char *arg_;
ssize_t cur_pos_; ssize_t cur_pos_;
void skip_whitespace_from(size_t pos); void skip_whitespace_from(size_t pos);
void skip_until_whitespace_from(size_t pos); void skip_until_whitespace_from(size_t pos);
protected:
virtual bool normalize_register(std::string *reg, int *reg_size) = 0;
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);
ssize_t parse_scale(ssize_t pos, Argument *dest);
ssize_t parse_expr(ssize_t pos, Argument *dest);
ssize_t parse_1(ssize_t pos, Argument *dest);
void print_error(ssize_t pos); void print_error(ssize_t pos);
public: public:
bool parse(Argument *dest); virtual bool parse(Argument *dest) = 0;
bool done() { return cur_pos_ < 0 || arg_[cur_pos_] == '\0'; } bool done() { return cur_pos_ < 0 || arg_[cur_pos_] == '\0'; }
ArgumentParser(const char *arg) : arg_(arg), cur_pos_(0) {} ArgumentParser(const char *arg) : arg_(arg), cur_pos_(0) {}
}; };
class ArgumentParser_powerpc64 : public ArgumentParser {
public:
bool parse(Argument *dest);
ArgumentParser_powerpc64(const char *arg) : ArgumentParser(arg) {}
};
class ArgumentParser_x64 : public ArgumentParser { class ArgumentParser_x64 : public ArgumentParser {
private:
enum Register { enum Register {
REG_A, REG_A,
REG_B, REG_B,
...@@ -133,8 +130,17 @@ class ArgumentParser_x64 : public ArgumentParser { ...@@ -133,8 +130,17 @@ class ArgumentParser_x64 : public ArgumentParser {
static const std::unordered_map<std::string, RegInfo> registers_; static const std::unordered_map<std::string, RegInfo> registers_;
bool normalize_register(std::string *reg, int *reg_size); bool normalize_register(std::string *reg, int *reg_size);
void reg_to_name(std::string *norm, Register reg); 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);
ssize_t parse_scale(ssize_t pos, Argument *dest);
ssize_t parse_expr(ssize_t pos, Argument *dest);
ssize_t parse_1(ssize_t pos, Argument *dest);
public: public:
bool parse(Argument *dest);
ArgumentParser_x64(const char *arg) : ArgumentParser(arg) {} ArgumentParser_x64(const char *arg) : ArgumentParser(arg) {}
}; };
......
...@@ -31,7 +31,13 @@ ...@@ -31,7 +31,13 @@
namespace USDT { namespace USDT {
Location::Location(uint64_t addr, const char *arg_fmt) : address_(addr) { Location::Location(uint64_t addr, const char *arg_fmt) : address_(addr) {
#ifdef __powerpc64__
ArgumentParser_powerpc64 parser(arg_fmt);
#elif defined(__x86_64__)
ArgumentParser_x64 parser(arg_fmt); ArgumentParser_x64 parser(arg_fmt);
#else
#error "bcc does not support this platform yet"
#endif
while (!parser.done()) { while (!parser.done()) {
Argument arg; Argument arg;
if (!parser.parse(&arg)) if (!parser.parse(&arg))
...@@ -173,7 +179,7 @@ bool Probe::usdt_getarg(std::ostream &stream) { ...@@ -173,7 +179,7 @@ bool Probe::usdt_getarg(std::ostream &stream) {
return false; return false;
stream << "\n return 0;\n}\n"; stream << "\n return 0;\n}\n";
} else { } else {
stream << " switch(ctx->ip) {\n"; stream << " switch(PT_REGS_IP(ctx)) {\n";
for (Location &location : locations_) { for (Location &location : locations_) {
uint64_t global_address; uint64_t global_address;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
#include <unordered_map> #include <unordered_map>
#include <regex>
#include "syms.h" #include "syms.h"
#include "usdt.h" #include "usdt.h"
...@@ -112,7 +113,87 @@ bool Argument::assign_to_local(std::ostream &stream, ...@@ -112,7 +113,87 @@ bool Argument::assign_to_local(std::ostream &stream,
return false; return false;
} }
ssize_t ArgumentParser::parse_number(ssize_t pos, optional<int> *result) { void ArgumentParser::print_error(ssize_t pos) {
fprintf(stderr, "Parse error:\n %s\n", arg_);
for (ssize_t i = 0; i < pos + 4; ++i) fputc('-', stderr);
fputc('^', stderr);
fputc('\n', stderr);
}
void ArgumentParser::skip_whitespace_from(size_t pos) {
while (isspace(arg_[pos])) pos++;
cur_pos_ = pos;
}
void ArgumentParser::skip_until_whitespace_from(size_t pos) {
while (arg_[pos] != '\0' && !isspace(arg_[pos]))
pos++;
cur_pos_ = pos;
}
bool ArgumentParser_powerpc64::parse(Argument *dest) {
if (done())
return false;
bool matched;
std::smatch matches;
std::string arg_str(&arg_[cur_pos_]);
std::regex arg_n_regex("^(\\-?[1248])\\@");
// Operands with constants of form iNUM or i-NUM
std::regex arg_op_regex_const("^i(\\-?[0-9]+)( +|$)");
// Operands with register only of form REG or %rREG
std::regex arg_op_regex_reg("^(?:%r)?([1-2]?[0-9]|3[0-1])( +|$)");
// Operands with a base register and an offset of form
// NUM(REG) or -NUM(REG) or NUM(%rREG) or -NUM(%rREG)
std::regex arg_op_regex_breg_off(
"^(\\-?[0-9]+)\\((?:%r)?([1-2]?[0-9]|3[0-1])\\)( +|$)");
// Operands with a base register and an index register
// of form REG,REG or %rREG,%rREG
std::regex arg_op_regex_breg_ireg(
"^(?:%r)?([1-2]?[0-9]|3[0-1])\\,(?:%r)?([1-2]?[0-9]|3[0-1])( +|$)");
matched = std::regex_search(arg_str, matches, arg_n_regex);
if (matched) {
dest->arg_size_ = stoi(matches.str(1));
cur_pos_ += matches.length(0);
arg_str = &arg_[cur_pos_];
if (std::regex_search(arg_str, matches, arg_op_regex_const)) {
dest->constant_ = stoi(matches.str(1));
} else if (std::regex_search(arg_str, matches, arg_op_regex_reg)) {
dest->base_register_name_ = "gpr[" + matches.str(1) + "]";
} else if (std::regex_search(arg_str, matches, arg_op_regex_breg_off)) {
dest->deref_offset_ = stoi(matches.str(1));
dest->base_register_name_ = "gpr[" + matches.str(2) + "]";
} else if (std::regex_search(arg_str, matches, arg_op_regex_breg_ireg)) {
dest->deref_offset_ = 0; // In powerpc64, such operands contain a base
// register and an index register which are
// part of an indexed load/store operation.
// Even if no offset value is present, this
// is required by Argument::assign_to_local()
// in order to generate code for reading the
// argument. So, this is set to zero.
dest->base_register_name_ = "gpr[" + matches.str(1) + "]";
dest->index_register_name_ = "gpr[" + matches.str(2) + "]";
dest->scale_ = abs(*dest->arg_size_);
} else {
matched = false;
}
}
if (!matched) {
print_error(cur_pos_);
skip_until_whitespace_from(cur_pos_);
skip_whitespace_from(cur_pos_);
return false;
}
cur_pos_ += matches.length(0);
skip_whitespace_from(cur_pos_);
return true;
}
ssize_t ArgumentParser_x64::parse_number(ssize_t pos, optional<int> *result) {
char *endp; char *endp;
int number = strtol(arg_ + pos, &endp, 0); int number = strtol(arg_ + pos, &endp, 0);
if (endp > arg_ + pos) if (endp > arg_ + pos)
...@@ -120,8 +201,8 @@ ssize_t ArgumentParser::parse_number(ssize_t pos, optional<int> *result) { ...@@ -120,8 +201,8 @@ ssize_t ArgumentParser::parse_number(ssize_t pos, optional<int> *result) {
return endp - arg_; return endp - arg_;
} }
ssize_t ArgumentParser::parse_identifier(ssize_t pos, ssize_t ArgumentParser_x64::parse_identifier(ssize_t pos,
optional<std::string> *result) { optional<std::string> *result) {
if (isalpha(arg_[pos]) || arg_[pos] == '_') { if (isalpha(arg_[pos]) || arg_[pos] == '_') {
ssize_t start = pos++; ssize_t start = pos++;
while (isalnum(arg_[pos]) || arg_[pos] == '_') pos++; while (isalnum(arg_[pos]) || arg_[pos] == '_') pos++;
...@@ -131,8 +212,8 @@ ssize_t ArgumentParser::parse_identifier(ssize_t pos, ...@@ -131,8 +212,8 @@ ssize_t ArgumentParser::parse_identifier(ssize_t pos,
return pos; return pos;
} }
ssize_t ArgumentParser::parse_register(ssize_t pos, std::string &name, ssize_t ArgumentParser_x64::parse_register(ssize_t pos, std::string &name,
int &size) { int &size) {
ssize_t start = ++pos; ssize_t start = ++pos;
if (arg_[start - 1] != '%') if (arg_[start - 1] != '%')
return -start; return -start;
...@@ -147,7 +228,7 @@ ssize_t ArgumentParser::parse_register(ssize_t pos, std::string &name, ...@@ -147,7 +228,7 @@ ssize_t ArgumentParser::parse_register(ssize_t pos, std::string &name,
return pos; return pos;
} }
ssize_t ArgumentParser::parse_base_register(ssize_t pos, Argument *dest) { ssize_t ArgumentParser_x64::parse_base_register(ssize_t pos, Argument *dest) {
int size; int size;
std::string name; std::string name;
ssize_t res = parse_register(pos, name, size); ssize_t res = parse_register(pos, name, size);
...@@ -161,7 +242,7 @@ ssize_t ArgumentParser::parse_base_register(ssize_t pos, Argument *dest) { ...@@ -161,7 +242,7 @@ ssize_t ArgumentParser::parse_base_register(ssize_t pos, Argument *dest) {
return res; return res;
} }
ssize_t ArgumentParser::parse_index_register(ssize_t pos, Argument *dest) { ssize_t ArgumentParser_x64::parse_index_register(ssize_t pos, Argument *dest) {
int size; int size;
std::string name; std::string name;
ssize_t res = parse_register(pos, name, size); ssize_t res = parse_register(pos, name, size);
...@@ -173,11 +254,11 @@ ssize_t ArgumentParser::parse_index_register(ssize_t pos, Argument *dest) { ...@@ -173,11 +254,11 @@ ssize_t ArgumentParser::parse_index_register(ssize_t pos, Argument *dest) {
return res; return res;
} }
ssize_t ArgumentParser::parse_scale(ssize_t pos, Argument *dest) { ssize_t ArgumentParser_x64::parse_scale(ssize_t pos, Argument *dest) {
return parse_number(pos, &dest->scale_); return parse_number(pos, &dest->scale_);
} }
ssize_t ArgumentParser::parse_expr(ssize_t pos, Argument *dest) { ssize_t ArgumentParser_x64::parse_expr(ssize_t pos, Argument *dest) {
if (arg_[pos] == '$') if (arg_[pos] == '$')
return parse_number(pos + 1, &dest->constant_); return parse_number(pos + 1, &dest->constant_);
...@@ -221,7 +302,7 @@ ssize_t ArgumentParser::parse_expr(ssize_t pos, Argument *dest) { ...@@ -221,7 +302,7 @@ ssize_t ArgumentParser::parse_expr(ssize_t pos, Argument *dest) {
return (arg_[pos] == ')') ? pos + 1 : -pos; return (arg_[pos] == ')') ? pos + 1 : -pos;
} }
ssize_t ArgumentParser::parse_1(ssize_t pos, Argument *dest) { ssize_t ArgumentParser_x64::parse_1(ssize_t pos, Argument *dest) {
if (isdigit(arg_[pos]) || arg_[pos] == '-') { if (isdigit(arg_[pos]) || arg_[pos] == '-') {
optional<int> asize; optional<int> asize;
ssize_t m = parse_number(pos, &asize); ssize_t m = parse_number(pos, &asize);
...@@ -233,25 +314,7 @@ ssize_t ArgumentParser::parse_1(ssize_t pos, Argument *dest) { ...@@ -233,25 +314,7 @@ ssize_t ArgumentParser::parse_1(ssize_t pos, Argument *dest) {
return parse_expr(pos, dest); return parse_expr(pos, dest);
} }
void ArgumentParser::print_error(ssize_t pos) { bool ArgumentParser_x64::parse(Argument *dest) {
fprintf(stderr, "Parse error:\n %s\n", arg_);
for (ssize_t i = 0; i < pos + 4; ++i) fputc('-', stderr);
fputc('^', stderr);
fputc('\n', stderr);
}
void ArgumentParser::skip_whitespace_from(size_t pos) {
while (isspace(arg_[pos])) pos++;
cur_pos_ = pos;
}
void ArgumentParser::skip_until_whitespace_from(size_t pos) {
while (arg_[pos] != '\0' && !isspace(arg_[pos]))
pos++;
cur_pos_ = pos;
}
bool ArgumentParser::parse(Argument *dest) {
if (done()) if (done())
return false; return false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment