diff --git a/src/dwarf_parser.cpp b/src/dwarf_parser.cpp index a8385edc003f..b8df3c3a0d53 100644 --- a/src/dwarf_parser.cpp +++ b/src/dwarf_parser.cpp @@ -196,30 +196,30 @@ SizedType Dwarf::get_stype(const std::string &type_name) return CreateNone(); } -void Dwarf::resolve_fields(std::shared_ptr str, lldb::SBType type) +void Dwarf::resolve_fields(std::shared_ptr &str, lldb::SBType type, size_t offset) { if (!type.IsValid()) return; - for (uint32_t i = 0; i < type.GetNumberOfVirtualBaseClasses(); i++) { - auto parent = type.GetVirtualBaseClassAtIndex(i); - resolve_fields(str, parent.GetType()); - } - - for (uint32_t i = 0; i < type.GetNumberOfDirectBaseClasses(); i++) { - auto parent = type.GetDirectBaseClassAtIndex(i); - resolve_fields(str, parent.GetType()); - } - for (uint32_t i = 0; i < type.GetNumberOfFields(); i++) { auto field = type.GetFieldAtIndex(i); auto field_type = get_stype(field.GetType()); str->AddField(field.GetName() ?: "", get_stype(field.GetType()), - field.GetOffsetInBytes(), + offset + field.GetOffsetInBytes(), resolve_bitfield(field), false); } + + for (uint32_t i = 0; i < type.GetNumberOfVirtualBaseClasses(); i++) { + auto parent = type.GetVirtualBaseClassAtIndex(i); + resolve_fields(str, parent.GetType(), parent.GetOffsetInBytes()); + } + + for (uint32_t i = 0; i < type.GetNumberOfDirectBaseClasses(); i++) { + auto parent = type.GetDirectBaseClassAtIndex(i); + resolve_fields(str, parent.GetType(), parent.GetOffsetInBytes()); + } } void Dwarf::resolve_fields(const SizedType &type) diff --git a/src/dwarf_parser.h b/src/dwarf_parser.h index 7ebd252068fa..da05b4d4e7ae 100644 --- a/src/dwarf_parser.h +++ b/src/dwarf_parser.h @@ -38,7 +38,7 @@ class Dwarf { std::string get_type_name(lldb::SBType type); SizedType get_stype(lldb::SBType type, bool resolve_structs = true); - void resolve_fields(std::shared_ptr str, lldb::SBType type); + void resolve_fields(std::shared_ptr &str, lldb::SBType type, size_t offset = 0); std::optional resolve_bitfield(lldb::SBTypeMember field); BPFtrace *bpftrace_; diff --git a/tests/data/data_source_cxx.cpp b/tests/data/data_source_cxx.cpp index c6cd3b2b07a8..6405b0658305 100644 --- a/tests/data/data_source_cxx.cpp +++ b/tests/data/data_source_cxx.cpp @@ -26,6 +26,28 @@ class LittleChild : public Child { LittleChild(int a, int b, int c, int d, int e, int f, int g) : Child(a, b, c, d, e, f), g(g) {} }; +struct Top { + int x; +}; + +struct Left : public Top { + int y; +}; + +struct Right : public Top { + int z; +}; + +struct Bottom : public Left, public Right { + int w; +}; + +struct Multi : public Parent, public Top { + int abc; + + Multi(int a, int b, int c, int d, int e) : Parent{a, b, c, d}, Top{e}, abc{e + 1} {} +}; + int func_1(Child &c, Parent &p __attribute__((unused))) { return dynamic_cast(c).d; @@ -36,6 +58,11 @@ int func_2(LittleChild &lc) return dynamic_cast(lc).d; } +int func_3(Multi &m, Bottom &b __attribute__((unused))) +{ + return m.abc; +} + int main(void) { Parent p{1, 2, 3, 4}; @@ -45,5 +72,18 @@ int main(void) LittleChild lc{1, 2, 3, 4, 5, 6, 7}; func_2(lc); + Multi m{1, 2, 3, 4, 5}; + Bottom b{ + { // Left + {1}, // Left's Top + 2 // Left's y + }, { // Right + {3}, // Right's Top + 4 // Right's z + }, + 5 // Bottom's w + }; + func_3(m, b); + return 0; } diff --git a/tests/field_analyser.cpp b/tests/field_analyser.cpp index a3ce1451c516..347dcbe57c01 100644 --- a/tests/field_analyser.cpp +++ b/tests/field_analyser.cpp @@ -564,6 +564,32 @@ TEST_F(field_analyser_dwarf, parse_inheritance_chain) CheckLittleChildFields(cls); } +TEST_F(field_analyser_dwarf, parse_inheritance_multi) +{ + BPFtrace bpftrace; + std::string uprobe = "uprobe:" + std::string(cxx_bin_); + test(bpftrace, uprobe + ":cpp:func_3 { $x = args.m->abc; }", 0); + + ASSERT_TRUE(bpftrace.structs.Has("struct Multi")); + auto cls = bpftrace.structs.Lookup("struct Multi").lock(); + + ASSERT_TRUE(cls->HasFields()); + ASSERT_EQ(cls->fields.size(), 6); + ASSERT_EQ(cls->size, 24); + + CheckParentFields(cls); + + EXPECT_TRUE(cls->HasField("x")); + EXPECT_TRUE(cls->GetField("x").type.IsIntTy()); + EXPECT_EQ(cls->GetField("x").type.GetSize(), 4); + EXPECT_EQ(cls->GetField("x").offset, 16); + + EXPECT_TRUE(cls->HasField("abc")); + EXPECT_TRUE(cls->GetField("abc").type.IsIntTy()); + EXPECT_EQ(cls->GetField("abc").type.GetSize(), 4); + EXPECT_EQ(cls->GetField("abc").offset, 20); +} + TEST_F(field_analyser_dwarf, parse_struct_anonymous_fields) { GTEST_SKIP() << "Anonymous fields not supported #3084";