Skip to content

Commit

Permalink
Add BTF related tests
Browse files Browse the repository at this point in the history
Adding BTF tests that work over included BTF binary data,
which is staticaly generated. The reason is to have the
stable BTF data to build test code on.

The data is generation is explained in the comment in
tests/btf_data.h file.

Adding 2 tests:
  TEST(btf, resolve_struct)
    - test of BTF::resolve_struct function and checks on the proper
      fields output
  TEST(btf, has_struct)
    - test of the BPFtrace::has_struct interface
  • Loading branch information
olsajiri committed Jun 7, 2019
1 parent 59d528b commit 0a1bf92
Show file tree
Hide file tree
Showing 3 changed files with 371 additions and 0 deletions.
9 changes: 9 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ if(HAVE_GET_CURRENT_CGROUP_ID)
endif(HAVE_GET_CURRENT_CGROUP_ID)
target_link_libraries(bpftrace_test arch ast parser resources)

find_library(BPF_LIB bpf)

if (LIBBPF_FOUND AND NOT STATIC_LINKING)
target_sources(bpftrace_test PRIVATE btf.cpp)
target_compile_definitions(bpftrace_test PRIVATE HAVE_LIBBPF)
target_link_libraries(bpftrace_test ${LIBBPF_LIBRARIES})
target_include_directories(bpftrace_test PUBLIC ${LIBBPF_INCLUDE_DIRS})
endif()

if (STATIC_LINKING)
target_link_libraries(bpftrace_test ${LIBBCC_LIBRARIES})
target_link_libraries(bpftrace_test ${LIBBPF_LIBRARY_STATIC})
Expand Down
170 changes: 170 additions & 0 deletions tests/btf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#include <cstdlib>
#include <unistd.h>
#include "gtest/gtest.h"
#include "btf.h"
#include "struct.h"
#include "bpftrace.h"
#include "mocks.h"

namespace bpftrace {
namespace test {
namespace btf {

#include "btf_data.h"

TEST(btf, resolve_struct)
{
BTF btf(data, data_len);

ASSERT_EQ(btf.has_data(), true);

std::map<std::string, Struct> structs;

btf.resolve_struct("Foo3", structs);

//btf.dump_struct("Foo2");

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);

structs.clear();

btf.resolve_struct("spinlock", structs);
//btf.dump_structs(structs);

ASSERT_EQ(structs.size(), 5U);
ASSERT_EQ(structs.count("qspinlock"), 1U);
ASSERT_EQ(structs.count("raw_spinlock"), 1U);
ASSERT_EQ(structs.count("spinlock"), 1U);
ASSERT_EQ(structs.count("type_0"), 1U);
ASSERT_EQ(structs.count("type_9"), 1U);

EXPECT_EQ(structs["qspinlock"].size, 4);
ASSERT_EQ(structs["qspinlock"].fields.size(), 3U);
ASSERT_EQ(structs["qspinlock"].fields.count("locked"), 1U);
ASSERT_EQ(structs["qspinlock"].fields.count("val"), 1U);
ASSERT_EQ(structs["qspinlock"].fields.count("pending"), 1U);

EXPECT_EQ(structs["qspinlock"].fields["locked"].type.type, Type::integer);
EXPECT_EQ(structs["qspinlock"].fields["locked"].type.size, 1U);
EXPECT_EQ(structs["qspinlock"].fields["locked"].offset, 0);

EXPECT_EQ(structs["qspinlock"].fields["pending"].type.type, Type::integer);
EXPECT_EQ(structs["qspinlock"].fields["pending"].type.size, 1U);
EXPECT_EQ(structs["qspinlock"].fields["pending"].offset, 1);

EXPECT_EQ(structs["qspinlock"].fields["val"].type.type, Type::cast);
EXPECT_EQ(structs["qspinlock"].fields["val"].type.size, 4U);
EXPECT_EQ(structs["qspinlock"].fields["val"].offset, 0);
EXPECT_EQ(structs["qspinlock"].fields["val"].type.cast_type, "type_9");

EXPECT_EQ(structs["raw_spinlock"].size, 16);
ASSERT_EQ(structs["raw_spinlock"].fields.size(), 2U);
ASSERT_EQ(structs["raw_spinlock"].fields.count("raw_lock"), 1U);
ASSERT_EQ(structs["raw_spinlock"].fields.count("owner"), 1U);

EXPECT_EQ(structs["raw_spinlock"].fields["raw_lock"].type.type, Type::cast);
EXPECT_EQ(structs["raw_spinlock"].fields["raw_lock"].type.size, 4U);
EXPECT_EQ(structs["raw_spinlock"].fields["raw_lock"].offset, 0);
EXPECT_EQ(structs["raw_spinlock"].fields["raw_lock"].type.cast_type, "qspinlock");

EXPECT_EQ(structs["raw_spinlock"].fields["owner"].type.type, Type::cast);
EXPECT_EQ(structs["raw_spinlock"].fields["owner"].type.size, 8U);
EXPECT_EQ(structs["raw_spinlock"].fields["owner"].offset, 8);
EXPECT_EQ(structs["raw_spinlock"].fields["owner"].type.cast_type, "type_0");
EXPECT_EQ(structs["raw_spinlock"].fields["owner"].type.is_pointer, true);

EXPECT_EQ(structs["spinlock"].size, 16);
ASSERT_EQ(structs["spinlock"].fields.size(), 2U);
ASSERT_EQ(structs["spinlock"].fields.count("padding"), 1U);
ASSERT_EQ(structs["spinlock"].fields.count("rlock"), 1U);

EXPECT_EQ(structs["spinlock"].fields["padding"].type.type, Type::string);
EXPECT_EQ(structs["spinlock"].fields["padding"].type.size, 10U);
EXPECT_EQ(structs["spinlock"].fields["padding"].offset, 0);

EXPECT_EQ(structs["spinlock"].fields["rlock"].type.type, Type::cast);
EXPECT_EQ(structs["spinlock"].fields["rlock"].type.size, 16U);
EXPECT_EQ(structs["spinlock"].fields["rlock"].offset, 0);
EXPECT_EQ(structs["spinlock"].fields["rlock"].type.cast_type, "raw_spinlock");
}

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

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

EXPECT_EQ(write(fd, data, data_len), data_len);
close(fd);

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

auto bpftrace = get_strict_mock_bpftrace();

ASSERT_EQ(bpftrace->has_struct("Foo1"), true);
ASSERT_EQ(bpftrace->has_struct("Foo"), false);
ASSERT_EQ(bpftrace->has_struct("Foo2"), true);
ASSERT_EQ(bpftrace->has_struct("Foo2"), true);
ASSERT_EQ(bpftrace->has_struct("qspinlock"), true);
ASSERT_EQ(bpftrace->has_struct("raw_spinlock"), true);
ASSERT_EQ(bpftrace->has_struct("spinlock"), true);

std::remove(path);
}

} // namespace btf
} // namespace test
} // namespace bpftrace
192 changes: 192 additions & 0 deletions tests/btf_data.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
#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;
};

typedef struct {
int counter;
} atomic_t;

typedef struct refcount_struct {
atomic_t refs;
} refcount_t;

typedef struct qspinlock {
union {
atomic_t val;
struct {
unsigned char locked;
unsigned char pending;
};
};
} arch_spinlock_t;

typedef struct raw_spinlock {
arch_spinlock_t raw_lock;
void *owner;
} raw_spinlock_t;

typedef struct spinlock {
union {
struct raw_spinlock rlock;
unsigned char padding[10];
};
} spinlock_t;


It is generated via following commands:

$ cat btf.c
struct Foo1 {
int a;
char b;
long c;
};

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

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

typedef struct {
int counter;
} atomic_t;

typedef struct refcount_struct {
atomic_t refs;
} refcount_t;

typedef struct qspinlock {
union {
atomic_t val;
struct {
unsigned char locked;
unsigned char pending;
};
};
} arch_spinlock_t;

typedef struct raw_spinlock {
arch_spinlock_t raw_lock;
void *owner;
} raw_spinlock_t;

typedef struct spinlock {
union {
struct raw_spinlock rlock;
unsigned char padding[10];
};
} spinlock_t;

struct Foo3 krava;
spinlock_t sl;
refcount_t ref;

int main(void)
{
return 0;
}

$ gcc -o btf -g btf.c
$ pahole -J btf
$ objcopy --dump-section .BTF=data btf
$ xxd -i data

The gcc optimize some union/structs out and do not include
their names in the data. We see type_9 instead of atomic_t
and refcount_t is left out completely.

#endif

unsigned char data[] = {
0x9f, 0xeb, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0xf0, 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,
0x2b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x2d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x01, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x53, 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,
0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00,
0x3e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x43, 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, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00,
0xa4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00,
0xbf, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0b, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
0x4c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05,
0x04, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x10, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04,
0x10, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05,
0x10, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x08, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x17, 0x00, 0x00, 0x00, 0x00, 0x46, 0x6f, 0x6f,
0x31, 0x00, 0x46, 0x6f, 0x6f, 0x32, 0x00, 0x46, 0x6f, 0x6f, 0x33, 0x00,
0x61, 0x00, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x73, 0x70, 0x69, 0x6e, 0x6c,
0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x00, 0x61, 0x74, 0x6f, 0x6d, 0x69, 0x63,
0x5f, 0x74, 0x00, 0x62, 0x00, 0x63, 0x00, 0x63, 0x68, 0x61, 0x72, 0x00,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x00, 0x66, 0x00, 0x66, 0x6f,
0x6f, 0x31, 0x00, 0x66, 0x6f, 0x6f, 0x32, 0x00, 0x69, 0x6e, 0x74, 0x00,
0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x20,
0x69, 0x6e, 0x74, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x75, 0x6e, 0x73,
0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x00, 0x6f, 0x77,
0x6e, 0x65, 0x72, 0x00, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x00,
0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x00, 0x71, 0x73, 0x70, 0x69,
0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x00, 0x72, 0x61, 0x77, 0x5f, 0x6c, 0x6f,
0x63, 0x6b, 0x00, 0x72, 0x61, 0x77, 0x5f, 0x73, 0x70, 0x69, 0x6e, 0x6c,
0x6f, 0x63, 0x6b, 0x00, 0x72, 0x65, 0x66, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x5f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x00, 0x72, 0x65, 0x66, 0x63,
0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x00, 0x72, 0x65, 0x66, 0x73, 0x00,
0x72, 0x6c, 0x6f, 0x63, 0x6b, 0x00, 0x73, 0x70, 0x69, 0x6e, 0x6c, 0x6f,
0x63, 0x6b, 0x00, 0x73, 0x70, 0x69, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
0x74, 0x00, 0x75, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x63,
0x68, 0x61, 0x72, 0x00, 0x76, 0x61, 0x6c, 0x00
};

unsigned int data_len = 812;

0 comments on commit 0a1bf92

Please sign in to comment.