Commit f158e693 authored by williangaspar's avatar williangaspar
parent c489081e
......@@ -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).
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
......@@ -12,7 +12,7 @@ For build and install instructions, see [INSTALL.md](INSTALL.md).
Count system calls using tracepoints:
```
# bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[name] = count(); }'
# bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe] = count(); }'
Attaching 320 probes...
^C
......@@ -248,7 +248,7 @@ Variables:
- `arg0`, `arg1`, ... etc. - Arguments to the function being traced
- `retval` - Return value from function 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.
- `rand` - Random number of type u32.
......
......@@ -165,7 +165,7 @@ Summarize the time spent in read(), in nanoseconds, as a histogram, by process n
# 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...
@[tracepoint:sched:sched_wakeup_new]: 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
Attaching 1 probe...
^C
@:
@:
[0, 1] 1 |@@ |
[2, 4) 0 | |
[4, 8) 0 | |
......@@ -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.
- 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.
- #include: these were necessary to include struct definitions for path and dentry.
......
......@@ -108,7 +108,7 @@ Syscall count by program
.
.TP
Syscall count by syscall
\fBtracepoint:syscalls:sys_enter_* { @[name] = count(); }\fR
\fBtracepoint:syscalls:sys_enter_* { @[probe] = count(); }\fR
.
.TP
Syscall count by process
......@@ -273,7 +273,7 @@ Return value from function being traced
Name of the function currently being traced
.
.TP
\fBname\fR
\fBprobe\fR
Full name of the probe
.
.TP
......
......@@ -50,7 +50,7 @@ class Builtin : public Expression {
public:
explicit Builtin(std::string ident) : ident(ident) { }
std::string ident;
int name_id;
int probe_id;
void accept(Visitor &v) override;
};
......
......@@ -117,13 +117,13 @@ void CodegenLLVM::visit(Builtin &builtin)
expr_ = b_.CreateLoad(dst);
b_.CreateLifetimeEnd(dst);
}
else if (builtin.ident == "name")
else if (builtin.ident == "probe")
{
static int name_id = 0;
bpftrace_.name_ids_.push_back(probefull_);
builtin.name_id = name_id;
name_id++;
expr_ = b_.getInt64(builtin.name_id);
static int probe_id = 0;
bpftrace_.probe_ids_.push_back(probefull_);
builtin.probe_id = probe_id;
probe_id++;
expr_ = b_.getInt64(builtin.probe_id);
}
else if (builtin.ident == "args")
{
......@@ -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
* 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
* ID for the match. Those programs will be called "s_kprobe:do_fcntl" etc.
*/
......
......@@ -80,8 +80,8 @@ void SemanticAnalyser::visit(Builtin &builtin)
err_ << arch::name() << " doesn't support " << builtin.ident << std::endl;
builtin.type = SizedType(Type::integer, 8);
}
else if (builtin.ident == "name") {
builtin.type = SizedType(Type::name, 8);
else if (builtin.ident == "probe") {
builtin.type = SizedType(Type::probe, 8);
probe_->need_expansion = true;
}
else if (builtin.ident == "username") {
......
......@@ -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()));
arg_values.push_back((uint64_t)resolved_usernames.back().get());
break;
case Type::name:
name = strdup(resolve_name(*(uint64_t*)(arg_data+arg.offset)).c_str());
case Type::probe:
name = strdup(resolve_probe(*(uint64_t*)(arg_data+arg.offset)).c_str());
arg_values.push_back((uint64_t)name);
break;
case Type::stack:
......@@ -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;
else if (map.type_.type == Type::max)
std::cout << max_value(value, ncpus_) / div << std::endl;
else if (map.type_.type == Type::name)
std::cout << resolve_name(*(uint64_t*)value.data()) << std::endl;
else if (map.type_.type == Type::probe)
std::cout << resolve_probe(*(uint64_t*)value.data()) << std::endl;
else
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)
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());
return name_ids_[name_id];
assert(probe_id < probe_ids_.size());
return probe_ids_[probe_id];
}
void BPFtrace::sort_by_key(std::vector<SizedType> key_args,
......
......@@ -64,7 +64,7 @@ public:
std::string resolve_uid(uintptr_t addr);
uint64_t resolve_kname(const std::string &name);
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);
std::vector<uint64_t> get_arg_values(std::vector<Field> args, uint8_t* arg_data);
int pid_;
......@@ -77,7 +77,7 @@ public:
std::unique_ptr<IMap> stackid_map_;
std::unique_ptr<IMap> join_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_argsize_;
......
......@@ -49,7 +49,7 @@ path :(\\.|[_\-\./a-zA-Z0-9])*:
<COMMENT>"*/" BEGIN(INITIAL);
<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); }
{path} { return Parser::make_PATH(yytext, loc); }
{map} { return Parser::make_MAP(yytext, loc); }
......
......@@ -76,8 +76,8 @@ std::string MapKey::argument_value(BPFtrace &bpftrace,
return bpftrace.resolve_usym(*(uint64_t*)data, *(uint64_t*)(arg_data + 8));
case Type::username:
return bpftrace.resolve_uid(*(uint64_t*)data);
case Type::name:
return bpftrace.name_ids_[*(uint64_t*)data];
case Type::probe:
return bpftrace.probe_ids_[*(uint64_t*)data];
case Type::string:
return std::string((char*)data);
}
......
......@@ -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++)
{
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::string; // Symbols should be printed as strings
int offset = 1;
......
......@@ -48,7 +48,7 @@ std::string typestr(Type t)
case Type::sym: return "sym"; break;
case Type::usym: return "usym"; break;
case Type::cast: return "cast"; break;
case Type::name: return "name"; break;
case Type::probe: return "probe"; break;
default: abort();
}
}
......
......@@ -31,7 +31,7 @@ enum class Type
usym,
cast,
join,
name,
probe,
username,
};
......
......@@ -902,9 +902,9 @@ attributes #1 = { argmemonly nounwind }
)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
declare i64 @llvm.bpf.pseudo(i64, i64) #0
......@@ -979,9 +979,9 @@ attributes #1 = { argmemonly nounwind }
)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
declare i64 @llvm.bpf.pseudo(i64, i64) #0
......
......@@ -40,7 +40,7 @@ TEST(Parser, builtin_variables)
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 { 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");
}
......
......@@ -63,7 +63,7 @@ TEST(semantic_analyser, builtin_variables)
test("kprobe:f { arg0 }", 0);
test("kprobe:f { retval }", 0);
test("kprobe:f { func }", 0);
test("kprobe:f { name }", 0);
test("kprobe:f { probe }", 0);
test("tracepoint:a:b { args }", 0);
// test("kprobe:f { fake }", 1);
}
......@@ -270,13 +270,13 @@ TEST(semantic_analyser, call_func)
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 { printf(\"%s\", name); }", 0);
test("kprobe:f { name(\"blah\"); }", 1);
test("kprobe:f { name(); }", 1);
test("kprobe:f { name(123); }", 1);
test("kprobe:f { @[probe] = count(); }", 0);
test("kprobe:f { printf(\"%s\", probe); }", 0);
test("kprobe:f { probe(\"blah\"); }", 1);
test("kprobe:f { probe(); }", 1);
test("kprobe:f { probe(123); }", 1);
}
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