| // 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_base_test_setup.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "src/developer/debug/zxdb/symbols/base_type.h" |
| #include "src/developer/debug/zxdb/symbols/data_member.h" |
| #include "src/developer/debug/zxdb/symbols/inherited_from.h" |
| #include "src/developer/debug/zxdb/symbols/mock_module_symbols.h" |
| #include "src/developer/debug/zxdb/symbols/mock_symbol_data_provider.h" |
| #include "src/developer/debug/zxdb/symbols/modified_type.h" |
| #include "src/developer/debug/zxdb/symbols/type.h" |
| #include "src/developer/debug/zxdb/symbols/type_test_support.h" |
| |
| namespace zxdb { |
| |
| constexpr uint32_t VirtualBaseTestSetup::kBaseOffset; |
| constexpr TargetPointer VirtualBaseTestSetup::kVtableRelativeAddress; |
| constexpr TargetPointer VirtualBaseTestSetup::kVtableAbsoluteAddress; |
| constexpr TargetPointer VirtualBaseTestSetup::kDerivedAddress; |
| constexpr TargetPointer VirtualBaseTestSetup::kBaseAddress; |
| const char* VirtualBaseTestSetup::kBaseIName = "base_i"; |
| constexpr uint32_t VirtualBaseTestSetup::kBaseI; |
| const char* VirtualBaseTestSetup::kDerivedIName = "derived_i"; |
| constexpr uint32_t VirtualBaseTestSetup::kDerivedI; |
| |
| VirtualBaseTestSetup::VirtualBaseTestSetup(MockSymbolDataProvider* data_provider, |
| MockModuleSymbols* mock_module_symbols) { |
| vtbl_entry_type = MakeUint64Type(); // Pointer to function "int()" in real life. |
| vtbl_ptr_type = fxl::MakeRefCounted<ModifiedType>(DwarfTag::kPointerType, vtbl_entry_type); |
| vtbl_ptr_type_ptr = fxl::MakeRefCounted<ModifiedType>(DwarfTag::kPointerType, vtbl_ptr_type); |
| |
| auto& index_root = mock_module_symbols->index().root(); |
| |
| // Base class. |
| auto int32_type = MakeInt32Type(); |
| const char kBaseClassName[] = "BaseClass"; |
| base_class = |
| MakeCollectionType(DwarfTag::kStructureType, kBaseClassName, |
| {{"_vptr$BaseClass", vtbl_ptr_type_ptr}, {kBaseIName, int32_type}}); |
| FX_DCHECK(base_class->byte_size() == 12); // point = 8 bytes, int32 = 4. |
| // The artificial flag must be set on the vtable pointer. |
| const_cast<DataMember*>(base_class->data_members()[0].Get()->AsDataMember()) |
| ->set_artificial(true); |
| base_class_indexed = std::make_unique<TestIndexedSymbol>(mock_module_symbols, &index_root, |
| kBaseClassName, base_class); |
| |
| base_class_ptr = fxl::MakeRefCounted<ModifiedType>(DwarfTag::kPointerType, base_class); |
| base_class_ref = fxl::MakeRefCounted<ModifiedType>(DwarfTag::kReferenceType, base_class); |
| |
| // Derived class. |
| // |
| // Leave room at the beginning of the structure for the base class' data. Note that the |
| // DerivedClass doesn't need a _vptr because it has no vtable of its own (its only virtual |
| // functions are on the BaseClass). |
| const char kDerivedClassName[] = "DerivedClass"; |
| derived_class = MakeCollectionTypeWithOffset(DwarfTag::kStructureType, kDerivedClassName, |
| kBaseOffset + base_class->byte_size(), |
| {{kDerivedIName, int32_type}}); |
| FX_DCHECK(derived_class->byte_size() == kBaseOffset + base_class->byte_size() + 4); |
| |
| auto inherited_from = fxl::MakeRefCounted<InheritedFrom>(base_class, kBaseOffset); |
| derived_class->set_inherited_from({LazySymbol(inherited_from)}); |
| derived_class_indexed = std::make_unique<TestIndexedSymbol>(mock_module_symbols, &index_root, |
| kDerivedClassName, derived_class); |
| |
| auto const_base_class = fxl::MakeRefCounted<ModifiedType>(DwarfTag::kConstType, base_class); |
| auto ptr_const_base_class = |
| fxl::MakeRefCounted<ModifiedType>(DwarfTag::kPointerType, const_base_class); |
| auto const_ptr_const_base_class = |
| fxl::MakeRefCounted<ModifiedType>(DwarfTag::kConstType, ptr_const_base_class); |
| |
| derived_data = std::vector<uint8_t>{ |
| // 4-bytes initial padding to make sure we handle offsets correctly. |
| 0, 0, 0, 0, |
| |
| // Base class' data to start with. |
| 0, 0, 0, 0, 0, 0, 0, 0, // _vptr$BaseClass = kVtableAbsoluteAddress |
| // (Filled in below from the constant.) |
| static_cast<uint8_t>(kBaseI), 0, 0, 0, // base_i = kBaseI. |
| |
| // Derived data follows. |
| static_cast<uint8_t>(kDerivedI), 0, 0, 0 // derived_i = kDerivedI. |
| }; |
| // Write the absolute vtable address from the constant. Assumes little-endian. |
| memcpy(&derived_data[4], &kVtableAbsoluteAddress, sizeof(uint64_t)); |
| |
| FX_DCHECK(derived_class->byte_size() == derived_data.size()); |
| data_provider->AddMemory(kDerivedAddress, derived_data); |
| |
| base_vtable = fxl::MakeRefCounted<ElfSymbol>( |
| nullptr, |
| ElfSymbolRecord(ElfSymbolType::kNormal, kVtableRelativeAddress, 0, "_ZTV9BaseClass")); |
| derived_vtable = fxl::MakeRefCounted<ElfSymbol>( |
| nullptr, |
| ElfSymbolRecord(ElfSymbolType::kNormal, kVtableRelativeAddress, 0, "_ZTV12DerivedClass")); |
| |
| // Hook up the vtable pointer. |
| mock_module_symbols->AddSymbolLocations( |
| kVtableAbsoluteAddress, {Location(kVtableAbsoluteAddress, FileLine(), 0, |
| SymbolContext::ForRelativeAddresses(), derived_vtable)}); |
| } |
| |
| } // namespace zxdb |