| // 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. |
| |
| #ifndef SRC_DEVELOPER_DEBUG_ZXDB_EXPR_VIRTUAL_INHERITANCE_TEST_SETUP_H_ |
| #define SRC_DEVELOPER_DEBUG_ZXDB_EXPR_VIRTUAL_INHERITANCE_TEST_SETUP_H_ |
| |
| #include <vector> |
| |
| #include "src/developer/debug/zxdb/expr/expr_value.h" |
| #include "src/developer/debug/zxdb/symbols/arch.h" |
| #include "src/developer/debug/zxdb/symbols/collection.h" |
| #include "src/developer/debug/zxdb/symbols/inherited_from.h" |
| |
| namespace zxdb { |
| |
| class MockEvalContext; |
| class MockSymbolDataProvider; |
| |
| // Setup the required information for a test hierarchy including virtual inheritance. Virtual |
| // inheritance in C++ isn't just inheritance with virtual functions, but rather: |
| // |
| // class Derived : public virtual Bar { ... } |
| // |
| // The "virtual" in this case means that the base class is accessed indirectly, allowing diamond |
| // inheritance to be resolved. This indirect operation is expressed as an expression in the |
| // DWARF inheritance information rather than the constant offset used by normal inheritance. |
| // |
| // This class sets up an inheritance hierarchy with three steps of inheritance between four classes: |
| // |
| // class Derived : public IntermediateDerived { // Non-virtual. |
| // int derived_i = 1; |
| // }; |
| // class IntermediateDerived : public virtual IntermediateBase { // Virtual |
| // int intermediate_derived_i = 2; |
| // }; |
| // class IntermediateBase : public Base { // Non-virtual |
| // int intermediate_base_i = 3; |
| // }; |
| // class Base { |
| // int base_i = 4; |
| // }; |
| // |
| // The binary structure looks like this: |
| // Value |
| // +----------------------------------+------------+ |
| // Derived -> | derived_i (4 bytes) | 1 | |
| // +----------------------------------+------------+ |
| // IntermediateDerived -> | <vtable_ptr> (8 bytes) | kVtablePtr | |
| // | intermediate_derived_i (4 bytes) | 2 | |
| // +----------------------------------+------------+ |
| // IntermediateBase -> | intermediate_base_i (4 bytes) | 3 | |
| // +----------------------------------+------------+ |
| // Base -> | base_i (4 bytes) | 4 | |
| // +----------------------------------+------------+ |
| // |
| // Note that this is actually backwards than most compilers will generated (they will normally |
| // put "Base" at the beginning of "IntermediateBase") but doing it this way allows us to have an |
| // offset for each step of inheritance which is better for testing. |
| // |
| // +---------------------------------------------------------------------+ |
| // kVirtualDataAddress -> | <offset of "IntermediateBase" from "IntermediateDerived"> (8 bytes) | |
| // | <some other value> (8 bytes) | |
| // | <some other value> (8 bytes) | |
| // +---------------------------------------------------------------------+ |
| // vtable_ptr -> | <vtable entries> | |
| // | ... | |
| // |
| // The vtable_ptr referenced in the structure is 24 bytes after the offset needed (this is taken |
| // from what GCC generated for a test). This offset is retrieved and added to the |
| // IntermediateDerived pointer to get the address of IntermediateBase (so the offset should be 4). |
| // |
| // This uses GCC's style of expressions. See also ResolveCollectionTest.VirtualInheritance which |
| // tests Clang's version of virtual inheritance. |
| struct VirtualInheritanceTestSetup { |
| VirtualInheritanceTestSetup(); |
| |
| // Sets the mock vtable data to be served. |
| void SaveMockData(MockSymbolDataProvider* mock) const; |
| |
| fxl::RefPtr<Collection> derived; |
| fxl::RefPtr<InheritedFrom> intermediate_derived_inherited; // Base -> IntermediateDerived. |
| fxl::RefPtr<Collection> intermediate_derived; |
| fxl::RefPtr<InheritedFrom> intermediate_base_inherited; // IntermediateDerived->IntermediateBase |
| fxl::RefPtr<Collection> intermediate_base; |
| fxl::RefPtr<InheritedFrom> base_inherited; // IntermediateBase -> Base |
| fxl::RefPtr<Collection> base; |
| |
| // If the object is placed at derived_address, the other addresses here should follow. |
| static constexpr TargetPointer kDerivedAddress = 0x12345678; |
| static constexpr TargetPointer kIntermediateDerivedAddress = kDerivedAddress + 4; |
| static constexpr TargetPointer kIntermediateBaseAddress = kIntermediateDerivedAddress + 12; |
| static constexpr TargetPointer kBaseAddress = kIntermediateBaseAddress + 4; |
| |
| static constexpr TargetPointer kVirtualDataAddress = 0x01020304; |
| static constexpr TargetPointer kVtablePtr = kVirtualDataAddress + 12; |
| |
| // Data representing a derived object. |
| ExprValue derived_value; |
| |
| // Data that goes at kVirtualDataAddress. |
| std::vector<uint8_t> virtual_data; |
| }; |
| |
| } // namespace zxdb |
| |
| #endif // SRC_DEVELOPER_DEBUG_ZXDB_EXPR_VIRTUAL_INHERITANCE_TEST_SETUP_H_ |