blob: 9c64616ad17407737e04a61ba5ddd2945854c7c5 [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/client/inline_thread_controller_test.h"
#include "src/developer/debug/ipc/records.h"
#include "src/developer/debug/zxdb/symbols/function.h"
#include "src/developer/debug/zxdb/symbols/symbol_context.h"
namespace zxdb {
namespace {
fxl::RefPtr<Function> MakeFunction(const char* name, bool is_inline,
AddressRanges ranges) {
DwarfTag tag =
is_inline ? DwarfTag::kInlinedSubroutine : DwarfTag::kSubprogram;
auto func = fxl::MakeRefCounted<Function>(tag);
func->set_assigned_name(name);
func->set_code_ranges(std::move(ranges));
return func;
}
} // namespace
const uint64_t InlineThreadControllerTest::kTopSP = 0x2010;
const uint64_t InlineThreadControllerTest::kMiddleSP = 0x2020;
const uint64_t InlineThreadControllerTest::kBottomSP = 0x2040;
// These address ranges must all be inside the symbolized module address so
// tests can mock symbols and line lookups inside of them.
const AddressRange InlineThreadControllerTest::kTopFunctionRange(
kSymbolizedModuleAddress + 0x30000, kSymbolizedModuleAddress + 0x40000);
// Must be inside the top function.
const AddressRange InlineThreadControllerTest::kTopInlineFunctionRange(
kSymbolizedModuleAddress + 0x30100, kSymbolizedModuleAddress + 0x30200);
const AddressRange InlineThreadControllerTest::kMiddleFunctionRange(
kSymbolizedModuleAddress + 0x10000, kSymbolizedModuleAddress + 0x20000);
// Must be inside the middle function
const AddressRange InlineThreadControllerTest::kMiddleInline1FunctionRange(
kSymbolizedModuleAddress + 0x10100, kSymbolizedModuleAddress + 0x10200);
// Must be inside the middle inline 1 function with same start address.
const AddressRange InlineThreadControllerTest::kMiddleInline2FunctionRange(
kSymbolizedModuleAddress + 0x10100, kSymbolizedModuleAddress + 0x10110);
// Note that the Stack object currently treats the location of caller of an
// inline frame to be the inline call site, while for physical frames this will
// be the following line. The reason for the difference is that inline
// functions don't necessarily have a clear return address, and the actual call
// is the easiest thing to compute.
const FileLine InlineThreadControllerTest::kTopInlineFileLine("file.cc", 11);
const FileLine InlineThreadControllerTest::kTopFileLine("file.cc", 15);
const FileLine InlineThreadControllerTest::kMiddleInline2FileLine("file.cc",
22);
const FileLine InlineThreadControllerTest::kMiddleInline1FileLine("file.cc",
25);
const FileLine InlineThreadControllerTest::kMiddleFileLine("file.cc", 30);
// static
fxl::RefPtr<Function> InlineThreadControllerTest::GetTopFunction() {
return MakeFunction("Top", false, AddressRanges(kTopFunctionRange));
}
// static
fxl::RefPtr<Function> InlineThreadControllerTest::GetTopInlineFunction() {
return MakeFunction("TopInline", true,
AddressRanges(kTopInlineFunctionRange));
}
// static
fxl::RefPtr<Function> InlineThreadControllerTest::GetMiddleFunction() {
return MakeFunction("Middle", false, AddressRanges(kMiddleFunctionRange));
}
// static
fxl::RefPtr<Function> InlineThreadControllerTest::GetMiddleInline1Function() {
return MakeFunction("MiddleInline1", true,
AddressRanges(kMiddleInline1FunctionRange));
}
// static
fxl::RefPtr<Function> InlineThreadControllerTest::GetMiddleInline2Function() {
return MakeFunction("MiddleInline2", true,
AddressRanges(kMiddleInline2FunctionRange));
}
// static
Location InlineThreadControllerTest::GetTopLocation(uint64_t address) {
return Location(address, kTopFileLine, 0,
SymbolContext::ForRelativeAddresses(),
LazySymbol(GetTopFunction()));
}
// static
Location InlineThreadControllerTest::GetTopInlineLocation(uint64_t address) {
return Location(address, kTopInlineFileLine, 0,
SymbolContext::ForRelativeAddresses(),
LazySymbol(GetTopInlineFunction()));
}
// static
Location InlineThreadControllerTest::GetMiddleLocation(uint64_t address) {
return Location(address, kMiddleFileLine, 0,
SymbolContext::ForRelativeAddresses(),
LazySymbol(GetMiddleFunction()));
}
// static
Location InlineThreadControllerTest::GetMiddleInline1Location(
uint64_t address) {
return Location(address, kMiddleInline1FileLine, 0,
SymbolContext::ForRelativeAddresses(),
LazySymbol(GetMiddleInline1Function()));
}
// static
Location InlineThreadControllerTest::GetMiddleInline2Location(
uint64_t address) {
return Location(address, kMiddleInline2FileLine, 0,
SymbolContext::ForRelativeAddresses(),
LazySymbol(GetMiddleInline2Function()));
}
// static
std::unique_ptr<MockFrame> InlineThreadControllerTest::GetTopFrame(
uint64_t address) {
return std::make_unique<MockFrame>(nullptr, nullptr,
debug_ipc::StackFrame(address, kTopSP),
GetTopLocation(address));
}
// static
std::unique_ptr<MockFrame> InlineThreadControllerTest::GetTopInlineFrame(
uint64_t address, MockFrame* top) {
// The location is ambiguous if the address is at the beginning of the range.
return std::make_unique<MockFrame>(
nullptr, nullptr, debug_ipc::StackFrame(address, kTopSP),
GetTopInlineLocation(address), kTopSP, top,
address == kTopInlineFunctionRange.begin());
}
// static
std::unique_ptr<MockFrame> InlineThreadControllerTest::GetMiddleFrame(
uint64_t address) {
return std::make_unique<MockFrame>(nullptr, nullptr,
debug_ipc::StackFrame(address, kMiddleSP),
GetMiddleLocation(address), kMiddleSP);
}
// static
std::unique_ptr<MockFrame> InlineThreadControllerTest::GetMiddleInline1Frame(
uint64_t address, MockFrame* middle) {
return std::make_unique<MockFrame>(
nullptr, nullptr, debug_ipc::StackFrame(address, kMiddleSP),
GetMiddleInline1Location(address), kMiddleSP, middle,
address == kMiddleInline1FunctionRange.begin());
}
// static
std::unique_ptr<MockFrame> InlineThreadControllerTest::GetMiddleInline2Frame(
uint64_t address, MockFrame* middle) {
return std::make_unique<MockFrame>(
nullptr, nullptr, debug_ipc::StackFrame(address, kMiddleSP),
GetMiddleInline2Location(address), kMiddleSP, middle,
address == kMiddleInline2FunctionRange.begin());
}
// static
std::unique_ptr<MockFrame> InlineThreadControllerTest::GetBottomFrame(
uint64_t address) {
return std::make_unique<MockFrame>(
nullptr, nullptr, debug_ipc::StackFrame(address, kBottomSP),
Location(Location::State::kSymbolized, address));
}
// static
std::vector<std::unique_ptr<MockFrame>> InlineThreadControllerTest::GetStack() {
AddressRange top_inline_range = kTopInlineFunctionRange;
auto top_frame = GetTopFrame(top_inline_range.begin());
AddressRange top_middle_inline2_range = kMiddleInline2FunctionRange;
auto middle_frame = GetMiddleFrame(top_middle_inline2_range.begin());
std::vector<std::unique_ptr<MockFrame>> frames;
frames.push_back(
GetTopInlineFrame(top_inline_range.begin(), top_frame.get()));
frames.push_back(std::move(top_frame));
// These inlined functions in the middle of the stack must not be ambiguous
// because the stack will never generate ambiguous inlined functions for
// anything but the top frame. To do this, the address bust be after the
// beginning of the code range.
frames.push_back(GetMiddleInline2Frame(top_middle_inline2_range.begin() + 1,
middle_frame.get()));
frames.push_back(GetMiddleInline1Frame(top_middle_inline2_range.begin() + 1,
middle_frame.get()));
frames.push_back(std::move(middle_frame));
frames.push_back(GetBottomFrame(0x100000000));
return frames;
}
// static
std::vector<std::unique_ptr<Frame>>
InlineThreadControllerTest::MockFrameVectorToFrameVector(
std::vector<std::unique_ptr<MockFrame>> mock_frames) {
std::vector<std::unique_ptr<Frame>> frames;
for (auto& mf : mock_frames)
frames.push_back(std::move(mf));
return frames;
}
} // namespace zxdb