1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "ast/ast.h"
#include "ast/context.h"
#include "common.h"
namespace bpftrace::test::codegen {
using ::testing::_;
class MockBPFtrace : public BPFtrace {
public:
#pragma GCC diagnostic push
#ifdef __clang__
#pragma GCC diagnostic ignored "-Winconsistent-missing-override"
#endif
MOCK_METHOD5(add_probe,
int(const ast::AttachPoint &,
const ast::Probe &,
ast::ExpansionType,
std::set<std::string>,
int));
#pragma GCC diagnostic pop
int resolve_uname(const std::string &name,
struct symbol *sym,
const std::string &path) const override
{
(void)path;
sym->name = name;
sym->address = 12345;
sym->size = 4;
return 0;
}
bool is_traceable_func(
const std::string &__attribute__((unused)) /*func_name*/) const override
{
return true;
}
bool has_kprobe_multi()
{
return feature_->has_kprobe_multi();
}
};
TEST(codegen, printf_offsets)
{
ast::ASTContext ast("stdin", R"(
struct Foo { char c; int i; char str[10]; }
kprobe:f
{
$foo = (struct Foo*)arg0;
printf("%c %u %s %p\n", $foo->c, $foo->i, $foo->str, 0)
})");
auto bpftrace = get_mock_bpftrace();
auto ok = ast::PassManager()
.put(ast)
.put<BPFtrace>(*bpftrace)
.add(ast::AllParsePasses())
.add(ast::CreateLLVMInitPass())
.add(ast::CreateClangBuildPass())
.add(ast::CreateTypeSystemPass())
.add(ast::CreateSemanticPass())
.add(ast::CreateResourcePass())
.add(ast::AllCompilePasses())
.run();
ASSERT_TRUE(ok && ast.diagnostics().ok());
EXPECT_EQ(bpftrace->resources.printf_args.size(), 1U);
auto fmt = std::get<0>(bpftrace->resources.printf_args[0]).str();
auto &args = std::get<1>(bpftrace->resources.printf_args[0]);
EXPECT_EQ(fmt, "%c %u %s %p\n");
EXPECT_EQ(args.size(), 4U);
EXPECT_TRUE(args[0].type.IsIntTy());
EXPECT_EQ(args[0].type.GetSize(), 1U);
EXPECT_EQ(args[0].offset, 0);
EXPECT_TRUE(args[1].type.IsIntTy());
EXPECT_EQ(args[1].type.GetSize(), 4U);
EXPECT_EQ(args[1].offset, 4);
// Note that the string type has size + 1 in order to signal well-formedness.
// See clang_parser.cpp for this logic.
EXPECT_TRUE(args[2].type.IsStringTy());
EXPECT_EQ(args[2].type.GetSize(), 10U + 1U);
EXPECT_EQ(args[2].offset, 8);
EXPECT_TRUE(args[3].type.IsIntTy());
EXPECT_EQ(args[3].type.GetSize(), 8U);
EXPECT_EQ(args[3].offset, 24);
}
TEST(codegen, probe_count)
{
ast::ASTContext ast("stdin", R"(
kprobe:f { 1; } kprobe:d { 1; }
)");
MockBPFtrace bpftrace;
EXPECT_CALL(bpftrace, add_probe(_, _, _, _, _)).Times(2);
// Override to mockbpffeature.
bpftrace.feature_ = std::make_unique<MockBPFfeature>(true);
auto ok = ast::PassManager()
.put(ast)
.put<BPFtrace>(bpftrace)
.add(ast::AllParsePasses())
.add(ast::CreateLLVMInitPass())
.add(ast::CreateClangBuildPass())
.add(ast::CreateTypeSystemPass())
.add(ast::CreateSemanticPass())
.add(ast::AllCompilePasses())
.run();
ASSERT_TRUE(ok && ast.diagnostics().ok());
}
} // namespace bpftrace::test::codegen
|