Commit c8ba4157 authored by 4ast's avatar 4ast Committed by GitHub

Merge pull request #988 from goldshtn/usdt-addressed-arg

Support base + index * scale addressing for USDT arguments
parents 0af31efb 8698bdb0
...@@ -39,11 +39,13 @@ struct bcc_usdt_location { ...@@ -39,11 +39,13 @@ struct bcc_usdt_location {
uint64_t address; uint64_t address;
}; };
#define BCC_USDT_ARGUMENT_NONE 0x0 #define BCC_USDT_ARGUMENT_NONE 0x0
#define BCC_USDT_ARGUMENT_CONSTANT 0x1 #define BCC_USDT_ARGUMENT_CONSTANT 0x1
#define BCC_USDT_ARGUMENT_DEREF_OFFSET 0x2 #define BCC_USDT_ARGUMENT_DEREF_OFFSET 0x2
#define BCC_USDT_ARGUMENT_DEREF_IDENT 0x4 #define BCC_USDT_ARGUMENT_DEREF_IDENT 0x4
#define BCC_USDT_ARGUMENT_REGISTER_NAME 0x8 #define BCC_USDT_ARGUMENT_BASE_REGISTER_NAME 0x8
#define BCC_USDT_ARGUMENT_INDEX_REGISTER_NAME 0x10
#define BCC_USDT_ARGUMENT_SCALE 0x20
struct bcc_usdt_argument { struct bcc_usdt_argument {
int size; int size;
...@@ -51,7 +53,9 @@ struct bcc_usdt_argument { ...@@ -51,7 +53,9 @@ struct bcc_usdt_argument {
int constant; int constant;
int deref_offset; int deref_offset;
const char *deref_ident; const char *deref_ident;
const char *register_name; const char *base_register_name;
const char *index_register_name;
int scale;
}; };
typedef void (*bcc_usdt_cb)(struct bcc_usdt *); typedef void (*bcc_usdt_cb)(struct bcc_usdt *);
......
...@@ -360,48 +360,56 @@ void bcc_usdt_foreach(void *usdt, bcc_usdt_cb callback) { ...@@ -360,48 +360,56 @@ void bcc_usdt_foreach(void *usdt, bcc_usdt_cb callback) {
int bcc_usdt_get_location(void *usdt, const char *probe_name, int bcc_usdt_get_location(void *usdt, const char *probe_name,
int index, struct bcc_usdt_location *location) { int index, struct bcc_usdt_location *location) {
USDT::Context *ctx = static_cast<USDT::Context *>(usdt); USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
USDT::Probe *probe = ctx->get(probe_name); USDT::Probe *probe = ctx->get(probe_name);
if (!probe) if (!probe)
return -1; return -1;
if (index < 0 || (size_t)index >= probe->num_locations()) if (index < 0 || (size_t)index >= probe->num_locations())
return -1; return -1;
location->address = probe->address(index); location->address = probe->address(index);
return 0; return 0;
} }
int bcc_usdt_get_argument(void *usdt, const char *probe_name, int bcc_usdt_get_argument(void *usdt, const char *probe_name,
int location_index, int argument_index, int location_index, int argument_index,
struct bcc_usdt_argument *argument) { struct bcc_usdt_argument *argument) {
USDT::Context *ctx = static_cast<USDT::Context *>(usdt); USDT::Context *ctx = static_cast<USDT::Context *>(usdt);
USDT::Probe *probe = ctx->get(probe_name); USDT::Probe *probe = ctx->get(probe_name);
if (!probe) if (!probe)
return -1; return -1;
if (argument_index < 0 || (size_t)argument_index >= probe->num_arguments()) if (argument_index < 0 || (size_t)argument_index >= probe->num_arguments())
return -1; return -1;
if (location_index < 0 || (size_t)location_index >= probe->num_locations()) if (location_index < 0 || (size_t)location_index >= probe->num_locations())
return -1; return -1;
auto const &location = probe->location(location_index); auto const &location = probe->location(location_index);
auto const &arg = location.arguments_[argument_index]; auto const &arg = location.arguments_[argument_index];
argument->size = arg.arg_size(); argument->size = arg.arg_size();
argument->valid = BCC_USDT_ARGUMENT_NONE; argument->valid = BCC_USDT_ARGUMENT_NONE;
if (arg.constant()) { if (arg.constant()) {
argument->valid |= BCC_USDT_ARGUMENT_CONSTANT; argument->valid |= BCC_USDT_ARGUMENT_CONSTANT;
argument->constant = *(arg.constant()); argument->constant = *(arg.constant());
} }
if (arg.deref_offset()) { if (arg.deref_offset()) {
argument->valid |= BCC_USDT_ARGUMENT_DEREF_OFFSET; argument->valid |= BCC_USDT_ARGUMENT_DEREF_OFFSET;
argument->deref_offset = *(arg.deref_offset()); argument->deref_offset = *(arg.deref_offset());
} }
if (arg.deref_ident()) { if (arg.deref_ident()) {
argument->valid |= BCC_USDT_ARGUMENT_DEREF_IDENT; argument->valid |= BCC_USDT_ARGUMENT_DEREF_IDENT;
argument->deref_ident = arg.deref_ident()->c_str(); argument->deref_ident = arg.deref_ident()->c_str();
} }
if (arg.register_name()) { if (arg.base_register_name()) {
argument->valid |= BCC_USDT_ARGUMENT_REGISTER_NAME; argument->valid |= BCC_USDT_ARGUMENT_BASE_REGISTER_NAME;
argument->register_name = arg.register_name()->c_str(); argument->base_register_name = arg.base_register_name()->c_str();
} }
return 0; if (arg.index_register_name()) {
argument->valid |= BCC_USDT_ARGUMENT_INDEX_REGISTER_NAME;
argument->index_register_name = arg.index_register_name()->c_str();
}
if (arg.scale()) {
argument->valid |= BCC_USDT_ARGUMENT_SCALE;
argument->scale = *(arg.scale());
}
return 0;
} }
void bcc_usdt_foreach_uprobe(void *usdt, bcc_usdt_uprobe_cb callback) { void bcc_usdt_foreach_uprobe(void *usdt, bcc_usdt_uprobe_cb callback) {
......
...@@ -40,7 +40,9 @@ private: ...@@ -40,7 +40,9 @@ private:
optional<int> constant_; optional<int> constant_;
optional<int> deref_offset_; optional<int> deref_offset_;
optional<std::string> deref_ident_; optional<std::string> deref_ident_;
optional<std::string> register_name_; optional<std::string> base_register_name_;
optional<std::string> index_register_name_;
optional<int> scale_;
bool get_global_address(uint64_t *address, const std::string &binpath, bool get_global_address(uint64_t *address, const std::string &binpath,
const optional<int> &pid) const; const optional<int> &pid) const;
...@@ -57,7 +59,13 @@ public: ...@@ -57,7 +59,13 @@ public:
std::string ctype() const; std::string ctype() const;
const optional<std::string> &deref_ident() const { return deref_ident_; } const optional<std::string> &deref_ident() const { return deref_ident_; }
const optional<std::string> &register_name() const { return register_name_; } const optional<std::string> &base_register_name() const {
return base_register_name_;
}
const optional<std::string> &index_register_name() const {
return index_register_name_;
}
const optional<int> scale() const { return scale_; }
const optional<int> constant() const { return constant_; } const optional<int> constant() const { return constant_; }
const optional<int> deref_offset() const { return deref_offset_; } const optional<int> deref_offset() const { return deref_offset_; }
...@@ -68,12 +76,18 @@ class ArgumentParser { ...@@ -68,12 +76,18 @@ class ArgumentParser {
const char *arg_; const char *arg_;
ssize_t cur_pos_; ssize_t cur_pos_;
void skip_whitespace_from(size_t pos);
void skip_until_whitespace_from(size_t pos);
protected: protected:
virtual bool normalize_register(std::string *reg, int *reg_size) = 0; 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_number(ssize_t pos, optional<int> *number);
ssize_t parse_identifier(ssize_t pos, optional<std::string> *ident); ssize_t parse_identifier(ssize_t pos, optional<std::string> *ident);
ssize_t parse_register(ssize_t pos, Argument *dest); 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_expr(ssize_t pos, Argument *dest);
ssize_t parse_1(ssize_t pos, Argument *dest); ssize_t parse_1(ssize_t pos, Argument *dest);
......
...@@ -61,20 +61,28 @@ bool Argument::assign_to_local(std::ostream &stream, ...@@ -61,20 +61,28 @@ bool Argument::assign_to_local(std::ostream &stream,
if (!deref_offset_) { if (!deref_offset_) {
tfm::format(stream, "%s = (%s)ctx->%s;", local_name, ctype(), tfm::format(stream, "%s = (%s)ctx->%s;", local_name, ctype(),
*register_name_); *base_register_name_);
return true; return true;
} }
if (deref_offset_ && !deref_ident_) { if (deref_offset_ && !deref_ident_) {
tfm::format(stream, "{ u64 __addr = ctx->%s + (%d)",
*base_register_name_, *deref_offset_);
if (index_register_name_) {
int scale = scale_.value_or(1);
tfm::format(stream, " + (ctx->%s * %d);", *index_register_name_, scale);
} else {
tfm::format(stream, ";");
}
tfm::format(stream, tfm::format(stream,
"{ u64 __addr = ctx->%s + (%d); %s __res = 0x0; " "%s __res = 0x0; "
"bpf_probe_read(&__res, sizeof(__res), (void *)__addr); " "bpf_probe_read(&__res, sizeof(__res), (void *)__addr); "
"%s = __res; }", "%s = __res; }",
*register_name_, *deref_offset_, ctype(), local_name); ctype(), local_name);
return true; return true;
} }
if (deref_offset_ && deref_ident_ && *register_name_ == "ip") { if (deref_offset_ && deref_ident_ && *base_register_name_ == "ip") {
uint64_t global_address; uint64_t global_address;
if (!get_global_address(&global_address, binpath, pid)) if (!get_global_address(&global_address, binpath, pid))
return false; return false;
...@@ -109,7 +117,8 @@ ssize_t ArgumentParser::parse_identifier(ssize_t pos, ...@@ -109,7 +117,8 @@ ssize_t ArgumentParser::parse_identifier(ssize_t pos,
return pos; return pos;
} }
ssize_t ArgumentParser::parse_register(ssize_t pos, Argument *dest) { ssize_t ArgumentParser::parse_register(ssize_t pos, std::string &name,
int &size) {
ssize_t start = ++pos; ssize_t start = ++pos;
if (arg_[start - 1] != '%') if (arg_[start - 1] != '%')
return -start; return -start;
...@@ -117,16 +126,41 @@ ssize_t ArgumentParser::parse_register(ssize_t pos, Argument *dest) { ...@@ -117,16 +126,41 @@ ssize_t ArgumentParser::parse_register(ssize_t pos, Argument *dest) {
while (isalnum(arg_[pos])) pos++; while (isalnum(arg_[pos])) pos++;
std::string regname(arg_ + start, pos - start); std::string regname(arg_ + start, pos - start);
int regsize = 0; if (!normalize_register(&regname, &size))
if (!normalize_register(&regname, &regsize))
return -start; return -start;
dest->register_name_ = regname; name = regname;
return pos;
}
ssize_t ArgumentParser::parse_base_register(ssize_t pos, Argument *dest) {
int size;
std::string name;
ssize_t res = parse_register(pos, name, size);
if (res < 0)
return res;
dest->base_register_name_ = name;
if (!dest->arg_size_) if (!dest->arg_size_)
dest->arg_size_ = regsize; dest->arg_size_ = size;
return pos; return res;
}
ssize_t ArgumentParser::parse_index_register(ssize_t pos, Argument *dest) {
int size;
std::string name;
ssize_t res = parse_register(pos, name, size);
if (res < 0)
return res;
dest->index_register_name_ = name;
return res;
}
ssize_t ArgumentParser::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::parse_expr(ssize_t pos, Argument *dest) {
...@@ -134,7 +168,7 @@ ssize_t ArgumentParser::parse_expr(ssize_t pos, Argument *dest) { ...@@ -134,7 +168,7 @@ ssize_t ArgumentParser::parse_expr(ssize_t pos, Argument *dest) {
return parse_number(pos + 1, &dest->constant_); return parse_number(pos + 1, &dest->constant_);
if (arg_[pos] == '%') if (arg_[pos] == '%')
return parse_register(pos, dest); return parse_base_register(pos, dest);
if (isdigit(arg_[pos]) || arg_[pos] == '-') { if (isdigit(arg_[pos]) || arg_[pos] == '-') {
pos = parse_number(pos, &dest->deref_offset_); pos = parse_number(pos, &dest->deref_offset_);
...@@ -154,10 +188,22 @@ ssize_t ArgumentParser::parse_expr(ssize_t pos, Argument *dest) { ...@@ -154,10 +188,22 @@ ssize_t ArgumentParser::parse_expr(ssize_t pos, Argument *dest) {
if (arg_[pos] != '(') if (arg_[pos] != '(')
return -pos; return -pos;
pos = parse_register(pos + 1, dest); pos = parse_base_register(pos + 1, dest);
if (pos < 0) if (pos < 0)
return pos; return pos;
if (arg_[pos] == ',') {
pos = parse_index_register(pos + 1, dest);
if (pos < 0)
return pos;
if (arg_[pos] == ',') {
pos = parse_scale(pos + 1, dest);
if (pos < 0)
return pos;
}
}
return (arg_[pos] == ')') ? pos + 1 : -pos; return (arg_[pos] == ')') ? pos + 1 : -pos;
} }
...@@ -180,6 +226,17 @@ void ArgumentParser::print_error(ssize_t pos) { ...@@ -180,6 +226,17 @@ void ArgumentParser::print_error(ssize_t pos) {
fputc('\n', 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::parse(Argument *dest) {
if (done()) if (done())
return false; return false;
...@@ -187,16 +244,15 @@ bool ArgumentParser::parse(Argument *dest) { ...@@ -187,16 +244,15 @@ bool ArgumentParser::parse(Argument *dest) {
ssize_t res = parse_1(cur_pos_, dest); ssize_t res = parse_1(cur_pos_, dest);
if (res < 0) { if (res < 0) {
print_error(-res); print_error(-res);
cur_pos_ = -res; skip_whitespace_from(-res + 1);
return false; return false;
} }
if (!isspace(arg_[res]) && arg_[res] != '\0') { if (!isspace(arg_[res]) && arg_[res] != '\0') {
print_error(res); print_error(res);
cur_pos_ = res; skip_until_whitespace_from(res);
return false; return false;
} }
while (isspace(arg_[res])) res++; skip_whitespace_from(res);
cur_pos_ = res;
return true; return true;
} }
......
...@@ -92,7 +92,7 @@ lib.bpf_attach_kprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p, ...@@ -92,7 +92,7 @@ lib.bpf_attach_kprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p,
lib.bpf_detach_kprobe.restype = ct.c_int lib.bpf_detach_kprobe.restype = ct.c_int
lib.bpf_detach_kprobe.argtypes = [ct.c_char_p] lib.bpf_detach_kprobe.argtypes = [ct.c_char_p]
lib.bpf_attach_uprobe.restype = ct.c_void_p lib.bpf_attach_uprobe.restype = ct.c_void_p
lib.bpf_attach_uprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p, lib.bpf_attach_uprobe.argtypes = [ct.c_int, ct.c_int, ct.c_char_p, ct.c_char_p,
ct.c_ulonglong, ct.c_int, ct.c_int, ct.c_int, _CB_TYPE, ct.py_object] ct.c_ulonglong, ct.c_int, ct.c_int, ct.c_int, _CB_TYPE, ct.py_object]
lib.bpf_detach_uprobe.restype = ct.c_int lib.bpf_detach_uprobe.restype = ct.c_int
lib.bpf_detach_uprobe.argtypes = [ct.c_char_p] lib.bpf_detach_uprobe.argtypes = [ct.c_char_p]
...@@ -197,7 +197,9 @@ class BCC_USDT_ARGUMENT_FLAGS(object): ...@@ -197,7 +197,9 @@ class BCC_USDT_ARGUMENT_FLAGS(object):
CONSTANT = 0x1 CONSTANT = 0x1
DEREF_OFFSET = 0x2 DEREF_OFFSET = 0x2
DEREF_IDENT = 0x4 DEREF_IDENT = 0x4
REGISTER_NAME = 0x8 BASE_REGISTER_NAME = 0x8
INDEX_REGISTER_NAME = 0x10
SCALE = 0x20
class bcc_usdt_argument(ct.Structure): class bcc_usdt_argument(ct.Structure):
_fields_ = [ _fields_ = [
...@@ -206,7 +208,9 @@ class bcc_usdt_argument(ct.Structure): ...@@ -206,7 +208,9 @@ class bcc_usdt_argument(ct.Structure):
('constant', ct.c_int), ('constant', ct.c_int),
('deref_offset', ct.c_int), ('deref_offset', ct.c_int),
('deref_ident', ct.c_char_p), ('deref_ident', ct.c_char_p),
('register_name', ct.c_char_p) ('base_register_name', ct.c_char_p),
('index_register_name', ct.c_char_p),
('scale', ct.c_int)
] ]
_USDT_CB = ct.CFUNCTYPE(None, ct.POINTER(bcc_usdt)) _USDT_CB = ct.CFUNCTYPE(None, ct.POINTER(bcc_usdt))
......
...@@ -32,8 +32,12 @@ class USDTProbeArgument(object): ...@@ -32,8 +32,12 @@ class USDTProbeArgument(object):
self.deref_offset = argument.deref_offset self.deref_offset = argument.deref_offset
if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_IDENT != 0: if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_IDENT != 0:
self.deref_ident = argument.deref_ident self.deref_ident = argument.deref_ident
if self.valid & BCC_USDT_ARGUMENT_FLAGS.REGISTER_NAME != 0: if self.valid & BCC_USDT_ARGUMENT_FLAGS.BASE_REGISTER_NAME != 0:
self.register_name = argument.register_name self.base_register_name = argument.base_register_name
if self.valid & BCC_USDT_ARGUMENT_FLAGS.INDEX_REGISTER_NAME != 0:
self.index_register_name = argument.index_register_name
if self.valid & BCC_USDT_ARGUMENT_FLAGS.SCALE != 0:
self.scale = argument.scale
def _size_prefix(self): def _size_prefix(self):
return "%d %s bytes" % \ return "%d %s bytes" % \
...@@ -45,16 +49,22 @@ class USDTProbeArgument(object): ...@@ -45,16 +49,22 @@ class USDTProbeArgument(object):
if self.valid & BCC_USDT_ARGUMENT_FLAGS.CONSTANT != 0: if self.valid & BCC_USDT_ARGUMENT_FLAGS.CONSTANT != 0:
return "%d" % self.constant return "%d" % self.constant
if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET == 0: if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET == 0:
return "%s" % self.register_name return "%s" % self.base_register_name
if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET != 0 and \ if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET != 0 and \
self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_IDENT == 0: self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_IDENT == 0:
if self.valid & BCC_USDT_ARGUMENT_FLAGS.INDEX_REGISTER_NAME != 0:
index_offset = " + %s" % self.index_register_name
if self.valid & BCC_USDT_ARGUMENT_FLAGS.SCALE != 0:
index_offset += " * %d" % self.scale
else:
index_offset = ""
sign = '+' if self.deref_offset >= 0 else '-' sign = '+' if self.deref_offset >= 0 else '-'
return "*(%s %s %d)" % (self.register_name, return "*(%s %s %d%s)" % (self.base_register_name,
sign, abs(self.deref_offset)) sign, abs(self.deref_offset), index_offset)
if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET != 0 and \ if self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_OFFSET != 0 and \
self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_IDENT != 0 and \ self.valid & BCC_USDT_ARGUMENT_FLAGS.DEREF_IDENT != 0 and \
self.valid & BCC_USDT_ARGUMENT_FLAGS.REGISTER_NAME != 0 and \ self.valid & BCC_USDT_ARGUMENT_FLAGS.BASE_REGISTER_NAME != 0 and \
self.register_name == "ip": self.base_register_name == "ip":
sign = '+' if self.deref_offset >= 0 else '-' sign = '+' if self.deref_offset >= 0 else '-'
return "*(&%s %s %d)" % (self.deref_ident, return "*(&%s %s %d)" % (self.deref_ident,
sign, abs(self.deref_offset)) sign, abs(self.deref_offset))
......
...@@ -35,16 +35,21 @@ static void verify_register(USDT::ArgumentParser_x64 &parser, int arg_size, ...@@ -35,16 +35,21 @@ static void verify_register(USDT::ArgumentParser_x64 &parser, int arg_size,
static void verify_register(USDT::ArgumentParser_x64 &parser, int arg_size, static void verify_register(USDT::ArgumentParser_x64 &parser, int arg_size,
const std::string &regname, const std::string &regname,
optional<int> deref_offset = nullopt, optional<int> deref_offset = nullopt,
optional<std::string> deref_ident = nullopt) { optional<std::string> deref_ident = nullopt,
optional<std::string> index_regname = nullopt,
optional<int> scale = nullopt) {
USDT::Argument arg; USDT::Argument arg;
REQUIRE(parser.parse(&arg)); REQUIRE(parser.parse(&arg));
REQUIRE(arg.arg_size() == arg_size); REQUIRE(arg.arg_size() == arg_size);
REQUIRE(arg.register_name()); REQUIRE(arg.base_register_name());
REQUIRE(arg.register_name() == regname); REQUIRE(arg.base_register_name() == regname);
REQUIRE(arg.deref_offset() == deref_offset); REQUIRE(arg.deref_offset() == deref_offset);
REQUIRE(arg.deref_ident() == deref_ident); REQUIRE(arg.deref_ident() == deref_ident);
REQUIRE(arg.index_register_name() == index_regname);
REQUIRE(arg.scale() == scale);
} }
TEST_CASE("test usdt argument parsing", "[usdt]") { TEST_CASE("test usdt argument parsing", "[usdt]") {
...@@ -66,7 +71,9 @@ TEST_CASE("test usdt argument parsing", "[usdt]") { ...@@ -66,7 +71,9 @@ TEST_CASE("test usdt argument parsing", "[usdt]") {
"-4@global_max_action(%rip) " "-4@global_max_action(%rip) "
"8@24+mp_(%rip) " "8@24+mp_(%rip) "
"-4@CheckpointStats+40(%rip) " "-4@CheckpointStats+40(%rip) "
"4@glob-2(%rip) "); "4@glob-2(%rip) "
"8@(%rax,%rdx,8) "
"4@(%rbx,%rcx)");
verify_register(parser, -4, 0); verify_register(parser, -4, 0);
verify_register(parser, 8, 1234); verify_register(parser, 8, 1234);
...@@ -85,6 +92,9 @@ TEST_CASE("test usdt argument parsing", "[usdt]") { ...@@ -85,6 +92,9 @@ TEST_CASE("test usdt argument parsing", "[usdt]") {
verify_register(parser, -4, "ip", 40, std::string("CheckpointStats")); verify_register(parser, -4, "ip", 40, std::string("CheckpointStats"));
verify_register(parser, 4, "ip", -2, std::string("glob")); verify_register(parser, 4, "ip", -2, std::string("glob"));
verify_register(parser, 8, "ax", 0, nullopt, std::string("dx"), 8);
verify_register(parser, 4, "bx", 0, nullopt, std::string("cx"));
REQUIRE(parser.done()); REQUIRE(parser.done());
} }
} }
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