blob: 0d27960ec75f4631517b9d1171a06c424bbee1ae [file] [log] [blame]
// 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_