| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/debug/zxdb/expr/virtual_inheritance_test_setup.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "llvm/BinaryFormat/Dwarf.h" |
| #include "src/developer/debug/zxdb/symbols/mock_symbol_data_provider.h" |
| #include "src/developer/debug/zxdb/symbols/type_test_support.h" |
| |
| namespace zxdb { |
| |
| VirtualInheritanceTestSetup::VirtualInheritanceTestSetup() { |
| auto int32_type = MakeInt32Type(); |
| |
| // Base. |
| base = MakeCollectionType(DwarfTag::kClassType, "Base", {{"base_i", int32_type}}); |
| |
| // IntermediateBase. |
| intermediate_base = MakeCollectionType(DwarfTag::kClassType, "IntermediateBase", |
| {{"intermediate_base_i", int32_type}}); |
| FX_CHECK(intermediate_base->byte_size() == kBaseAddress - kIntermediateBaseAddress); |
| // Make room for "Base" which follows the intermediate_base_i data. |
| base_inherited = fxl::MakeRefCounted<InheritedFrom>(base, intermediate_base->byte_size()); |
| intermediate_base->set_byte_size(intermediate_base->byte_size() + base->byte_size()); |
| intermediate_base->set_inherited_from({LazySymbol(base_inherited)}); |
| |
| // IntermediateDerived. |
| // |
| // The vtable pointer will actually be declared as some kind of pointer. But we never need the |
| // type so just make an 8-byte value as a placeholder. |
| auto uint64_type = MakeUint64Type(); |
| intermediate_derived = MakeCollectionType( |
| DwarfTag::kClassType, "IntermediateDerived", |
| {{"_vptr.IntermediateDerived", uint64_type}, {"intermediate_derived_i", int32_type}}); |
| FX_CHECK(intermediate_derived->byte_size() == |
| kIntermediateBaseAddress - kIntermediateDerivedAddress); |
| // Make room for the base classes. |
| intermediate_derived->set_byte_size(intermediate_derived->byte_size() + |
| intermediate_base->byte_size()); |
| |
| // Virtual inheritance. This expression is what GCC generated for a simple example. Recall the |
| // initial stack state for running this program will have the address of IntermediateDerived. |
| DwarfExpr expression({ |
| llvm::dwarf::DW_OP_dup, // Make 2 copies of the IntermediateDerived address. |
| llvm::dwarf::DW_OP_deref, // Read the vtable_ptr to top of stack. |
| llvm::dwarf::DW_OP_lit24, // Move pointer backwards 24 bytes to point to the offset. |
| llvm::dwarf::DW_OP_minus, // (cont) |
| llvm::dwarf::DW_OP_deref, // Read the offset from the computed pointer. |
| llvm::dwarf::DW_OP_plus // Add the IntermediateDerived address and the offset. |
| }); |
| intermediate_base_inherited = fxl::MakeRefCounted<InheritedFrom>(intermediate_base, expression); |
| intermediate_derived->set_inherited_from({LazySymbol(intermediate_base_inherited)}); |
| |
| // Derived. |
| derived = MakeCollectionType(DwarfTag::kClassType, "Derived", {{"derived_i", int32_type}}); |
| FX_CHECK(derived->byte_size() == kIntermediateDerivedAddress - kDerivedAddress); |
| intermediate_derived_inherited = |
| fxl::MakeRefCounted<InheritedFrom>(intermediate_derived, derived->byte_size()); |
| derived->set_byte_size(derived->byte_size() + intermediate_derived->byte_size()); |
| derived->set_inherited_from({LazySymbol(intermediate_derived_inherited)}); |
| |
| // Object. |
| std::vector<uint8_t> derived_data = { |
| 0x01, 0x00, 0x00, 0x00, // derived_i = 1. |
| 0x1c, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, // vtable_ptr = kVtablePtr. |
| 0x02, 0x00, 0x00, 0x00, // intermediate_derived_i = 2. |
| 0x03, 0x00, 0x00, 0x00, // intermediate_base_i = 3. |
| 0x04, 0x00, 0x00, 0x00, // base_i = 4. |
| }; |
| FX_CHECK(derived_data.size() == derived->byte_size()); |
| derived_value = ExprValue(derived, derived_data, ExprValueSource(kDerivedAddress)); |
| |
| // Vtable data. |
| virtual_data = std::vector<uint8_t>{ |
| // Offset of base in derived for the virtual inheritance, expressed in 64-bit little-endian. |
| static_cast<uint8_t>(kIntermediateBaseAddress - kIntermediateDerivedAddress), 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, |
| |
| // This is extra data to cover the whole vtable range. It shouldn't be technically needed. |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| } |
| |
| void VirtualInheritanceTestSetup::SaveMockData(MockSymbolDataProvider* mock) const { |
| mock->AddMemory(kDerivedAddress, derived_value.data().bytes()); |
| mock->AddMemory(kVirtualDataAddress, virtual_data); |
| } |
| |
| } // namespace zxdb |