Skip to content

Commit

Permalink
FieldAnalyser: Resolve fields for structs inside arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
ajor committed Aug 28, 2024
1 parent 85e5d65 commit 105b78f
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ and this project adheres to
- [#3336](https://github.com/bpftrace/bpftrace/pull/3336)
- Fix json formatting for `strftime` function
- [#3381](https://github.com/bpftrace/bpftrace/pull/3381)
- Fix BTF/DWARF parsing for structs contained in arrays
- [#3422](https://github.com/bpftrace/bpftrace/pull/3422)
#### Security
#### Docs
- Remove mention of unsupported character literals
Expand Down
33 changes: 17 additions & 16 deletions src/ast/passes/field_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,22 +90,20 @@ void FieldAnalyser::visit(FieldAccess &acc)
sized_type_ = arg->type;

has_builtin_args_ = false;
} else if (!sized_type_.IsNoneTy()) {
// If the struct type or the field type has not been resolved, add the type
// to the BTF set to let ClangParser resolve it
if (bpftrace_.has_btf_data() && sized_type_.IsRecordTy()) {
SizedType field_type = CreateNone();
if (sized_type_.HasField(acc.field))
field_type = sized_type_.GetField(acc.field).type;

if (!field_type.IsNoneTy())
sized_type_ = field_type;
else {
bpftrace_.btf_set_.insert(sized_type_.GetName());
auto field_type_name = bpftrace_.btf_->type_of(sized_type_.GetName(),
acc.field);
bpftrace_.btf_set_.insert(field_type_name);
}
} else if (sized_type_.IsRecordTy()) {
SizedType field_type = CreateNone();
if (sized_type_.HasField(acc.field))
field_type = sized_type_.GetField(acc.field).type;

if (!field_type.IsNoneTy()) {
sized_type_ = field_type;
} else if (bpftrace_.has_btf_data()) {
// If the struct type or the field type has not been resolved, add the
// type to the BTF set to let ClangParser resolve it
bpftrace_.btf_set_.insert(sized_type_.GetName());
auto field_type_name = bpftrace_.btf_->type_of(sized_type_.GetName(),
acc.field);
bpftrace_.btf_set_.insert(field_type_name);
}
}
}
Expand All @@ -117,6 +115,9 @@ void FieldAnalyser::visit(ArrayAccess &arr)
if (sized_type_.IsPtrTy()) {
sized_type_ = *sized_type_.GetPointeeTy();
resolve_fields(sized_type_);
} else if (sized_type_.IsArrayTy()) {
sized_type_ = *sized_type_.GetElementTy();
resolve_fields(sized_type_);
}
}

Expand Down
8 changes: 8 additions & 0 deletions tests/data/data_source.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ struct Arrays *func_arrays(struct Arrays *arr)
return 0;
}

struct ArrayWithCompoundData {
struct Foo3 *data[2];
};

void func_array_with_compound_data(struct ArrayWithCompoundData *arr)
{
}

struct task_struct {
int pid;
int pgid;
Expand Down
56 changes: 56 additions & 0 deletions tests/field_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,50 @@ TEST_F(field_analyser_btf, btf_arrays_multi_dim)
4U);
}

void test_arrays_compound_data(BPFtrace &bpftrace)
{
ASSERT_TRUE(bpftrace.structs.Has("struct ArrayWithCompoundData"));
auto arrs = bpftrace.structs.Lookup("struct ArrayWithCompoundData").lock();

EXPECT_EQ(arrs->size, 2 * sizeof(uintptr_t));
ASSERT_EQ(arrs->fields.size(), 1U);
ASSERT_TRUE(arrs->HasField("data"));

auto &data_type = arrs->GetField("data").type;
EXPECT_TRUE(data_type.IsArrayTy());
EXPECT_EQ(data_type.GetNumElements(), 2);
EXPECT_EQ(data_type.GetSize(), 2 * sizeof(uintptr_t));

// Check that referenced types n-levels deep are all parsed from BTF

auto &foo3_ptr_type = *data_type.GetElementTy();
ASSERT_TRUE(foo3_ptr_type.IsPtrTy());

auto &foo3_type = *foo3_ptr_type.GetPointeeTy();
ASSERT_TRUE(foo3_type.IsRecordTy());
ASSERT_TRUE(foo3_type.HasField("foo1"));

auto &foo1_ptr_type = foo3_type.GetField("foo1").type;
ASSERT_TRUE(foo1_ptr_type.IsPtrTy());

auto &foo1_type = *foo1_ptr_type.GetPointeeTy();
ASSERT_TRUE(foo1_type.IsRecordTy());
ASSERT_TRUE(foo1_type.HasField("a"));
}

TEST_F(field_analyser_btf, arrays_compound_data)
{
BPFtrace bpftrace;
bpftrace.parse_btf({});
test(bpftrace,
"BEGIN {\n"
" $x = (struct ArrayWithCompoundData *) 0;\n"
" $x->data[0]->foo1->a\n"
"}",
0);
test_arrays_compound_data(bpftrace);
}

TEST_F(field_analyser_btf, btf_types_struct_ptr)
{
BPFtrace bpftrace;
Expand Down Expand Up @@ -495,6 +539,18 @@ TEST_F(field_analyser_dwarf, parse_arrays)
EXPECT_EQ(arrs->GetField("flexible").offset, 64);
}

TEST_F(field_analyser_dwarf, arrays_compound_data)
{
BPFtrace bpftrace;
test(bpftrace,
"uprobe:" + std::string{ bin_ } +
":func_array_with_compound_data {\n"
" args.arr->data[0]->foo1->a;\n"
"}",
0);
test_arrays_compound_data(bpftrace);
}

static void CheckParentFields(const std::shared_ptr<Struct> &cls,
bool is_d_shadowed = false)
{
Expand Down

0 comments on commit 105b78f

Please sign in to comment.