Commit f158e693 authored by williangaspar's avatar williangaspar
parent c489081e
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
BPFtrace is a high-level tracing language for Linux enhanced Berkeley Packet Filter (eBPF) available in recent Linux kernels (4.x). BPFtrace uses LLVM as a backend to compile scripts to BPF-bytecode and makes use of [BCC](https://github.com/iovisor/bcc) for interacting with the Linux BPF system, as well as existing Linux tracing capabilities: kernel dynamic tracing (kprobes), user-level dynamic tracing (uprobes), and tracepoints. The BPFtrace language is inspired by awk and C, and predecessor tracers such as DTrace and SystemTap. BPFtrace was created by [Alastair Robertson](https://github.com/ajor). BPFtrace is a high-level tracing language for Linux enhanced Berkeley Packet Filter (eBPF) available in recent Linux kernels (4.x). BPFtrace uses LLVM as a backend to compile scripts to BPF-bytecode and makes use of [BCC](https://github.com/iovisor/bcc) for interacting with the Linux BPF system, as well as existing Linux tracing capabilities: kernel dynamic tracing (kprobes), user-level dynamic tracing (uprobes), and tracepoints. The BPFtrace language is inspired by awk and C, and predecessor tracers such as DTrace and SystemTap. BPFtrace was created by [Alastair Robertson](https://github.com/ajor).
To learn more about BPFtrace, see the [Reference Guide](docs/reference_guide.md) and [One-Liner Tutorial](docs/tutorial_one_liners.md). To learn more about BPFtrace, see the [Reference Guide](docs/reference_guide.md) and [One-Liner Tutorial](docs/tutorial_one_liners.md).
## Install ## Install
...@@ -12,7 +12,7 @@ For build and install instructions, see [INSTALL.md](INSTALL.md). ...@@ -12,7 +12,7 @@ For build and install instructions, see [INSTALL.md](INSTALL.md).
Count system calls using tracepoints: Count system calls using tracepoints:
``` ```
# bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[name] = count(); }' # bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe] = count(); }'
Attaching 320 probes... Attaching 320 probes...
^C ^C
...@@ -248,7 +248,7 @@ Variables: ...@@ -248,7 +248,7 @@ Variables:
- `arg0`, `arg1`, ... etc. - Arguments to the function being traced - `arg0`, `arg1`, ... etc. - Arguments to the function being traced
- `retval` - Return value from function being traced - `retval` - Return value from function being traced
- `func` - Name of the function currently being traced - `func` - Name of the function currently being traced
- `name` - Full name of the probe - `probe` - Full name of the probe
- `curtask` - Current task_struct as a u64. - `curtask` - Current task_struct as a u64.
- `rand` - Random number of type u32. - `rand` - Random number of type u32.
......
...@@ -165,7 +165,7 @@ Summarize the time spent in read(), in nanoseconds, as a histogram, by process n ...@@ -165,7 +165,7 @@ Summarize the time spent in read(), in nanoseconds, as a histogram, by process n
# Lesson 8. Count Process-Level Events # Lesson 8. Count Process-Level Events
``` ```
# bpftrace -e 'tracepoint:sched:sched* { @[name] = count(); } interval:s:5 { exit(); }' # bpftrace -e 'tracepoint:sched:sched* { @[probe] = count(); } interval:s:5 { exit(); }'
Attaching 25 probes... Attaching 25 probes...
@[tracepoint:sched:sched_wakeup_new]: 1 @[tracepoint:sched:sched_wakeup_new]: 1
@[tracepoint:sched:sched_process_fork]: 1 @[tracepoint:sched:sched_process_fork]: 1
...@@ -258,7 +258,7 @@ This counts stack traces that led to context switching (off-CPU) events. The abo ...@@ -258,7 +258,7 @@ This counts stack traces that led to context switching (off-CPU) events. The abo
Attaching 1 probe... Attaching 1 probe...
^C ^C
@: @:
[0, 1] 1 |@@ | [0, 1] 1 |@@ |
[2, 4) 0 | | [2, 4) 0 | |
[4, 8) 0 | | [4, 8) 0 | |
...@@ -310,7 +310,7 @@ open path: retrans_time_ms ...@@ -310,7 +310,7 @@ open path: retrans_time_ms
This uses kernel dynamic tracing of the vfs_open() function, which has a (struct path *) as the first argument. This uses kernel dynamic tracing of the vfs_open() function, which has a (struct path *) as the first argument.
- kprobe: As mentioned earlier, this is the kernel dynamic tracing probe type, which traces the entry of kernel functions (use kretprobe to trace their returns). - kprobe: As mentioned earlier, this is the kernel dynamic tracing probe type, which traces the entry of kernel functions (use kretprobe to trace their returns).
- ((path *)arg0)->dentry->d_name.name: this casts arg0 as path *, then dereferences dentry, etc. - ((path *)arg0)->dentry->d_name.name: this casts arg0 as path *, then dereferences dentry, etc.
- #include: these were necessary to include struct definitions for path and dentry. - #include: these were necessary to include struct definitions for path and dentry.
......
...@@ -108,7 +108,7 @@ Syscall count by program ...@@ -108,7 +108,7 @@ Syscall count by program
. .
.TP .TP
Syscall count by syscall Syscall count by syscall
\fBtracepoint:syscalls:sys_enter_* { @[name] = count(); }\fR \fBtracepoint:syscalls:sys_enter_* { @[probe] = count(); }\fR
. .
.TP .TP
Syscall count by process Syscall count by process
...@@ -273,7 +273,7 @@ Return value from function being traced ...@@ -273,7 +273,7 @@ Return value from function being traced
Name of the function currently being traced Name of the function currently being traced
. .
.TP .TP
\fBname\fR \fBprobe\fR
Full name of the probe Full name of the probe
. .
.TP .TP
......
...@@ -50,7 +50,7 @@ class Builtin : public Expression { ...@@ -50,7 +50,7 @@ class Builtin : public Expression {
public: public:
explicit Builtin(std::string ident) : ident(ident) { } explicit Builtin(std::string ident) : ident(ident) { }
std::string ident; std::string ident;
int name_id; int probe_id;
void accept(Visitor &v) override; void accept(Visitor &v) override;
}; };
......
...@@ -117,13 +117,13 @@ void CodegenLLVM::visit(Builtin &builtin) ...@@ -117,13 +117,13 @@ void CodegenLLVM::visit(Builtin &builtin)
expr_ = b_.CreateLoad(dst); expr_ = b_.CreateLoad(dst);
b_.CreateLifetimeEnd(dst); b_.CreateLifetimeEnd(dst);
} }
else if (builtin.ident == "name") else if (builtin.ident == "probe")
{ {
static int name_id = 0; static int probe_id = 0;
bpftrace_.name_ids_.push_back(probefull_); bpftrace_.probe_ids_.push_back(probefull_);
builtin.name_id = name_id; builtin.probe_id = probe_id;
name_id++; probe_id++;
expr_ = b_.getInt64(builtin.name_id); expr_ = b_.getInt64(builtin.probe_id);
} }
else if (builtin.ident == "args") else if (builtin.ident == "args")
{ {
...@@ -1057,7 +1057,7 @@ void CodegenLLVM::visit(Probe &probe) ...@@ -1057,7 +1057,7 @@ void CodegenLLVM::visit(Probe &probe)
/* /*
* Most of the time, we can take a probe like kprobe:do_f* and build a * Most of the time, we can take a probe like kprobe:do_f* and build a
* single BPF program for that, called "s_kprobe:do_f*", and attach it to * single BPF program for that, called "s_kprobe:do_f*", and attach it to
* each wildcard match. An exception is the "name" builtin, where we need * each wildcard match. An exception is the "probe" builtin, where we need
* to build different BPF programs for each wildcard match that cantains an * to build different BPF programs for each wildcard match that cantains an
* ID for the match. Those programs will be called "s_kprobe:do_fcntl" etc. * ID for the match. Those programs will be called "s_kprobe:do_fcntl" etc.
*/ */
......
...@@ -80,8 +80,8 @@ void SemanticAnalyser::visit(Builtin &builtin) ...@@ -80,8 +80,8 @@ void SemanticAnalyser::visit(Builtin &builtin)
err_ << arch::name() << " doesn't support " << builtin.ident << std::endl; err_ << arch::name() << " doesn't support " << builtin.ident << std::endl;
builtin.type = SizedType(Type::integer, 8); builtin.type = SizedType(Type::integer, 8);
} }
else if (builtin.ident == "name") { else if (builtin.ident == "probe") {
builtin.type = SizedType(Type::name, 8); builtin.type = SizedType(Type::probe, 8);
probe_->need_expansion = true; probe_->need_expansion = true;
} }
else if (builtin.ident == "username") { else if (builtin.ident == "username") {
......
...@@ -350,8 +350,8 @@ std::vector<uint64_t> BPFtrace::get_arg_values(std::vector<Field> args, uint8_t* ...@@ -350,8 +350,8 @@ std::vector<uint64_t> BPFtrace::get_arg_values(std::vector<Field> args, uint8_t*
resolve_uid(*(uint64_t*)(arg_data+arg.offset)).c_str())); resolve_uid(*(uint64_t*)(arg_data+arg.offset)).c_str()));
arg_values.push_back((uint64_t)resolved_usernames.back().get()); arg_values.push_back((uint64_t)resolved_usernames.back().get());
break; break;
case Type::name: case Type::probe:
name = strdup(resolve_name(*(uint64_t*)(arg_data+arg.offset)).c_str()); name = strdup(resolve_probe(*(uint64_t*)(arg_data+arg.offset)).c_str());
arg_values.push_back((uint64_t)name); arg_values.push_back((uint64_t)name);
break; break;
case Type::stack: case Type::stack:
...@@ -757,8 +757,8 @@ int BPFtrace::print_map(IMap &map, uint32_t top, uint32_t div) ...@@ -757,8 +757,8 @@ int BPFtrace::print_map(IMap &map, uint32_t top, uint32_t div)
std::cout << min_value(value, ncpus_) / div << std::endl; std::cout << min_value(value, ncpus_) / div << std::endl;
else if (map.type_.type == Type::max) else if (map.type_.type == Type::max)
std::cout << max_value(value, ncpus_) / div << std::endl; std::cout << max_value(value, ncpus_) / div << std::endl;
else if (map.type_.type == Type::name) else if (map.type_.type == Type::probe)
std::cout << resolve_name(*(uint64_t*)value.data()) << std::endl; std::cout << resolve_probe(*(uint64_t*)value.data()) << std::endl;
else else
std::cout << *(int64_t*)value.data() / div << std::endl; std::cout << *(int64_t*)value.data() / div << std::endl;
} }
...@@ -1372,10 +1372,10 @@ std::string BPFtrace::resolve_usym(uintptr_t addr, int pid, bool show_offset) ...@@ -1372,10 +1372,10 @@ std::string BPFtrace::resolve_usym(uintptr_t addr, int pid, bool show_offset)
return symbol.str(); return symbol.str();
} }
std::string BPFtrace::resolve_name(uint64_t name_id) std::string BPFtrace::resolve_probe(uint64_t probe_id)
{ {
assert(name_id < name_ids_.size()); assert(probe_id < probe_ids_.size());
return name_ids_[name_id]; return probe_ids_[probe_id];
} }
void BPFtrace::sort_by_key(std::vector<SizedType> key_args, void BPFtrace::sort_by_key(std::vector<SizedType> key_args,
......
...@@ -64,7 +64,7 @@ public: ...@@ -64,7 +64,7 @@ public:
std::string resolve_uid(uintptr_t addr); std::string resolve_uid(uintptr_t addr);
uint64_t resolve_kname(const std::string &name); uint64_t resolve_kname(const std::string &name);
uint64_t resolve_uname(const std::string &name, const std::string &path); uint64_t resolve_uname(const std::string &name, const std::string &path);
std::string resolve_name(uint64_t name_id); std::string resolve_probe(uint64_t probe_id);
uint64_t resolve_cgroupid(const std::string &path); uint64_t resolve_cgroupid(const std::string &path);
std::vector<uint64_t> get_arg_values(std::vector<Field> args, uint8_t* arg_data); std::vector<uint64_t> get_arg_values(std::vector<Field> args, uint8_t* arg_data);
int pid_; int pid_;
...@@ -77,7 +77,7 @@ public: ...@@ -77,7 +77,7 @@ public:
std::unique_ptr<IMap> stackid_map_; std::unique_ptr<IMap> stackid_map_;
std::unique_ptr<IMap> join_map_; std::unique_ptr<IMap> join_map_;
std::unique_ptr<IMap> perf_event_map_; std::unique_ptr<IMap> perf_event_map_;
std::vector<std::string> name_ids_; std::vector<std::string> probe_ids_;
int join_argnum_; int join_argnum_;
int join_argsize_; int join_argsize_;
......
...@@ -49,7 +49,7 @@ path :(\\.|[_\-\./a-zA-Z0-9])*: ...@@ -49,7 +49,7 @@ path :(\\.|[_\-\./a-zA-Z0-9])*:
<COMMENT>"*/" BEGIN(INITIAL); <COMMENT>"*/" BEGIN(INITIAL);
<COMMENT>"EOF" driver.error(loc, std::string("end of file during comment")); <COMMENT>"EOF" driver.error(loc, std::string("end of file during comment"));
pid|tid|cgroup|uid|gid|nsecs|cpu|comm|stack|ustack|arg[0-9]|retval|func|name|curtask|rand|ctx|username|args { pid|tid|cgroup|uid|gid|nsecs|cpu|comm|stack|ustack|arg[0-9]|retval|func|probe|curtask|rand|ctx|username|args {
return Parser::make_BUILTIN(yytext, loc); } return Parser::make_BUILTIN(yytext, loc); }
{path} { return Parser::make_PATH(yytext, loc); } {path} { return Parser::make_PATH(yytext, loc); }
{map} { return Parser::make_MAP(yytext, loc); } {map} { return Parser::make_MAP(yytext, loc); }
......
...@@ -76,8 +76,8 @@ std::string MapKey::argument_value(BPFtrace &bpftrace, ...@@ -76,8 +76,8 @@ std::string MapKey::argument_value(BPFtrace &bpftrace,
return bpftrace.resolve_usym(*(uint64_t*)data, *(uint64_t*)(arg_data + 8)); return bpftrace.resolve_usym(*(uint64_t*)data, *(uint64_t*)(arg_data + 8));
case Type::username: case Type::username:
return bpftrace.resolve_uid(*(uint64_t*)data); return bpftrace.resolve_uid(*(uint64_t*)data);
case Type::name: case Type::probe:
return bpftrace.name_ids_[*(uint64_t*)data]; return bpftrace.probe_ids_[*(uint64_t*)data];
case Type::string: case Type::string:
return std::string((char*)data); return std::string((char*)data);
} }
......
...@@ -33,7 +33,7 @@ std::string verify_format_string(const std::string &fmt, std::vector<Field> args ...@@ -33,7 +33,7 @@ std::string verify_format_string(const std::string &fmt, std::vector<Field> args
for (int i=0; i<num_args; i++, token_iter++) for (int i=0; i<num_args; i++, token_iter++)
{ {
Type arg_type = args.at(i).type.type; Type arg_type = args.at(i).type.type;
if (arg_type == Type::sym || arg_type == Type::usym || arg_type == Type::name || if (arg_type == Type::sym || arg_type == Type::usym || arg_type == Type::probe ||
arg_type == Type::username || arg_type == Type::stack || arg_type == Type::ustack) arg_type == Type::username || arg_type == Type::stack || arg_type == Type::ustack)
arg_type = Type::string; // Symbols should be printed as strings arg_type = Type::string; // Symbols should be printed as strings
int offset = 1; int offset = 1;
......
...@@ -48,7 +48,7 @@ std::string typestr(Type t) ...@@ -48,7 +48,7 @@ std::string typestr(Type t)
case Type::sym: return "sym"; break; case Type::sym: return "sym"; break;
case Type::usym: return "usym"; break; case Type::usym: return "usym"; break;
case Type::cast: return "cast"; break; case Type::cast: return "cast"; break;
case Type::name: return "name"; break; case Type::probe: return "probe"; break;
default: abort(); default: abort();
} }
} }
......
...@@ -31,7 +31,7 @@ enum class Type ...@@ -31,7 +31,7 @@ enum class Type
usym, usym,
cast, cast,
join, join,
name, probe,
username, username,
}; };
......
...@@ -902,9 +902,9 @@ attributes #1 = { argmemonly nounwind } ...@@ -902,9 +902,9 @@ attributes #1 = { argmemonly nounwind }
)EXPECTED"); )EXPECTED");
} }
TEST(codegen, builtin_name) TEST(codegen, builtin_probe)
{ {
test("tracepoint:syscalls:sys_enter_nanosleep { @x = name }", test("tracepoint:syscalls:sys_enter_nanosleep { @x = probe }",
R"EXPECTED(; Function Attrs: nounwind R"EXPECTED(; Function Attrs: nounwind
declare i64 @llvm.bpf.pseudo(i64, i64) #0 declare i64 @llvm.bpf.pseudo(i64, i64) #0
...@@ -979,9 +979,9 @@ attributes #1 = { argmemonly nounwind } ...@@ -979,9 +979,9 @@ attributes #1 = { argmemonly nounwind }
)EXPECTED"); )EXPECTED");
} }
TEST(codegen, builtin_name_wild) TEST(codegen, builtin_probe_wild)
{ {
test("tracepoint:syscalls:sys_enter_nanoslee* { @x = name }", test("tracepoint:syscalls:sys_enter_nanoslee* { @x = probe }",
R"EXPECTED(; Function Attrs: nounwind R"EXPECTED(; Function Attrs: nounwind
declare i64 @llvm.bpf.pseudo(i64, i64) #0 declare i64 @llvm.bpf.pseudo(i64, i64) #0
......
...@@ -40,7 +40,7 @@ TEST(Parser, builtin_variables) ...@@ -40,7 +40,7 @@ TEST(Parser, builtin_variables)
test("kprobe:f { arg0 }", "Program\n kprobe:f\n builtin: arg0\n"); test("kprobe:f { arg0 }", "Program\n kprobe:f\n builtin: arg0\n");
test("kprobe:f { retval }", "Program\n kprobe:f\n builtin: retval\n"); test("kprobe:f { retval }", "Program\n kprobe:f\n builtin: retval\n");
test("kprobe:f { func }", "Program\n kprobe:f\n builtin: func\n"); test("kprobe:f { func }", "Program\n kprobe:f\n builtin: func\n");
test("kprobe:f { name }", "Program\n kprobe:f\n builtin: name\n"); test("kprobe:f { probe }", "Program\n kprobe:f\n builtin: prove\n");
test("kprobe:f { args }", "Program\n kprobe:f\n builtin: args\n"); test("kprobe:f { args }", "Program\n kprobe:f\n builtin: args\n");
} }
......
...@@ -63,7 +63,7 @@ TEST(semantic_analyser, builtin_variables) ...@@ -63,7 +63,7 @@ TEST(semantic_analyser, builtin_variables)
test("kprobe:f { arg0 }", 0); test("kprobe:f { arg0 }", 0);
test("kprobe:f { retval }", 0); test("kprobe:f { retval }", 0);
test("kprobe:f { func }", 0); test("kprobe:f { func }", 0);
test("kprobe:f { name }", 0); test("kprobe:f { probe }", 0);
test("tracepoint:a:b { args }", 0); test("tracepoint:a:b { args }", 0);
// test("kprobe:f { fake }", 1); // test("kprobe:f { fake }", 1);
} }
...@@ -270,13 +270,13 @@ TEST(semantic_analyser, call_func) ...@@ -270,13 +270,13 @@ TEST(semantic_analyser, call_func)
test("kprobe:f { func(123); }", 1); test("kprobe:f { func(123); }", 1);
} }
TEST(semantic_analyser, call_name) TEST(semantic_analyser, call_probe)
{ {
test("kprobe:f { @[name] = count(); }", 0); test("kprobe:f { @[probe] = count(); }", 0);
test("kprobe:f { printf(\"%s\", name); }", 0); test("kprobe:f { printf(\"%s\", probe); }", 0);
test("kprobe:f { name(\"blah\"); }", 1); test("kprobe:f { probe(\"blah\"); }", 1);
test("kprobe:f { name(); }", 1); test("kprobe:f { probe(); }", 1);
test("kprobe:f { name(123); }", 1); test("kprobe:f { probe(123); }", 1);
} }
TEST(semantic_analyser, map_reassignment) TEST(semantic_analyser, map_reassignment)
......
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