Skip to content

Commit

Permalink
Add BTF tests
Browse files Browse the repository at this point in the history
Adding BTF test to clang_parser modules
with generated BTF data.
  • Loading branch information
olsajiri committed Jul 29, 2019
1 parent 1df787d commit 1d46b50
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 2 deletions.
78 changes: 78 additions & 0 deletions src/btf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,89 @@ static int libbpf_print(enum libbpf_print_level level, const char *msg, va_list
return vfprintf(stderr, msg, ap);
}

static unsigned char *get_data(const char *file, ssize_t *sizep)
{
ssize_t ret;
int fd;

fd = open(file, O_RDONLY);
if (fd < 0)
return NULL;

struct stat st;

if (fstat(fd, &st))
{
close(fd);
return NULL;
}

unsigned char *data;
unsigned int size;

size = st.st_size;

data = (unsigned char *) malloc(size);
if (!data)
{
close(fd);
return NULL;
}

ret = read(fd, data, size);
if (ret <= 0)
{
close(fd);
free(data);
return NULL;
}

close(fd);

*sizep = size;
return data;
}

void BTF::init_test(char *file)
{
unsigned char *data;
ssize_t size;

data = get_data(file, &size);
if (data == NULL)
{
std::cerr << "BTF: failed to read data from: " << file << std::endl;
btf = NULL;
return;
}

btf = btf__new(data, (__u32) size);
if (IS_ERR(btf))
{
std::cerr << "BTF: failed to initialize data" << std::endl;
btf = NULL;
}
else
{
libbpf_set_print(libbpf_print);
state = OK;
}
free(data);
}

BTF::BTF(void) : btf(NULL), state(NODATA)
{
struct utsname uts;
char *path;

// Try to get BTF file from BPFTRACE_BTF_TEST env
path = std::getenv("BPFTRACE_BTF_TEST");
if (path)
{
init_test(path);
return;
}

if (uname(&uts))
{
std::cerr << "BTF: failed to get uname" << std::endl;
Expand Down
2 changes: 2 additions & 0 deletions src/btf.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class BTF
std::string c_def(std::string& name);

private:
void init_test(char *file);

struct btf *btf;
enum state state = NODATA;
};
Expand Down
48 changes: 48 additions & 0 deletions tests/btf_data.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#if 0
The data consists of following source file objects:

struct Foo1 {
int a;
char b;
long c;
};

struct Foo2 {
int a;
struct Foo1 f;
};

struct Foo3 {
struct Foo1 *foo1;
struct Foo2 *foo2;
};
#endif

unsigned char btf_data[] = {
0x9f, 0xeb, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x01, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01,
0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00,
0x1d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00,
0x00, 0x46, 0x6f, 0x6f, 0x31, 0x00, 0x46, 0x6f, 0x6f, 0x32, 0x00, 0x46,
0x6f, 0x6f, 0x33, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x63, 0x68,
0x61, 0x72, 0x00, 0x66, 0x00, 0x66, 0x6f, 0x6f, 0x31, 0x00, 0x66, 0x6f,
0x6f, 0x32, 0x00, 0x69, 0x6e, 0x74, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x20,
0x69, 0x6e, 0x74, 0x00
};
unsigned int btf_data_len = 268;
92 changes: 90 additions & 2 deletions tests/clang_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ namespace clang_parser {

using StructMap = std::map<std::string, Struct>;

static void parse(const std::string &input, BPFtrace &bpftrace, bool result = true)
static void parse(const std::string &input, BPFtrace &bpftrace, bool result = true,
const std::string& probe = "kprobe:sys_read { 1 }")
{
auto extended_input = input + "kprobe:sys_read { 1 }";
auto extended_input = input + probe;
Driver driver(bpftrace);
ASSERT_EQ(driver.parse_str(extended_input), 0);

Expand Down Expand Up @@ -380,6 +381,93 @@ TEST(clang_parser, parse_fail)
parse("struct a { int a; struct b b; };", bpftrace, false);
}

#ifdef HAVE_LIBBPF_BTF_DUMP

#include "btf_data.h"

TEST(clang_parser, btf)
{
char *path = strdup("/tmp/XXXXXX");
ASSERT_TRUE(path != NULL);

int fd = mkstemp(path);
ASSERT_TRUE(fd >= 0);

EXPECT_EQ(write(fd, btf_data, btf_data_len), btf_data_len);
close(fd);

ASSERT_EQ(setenv("BPFTRACE_BTF_TEST", path, true), 0);

BPFtrace bpftrace;
parse("", bpftrace, true,
"kprobe:sys_read {\n"
" @x1 = (struct Foo1 *) curtask;\n"
" @x2 = (struct Foo2 *) curtask;\n"
" @x3 = (struct Foo3 *) curtask;\n"
"}");

// clear the environment
unsetenv("BPFTRACE_BTF_TEST");
std::remove(path);

StructMap &structs = bpftrace.structs_;

ASSERT_EQ(structs.size(), 3U);
ASSERT_EQ(structs.count("Foo1"), 1U);
ASSERT_EQ(structs.count("Foo2"), 1U);
ASSERT_EQ(structs.count("Foo3"), 1U);

EXPECT_EQ(structs["Foo1"].size, 16);
ASSERT_EQ(structs["Foo1"].fields.size(), 3U);
ASSERT_EQ(structs["Foo1"].fields.count("a"), 1U);
ASSERT_EQ(structs["Foo1"].fields.count("b"), 1U);
ASSERT_EQ(structs["Foo1"].fields.count("c"), 1U);

EXPECT_EQ(structs["Foo1"].fields["a"].type.type, Type::integer);
EXPECT_EQ(structs["Foo1"].fields["a"].type.size, 4U);
EXPECT_EQ(structs["Foo1"].fields["a"].offset, 0);

EXPECT_EQ(structs["Foo1"].fields["b"].type.type, Type::integer);
EXPECT_EQ(structs["Foo1"].fields["b"].type.size, 1U);
EXPECT_EQ(structs["Foo1"].fields["b"].offset, 4);

EXPECT_EQ(structs["Foo1"].fields["c"].type.type, Type::integer);
EXPECT_EQ(structs["Foo1"].fields["c"].type.size, 8U);
EXPECT_EQ(structs["Foo1"].fields["c"].offset, 8);

EXPECT_EQ(structs["Foo2"].size, 24);
ASSERT_EQ(structs["Foo2"].fields.size(), 2U);
ASSERT_EQ(structs["Foo2"].fields.count("a"), 1U);
ASSERT_EQ(structs["Foo2"].fields.count("f"), 1U);

EXPECT_EQ(structs["Foo2"].fields["a"].type.type, Type::integer);
EXPECT_EQ(structs["Foo2"].fields["a"].type.size, 4U);
EXPECT_EQ(structs["Foo2"].fields["a"].offset, 0);

EXPECT_EQ(structs["Foo2"].fields["f"].type.type, Type::cast);
EXPECT_EQ(structs["Foo2"].fields["f"].type.size, 16U);
EXPECT_EQ(structs["Foo2"].fields["f"].offset, 8);

EXPECT_EQ(structs["Foo3"].size, 16);
ASSERT_EQ(structs["Foo3"].fields.size(), 2U);
ASSERT_EQ(structs["Foo3"].fields.count("foo1"), 1U);
ASSERT_EQ(structs["Foo3"].fields.count("foo2"), 1U);

EXPECT_EQ(structs["Foo3"].fields["foo1"].type.type, Type::cast);
EXPECT_EQ(structs["Foo3"].fields["foo1"].type.size, 8U);
EXPECT_EQ(structs["Foo3"].fields["foo1"].type.is_pointer, true);
EXPECT_EQ(structs["Foo3"].fields["foo1"].type.cast_type, "Foo1");
EXPECT_EQ(structs["Foo3"].fields["foo1"].offset, 0);

EXPECT_EQ(structs["Foo3"].fields["foo2"].type.type, Type::cast);
EXPECT_EQ(structs["Foo3"].fields["foo2"].type.size, 8U);
EXPECT_EQ(structs["Foo3"].fields["foo2"].type.is_pointer, true);
EXPECT_EQ(structs["Foo3"].fields["foo2"].type.cast_type, "Foo2");
EXPECT_EQ(structs["Foo3"].fields["foo2"].offset, 8);
}

#endif // HAVE_LIBBPF_BTF_DUMP

} // namespace clang_parser
} // namespace test
} // namespace bpftrace

0 comments on commit 1d46b50

Please sign in to comment.