Commit 422db709 authored by yonghong-song's avatar yonghong-song Committed by GitHub

Merge pull request #1365 from sandip4n/add-usdt-ppc64

Add basic USDT support for powerpc64
parents 91837cac f86f0538
......@@ -74,37 +74,34 @@ public:
const optional<int> deref_offset() const { return deref_offset_; }
friend class ArgumentParser;
friend class ArgumentParser_powerpc64;
friend class ArgumentParser_x64;
};
class ArgumentParser {
protected:
const char *arg_;
ssize_t cur_pos_;
void skip_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);
public:
bool parse(Argument *dest);
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_powerpc64 : public ArgumentParser {
public:
bool parse(Argument *dest);
ArgumentParser_powerpc64(const char *arg) : ArgumentParser(arg) {}
};
class ArgumentParser_x64 : public ArgumentParser {
private:
enum Register {
REG_A,
REG_B,
......@@ -133,8 +130,17 @@ class ArgumentParser_x64 : public ArgumentParser {
static const std::unordered_map<std::string, RegInfo> registers_;
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);
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:
bool parse(Argument *dest);
ArgumentParser_x64(const char *arg) : ArgumentParser(arg) {}
};
......
......@@ -32,7 +32,13 @@
namespace USDT {
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);
#else
#error "bcc does not support this platform yet"
#endif
while (!parser.done()) {
Argument arg;
if (!parser.parse(&arg))
......@@ -174,7 +180,7 @@ bool Probe::usdt_getarg(std::ostream &stream) {
return false;
stream << "\n return 0;\n}\n";
} else {
stream << " switch(ctx->ip) {\n";
stream << " switch(PT_REGS_IP(ctx)) {\n";
for (Location &location : locations_) {
uint64_t global_address;
......
......@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <unordered_map>
#include <regex>
#include "syms.h"
#include "usdt.h"
......@@ -112,7 +113,87 @@ bool Argument::assign_to_local(std::ostream &stream,
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;
int number = strtol(arg_ + pos, &endp, 0);
if (endp > arg_ + pos)
......@@ -120,8 +201,8 @@ ssize_t ArgumentParser::parse_number(ssize_t pos, optional<int> *result) {
return endp - arg_;
}
ssize_t ArgumentParser::parse_identifier(ssize_t pos,
optional<std::string> *result) {
ssize_t ArgumentParser_x64::parse_identifier(ssize_t pos,
optional<std::string> *result) {
if (isalpha(arg_[pos]) || arg_[pos] == '_') {
ssize_t start = pos++;
while (isalnum(arg_[pos]) || arg_[pos] == '_') pos++;
......@@ -131,8 +212,8 @@ ssize_t ArgumentParser::parse_identifier(ssize_t pos,
return pos;
}
ssize_t ArgumentParser::parse_register(ssize_t pos, std::string &name,
int &size) {
ssize_t ArgumentParser_x64::parse_register(ssize_t pos, std::string &name,
int &size) {
ssize_t start = ++pos;
if (arg_[start - 1] != '%')
return -start;
......@@ -147,7 +228,7 @@ ssize_t ArgumentParser::parse_register(ssize_t pos, std::string &name,
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;
std::string name;
ssize_t res = parse_register(pos, name, size);
......@@ -161,7 +242,7 @@ ssize_t ArgumentParser::parse_base_register(ssize_t pos, Argument *dest) {
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;
std::string name;
ssize_t res = parse_register(pos, name, size);
......@@ -173,11 +254,11 @@ ssize_t ArgumentParser::parse_index_register(ssize_t pos, Argument *dest) {
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_);
}
ssize_t ArgumentParser::parse_expr(ssize_t pos, Argument *dest) {
ssize_t ArgumentParser_x64::parse_expr(ssize_t pos, Argument *dest) {
if (arg_[pos] == '$')
return parse_number(pos + 1, &dest->constant_);
......@@ -221,7 +302,7 @@ ssize_t ArgumentParser::parse_expr(ssize_t pos, Argument *dest) {
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] == '-') {
optional<int> asize;
ssize_t m = parse_number(pos, &asize);
......@@ -233,25 +314,7 @@ ssize_t ArgumentParser::parse_1(ssize_t pos, Argument *dest) {
return parse_expr(pos, dest);
}
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::parse(Argument *dest) {
bool ArgumentParser_x64::parse(Argument *dest) {
if (done())
return false;
......
......@@ -22,7 +22,7 @@
using std::experimental::optional;
using std::experimental::nullopt;
static void verify_register(USDT::ArgumentParser_x64 &parser, int arg_size,
static void verify_register(USDT::ArgumentParser &parser, int arg_size,
int constant) {
USDT::Argument arg;
REQUIRE(parser.parse(&arg));
......@@ -32,7 +32,7 @@ static void verify_register(USDT::ArgumentParser_x64 &parser, int arg_size,
REQUIRE(arg.constant() == constant);
}
static void verify_register(USDT::ArgumentParser_x64 &parser, int arg_size,
static void verify_register(USDT::ArgumentParser &parser, int arg_size,
const std::string &regname,
optional<int> deref_offset = nullopt,
optional<std::string> deref_ident = nullopt,
......@@ -54,7 +54,11 @@ static void verify_register(USDT::ArgumentParser_x64 &parser, int arg_size,
TEST_CASE("test usdt argument parsing", "[usdt]") {
SECTION("parse failure") {
#ifdef __powerpc64__
USDT::ArgumentParser_powerpc64 parser("4@-12(42)");
#elif defined(__x86_64__)
USDT::ArgumentParser_x64 parser("4@i%ra+1r");
#endif
USDT::Argument arg;
REQUIRE(!parser.parse(&arg));
int i;
......@@ -65,6 +69,51 @@ TEST_CASE("test usdt argument parsing", "[usdt]") {
REQUIRE(i < 10);
}
SECTION("argument examples from the Python implementation") {
#ifdef __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) "
"2@7 4@%r11 4@i-67 8@-16(%r17) 1@-52(11) "
"-8@13 -8@%r25 2@i-11 -2@14(%r26) -8@-32(24) "
"4@29 2@%r17 -8@i-693 -1@-23(%r31) 4@28(30) "
"-2@31 -4@%r30 2@i1097 4@108(%r30) -2@-4(31)");
verify_register(parser, -4, "gpr[0]");
verify_register(parser, 8, "gpr[0]");
verify_register(parser, 8, 0);
verify_register(parser, 4, "gpr[0]", 0);
verify_register(parser, -2, "gpr[0]", 0);
verify_register(parser, 1, "gpr[0]");
verify_register(parser, -2, "gpr[3]");
verify_register(parser, -8, 9);
verify_register(parser, -1, "gpr[4]", 0);
verify_register(parser, -4, "gpr[6]", 16);
verify_register(parser, 2, "gpr[7]");
verify_register(parser, 4, "gpr[11]");
verify_register(parser, 4, -67);
verify_register(parser, 8, "gpr[17]", -16);
verify_register(parser, 1, "gpr[11]", -52);
verify_register(parser, -8, "gpr[13]");
verify_register(parser, -8, "gpr[25]");
verify_register(parser, 2, -11);
verify_register(parser, -2, "gpr[26]", 14);
verify_register(parser, -8, "gpr[24]", -32);
verify_register(parser, 4, "gpr[29]");
verify_register(parser, 2, "gpr[17]");
verify_register(parser, -8, -693);
verify_register(parser, -1, "gpr[31]", -23);
verify_register(parser, 4, "gpr[30]", 28);
verify_register(parser, -2, "gpr[31]");
verify_register(parser, -4, "gpr[30]");
verify_register(parser, 2, 1097);
verify_register(parser, 4, "gpr[30]", 108);
verify_register(parser, -2, "gpr[31]", -4);
#elif defined(__x86_64__)
USDT::ArgumentParser_x64 parser(
"-4@$0 8@$1234 %rdi %rax %rsi "
"-8@%rbx 4@%r12 8@-8(%rbp) 4@(%rax) "
......@@ -94,6 +143,7 @@ TEST_CASE("test usdt argument parsing", "[usdt]") {
verify_register(parser, 8, "ax", 0, nullopt, std::string("dx"), 8);
verify_register(parser, 4, "bx", 0, nullopt, std::string("cx"));
#endif
REQUIRE(parser.done());
}
......
......@@ -18,8 +18,12 @@
// Default constraint for the probe arguments as operands.
#ifndef FOLLY_SDT_ARG_CONSTRAINT
#if defined(__powerpc64__) || defined(__powerpc__)
#define FOLLY_SDT_ARG_CONSTRAINT "nQr"
#elif defined(__x86_64__) || defined(__i386__)
#define FOLLY_SDT_ARG_CONSTRAINT "nor"
#endif
#endif
// Instruction to emit for the probe.
#define FOLLY_SDT_NOP nop
......@@ -73,7 +77,14 @@
FOLLY_SDT_OPERANDS_7(_1, _2, _3, _4, _5, _6, _7), FOLLY_SDT_ARG(8, _8)
// Templates to reference the arguments from operands in note section.
#define FOLLY_SDT_ARGFMT(no) %n[FOLLY_SDT_S##no]@%[FOLLY_SDT_A##no]
#if defined(__powerpc64__ ) || defined(__powerpc__)
#define FOLLY_SDT_ARGTMPL(id) %I[id]%[id]
#elif defined(__i386__)
#define FOLLY_SDT_ARGTMPL(id) %w[id]
#else
#define FOLLY_SDT_ARGTMPL(id) %[id]
#endif
#define FOLLY_SDT_ARGFMT(no) %n[FOLLY_SDT_S##no]@FOLLY_SDT_ARGTMPL(FOLLY_SDT_A##no)
#define FOLLY_SDT_ARG_TEMPLATE_0 /*No arguments*/
#define FOLLY_SDT_ARG_TEMPLATE_1 FOLLY_SDT_ARGFMT(1)
#define FOLLY_SDT_ARG_TEMPLATE_2 FOLLY_SDT_ARG_TEMPLATE_1 FOLLY_SDT_ARGFMT(2)
......
......@@ -16,8 +16,10 @@
#pragma once
#if defined(__ELF__) && (defined(__x86_64__) || defined(__i386__))
#include <folly/tracing/StaticTracepoint-ELFx86.h>
#if defined(__ELF__) && \
(defined(__powerpc64__) || defined(__powerpc__) || \
defined(__x86_64__) || defined(__i386__))
#include <folly/tracing/StaticTracepoint-ELF.h>
#define FOLLY_SDT(provider, name, ...) \
FOLLY_SDT_PROBE_N( \
......
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