Commit 7404d0e8 authored by Brendan Gregg's avatar Brendan Gregg Committed by GitHub

Merge pull request #95 from iovisor/username

add username builtin
parents d0ba7cd8 83a9e292
......@@ -54,10 +54,10 @@ void CodegenLLVM::visit(Builtin &builtin)
expr_ = b_.CreateAnd(pidtgid, 0xffffffff);
}
}
else if (builtin.ident == "uid" || builtin.ident == "gid")
else if (builtin.ident == "uid" || builtin.ident == "gid" || builtin.ident == "username")
{
Value *uidgid = b_.CreateGetUidGid();
if (builtin.ident == "uid")
if (builtin.ident == "uid" || builtin.ident == "username")
{
expr_ = b_.CreateAnd(uidgid, 0xffffffff);
}
......
......@@ -76,6 +76,9 @@ void SemanticAnalyser::visit(Builtin &builtin)
builtin.type = SizedType(Type::name, 8);
probe_->need_expansion = true;
}
else if (builtin.ident == "username") {
builtin.type = SizedType(Type::username, 8);
}
else {
builtin.type = SizedType(Type::none, 0);
err_ << "Unknown builtin variable: '" << builtin.ident << "'" << std::endl;
......
......@@ -212,6 +212,8 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
auto args = std::get<1>(bpftrace->printf_args_[printf_id]);
std::vector<uint64_t> arg_values;
std::vector<std::unique_ptr<char>> resolved_symbols;
std::vector<std::unique_ptr<char>> resolved_usernames;
char *name;
for (auto arg : args)
{
......@@ -249,6 +251,11 @@ void perf_event_printer(void *cb_cookie, void *data, int size)
bpftrace->resolve_usym(*(uint64_t*)(arg_data+arg.offset), *(uint64_t*)(arg_data+arg.offset + 8)).c_str()));
arg_values.push_back((uint64_t)resolved_symbols.back().get());
break;
case Type::username:
resolved_usernames.emplace_back(strdup(
bpftrace->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(bpftrace->resolve_name(*(uint64_t*)(arg_data+arg.offset)).c_str());
arg_values.push_back((uint64_t)name);
......@@ -660,6 +667,8 @@ int BPFtrace::print_map(IMap &map, uint32_t top, uint32_t div)
std::cout << resolve_sym(*(uintptr_t*)value.data());
else if (map.type_.type == Type::usym)
std::cout << resolve_usym(*(uintptr_t*)value.data(), *(uint64_t*)(value.data() + 8));
else if (map.type_.type == Type::username)
std::cout << resolve_uid(*(uint64_t*)(value.data())) << std::endl;
else if (map.type_.type == Type::string)
std::cout << value.data() << std::endl;
else if (map.type_.type == Type::count || map.type_.type == Type::sum)
......@@ -1107,6 +1116,49 @@ std::string BPFtrace::get_stack(uint64_t stackidpid, bool ustack, int indent)
return stack.str();
}
std::string BPFtrace::resolve_uid(uintptr_t addr)
{
std::string file_name = "/etc/passwd";
std::string uid = std::to_string(addr);
std::string username = "";
std::ifstream file(file_name);
if (file.fail())
{
std::cerr << strerror(errno) << ": " << file_name << std::endl;
return username;
}
std::string line;
bool found = false;
while (std::getline(file, line) && !found)
{
auto fields = split_string(line, ':');
if (fields[2] == uid)
{
found = true;
username = fields[0];
}
}
file.close();
return username;
}
std::vector<std::string> BPFtrace::split_string(std::string &str, char split_by)
{
std::vector<std::string> elems;
std::stringstream ss(str);
std::string value;
while(std::getline(ss, value, split_by)) {
elems.push_back(value);
}
return elems;
}
std::string BPFtrace::resolve_sym(uintptr_t addr, bool show_offset)
{
struct bcc_symbol sym;
......
......@@ -37,6 +37,7 @@ public:
std::string get_stack(uint64_t stackidpid, bool ustack, int indent=0);
std::string resolve_sym(uintptr_t addr, bool show_offset=false);
std::string resolve_usym(uintptr_t addr, int pid, bool show_offset=false);
std::string resolve_uid(uintptr_t addr);
uint64_t resolve_kname(const char *name);
uint64_t resolve_uname(const char *name, const char *path);
std::string resolve_name(uint64_t name_id);
......@@ -87,6 +88,7 @@ private:
static std::string exec_system(const char* cmd);
static std::string hist_index_label(int power);
static std::string lhist_index_label(int number);
static std::vector<std::string> split_string(std::string &str, char split_by);
std::vector<uint8_t> find_empty_key(IMap &map, size_t size) const;
};
......
......@@ -48,7 +48,7 @@ path :(\\.|[_\-\./a-zA-Z0-9])*:
<COMMENT>"*/" BEGIN(INITIAL);
<COMMENT>"EOF" driver.error(loc, std::string("end of file during comment"));
pid|tid|uid|gid|nsecs|cpu|comm|stack|ustack|arg[0-9]|retval|func|name|curtask|rand|ctx {
pid|tid|uid|gid|nsecs|cpu|comm|stack|ustack|arg[0-9]|retval|func|name|curtask|rand|ctx|username {
return Parser::make_BUILTIN(yytext, loc); }
{path} { return Parser::make_PATH(yytext, loc); }
{map} { return Parser::make_MAP(yytext, loc); }
......
......@@ -74,6 +74,8 @@ std::string MapKey::argument_value(BPFtrace &bpftrace,
return bpftrace.resolve_sym(*(uint64_t*)data);
case Type::usym:
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::string:
......
......@@ -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::name || arg_type == Type::username)
arg_type = Type::string; // Symbols should be printed as strings
int offset = 1;
......
......@@ -32,6 +32,7 @@ enum class Type
cast,
join,
name,
username,
};
std::ostream &operator<<(std::ostream &os, Type type);
......
......@@ -1024,6 +1024,57 @@ attributes #1 = { argmemonly nounwind }
)EXPECTED");
}
TEST(codegen, builtin_username)
{
test("kprobe:f { @x = username; @y = gid}",
R"EXPECTED(; Function Attrs: nounwind
declare i64 @llvm.bpf.pseudo(i64, i64) #0
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
define i64 @"kprobe:f"(i8* nocapture readnone) local_unnamed_addr section "s_kprobe:f" {
entry:
%"@y_val" = alloca i64, align 8
%"@y_key" = alloca i64, align 8
%"@x_val" = alloca i64, align 8
%"@x_key" = alloca i64, align 8
%get_uid_gid = tail call i64 inttoptr (i64 15 to i64 ()*)()
%1 = and i64 %get_uid_gid, 4294967295
%2 = bitcast i64* %"@x_key" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %2)
store i64 0, i64* %"@x_key", align 8
%3 = bitcast i64* %"@x_val" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %3)
store i64 %1, i64* %"@x_val", align 8
%pseudo = tail call i64 @llvm.bpf.pseudo(i64 1, i64 1)
%update_elem = call i64 inttoptr (i64 2 to i64 (i8*, i8*, i8*, i64)*)(i64 %pseudo, i64* nonnull %"@x_key", i64* nonnull %"@x_val", i64 0)
call void @llvm.lifetime.end.p0i8(i64 -1, i8* nonnull %2)
call void @llvm.lifetime.end.p0i8(i64 -1, i8* nonnull %3)
%get_uid_gid1 = call i64 inttoptr (i64 15 to i64 ()*)()
%4 = lshr i64 %get_uid_gid1, 32
%5 = bitcast i64* %"@y_key" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %5)
store i64 0, i64* %"@y_key", align 8
%6 = bitcast i64* %"@y_val" to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %6)
store i64 %4, i64* %"@y_val", align 8
%pseudo2 = call i64 @llvm.bpf.pseudo(i64 1, i64 2)
%update_elem3 = call i64 inttoptr (i64 2 to i64 (i8*, i8*, i8*, i64)*)(i64 %pseudo2, i64* nonnull %"@y_key", i64* nonnull %"@y_val", i64 0)
call void @llvm.lifetime.end.p0i8(i64 -1, i8* nonnull %5)
call void @llvm.lifetime.end.p0i8(i64 -1, i8* nonnull %6)
ret i64 0
}
; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
attributes #0 = { nounwind }
attributes #1 = { argmemonly nounwind }
)EXPECTED");
}
TEST(codegen, call_kaddr)
{
// TODO: test kaddr()
......
......@@ -26,6 +26,7 @@ TEST(Parser, builtin_variables)
test("kprobe:f { pid }", "Program\n kprobe:f\n builtin: pid\n");
test("kprobe:f { tid }", "Program\n kprobe:f\n builtin: tid\n");
test("kprobe:f { uid }", "Program\n kprobe:f\n builtin: uid\n");
test("kprobe:f { username }", "Program\n kprobe:f\n builtin: username\n");
test("kprobe:f { gid }", "Program\n kprobe:f\n builtin: gid\n");
test("kprobe:f { nsecs }", "Program\n kprobe:f\n builtin: nsecs\n");
test("kprobe:f { cpu }", "Program\n kprobe:f\n builtin: cpu\n");
......
......@@ -54,6 +54,7 @@ TEST(semantic_analyser, builtin_variables)
test("kprobe:f { pid }", 0);
test("kprobe:f { tid }", 0);
test("kprobe:f { uid }", 0);
test("kprobe:f { username }", 0);
test("kprobe:f { gid }", 0);
test("kprobe:f { nsecs }", 0);
test("kprobe:f { cpu }", 0);
......
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