Commit 0e82af01 authored by Alastair Robertson's avatar Alastair Robertson

Add func builtin

parent 834a8eae
...@@ -104,6 +104,7 @@ Variables: ...@@ -104,6 +104,7 @@ Variables:
- `ustack` - User stack trace - `ustack` - User stack trace
- `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
Functions: Functions:
- `quantize(int n)` - produce a log2 histogram of values of `n` - `quantize(int n)` - produce a log2 histogram of values of `n`
......
...@@ -8,6 +8,7 @@ namespace arch { ...@@ -8,6 +8,7 @@ namespace arch {
int max_arg(); int max_arg();
int arg_offset(int arg_num); int arg_offset(int arg_num);
int ret_offset(); int ret_offset();
int pc_offset();
std::string name(); std::string name();
} // namespace arch } // namespace arch
......
...@@ -29,6 +29,11 @@ int ret_offset() ...@@ -29,6 +29,11 @@ int ret_offset()
return 10; // ax return 10; // ax
} }
int pc_offset()
{
return 16; // ip
}
std::string name() std::string name()
{ {
return std::string("x86_64"); return std::string("x86_64");
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include "bcc_syms.h" #include "bcc_syms.h"
#include "common.h" #include "common.h"
#include "perf_reader.h" #include "perf_reader.h"
#include "syms.h"
#include "bpftrace.h" #include "bpftrace.h"
#include "attached_probe.h" #include "attached_probe.h"
...@@ -20,17 +19,10 @@ int BPFtrace::add_probe(ast::Probe &p) ...@@ -20,17 +19,10 @@ int BPFtrace::add_probe(ast::Probe &p)
probe.path = p.path; probe.path = p.path;
probe.attach_point = p.attach_point; probe.attach_point = p.attach_point;
probe.name = p.name; probe.name = p.name;
if (p.type == "kprobe") probe.type = probetype(p.type);
probe.type = ProbeType::kprobe;
else if (p.type == "kretprobe") if (p.type == "BEGIN")
probe.type = ProbeType::kretprobe;
else if (p.type == "uprobe")
probe.type = ProbeType::uprobe;
else if (p.type == "uretprobe")
probe.type = ProbeType::uretprobe;
else if (p.type == "BEGIN")
{ {
probe.type = ProbeType::uprobe;
probe.path = bpftrace_path_; probe.path = bpftrace_path_;
probe.attach_point = "BEGIN_trigger"; probe.attach_point = "BEGIN_trigger";
special_probes_.push_back(probe); special_probes_.push_back(probe);
...@@ -38,14 +30,11 @@ int BPFtrace::add_probe(ast::Probe &p) ...@@ -38,14 +30,11 @@ int BPFtrace::add_probe(ast::Probe &p)
} }
else if (p.type == "END") else if (p.type == "END")
{ {
probe.type = ProbeType::uprobe;
probe.path = bpftrace_path_; probe.path = bpftrace_path_;
probe.attach_point = "END_trigger"; probe.attach_point = "END_trigger";
special_probes_.push_back(probe); special_probes_.push_back(probe);
return 0; return 0;
} }
else
abort();
probes_.push_back(probe); probes_.push_back(probe);
return 0; return 0;
...@@ -60,6 +49,7 @@ void perf_event_printer(void *cb_cookie, void *data, int size) ...@@ -60,6 +49,7 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
auto args = bpftrace->format_strings_[fmt]; auto args = bpftrace->format_strings_[fmt];
std::vector<uint64_t> arg_values; std::vector<uint64_t> arg_values;
std::vector<std::string> resolved_symbols;
for (auto arg : args) for (auto arg : args)
{ {
switch (arg.type) switch (arg.type)
...@@ -70,6 +60,14 @@ void perf_event_printer(void *cb_cookie, void *data, int size) ...@@ -70,6 +60,14 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
case Type::string: case Type::string:
arg_values.push_back((uint64_t)arg_data); arg_values.push_back((uint64_t)arg_data);
break; break;
case Type::sym:
resolved_symbols.push_back(bpftrace->resolve_sym(*(uint64_t*)arg_data));
arg_values.push_back((uint64_t)resolved_symbols.back().c_str());
break;
case Type::usym:
resolved_symbols.push_back(bpftrace->resolve_usym(*(uint64_t*)arg_data));
arg_values.push_back((uint64_t)resolved_symbols.back().c_str());
break;
default: default:
abort(); abort();
} }
...@@ -221,7 +219,7 @@ void BPFtrace::poll_perf_events(int epollfd, int timeout) ...@@ -221,7 +219,7 @@ void BPFtrace::poll_perf_events(int epollfd, int timeout)
return; return;
} }
int BPFtrace::print_maps() const int BPFtrace::print_maps()
{ {
for(auto &mapmap : maps_) for(auto &mapmap : maps_)
{ {
...@@ -239,7 +237,7 @@ int BPFtrace::print_maps() const ...@@ -239,7 +237,7 @@ int BPFtrace::print_maps() const
return 0; return 0;
} }
int BPFtrace::print_map(Map &map) const int BPFtrace::print_map(Map &map)
{ {
std::vector<uint8_t> old_key; std::vector<uint8_t> old_key;
try try
...@@ -269,6 +267,10 @@ int BPFtrace::print_map(Map &map) const ...@@ -269,6 +267,10 @@ int BPFtrace::print_map(Map &map) const
std::cout << get_stack(*(uint32_t*)value.data(), false, 8); std::cout << get_stack(*(uint32_t*)value.data(), false, 8);
else if (map.type_.type == Type::ustack) else if (map.type_.type == Type::ustack)
std::cout << get_stack(*(uint32_t*)value.data(), true, 8); std::cout << get_stack(*(uint32_t*)value.data(), true, 8);
else if (map.type_.type == Type::sym)
std::cout << resolve_sym(*(uint64_t*)value.data());
else if (map.type_.type == Type::usym)
std::cout << resolve_usym(*(uint64_t*)value.data());
else if (map.type_.type == Type::string) else if (map.type_.type == Type::string)
std::cout << value.data() << std::endl; std::cout << value.data() << std::endl;
else else
...@@ -282,7 +284,7 @@ int BPFtrace::print_map(Map &map) const ...@@ -282,7 +284,7 @@ int BPFtrace::print_map(Map &map) const
return 0; return 0;
} }
int BPFtrace::print_map_quantize(Map &map) const int BPFtrace::print_map_quantize(Map &map)
{ {
// A quantize-map adds an extra 8 bytes onto the end of its key for storing // A quantize-map adds an extra 8 bytes onto the end of its key for storing
// the bucket number. // the bucket number.
...@@ -436,7 +438,7 @@ std::vector<uint8_t> BPFtrace::find_empty_key(Map &map, size_t size) const ...@@ -436,7 +438,7 @@ std::vector<uint8_t> BPFtrace::find_empty_key(Map &map, size_t size) const
throw std::runtime_error("Could not find empty key"); throw std::runtime_error("Could not find empty key");
} }
std::string BPFtrace::get_stack(uint32_t stackid, bool ustack, int indent) const std::string BPFtrace::get_stack(uint32_t stackid, bool ustack, int indent)
{ {
auto stack_trace = std::vector<uint64_t>(MAX_STACK_SIZE); auto stack_trace = std::vector<uint64_t>(MAX_STACK_SIZE);
int err = bpf_lookup_elem(stackid_map_->mapfd_, &stackid, stack_trace.data()); int err = bpf_lookup_elem(stackid_map_->mapfd_, &stackid, stack_trace.data());
...@@ -448,21 +450,46 @@ std::string BPFtrace::get_stack(uint32_t stackid, bool ustack, int indent) const ...@@ -448,21 +450,46 @@ std::string BPFtrace::get_stack(uint32_t stackid, bool ustack, int indent) const
std::ostringstream stack; std::ostringstream stack;
std::string padding(indent, ' '); std::string padding(indent, ' ');
struct bcc_symbol sym;
KSyms ksyms;
stack << "\n"; stack << "\n";
for (auto &addr : stack_trace) for (auto &addr : stack_trace)
{ {
if (addr == 0) if (addr == 0)
break; break;
if (!ustack && ksyms.resolve_addr(addr, &sym)) if (!ustack)
stack << padding << sym.name << "+" << sym.offset << ":" << sym.module << std::endl; stack << padding << resolve_sym(addr, true) << std::endl;
else else
stack << padding << (void*)addr << std::endl; stack << padding << resolve_usym(addr) << std::endl;
} }
return stack.str(); return stack.str();
} }
std::string BPFtrace::resolve_sym(uint64_t addr, bool show_offset)
{
struct bcc_symbol sym;
std::ostringstream symbol;
if (ksyms.resolve_addr(addr, &sym))
{
symbol << sym.name;
if (show_offset)
symbol << "+" << sym.offset;
}
else
{
symbol << (void*)addr;
}
return symbol.str();
}
std::string BPFtrace::resolve_usym(uint64_t addr) const
{
// TODO
std::ostringstream symbol;
symbol << (void*)addr;
return symbol.str();
}
} // namespace bpftrace } // namespace bpftrace
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "syms.h"
#include "ast.h" #include "ast.h"
#include "attached_probe.h" #include "attached_probe.h"
#include "map.h" #include "map.h"
...@@ -18,8 +20,10 @@ public: ...@@ -18,8 +20,10 @@ public:
virtual ~BPFtrace() { } virtual ~BPFtrace() { }
virtual int add_probe(ast::Probe &p); virtual int add_probe(ast::Probe &p);
int run(); int run();
int print_maps() const; int print_maps();
std::string get_stack(uint32_t stackid, bool ustack, int indent=0) const; std::string get_stack(uint32_t stackid, bool ustack, int indent=0);
std::string resolve_sym(uint64_t addr, bool show_offset=false);
std::string resolve_usym(uint64_t addr) const;
std::map<std::string, std::unique_ptr<Map>> maps_; std::map<std::string, std::unique_ptr<Map>> maps_;
std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_; std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_;
...@@ -33,12 +37,13 @@ private: ...@@ -33,12 +37,13 @@ private:
std::vector<Probe> special_probes_; std::vector<Probe> special_probes_;
std::vector<std::unique_ptr<AttachedProbe>> attached_probes_; std::vector<std::unique_ptr<AttachedProbe>> attached_probes_;
std::vector<std::unique_ptr<AttachedProbe>> special_attached_probes_; std::vector<std::unique_ptr<AttachedProbe>> special_attached_probes_;
KSyms ksyms;
std::unique_ptr<AttachedProbe> attach_probe(Probe &probe); std::unique_ptr<AttachedProbe> attach_probe(Probe &probe);
int setup_perf_events(); int setup_perf_events();
static void poll_perf_events(int epollfd, int timeout=-1); static void poll_perf_events(int epollfd, int timeout=-1);
int print_map(Map &map) const; int print_map(Map &map);
int print_map_quantize(Map &map) const; int print_map_quantize(Map &map);
int print_quantize(std::vector<uint64_t> values) const; int print_quantize(std::vector<uint64_t> values) const;
std::string quantize_index_label(int power) const; std::string quantize_index_label(int power) const;
std::vector<uint8_t> find_empty_key(Map &map, size_t size) const; std::vector<uint8_t> find_empty_key(Map &map, size_t size) const;
......
...@@ -89,6 +89,14 @@ void CodegenLLVM::visit(Builtin &builtin) ...@@ -89,6 +89,14 @@ void CodegenLLVM::visit(Builtin &builtin)
b_.CreateProbeRead(dst, 8, src); b_.CreateProbeRead(dst, 8, src);
expr_ = b_.CreateLoad(dst); expr_ = b_.CreateLoad(dst);
} }
else if (builtin.ident == "func")
{
AllocaInst *dst = b_.CreateAllocaBPF(builtin.type, builtin.ident);
int offset = arch::pc_offset() * sizeof(uintptr_t);
Value *src = b_.CreateGEP(ctx_, b_.getInt64(offset));
b_.CreateProbeRead(dst, 8, src);
expr_ = b_.CreateLoad(dst);
}
else else
{ {
abort(); abort();
...@@ -147,6 +155,8 @@ void CodegenLLVM::visit(Call &call) ...@@ -147,6 +155,8 @@ void CodegenLLVM::visit(Call &call)
switch (t.type) switch (t.type)
{ {
case Type::integer: case Type::integer:
case Type::sym:
case Type::usym:
elements.push_back(b_.getInt64Ty()); elements.push_back(b_.getInt64Ty());
break; break;
case Type::string: case Type::string:
......
...@@ -30,7 +30,7 @@ std::string MapKey::argument_type_list() const ...@@ -30,7 +30,7 @@ std::string MapKey::argument_type_list() const
return list.str(); return list.str();
} }
std::string MapKey::argument_value_list(const BPFtrace &bpftrace, std::string MapKey::argument_value_list(BPFtrace &bpftrace,
const std::vector<uint8_t> &data) const const std::vector<uint8_t> &data) const
{ {
size_t n = args_.size(); size_t n = args_.size();
...@@ -51,7 +51,7 @@ std::string MapKey::argument_value_list(const BPFtrace &bpftrace, ...@@ -51,7 +51,7 @@ std::string MapKey::argument_value_list(const BPFtrace &bpftrace,
return list.str(); return list.str();
} }
std::string MapKey::argument_value(const BPFtrace &bpftrace, std::string MapKey::argument_value(BPFtrace &bpftrace,
const SizedType &arg, const SizedType &arg,
const void *data) const void *data)
{ {
...@@ -69,6 +69,10 @@ std::string MapKey::argument_value(const BPFtrace &bpftrace, ...@@ -69,6 +69,10 @@ std::string MapKey::argument_value(const BPFtrace &bpftrace,
return bpftrace.get_stack(*(uint32_t*)data, false); return bpftrace.get_stack(*(uint32_t*)data, false);
case Type::ustack: case Type::ustack:
return bpftrace.get_stack(*(uint32_t*)data, true); return bpftrace.get_stack(*(uint32_t*)data, true);
case Type::sym:
return bpftrace.resolve_sym(*(uint64_t*)data);
case Type::usym:
return bpftrace.resolve_usym(*(uint64_t*)data);
case Type::string: case Type::string:
return std::string((char*)data); return std::string((char*)data);
} }
......
...@@ -18,11 +18,11 @@ public: ...@@ -18,11 +18,11 @@ public:
size_t size() const; size_t size() const;
std::string argument_type_list() const; std::string argument_type_list() const;
std::string argument_value_list(const BPFtrace &bpftrace, std::string argument_value_list(BPFtrace &bpftrace,
const std::vector<uint8_t> &data) const; const std::vector<uint8_t> &data) const;
private: private:
static std::string argument_value(const BPFtrace &bpftrace, static std::string argument_value(BPFtrace &bpftrace,
const SizedType &arg, const SizedType &arg,
const void *data); const void *data);
}; };
......
...@@ -31,6 +31,8 @@ std::string verify_format_string(const std::string &fmt, std::vector<SizedType> ...@@ -31,6 +31,8 @@ std::string verify_format_string(const std::string &fmt, std::vector<SizedType>
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 arg_type = args.at(i).type;
if (arg_type == Type::sym || arg_type == Type::usym)
arg_type = Type::string; // Symbols should be printed as strings
char token = token_iter->str()[1]; char token = token_iter->str()[1];
Type token_type; Type token_type;
......
...@@ -46,6 +46,16 @@ void SemanticAnalyser::visit(Builtin &builtin) ...@@ -46,6 +46,16 @@ void SemanticAnalyser::visit(Builtin &builtin)
else if (builtin.ident == "comm") { else if (builtin.ident == "comm") {
builtin.type = SizedType(Type::string, STRING_SIZE); builtin.type = SizedType(Type::string, STRING_SIZE);
} }
else if (builtin.ident == "func") {
ProbeType type = probetype(probe_->type);
if (type == ProbeType::kprobe || type == ProbeType::kretprobe)
builtin.type = SizedType(Type::sym, 8);
else if (type == ProbeType::uprobe || type == ProbeType::uretprobe)
builtin.type = SizedType(Type::usym, 8);
else
err_ << "The func builtin can not be used with '" << probe_->type
<< "' probes" << std::endl;
}
else if (!builtin.ident.compare(0, 3, "arg") && builtin.ident.size() == 4 && else if (!builtin.ident.compare(0, 3, "arg") && builtin.ident.size() == 4 &&
builtin.ident.at(3) >= '0' && builtin.ident.at(3) <= '9') { builtin.ident.at(3) >= '0' && builtin.ident.at(3) <= '9') {
int arg_num = atoi(builtin.ident.substr(3).c_str()); int arg_num = atoi(builtin.ident.substr(3).c_str());
...@@ -309,6 +319,7 @@ void SemanticAnalyser::visit(Probe &probe) ...@@ -309,6 +319,7 @@ void SemanticAnalyser::visit(Probe &probe)
{ {
// Clear out map of variable names - variables should be probe-local // Clear out map of variable names - variables should be probe-local
variable_val_.clear(); variable_val_.clear();
probe_ = &probe;
if (probe.type == "kprobe" || probe.type == "kretprobe") { if (probe.type == "kprobe" || probe.type == "kretprobe") {
if (probe.attach_point == "") if (probe.attach_point == "")
......
...@@ -45,6 +45,7 @@ private: ...@@ -45,6 +45,7 @@ private:
bool is_final_pass() const; bool is_final_pass() const;
Probe *probe_;
std::map<std::string, SizedType> variable_val_; std::map<std::string, SizedType> variable_val_;
std::map<std::string, SizedType> map_val_; std::map<std::string, SizedType> map_val_;
std::map<std::string, MapKey> map_key_; std::map<std::string, MapKey> map_key_;
......
...@@ -32,8 +32,27 @@ std::string typestr(Type t) ...@@ -32,8 +32,27 @@ std::string typestr(Type t)
case Type::stack: return "stack"; break; case Type::stack: return "stack"; break;
case Type::ustack: return "ustack"; break; case Type::ustack: return "ustack"; break;
case Type::string: return "string"; break; case Type::string: return "string"; break;
case Type::sym: return "sym"; break;
case Type::usym: return "usym"; break;
default: abort(); default: abort();
} }
} }
ProbeType probetype(const std::string &type)
{
if (type == "kprobe")
return ProbeType::kprobe;
else if (type == "kretprobe")
return ProbeType::kretprobe;
else if (type == "uprobe")
return ProbeType::uprobe;
else if (type == "uretprobe")
return ProbeType::uretprobe;
else if (type == "BEGIN")
return ProbeType::uprobe;
else if (type == "END")
return ProbeType::uprobe;
return ProbeType::invalid;
}
} // namespace bpftrace } // namespace bpftrace
...@@ -21,6 +21,8 @@ enum class Type ...@@ -21,6 +21,8 @@ enum class Type
stack, stack,
ustack, ustack,
string, string,
sym,
usym,
}; };
std::ostream &operator<<(std::ostream &os, Type type); std::ostream &operator<<(std::ostream &os, Type type);
...@@ -40,6 +42,7 @@ std::ostream &operator<<(std::ostream &os, const SizedType &type); ...@@ -40,6 +42,7 @@ std::ostream &operator<<(std::ostream &os, const SizedType &type);
enum class ProbeType enum class ProbeType
{ {
invalid,
kprobe, kprobe,
kretprobe, kretprobe,
uprobe, uprobe,
...@@ -47,6 +50,7 @@ enum class ProbeType ...@@ -47,6 +50,7 @@ enum class ProbeType
}; };
std::string typestr(Type t); std::string typestr(Type t);
ProbeType probetype(const std::string &type);
class Probe class Probe
{ {
......
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