[LLDB] Dump valid ranges of variables

This allows `image lookup -a ... -v` to print variables only if the given
address is covered by the valid ranges of the variables. Since variables created
in dwarf plugin always has empty scope range, print the variable if it has
empty scope.

Differential Revision: https://reviews.llvm.org/D119963
This commit is contained in:
Zequan Wu 2022-02-16 11:18:54 -08:00
parent c33dbc2a2d
commit 15983c28aa
16 changed files with 218 additions and 136 deletions

View File

@ -229,6 +229,14 @@ public:
/// \param[in] fallback_style
/// The display style for the address.
///
/// \param[in] addr_byte_size
/// The address byte size for the address.
///
/// \param[in] all_ranges
/// If true, dump all valid ranges and value ranges for the variable that
/// contains the address, otherwise dumping the range that contains the
/// address.
///
/// \return
/// Returns \b true if the address was able to be displayed.
/// File and load addresses may be unresolved and it may not be
@ -238,7 +246,8 @@ public:
/// \see Address::DumpStyle
bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
DumpStyle fallback_style = DumpStyleInvalid,
uint32_t addr_byte_size = UINT32_MAX) const;
uint32_t addr_byte_size = UINT32_MAX,
bool all_ranges = false) const;
AddressClass GetAddressClass() const;

View File

@ -15,6 +15,7 @@
#include "lldb/Utility/Scalar.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-private.h"
#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
#include <functional>
class DWARFUnit;
@ -55,18 +56,10 @@ public:
/// \param[in] level
/// The level of verbosity to use.
///
/// \param[in] location_list_base_addr
/// If this is a location list based expression, this is the
/// address of the object that owns it. NOTE: this value is
/// different from the DWARF version of the location list base
/// address which is compile unit relative. This base address
/// is the address of the object that owns the location list.
///
/// \param[in] abi
/// An optional ABI plug-in that can be used to resolve register
/// names.
void GetDescription(Stream *s, lldb::DescriptionLevel level,
lldb::addr_t location_list_base_addr, ABI *abi) const;
void GetDescription(Stream *s, lldb::DescriptionLevel level, ABI *abi) const;
/// Return true if the location expression contains data
bool IsValid() const;
@ -217,6 +210,13 @@ public:
lldb::addr_t func_load_addr, lldb::addr_t address,
ABI *abi);
bool DumpLocations(Stream *s, lldb::DescriptionLevel level,
lldb::addr_t func_load_addr, lldb::addr_t addr, ABI *abi);
bool GetLocationExpressions(
lldb::addr_t load_function_start,
llvm::function_ref<bool(llvm::DWARFLocationExpression)> callback) const;
bool MatchesOperand(StackFrame &frame, const Instruction::Operand &op);
llvm::Optional<DataExtractor>

View File

@ -77,7 +77,9 @@ public:
const DWARFExpression &LocationExpression() const { return m_location; }
bool DumpLocationForAddress(Stream *s, const Address &address);
// When given invalid address, it dumps all locations. Otherwise it only dumps
// the location that contains this address.
bool DumpLocations(Stream *s, const Address &address);
size_t MemorySize() const;

View File

@ -50,6 +50,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/Timer.h"
#include "lldb/lldb-private-enumerations.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/FileSystem.h"
@ -1429,7 +1430,8 @@ static bool DumpModuleSymbolFile(Stream &strm, Module *module) {
}
static void DumpAddress(ExecutionContextScope *exe_scope,
const Address &so_addr, bool verbose, Stream &strm) {
const Address &so_addr, bool verbose, bool all_ranges,
Stream &strm) {
strm.IndentMore();
strm.Indent(" Address: ");
so_addr.Dump(&strm, exe_scope, Address::DumpStyleModuleWithFileAddress);
@ -1444,7 +1446,8 @@ static void DumpAddress(ExecutionContextScope *exe_scope,
// Print out detailed address information when verbose is enabled
if (verbose) {
strm.EOL();
so_addr.Dump(&strm, exe_scope, Address::DumpStyleDetailedSymbolContext);
so_addr.Dump(&strm, exe_scope, Address::DumpStyleDetailedSymbolContext,
Address::DumpStyleInvalid, UINT32_MAX, all_ranges);
}
strm.IndentLess();
}
@ -1452,7 +1455,7 @@ static void DumpAddress(ExecutionContextScope *exe_scope,
static bool LookupAddressInModule(CommandInterpreter &interpreter, Stream &strm,
Module *module, uint32_t resolve_mask,
lldb::addr_t raw_addr, lldb::addr_t offset,
bool verbose) {
bool verbose, bool all_ranges) {
if (module) {
lldb::addr_t addr = raw_addr - offset;
Address so_addr;
@ -1470,7 +1473,7 @@ static bool LookupAddressInModule(CommandInterpreter &interpreter, Stream &strm,
ExecutionContextScope *exe_scope =
interpreter.GetExecutionContext().GetBestExecutionContextScope();
DumpAddress(exe_scope, so_addr, verbose, strm);
DumpAddress(exe_scope, so_addr, verbose, all_ranges, strm);
// strm.IndentMore();
// strm.Indent (" Address: ");
// so_addr.Dump (&strm, exe_scope,
@ -1502,7 +1505,7 @@ static bool LookupAddressInModule(CommandInterpreter &interpreter, Stream &strm,
static uint32_t LookupSymbolInModule(CommandInterpreter &interpreter,
Stream &strm, Module *module,
const char *name, bool name_is_regex,
bool verbose) {
bool verbose, bool all_ranges) {
if (!module)
return 0;
@ -1535,7 +1538,7 @@ static uint32_t LookupSymbolInModule(CommandInterpreter &interpreter,
if (symbol && symbol->ValueIsAddress()) {
DumpAddress(
interpreter.GetExecutionContext().GetBestExecutionContextScope(),
symbol->GetAddressRef(), verbose, strm);
symbol->GetAddressRef(), verbose, all_ranges, strm);
}
}
strm.IndentLess();
@ -1545,7 +1548,7 @@ static uint32_t LookupSymbolInModule(CommandInterpreter &interpreter,
static void DumpSymbolContextList(ExecutionContextScope *exe_scope,
Stream &strm, SymbolContextList &sc_list,
bool verbose) {
bool verbose, bool all_ranges) {
strm.IndentMore();
const uint32_t num_matches = sc_list.GetSize();
@ -1557,7 +1560,7 @@ static void DumpSymbolContextList(ExecutionContextScope *exe_scope,
sc.GetAddressRange(eSymbolContextEverything, 0, true, range);
DumpAddress(exe_scope, range.GetBaseAddress(), verbose, strm);
DumpAddress(exe_scope, range.GetBaseAddress(), verbose, all_ranges, strm);
}
}
strm.IndentLess();
@ -1567,7 +1570,7 @@ static size_t LookupFunctionInModule(CommandInterpreter &interpreter,
Stream &strm, Module *module,
const char *name, bool name_is_regex,
const ModuleFunctionSearchOptions &options,
bool verbose) {
bool verbose, bool all_ranges) {
if (module && name && name[0]) {
SymbolContextList sc_list;
size_t num_matches = 0;
@ -1588,7 +1591,7 @@ static size_t LookupFunctionInModule(CommandInterpreter &interpreter,
strm.PutCString(":\n");
DumpSymbolContextList(
interpreter.GetExecutionContext().GetBestExecutionContextScope(),
strm, sc_list, verbose);
strm, sc_list, verbose, all_ranges);
}
return num_matches;
}
@ -1693,7 +1696,7 @@ static uint32_t LookupFileAndLineInModule(CommandInterpreter &interpreter,
Stream &strm, Module *module,
const FileSpec &file_spec,
uint32_t line, bool check_inlines,
bool verbose) {
bool verbose, bool all_ranges) {
if (module && file_spec) {
SymbolContextList sc_list;
const uint32_t num_matches = module->ResolveSymbolContextsForFileSpec(
@ -1710,7 +1713,7 @@ static uint32_t LookupFileAndLineInModule(CommandInterpreter &interpreter,
strm.PutCString(":\n");
DumpSymbolContextList(
interpreter.GetExecutionContext().GetBestExecutionContextScope(),
strm, sc_list, verbose);
strm, sc_list, verbose, all_ranges);
return num_matches;
}
}
@ -3598,6 +3601,10 @@ public:
case 'r':
m_use_regex = true;
break;
case '\x01':
m_all_ranges = true;
break;
default:
llvm_unreachable("Unimplemented option");
}
@ -3614,6 +3621,7 @@ public:
m_line_number = 0;
m_use_regex = false;
m_include_inlines = true;
m_all_ranges = false;
m_verbose = false;
m_print_all = false;
}
@ -3632,6 +3640,7 @@ public:
bool m_use_regex; // Name lookups in m_str are regular expressions.
bool m_include_inlines; // Check for inline entries when looking up by
// file/line.
bool m_all_ranges; // Print all ranges or single range.
bool m_verbose; // Enable verbose lookup info
bool m_print_all; // Print all matches, even in cases where there's a best
// match.
@ -3714,7 +3723,8 @@ public:
(m_options.m_verbose
? static_cast<int>(eSymbolContextVariable)
: 0),
m_options.m_addr, m_options.m_offset, m_options.m_verbose)) {
m_options.m_addr, m_options.m_offset, m_options.m_verbose,
m_options.m_all_ranges)) {
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
@ -3725,7 +3735,8 @@ public:
if (!m_options.m_str.empty()) {
if (LookupSymbolInModule(m_interpreter, result.GetOutputStream(),
module, m_options.m_str.c_str(),
m_options.m_use_regex, m_options.m_verbose)) {
m_options.m_use_regex, m_options.m_verbose,
m_options.m_all_ranges)) {
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
@ -3737,7 +3748,8 @@ public:
if (LookupFileAndLineInModule(
m_interpreter, result.GetOutputStream(), module,
m_options.m_file, m_options.m_line_number,
m_options.m_include_inlines, m_options.m_verbose)) {
m_options.m_include_inlines, m_options.m_verbose,
m_options.m_all_ranges)) {
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
@ -3755,7 +3767,8 @@ public:
if (LookupFunctionInModule(m_interpreter, result.GetOutputStream(),
module, m_options.m_str.c_str(),
m_options.m_use_regex, function_options,
m_options.m_verbose)) {
m_options.m_verbose,
m_options.m_all_ranges)) {
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}

View File

@ -957,6 +957,9 @@ let Command = "target modules lookup" in {
def target_modules_lookup_type : Option<"type", "t">, Group<6>, Arg<"Name">,
Required, Desc<"Lookup a type by name in the debug symbols in one or more "
"target modules.">;
def target_modules_lookup_variables_ranges : Option<"show-variable-ranges",
"\\x01">, GroupRange<1, 6>, Desc<"Dump valid ranges of variables (must be "
"used in conjunction with --verbose">;
def target_modules_lookup_verbose : Option<"verbose", "v">,
Desc<"Enable verbose lookup information.">;
def target_modules_lookup_all : Option<"all", "A">, Desc<"Print all matches, "

View File

@ -22,6 +22,7 @@
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/Process.h"
@ -403,7 +404,8 @@ bool Address::GetDescription(Stream &s, Target &target,
}
bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
DumpStyle fallback_style, uint32_t addr_size) const {
DumpStyle fallback_style, uint32_t addr_size,
bool all_ranges) const {
// If the section was nullptr, only load address is going to work unless we
// are trying to deref a pointer
SectionSP section_sp(GetSection());
@ -720,27 +722,42 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
bool get_parent_variables = true;
bool stop_if_block_is_inlined_function = false;
VariableList variable_list;
sc.block->AppendVariables(can_create, get_parent_variables,
stop_if_block_is_inlined_function,
[](Variable *) { return true; },
&variable_list);
addr_t file_addr = GetFileAddress();
sc.block->AppendVariables(
can_create, get_parent_variables,
stop_if_block_is_inlined_function,
[&](Variable *var) {
return var && var->LocationIsValidForAddress(*this);
},
&variable_list);
ABISP abi =
ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
for (const VariableSP &var_sp : variable_list) {
if (var_sp && var_sp->LocationIsValidForAddress(*this)) {
s->Indent();
s->Printf(" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\"",
var_sp->GetID(), var_sp->GetName().GetCString());
Type *type = var_sp->GetType();
if (type)
s->Printf(", type = \"%s\"", type->GetName().GetCString());
else
s->PutCString(", type = <unknown>");
s->PutCString(", location = ");
var_sp->DumpLocationForAddress(s, *this);
s->PutCString(", decl = ");
var_sp->GetDeclaration().DumpStopContext(s, false);
s->EOL();
}
s->Indent();
s->Printf(" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\"",
var_sp->GetID(), var_sp->GetName().GetCString());
Type *type = var_sp->GetType();
if (type)
s->Printf(", type = \"%s\"", type->GetName().GetCString());
else
s->PutCString(", type = <unknown>");
s->PutCString(", valid ranges = ");
if (var_sp->GetScopeRange().IsEmpty())
s->PutCString("<block>");
else if (all_ranges) {
for (auto range : var_sp->GetScopeRange())
DumpAddressRange(s->AsRawOstream(), range.GetRangeBase(),
range.GetRangeEnd(), addr_size);
} else if (auto *range =
var_sp->GetScopeRange().FindEntryThatContains(
file_addr))
DumpAddressRange(s->AsRawOstream(), range->GetRangeBase(),
range->GetRangeEnd(), addr_size);
s->PutCString(", location = ");
var_sp->DumpLocations(s, all_ranges ? LLDB_INVALID_ADDRESS : *this);
s->PutCString(", decl = ");
var_sp->GetDeclaration().DumpStopContext(s, false);
s->EOL();
}
}
}

View File

@ -129,7 +129,6 @@ private:
}
void DWARFExpression::GetDescription(Stream *s, lldb::DescriptionLevel level,
addr_t location_list_base_addr,
ABI *abi) const {
if (IsLocationList()) {
// We have a location list
@ -2673,14 +2672,50 @@ static DataExtractor ToDataExtractor(const llvm::DWARFLocationExpression &loc,
return DataExtractor(buffer_sp, byte_order, addr_size);
}
llvm::Optional<DataExtractor>
DWARFExpression::GetLocationExpression(addr_t load_function_start,
addr_t addr) const {
bool DWARFExpression::DumpLocations(Stream *s, lldb::DescriptionLevel level,
addr_t load_function_start, addr_t addr,
ABI *abi) {
if (!IsLocationList()) {
DumpLocation(s, m_data, level, abi);
return true;
}
bool dump_all = addr == LLDB_INVALID_ADDRESS;
llvm::ListSeparator separator;
auto callback = [&](llvm::DWARFLocationExpression loc) -> bool {
if (loc.Range &&
(dump_all || (loc.Range->LowPC <= addr && addr < loc.Range->HighPC))) {
uint32_t addr_size = m_data.GetAddressByteSize();
DataExtractor data = ToDataExtractor(loc, m_data.GetByteOrder(),
m_data.GetAddressByteSize());
s->AsRawOstream() << separator;
s->PutCString("[");
s->AsRawOstream() << llvm::format_hex(loc.Range->LowPC,
2 + 2 * addr_size);
s->PutCString(", ");
s->AsRawOstream() << llvm::format_hex(loc.Range->HighPC,
2 + 2 * addr_size);
s->PutCString(") -> ");
DumpLocation(s, data, level, abi);
return dump_all;
}
return true;
};
if (!GetLocationExpressions(load_function_start, callback))
return false;
return true;
}
bool DWARFExpression::GetLocationExpressions(
addr_t load_function_start,
llvm::function_ref<bool(llvm::DWARFLocationExpression)> callback) const {
if (load_function_start == LLDB_INVALID_ADDRESS)
return false;
Log *log = GetLog(LLDBLog::Expressions);
std::unique_ptr<llvm::DWARFLocationTable> loctable_up =
m_dwarf_cu->GetLocationTable(m_data);
llvm::Optional<DataExtractor> result;
uint64_t offset = 0;
auto lookup_addr =
[&](uint32_t index) -> llvm::Optional<llvm::object::SectionedAddress> {
@ -2700,19 +2735,32 @@ DWARFExpression::GetLocationExpression(addr_t load_function_start,
addr_t slide = load_function_start - m_loclist_addresses->func_file_addr;
loc->Range->LowPC += slide;
loc->Range->HighPC += slide;
if (loc->Range->LowPC <= addr && addr < loc->Range->HighPC)
result = ToDataExtractor(*loc, m_data.GetByteOrder(),
m_data.GetAddressByteSize());
}
return !result;
return callback(*loc);
};
llvm::Error E = loctable_up->visitAbsoluteLocationList(
llvm::Error error = loctable_up->visitAbsoluteLocationList(
offset, llvm::object::SectionedAddress{m_loclist_addresses->cu_file_addr},
lookup_addr, process_list);
if (E)
LLDB_LOG_ERROR(log, std::move(E), "{0}");
return result;
if (error) {
LLDB_LOG_ERROR(log, std::move(error), "{0}");
return false;
}
return true;
}
llvm::Optional<DataExtractor>
DWARFExpression::GetLocationExpression(addr_t load_function_start,
addr_t addr) const {
llvm::Optional<DataExtractor> data;
auto callback = [&](llvm::DWARFLocationExpression loc) {
if (loc.Range && loc.Range->LowPC <= addr && addr < loc.Range->HighPC) {
data = ToDataExtractor(loc, m_data.GetByteOrder(),
m_data.GetAddressByteSize());
}
return !data;
};
GetLocationExpressions(load_function_start, callback);
return data;
}
bool DWARFExpression::MatchesOperand(StackFrame &frame,
@ -2738,7 +2786,8 @@ bool DWARFExpression::MatchesOperand(StackFrame &frame,
addr_t pc = frame.GetFrameCodeAddress().GetLoadAddress(
frame.CalculateTarget().get());
if (llvm::Optional<DataExtractor> expr = GetLocationExpression(load_function_start, pc))
if (llvm::Optional<DataExtractor> expr =
GetLocationExpression(load_function_start, pc))
opcodes = std::move(*expr);
else
return false;

View File

@ -3923,7 +3923,7 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) {
if (log) {
StreamString call_target_desc;
call_target->GetDescription(&call_target_desc, eDescriptionLevelBrief,
LLDB_INVALID_ADDRESS, nullptr);
nullptr);
LLDB_LOG(log, "CollectCallEdges: Found indirect call target: {0}",
call_target_desc.GetString());
}
@ -3936,11 +3936,9 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) {
for (const CallSiteParameter &param : parameters) {
StreamString callee_loc_desc, caller_loc_desc;
param.LocationInCallee.GetDescription(&callee_loc_desc,
eDescriptionLevelBrief,
LLDB_INVALID_ADDRESS, nullptr);
eDescriptionLevelBrief, nullptr);
param.LocationInCaller.GetDescription(&caller_loc_desc,
eDescriptionLevelBrief,
LLDB_INVALID_ADDRESS, nullptr);
eDescriptionLevelBrief, nullptr);
LLDB_LOG(log, "CollectCallEdges: \tparam: {0} => {1}",
callee_loc_desc.GetString(), caller_loc_desc.GetString());
}

View File

@ -147,23 +147,13 @@ void Variable::Dump(Stream *s, bool show_context) const {
if (m_location.IsValid()) {
s->PutCString(", location = ");
lldb::addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
if (m_location.IsLocationList()) {
SymbolContext variable_sc;
m_owner_scope->CalculateSymbolContext(&variable_sc);
if (variable_sc.function)
loclist_base_addr = variable_sc.function->GetAddressRange()
.GetBaseAddress()
.GetFileAddress();
}
ABISP abi;
if (m_owner_scope) {
ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
if (module_sp)
abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
}
m_location.GetDescription(s, lldb::eDescriptionLevelBrief,
loclist_base_addr, abi.get());
m_location.GetDescription(s, lldb::eDescriptionLevelBrief, abi.get());
}
if (m_external)
@ -445,36 +435,25 @@ Status Variable::GetValuesForVariableExpressionPath(
return error;
}
bool Variable::DumpLocationForAddress(Stream *s, const Address &address) {
// Be sure to resolve the address to section offset prior to calling this
// function.
if (address.IsSectionOffset()) {
SymbolContext sc;
CalculateSymbolContext(&sc);
if (sc.module_sp == address.GetModule()) {
ABISP abi;
if (m_owner_scope) {
ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
if (module_sp)
abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
}
bool Variable::DumpLocations(Stream *s, const Address &address) {
SymbolContext sc;
CalculateSymbolContext(&sc);
ABISP abi;
if (m_owner_scope) {
ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());
if (module_sp)
abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
}
const addr_t file_addr = address.GetFileAddress();
if (sc.function) {
if (sc.function->GetAddressRange().ContainsFileAddress(address)) {
addr_t loclist_base_file_addr =
sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
return false;
return m_location.DumpLocationForAddress(s, eDescriptionLevelBrief,
loclist_base_file_addr,
file_addr, abi.get());
}
}
return m_location.DumpLocationForAddress(s, eDescriptionLevelBrief,
LLDB_INVALID_ADDRESS, file_addr,
abi.get());
}
const addr_t file_addr = address.GetFileAddress();
if (sc.function) {
addr_t loclist_base_file_addr =
sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
return false;
return m_location.DumpLocations(s, eDescriptionLevelBrief,
loclist_base_file_addr, file_addr,
abi.get());
}
return false;
}

View File

@ -2,7 +2,7 @@
# RUN: %lldb %t -o "image lookup -v -s lookup_loclists" -o exit | FileCheck %s
# CHECK-LABEL: image lookup -v -s lookup_loclists
# CHECK: Variable: {{.*}}, name = "x0", type = "int", location = DW_OP_reg0 RAX,
# CHECK: Variable: {{.*}}, name = "x0", type = "int", valid ranges = <block>, location = [0x0000000000000000, 0x0000000000000003) -> DW_OP_reg0 RAX,
# CHECK-NOT: Variable:
loclists:

View File

@ -8,18 +8,30 @@
# RUN: %lldb %t -o "image lookup -v -a 0" -o "image lookup -v -a 2" \
# RUN: -o "image dump symfile" -o exit | FileCheck %s
# RUN: %lldb %t -o "image lookup -v -a 0 -show-variable-ranges" -o \
# RUN: "image lookup -v -a 2 -show-variable-ranges" \
# RUN: -o exit | FileCheck %s --check-prefix=ALL-RANGES
# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj %s --defsym LOCLISTS=0 > %t
# RUN: %lldb %t -o "image lookup -v -a 0" -o "image lookup -v -a 2" \
# RUN: -o "image dump symfile" -o exit | FileCheck %s --check-prefix=CHECK --check-prefix=LOCLISTS
# ALL-RANGES-LABEL: image lookup -v -a 0 -show-variable-ranges
# ALL-RANGES: Variable: id = {{.*}}, name = "x0", type = "int", valid ranges = <block>, location = [0x0000000000000000, 0x0000000000000001) -> DW_OP_reg5 RDI, [0x0000000000000001, 0x0000000000000006) -> DW_OP_reg0 RAX
# ALL-RANGES: Variable: id = {{.*}}, name = "x1", type = "int", valid ranges = <block>, location = <empty>
# ALL-RANGES-LABEL: image lookup -v -a 2 -show-variable-ranges
# ALL-RANGES: Variable: id = {{.*}}, name = "x0", type = "int", valid ranges = <block>, location = [0x0000000000000000, 0x0000000000000001) -> DW_OP_reg5 RDI, [0x0000000000000001, 0x0000000000000006) -> DW_OP_reg0 RAX
# ALL-RANGES: Variable: id = {{.*}}, name = "x1", type = "int", valid ranges = <block>, location = <empty>
# ALL-RANGES: Variable: id = {{.*}}, name = "x3", type = "int", valid ranges = <block>, location = [0x0000000000000002, 0x0000000000000003) -> DW_OP_reg1 RDX
# CHECK-LABEL: image lookup -v -a 0
# CHECK: Variable: {{.*}}, name = "x0", type = "int", location = DW_OP_reg5 RDI,
# CHECK: Variable: {{.*}}, name = "x1", type = "int", location = <empty>,
# CHECK: Variable: {{.*}}, name = "x0", type = "int", valid ranges = <block>, location = [0x0000000000000000, 0x0000000000000001) -> DW_OP_reg5 RDI
# CHECK: Variable: {{.*}}, name = "x1", type = "int", valid ranges = <block>, location = <empty>,
# CHECK-LABEL: image lookup -v -a 2
# CHECK: Variable: {{.*}}, name = "x0", type = "int", location = DW_OP_reg0 RAX,
# CHECK: Variable: {{.*}}, name = "x1", type = "int", location = <empty>,
# CHECK: Variable: {{.*}}, name = "x3", type = "int", location = DW_OP_reg1 RDX,
# CHECK: Variable: {{.*}}, name = "x0", type = "int", valid ranges = <block>, location = [0x0000000000000001, 0x0000000000000006) -> DW_OP_reg0 RAX
# CHECK: Variable: {{.*}}, name = "x1", type = "int", valid ranges = <block>, location = <empty>,
# CHECK: Variable: {{.*}}, name = "x3", type = "int", valid ranges = <block>, location = [0x0000000000000002, 0x0000000000000003) -> DW_OP_reg1 RDX
# CHECK-LABEL: image dump symfile
# CHECK: CompileUnit{0x00000000}

View File

@ -7,10 +7,10 @@
# CHECK-LABEL: image lookup -v -s loc
# CHECK: Variable: {{.*}}, name = "x0", type = "int", location = DW_OP_reg5 RDI,
# CHECK: Variable: {{.*}}, name = "x0", type = "int", valid ranges = <block>, location = [0x0000000000000000, 0x0000000000000001) -> DW_OP_reg5 RDI,
# CHECK-LABEL: image lookup -v -s loclists
# CHECK: Variable: {{.*}}, name = "x1", type = "int", location = DW_OP_reg0 RAX,
# CHECK: Variable: {{.*}}, name = "x1", type = "int", valid ranges = <block>, location = [0x0000000000000001, 0x0000000000000002) -> DW_OP_reg0 RAX,
loc:

View File

@ -3,8 +3,8 @@
# RUN: %lldb debug_loclists-dwo.o -o "image lookup -v -s lookup_loclists" -o exit | FileCheck %s
# CHECK-LABEL: image lookup -v -s lookup_loclists
# CHECK: Variable: {{.*}}, name = "x0", type = "int", location = DW_OP_reg0 RAX,
# CHECK: Variable: {{.*}}, name = "x1", type = "int", location = DW_OP_reg1 RDX,
# CHECK: Variable: {{.*}}, name = "x0", type = "int", valid ranges = <block>, location = [0x0000000000000000, 0x0000000000000003) -> DW_OP_reg0 RAX,
# CHECK: Variable: {{.*}}, name = "x1", type = "int", valid ranges = <block>, location = [0x0000000000000002, 0x0000000000000004) -> DW_OP_reg1 RDX,
loclists:
nop

View File

@ -6,8 +6,8 @@
# RUN: %lldb %t -o "image lookup -v -s lookup_loclists" -o exit | FileCheck %s
# CHECK-LABEL: image lookup -v -s lookup_loclists
# CHECK: Variable: id = {{.*}}, name = "x0", type = "int", location = DW_OP_reg0 RAX,
# CHECK: Variable: id = {{.*}}, name = "x1", type = "int", location = DW_OP_reg1 RDX,
# CHECK: Variable: id = {{.*}}, name = "x0", type = "int", valid ranges = <block>, location = [0x0000000000000000, 0x0000000000000003) -> DW_OP_reg0 RAX,
# CHECK: Variable: id = {{.*}}, name = "x1", type = "int", valid ranges = <block>, location = [0x0000000000000002, 0x0000000000000004) -> DW_OP_reg1 RDX,
## This part is kept in both the main and the dwp file to be able to reference the offsets.
loclists:

View File

@ -12,7 +12,7 @@
# CHECK-LABEL: image lookup -v -n F1
# CHECK: CompileUnit: id = {0x00000001}, file = "1.c", language = "<not loaded>"
# CHECK: Function: {{.*}}, name = "F1", range = [0x0000000000000001-0x0000000000000002)
# CHECK: Variable: {{.*}}, name = "x", type = "int", location = DW_OP_reg1 RDX
# CHECK: Variable: {{.*}}, name = "x", type = "int", valid ranges = <block>, location = [0x0000000000000001, 0x0000000000000002) -> DW_OP_reg1 RDX
# SYMBOLS: Compile units:
# SYMBOLS-NEXT: CompileUnit{0x00000000}, language = "<not loaded>", file = '0.c'

View File

@ -14,35 +14,35 @@
# at the inlined function entry.
image lookup -v -s break_at_inlined_f_in_main
# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main
# CHECK: name = "unused1", type = "void *", location = <empty>
# CHECK: name = "used", type = "int", location = DW_OP_consts +42
# CHECK: name = "unused2", type = "int", location = <empty>
# CHECK: name = "partial", type = "int", location = DW_OP_reg4 RSI
# CHECK: name = "unused3", type = "int", location = <empty>
# CHECK: name = "unused1", type = "void *", valid ranges = <block>, location = <empty>
# CHECK: name = "used", type = "int", valid ranges = <block>, location = [0x0000000000000011, 0x0000000000000014) -> DW_OP_consts +42
# CHECK: name = "unused2", type = "int", valid ranges = <block>, location = <empty>
# CHECK: name = "partial", type = "int", valid ranges = <block>, location = [0x0000000000000011, 0x0000000000000019) -> DW_OP_reg4 RSI
# CHECK: name = "unused3", type = "int", valid ranges = <block>, location = <empty>
# Show variables outsid of the live range of the 'partial' parameter
# and verify that the output is as expected.
image lookup -v -s break_at_inlined_f_in_main_between_printfs
# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_main_between_printfs
# CHECK: name = "unused1", type = "void *", location = <empty>
# CHECK: name = "used", type = "int", location = DW_OP_reg3 RBX
# CHECK: name = "unused2", type = "int", location = <empty>
# CHECK: name = "unused1", type = "void *", valid ranges = <block>, location = <empty>
# CHECK: name = "used", type = "int", valid ranges = <block>, location = [0x0000000000000014, 0x000000000000001e) -> DW_OP_reg3 RBX
# CHECK: name = "unused2", type = "int", valid ranges = <block>, location = <empty>
# Note: image lookup does not show variables outside of their
# location, so |partial| is missing here.
# CHECK-NOT: partial
# CHECK: name = "unused3", type = "int", location = <empty>
# CHECK: name = "unused3", type = "int", valid ranges = <block>, location = <empty>
# Check that we show parameters even if all of them are compiled away.
image lookup -v -s break_at_inlined_g_in_main
# CHECK-LABEL: image lookup -v -s break_at_inlined_g_in_main
# CHECK: name = "unused", type = "int", location = <empty>
# CHECK: name = "unused", type = "int", valid ranges = <block>, location = <empty>
# Check that even the other inlined instance of f displays the correct
# parameters.
image lookup -v -s break_at_inlined_f_in_other
# CHECK-LABEL: image lookup -v -s break_at_inlined_f_in_other
# CHECK: name = "unused1", type = "void *", location = <empty>
# CHECK: name = "used", type = "int", location = DW_OP_consts +1
# CHECK: name = "unused2", type = "int", location = <empty>
# CHECK: name = "partial", type = "int", location = DW_OP_consts +2
# CHECK: name = "unused3", type = "int", location = <empty>
# CHECK: name = "unused1", type = "void *", valid ranges = <block>, location = <empty>
# CHECK: name = "used", type = "int", valid ranges = <block>, location = [0x0000000000000001, 0x000000000000000b) -> DW_OP_consts +1
# CHECK: name = "unused2", type = "int", valid ranges = <block>, location = <empty>
# CHECK: name = "partial", type = "int", valid ranges = <block>, location = [0x0000000000000001, 0x0000000000000006) -> DW_OP_consts +2
# CHECK: name = "unused3", type = "int", valid ranges = <block>, location = <empty>