| // 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. | |
| std::vector<uint8_t> 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()); | |
| mock->AddMemory(kVirtualDataAddress, virtual_data); | |
| } | |
| } // namespace zxdb |