blob: 3cf549bb4f9d5699a016865a64346db6a89169ab [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.
#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