blob: aa6d884de1b7f520ac8a67cee31c99dfd5220b10 [file] [log] [blame]
// Copyright 2020 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/console/format_symbol.h"
#include <gtest/gtest.h>
#include "src/developer/debug/zxdb/symbols/call_site.h"
#include "src/developer/debug/zxdb/symbols/call_site_parameter.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/modified_type.h"
#include "src/developer/debug/zxdb/symbols/type_test_support.h"
#include "src/developer/debug/zxdb/symbols/variable.h"
namespace zxdb {
TEST(FormatSymbol, Variable) {
auto int32_type = MakeInt32Type();
std::vector<VariableLocation::Entry> loc_entries;
loc_entries.resize(2);
loc_entries[0].range = AddressRange(0x1000, 0x2000);
loc_entries[0].expression = DwarfExpr({0x30, // DW_OP_lit0
0x71, // DW_OP_breg1
1}); // 1 (param for breg).
loc_entries[1].range = AddressRange(0x3000, 0x4000);
loc_entries[1].expression = DwarfExpr({0x31}); // DW_OP_lit1
auto var = fxl::MakeRefCounted<Variable>(DwarfTag::kVariable, "my_var", int32_type,
VariableLocation(loc_entries));
FormatSymbolOptions opts;
opts.arch = debug::Arch::kX64;
// Format expressions as bytes.
opts.dwarf_expr = FormatSymbolOptions::DwarfExpr::kBytes;
OutputBuffer out = FormatSymbol(nullptr, var.get(), opts);
const char kExpectedBytes[] =
"Variable: my_var\n"
" Type: int32_t\n"
" DWARF tag: DW_TAG_variable (0x34)\n"
" DWARF location (address range + DWARF expression):\n"
" [0x1000, 0x2000): 0x30 0x71 0x01\n"
" [0x3000, 0x4000): 0x31\n";
EXPECT_EQ(kExpectedBytes, out.AsString());
// Format expressions as DWARF operations.
opts.dwarf_expr = FormatSymbolOptions::DwarfExpr::kOps;
out = FormatSymbol(nullptr, var.get(), opts);
const char kExpectedOps[] =
"Variable: my_var\n"
" Type: int32_t\n"
" DWARF tag: DW_TAG_variable (0x34)\n"
" DWARF location (address range + DWARF expression):\n"
" [0x1000, 0x2000): DW_OP_lit0, DW_OP_breg1(1)\n"
" [0x3000, 0x4000): DW_OP_lit1\n";
EXPECT_EQ(kExpectedOps, out.AsString());
// Pretty formatting of expressions.
opts.dwarf_expr = FormatSymbolOptions::DwarfExpr::kPretty;
out = FormatSymbol(nullptr, var.get(), opts);
const char kExpectedPretty[] =
"Variable: my_var\n"
" Type: int32_t\n"
" DWARF tag: DW_TAG_variable (0x34)\n"
" DWARF location (address range + DWARF expression):\n"
" [0x1000, 0x2000): push(0), register(rdx) + 1\n"
" [0x3000, 0x4000): push(1)\n";
EXPECT_EQ(kExpectedPretty, out.AsString());
}
TEST(FormatSymbol, BaseType) {
auto int32_type = MakeInt32Type();
OutputBuffer out = FormatSymbol(nullptr, int32_type.get(), FormatSymbolOptions());
const char kExpected[] =
"Type: int32_t\n"
" DWARF tag: DW_TAG_base_type (0x24)\n"
" Byte size: 4\n"
" DWARF base type: DW_ATE_signed (0x05)\n";
EXPECT_EQ(kExpected, out.AsString());
}
TEST(FormatSymbol, Collection) {
auto int32_type = MakeInt32Type();
// Create a collection. The second member leaves a gap so we can test padding.
auto coll = MakeCollectionType(DwarfTag::kStructureType, "MyStruct",
{{"a", int32_type}, {"b", int32_type}});
// This const cast is evil but it's cleaner to use the test utilities to create all the data
// members and then reach in and make them the way we want (with extra padding) than duplicate all
// of that logic.
const_cast<DataMember*>(coll->data_members()[1].Get()->As<DataMember>())->set_member_location(8);
coll->set_byte_size(12);
// Say it inherits from this empty base class. Since it's empty, it will start at the same offset
// as the first member.
auto base_type = MakeCollectionType(DwarfTag::kStructureType, "BaseStruct", {});
auto base_from = fxl::MakeRefCounted<InheritedFrom>(base_type, 0);
// Virtual inheritance has no location but an expression to compute it. We use a dummy expression.
auto virtual_base_type = MakeCollectionType(DwarfTag::kStructureType, "VirtualBase", {});
auto virtual_base_from = fxl::MakeRefCounted<InheritedFrom>(virtual_base_type, DwarfExpr({0x01}));
coll->set_inherited_from({LazySymbol(base_from), LazySymbol(virtual_base_from)});
OutputBuffer out = FormatSymbol(nullptr, coll.get(), FormatSymbolOptions());
const char kExpectedHeader[] =
"Type: MyStruct\n"
" DWARF tag: DW_TAG_structure_type (0x13)\n"
" Byte size: 12\n"
" Calling convention: DW_CC_normal\n";
const char kMembers[] = // Split off to allow re-use below.
" Members:\n"
" Offset Size Name Type\n"
" <virtual> 0 <base class> VirtualBase\n"
" 0 0 <base class> BaseStruct\n"
" 0 4 a int32_t\n"
" 4 4 <padding>\n"
" 8 4 b int32_t\n";
EXPECT_EQ(std::string(kExpectedHeader) + std::string(kMembers), out.AsString());
// Re-test with a typedef. Typedefs of structures should show the members.
auto coll_typedef = fxl::MakeRefCounted<ModifiedType>(DwarfTag::kTypedef, coll);
coll_typedef->set_assigned_name("MyTypedef");
const char kTypedefHeader[] =
"Type: MyTypedef\n"
" DWARF tag: DW_TAG_typedef (0x16)\n"
" Byte size: 12\n"
" Underlying type: MyStruct\n";
out = FormatSymbol(nullptr, coll_typedef.get(), FormatSymbolOptions());
EXPECT_EQ(std::string(kTypedefHeader) + std::string(kMembers), out.AsString());
}
TEST(FormatSymbol, CallSite) {
DwarfExpr value_expr({0x30, // DW_OP_lit0
0x71, // DW_OP_breg1
1}); // 1 (param for breg).
auto param1 = fxl::MakeRefCounted<CallSiteParameter>(5, value_expr);
auto param2 = fxl::MakeRefCounted<CallSiteParameter>(6, value_expr);
auto call = fxl::MakeRefCounted<CallSite>(0x1000, std::vector<LazySymbol>{param1, param2});
OutputBuffer out = FormatSymbol(nullptr, call.get(), FormatSymbolOptions());
EXPECT_EQ(
"Call Site\n"
" Return to: 0x1000\n"
" Parameters:\n"
" Call site parameter:\n"
" DWARF register #: 5\n"
" Value expression: push(0), dwarf_register(1) + 1\n"
" Call site parameter:\n"
" DWARF register #: 6\n"
" Value expression: push(0), dwarf_register(1) + 1\n",
out.AsString());
}
} // namespace zxdb