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

Add func builtin

parent 834a8eae
......@@ -104,6 +104,7 @@ Variables:
- `ustack` - User stack trace
- `arg0`, `arg1`, ... etc. - Arguments to the function being traced
- `retval` - Return value from function being traced
- `func` - Name of the function currently being traced
Functions:
- `quantize(int n)` - produce a log2 histogram of values of `n`
......
......@@ -8,6 +8,7 @@ namespace arch {
int max_arg();
int arg_offset(int arg_num);
int ret_offset();
int pc_offset();
std::string name();
} // namespace arch
......
......@@ -29,6 +29,11 @@ int ret_offset()
return 10; // ax
}
int pc_offset()
{
return 16; // ip
}
std::string name()
{
return std::string("x86_64");
......
......@@ -6,7 +6,6 @@
#include "bcc_syms.h"
#include "common.h"
#include "perf_reader.h"
#include "syms.h"
#include "bpftrace.h"
#include "attached_probe.h"
......@@ -20,17 +19,10 @@ int BPFtrace::add_probe(ast::Probe &p)
probe.path = p.path;
probe.attach_point = p.attach_point;
probe.name = p.name;
if (p.type == "kprobe")
probe.type = ProbeType::kprobe;
else if (p.type == "kretprobe")
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(p.type);
if (p.type == "BEGIN")
{
probe.type = ProbeType::uprobe;
probe.path = bpftrace_path_;
probe.attach_point = "BEGIN_trigger";
special_probes_.push_back(probe);
......@@ -38,14 +30,11 @@ int BPFtrace::add_probe(ast::Probe &p)
}
else if (p.type == "END")
{
probe.type = ProbeType::uprobe;
probe.path = bpftrace_path_;
probe.attach_point = "END_trigger";
special_probes_.push_back(probe);
return 0;
}
else
abort();
probes_.push_back(probe);
return 0;
......@@ -60,6 +49,7 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
auto args = bpftrace->format_strings_[fmt];
std::vector<uint64_t> arg_values;
std::vector<std::string> resolved_symbols;
for (auto arg : args)
{
switch (arg.type)
......@@ -70,6 +60,14 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
case Type::string:
arg_values.push_back((uint64_t)arg_data);
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:
abort();
}
......@@ -221,7 +219,7 @@ void BPFtrace::poll_perf_events(int epollfd, int timeout)
return;
}
int BPFtrace::print_maps() const
int BPFtrace::print_maps()
{
for(auto &mapmap : maps_)
{
......@@ -239,7 +237,7 @@ int BPFtrace::print_maps() const
return 0;
}
int BPFtrace::print_map(Map &map) const
int BPFtrace::print_map(Map &map)
{
std::vector<uint8_t> old_key;
try
......@@ -269,6 +267,10 @@ int BPFtrace::print_map(Map &map) const
std::cout << get_stack(*(uint32_t*)value.data(), false, 8);
else if (map.type_.type == Type::ustack)
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)
std::cout << value.data() << std::endl;
else
......@@ -282,7 +284,7 @@ int BPFtrace::print_map(Map &map) const
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
// the bucket number.
......@@ -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");
}
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);
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
std::ostringstream stack;
std::string padding(indent, ' ');
struct bcc_symbol sym;
KSyms ksyms;
stack << "\n";
for (auto &addr : stack_trace)
{
if (addr == 0)
break;
if (!ustack && ksyms.resolve_addr(addr, &sym))
stack << padding << sym.name << "+" << sym.offset << ":" << sym.module << std::endl;
if (!ustack)
stack << padding << resolve_sym(addr, true) << std::endl;
else
stack << padding << (void*)addr << std::endl;
stack << padding << resolve_usym(addr) << std::endl;
}
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
......@@ -4,6 +4,8 @@
#include <memory>
#include <vector>
#include "syms.h"
#include "ast.h"
#include "attached_probe.h"
#include "map.h"
......@@ -18,8 +20,10 @@ public:
virtual ~BPFtrace() { }
virtual int add_probe(ast::Probe &p);
int run();
int print_maps() const;
std::string get_stack(uint32_t stackid, bool ustack, int indent=0) const;
int print_maps();
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::tuple<uint8_t *, uintptr_t>> sections_;
......@@ -33,12 +37,13 @@ private:
std::vector<Probe> special_probes_;
std::vector<std::unique_ptr<AttachedProbe>> attached_probes_;
std::vector<std::unique_ptr<AttachedProbe>> special_attached_probes_;
KSyms ksyms;
std::unique_ptr<AttachedProbe> attach_probe(Probe &probe);
int setup_perf_events();
static void poll_perf_events(int epollfd, int timeout=-1);
int print_map(Map &map) const;
int print_map_quantize(Map &map) const;
int print_map(Map &map);
int print_map_quantize(Map &map);
int print_quantize(std::vector<uint64_t> values) const;
std::string quantize_index_label(int power) const;
std::vector<uint8_t> find_empty_key(Map &map, size_t size) const;
......
......@@ -89,6 +89,14 @@ void CodegenLLVM::visit(Builtin &builtin)
b_.CreateProbeRead(dst, 8, src);
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
{
abort();
......@@ -147,6 +155,8 @@ void CodegenLLVM::visit(Call &call)
switch (t.type)
{
case Type::integer:
case Type::sym:
case Type::usym:
elements.push_back(b_.getInt64Ty());
break;
case Type::string:
......
......@@ -30,7 +30,7 @@ std::string MapKey::argument_type_list() const
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
{
size_t n = args_.size();
......@@ -51,7 +51,7 @@ std::string MapKey::argument_value_list(const BPFtrace &bpftrace,
return list.str();
}
std::string MapKey::argument_value(const BPFtrace &bpftrace,
std::string MapKey::argument_value(BPFtrace &bpftrace,
const SizedType &arg,
const void *data)
{
......@@ -69,6 +69,10 @@ std::string MapKey::argument_value(const BPFtrace &bpftrace,
return bpftrace.get_stack(*(uint32_t*)data, false);
case Type::ustack:
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:
return std::string((char*)data);
}
......
......@@ -18,11 +18,11 @@ public:
size_t size() 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;
private:
static std::string argument_value(const BPFtrace &bpftrace,
static std::string argument_value(BPFtrace &bpftrace,
const SizedType &arg,
const void *data);
};
......
......@@ -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++)
{
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];
Type token_type;
......
......@@ -46,6 +46,16 @@ void SemanticAnalyser::visit(Builtin &builtin)
else if (builtin.ident == "comm") {
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 &&
builtin.ident.at(3) >= '0' && builtin.ident.at(3) <= '9') {
int arg_num = atoi(builtin.ident.substr(3).c_str());
......@@ -309,6 +319,7 @@ void SemanticAnalyser::visit(Probe &probe)
{
// Clear out map of variable names - variables should be probe-local
variable_val_.clear();
probe_ = &probe;
if (probe.type == "kprobe" || probe.type == "kretprobe") {
if (probe.attach_point == "")
......
......@@ -45,6 +45,7 @@ private:
bool is_final_pass() const;
Probe *probe_;
std::map<std::string, SizedType> variable_val_;
std::map<std::string, SizedType> map_val_;
std::map<std::string, MapKey> map_key_;
......
......@@ -32,8 +32,27 @@ std::string typestr(Type t)
case Type::stack: return "stack"; break;
case Type::ustack: return "ustack"; break;
case Type::string: return "string"; break;
case Type::sym: return "sym"; break;
case Type::usym: return "usym"; break;
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
......@@ -21,6 +21,8 @@ enum class Type
stack,
ustack,
string,
sym,
usym,
};
std::ostream &operator<<(std::ostream &os, Type type);
......@@ -40,6 +42,7 @@ std::ostream &operator<<(std::ostream &os, const SizedType &type);
enum class ProbeType
{
invalid,
kprobe,
kretprobe,
uprobe,
......@@ -47,6 +50,7 @@ enum class ProbeType
};
std::string typestr(Type t);
ProbeType probetype(const std::string &type);
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