diff --git a/lldb/include/lldb/Core/Address.h b/lldb/include/lldb/Core/Address.h --- a/lldb/include/lldb/Core/Address.h +++ b/lldb/include/lldb/Core/Address.h @@ -236,9 +236,11 @@ /// in such cases. /// /// \see Address::DumpStyle - bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, - DumpStyle fallback_style = DumpStyleInvalid, - uint32_t addr_byte_size = UINT32_MAX) const; + bool + Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, + DumpStyle fallback_style = DumpStyleInvalid, + uint32_t addr_byte_size = UINT32_MAX, + ModuleLookupShowRange show_range = ModuleLookupShowRange::None) const; AddressClass GetAddressClass() const; diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h --- a/lldb/include/lldb/Expression/DWARFExpression.h +++ b/lldb/include/lldb/Expression/DWARFExpression.h @@ -15,6 +15,8 @@ #include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-private.h" +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" +#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" #include class DWARFUnit; @@ -217,6 +219,16 @@ 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, + ABI *abi, + llvm::function_ref + filter, + llvm::function_ref printer); + + bool GetLocationExpressions( + llvm::function_ref fn) const; + bool MatchesOperand(StackFrame &frame, const Instruction::Operand &op); llvm::Optional diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -222,6 +222,11 @@ StatisticMax = 4 }; +enum class ModuleLookupShowRange { + None = 0, + Single = 1, + All = 2, +}; inline std::string GetStatDescription(lldb_private::StatisticKind K) { switch (K) { diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -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 void DumpAddress(ExecutionContextScope *exe_scope, - const Address &so_addr, bool verbose, Stream &strm) { + const Address &so_addr, bool verbose, + ModuleLookupShowRange show_range, Stream &strm) { strm.IndentMore(); strm.Indent(" Address: "); so_addr.Dump(&strm, exe_scope, Address::DumpStyleModuleWithFileAddress); @@ -1444,7 +1446,8 @@ // 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, show_range); } strm.IndentLess(); } @@ -1452,7 +1455,8 @@ 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, + ModuleLookupShowRange show_range) { if (module) { lldb::addr_t addr = raw_addr - offset; Address so_addr; @@ -1470,7 +1474,7 @@ ExecutionContextScope *exe_scope = interpreter.GetExecutionContext().GetBestExecutionContextScope(); - DumpAddress(exe_scope, so_addr, verbose, strm); + DumpAddress(exe_scope, so_addr, verbose, show_range, strm); // strm.IndentMore(); // strm.Indent (" Address: "); // so_addr.Dump (&strm, exe_scope, @@ -1502,7 +1506,8 @@ static uint32_t LookupSymbolInModule(CommandInterpreter &interpreter, Stream &strm, Module *module, const char *name, bool name_is_regex, - bool verbose) { + bool verbose, + ModuleLookupShowRange show_range) { if (!module) return 0; @@ -1535,7 +1540,7 @@ if (symbol && symbol->ValueIsAddress()) { DumpAddress( interpreter.GetExecutionContext().GetBestExecutionContextScope(), - symbol->GetAddressRef(), verbose, strm); + symbol->GetAddressRef(), verbose, show_range, strm); } } strm.IndentLess(); @@ -1545,7 +1550,8 @@ static void DumpSymbolContextList(ExecutionContextScope *exe_scope, Stream &strm, SymbolContextList &sc_list, - bool verbose) { + bool verbose, + ModuleLookupShowRange show_range) { strm.IndentMore(); const uint32_t num_matches = sc_list.GetSize(); @@ -1557,7 +1563,7 @@ sc.GetAddressRange(eSymbolContextEverything, 0, true, range); - DumpAddress(exe_scope, range.GetBaseAddress(), verbose, strm); + DumpAddress(exe_scope, range.GetBaseAddress(), verbose, show_range, strm); } } strm.IndentLess(); @@ -1567,7 +1573,8 @@ Stream &strm, Module *module, const char *name, bool name_is_regex, const ModuleFunctionSearchOptions &options, - bool verbose) { + bool verbose, + ModuleLookupShowRange show_range) { if (module && name && name[0]) { SymbolContextList sc_list; size_t num_matches = 0; @@ -1588,7 +1595,7 @@ strm.PutCString(":\n"); DumpSymbolContextList( interpreter.GetExecutionContext().GetBestExecutionContextScope(), - strm, sc_list, verbose); + strm, sc_list, verbose, show_range); } return num_matches; } @@ -1693,7 +1700,8 @@ Stream &strm, Module *module, const FileSpec &file_spec, uint32_t line, bool check_inlines, - bool verbose) { + bool verbose, + ModuleLookupShowRange show_range) { if (module && file_spec) { SymbolContextList sc_list; const uint32_t num_matches = module->ResolveSymbolContextsForFileSpec( @@ -1710,7 +1718,7 @@ strm.PutCString(":\n"); DumpSymbolContextList( interpreter.GetExecutionContext().GetBestExecutionContextScope(), - strm, sc_list, verbose); + strm, sc_list, verbose, show_range); return num_matches; } } @@ -3507,6 +3515,20 @@ CommandOptions m_options; }; +// Verbose level. +static constexpr OptionEnumValueElement g_target_modules_lookup_show_range[] = { + { + (int64_t)ModuleLookupShowRange::Single, + "single", + "Only print the range that contains file address being looked up", + }, + { + (int64_t)ModuleLookupShowRange::All, + "all", + "Print all ranges", + }, +}; + // Lookup information in images #define LLDB_OPTIONS_target_modules_lookup #include "CommandOptions.inc" @@ -3598,6 +3620,12 @@ case 'r': m_use_regex = true; break; + + case 'R': + m_show_range = (ModuleLookupShowRange)OptionArgParser::ToOptionEnum( + option_arg, GetDefinitions()[option_idx].enum_values, + (int32_t)ModuleLookupShowRange::None, error); + break; default: llvm_unreachable("Unimplemented option"); } @@ -3614,6 +3642,7 @@ m_line_number = 0; m_use_regex = false; m_include_inlines = true; + m_show_range = ModuleLookupShowRange::None; m_verbose = false; m_print_all = false; } @@ -3632,6 +3661,7 @@ 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. + ModuleLookupShowRange m_show_range; // 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 +3744,8 @@ (m_options.m_verbose ? static_cast(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_show_range)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -3725,7 +3756,8 @@ 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_show_range)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -3737,7 +3769,8 @@ 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_show_range)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -3755,7 +3788,8 @@ 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_show_range)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -957,6 +957,10 @@ 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", + "R">, GroupRange<1, 6>, EnumArg<"Value", + "OptionEnumValues(g_target_modules_lookup_show_range)">, 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, " diff --git a/lldb/source/Core/Address.cpp b/lldb/source/Core/Address.cpp --- a/lldb/source/Core/Address.cpp +++ b/lldb/source/Core/Address.cpp @@ -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::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, - DumpStyle fallback_style, uint32_t addr_size) const { + DumpStyle fallback_style, uint32_t addr_size, + ModuleLookupShowRange show_range) 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,91 @@ 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); + auto dump_range = [&s, addr_size](Variable::RangeList::Entry range) { + s->PutCString(" ["); + s->AsRawOstream() + << llvm::format_hex(range.GetRangeBase(), 2 + 2 * addr_size); + s->PutCString(", "); + s->AsRawOstream() + << llvm::format_hex(range.GetRangeEnd(), 2 + 2 * addr_size); + s->PutCString(")"); + }; + 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 = "); + DWARFExpression &expr = var_sp->LocationExpression(); + 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 = "); + if (show_range == ModuleLookupShowRange::None) { s->PutCString(", location = "); var_sp->DumpLocationForAddress(s, *this); s->PutCString(", decl = "); var_sp->GetDeclaration().DumpStopContext(s, false); - s->EOL(); + } else { + s->PutCString(", valid ranges ="); + if (show_range == ModuleLookupShowRange::All) { + for (auto range : var_sp->GetScopeRange()) + dump_range(range); + } else if (auto *range = + var_sp->GetScopeRange().FindEntryThatContains( + file_addr)) + dump_range(*range); + + addr_t function_load_addr = + sc.block->CalculateSymbolContextFunction() + ->GetAddressRange() + .GetBaseAddress() + .GetFileAddress(); + auto filter = [&](llvm::DWARFAddressRange range, + addr_t func_file_addr, bool &should_continue) { + if (show_range == ModuleLookupShowRange::All) { + should_continue = true; + return true; + } + addr_t slide = function_load_addr - func_file_addr; + range.LowPC += slide; + range.HighPC += slide; + + if (range.LowPC <= file_addr && file_addr < range.HighPC) { + should_continue = false; + return true; + } + return false; + }; + auto range_printer = [&](llvm::DWARFAddressRange range, + bool is_first) { + if (!is_first) + s->PutCString(", "); + s->PutCString("["); + s->AsRawOstream() + << llvm::format_hex(range.LowPC, 2 + 2 * addr_size); + s->PutCString(", "); + s->AsRawOstream() + << llvm::format_hex(range.HighPC, 2 + 2 * addr_size); + s->PutCString(") -> "); + }; + s->PutCString(", location = "); + expr.DumpLocations(s, lldb::eDescriptionLevelBrief, + function_load_addr, abi.get(), filter, + range_printer); + s->PutCString(", decl = "); + var_sp->GetDeclaration().DumpStopContext(s, false); } + s->EOL(); } } } diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -2673,14 +2673,40 @@ return DataExtractor(buffer_sp, byte_order, addr_size); } -llvm::Optional -DWARFExpression::GetLocationExpression(addr_t load_function_start, - addr_t addr) const { +bool DWARFExpression::DumpLocations( + Stream *s, lldb::DescriptionLevel level, lldb::addr_t load_function_start, + ABI *abi, + llvm::function_ref filter, + llvm::function_ref range_printer) { + if (!IsLocationList()) { + DumpLocation(s, m_data, level, abi); + return true; + } + bool is_first = true; + auto callback = [&](llvm::DWARFLocationExpression loc) -> bool { + bool should_continue = true; + if (loc.Range && filter(*loc.Range, m_loclist_addresses->func_file_addr, + should_continue)) { + DataExtractor data = ToDataExtractor(loc, m_data.GetByteOrder(), + m_data.GetAddressByteSize()); + range_printer(*loc.Range, is_first); + DumpLocation(s, data, level, abi); + is_first = false; + } + return should_continue; + }; + if (!GetLocationExpressions(callback)) + return false; + return true; +} + +bool DWARFExpression::GetLocationExpressions( + llvm::function_ref callback) const { Log *log = GetLog(LLDBLog::Expressions); std::unique_ptr loctable_up = m_dwarf_cu->GetLocationTable(m_data); - llvm::Optional result; + uint64_t offset = 0; auto lookup_addr = [&](uint32_t index) -> llvm::Optional { @@ -2694,25 +2720,38 @@ LLDB_LOG_ERROR(log, loc.takeError(), "{0}"); return true; } - if (loc->Range) { + return callback(*loc); + }; + llvm::Error E = 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 false; + } + return true; +} + +llvm::Optional +DWARFExpression::GetLocationExpression(addr_t load_function_start, + addr_t addr) const { + llvm::Optional data; + auto callback = [&](llvm::DWARFLocationExpression loc) { + if (loc.Range) { // This relocates low_pc and high_pc by adding the difference between the // function file address, and the actual address it is loaded in memory. addr_t slide = load_function_start - m_loclist_addresses->func_file_addr; - loc->Range->LowPC += slide; - loc->Range->HighPC += slide; + 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()); + if (loc.Range->LowPC <= addr && addr < loc.Range->HighPC) + data = ToDataExtractor(loc, m_data.GetByteOrder(), + m_data.GetAddressByteSize()); } - return !result; + return !data; }; - llvm::Error E = 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; + GetLocationExpressions(callback); + return data; } bool DWARFExpression::MatchesOperand(StackFrame &frame, @@ -2738,7 +2777,8 @@ addr_t pc = frame.GetFrameCodeAddress().GetLoadAddress( frame.CalculateTarget().get()); - if (llvm::Optional expr = GetLocationExpression(load_function_start, pc)) + if (llvm::Optional expr = + GetLocationExpression(load_function_start, pc)) opcodes = std::move(*expr); else return false; diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/debug_loc.s b/lldb/test/Shell/SymbolFile/DWARF/x86/debug_loc.s --- a/lldb/test/Shell/SymbolFile/DWARF/x86/debug_loc.s +++ b/lldb/test/Shell/SymbolFile/DWARF/x86/debug_loc.s @@ -8,10 +8,32 @@ # 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 -R s" -o "image lookup -v -a 2 -R s" \ +# RUN: -o exit | FileCheck %s --check-prefix=SINGLE-RANGE + +# RUN: %lldb %t -o "image lookup -v -a 0 -R a" -o "image lookup -v -a 2 -R a" \ +# 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 +# SINGLE-RANGE-LABEL: image lookup -v -a 0 -R s +# SINGLE-RANGE: Variable: id = {{.*}}, name = "x0", type = "int", valid ranges =, location = [0x0000000000000000, 0x0000000000000001) -> DW_OP_reg5 RDI, decl = +# SINGLE-RANGE: Variable: id = {{.*}}, name = "x1", type = "int", valid ranges =, location = , decl = +# SINGLE-RANGE-LABEL: image lookup -v -a 2 -R s +# SINGLE-RANGE: Variable: id = {{.*}}, name = "x0", type = "int", valid ranges =, location = [0x0000000000000001, 0x0000000000000006) -> DW_OP_reg0 RAX, decl = +# SINGLE-RANGE: Variable: id = {{.*}}, name = "x1", type = "int", valid ranges =, location = , decl = +# SINGLE-RANGE: Variable: id = {{.*}}, name = "x3", type = "int", valid ranges =, location = [0x0000000000000002, 0x0000000000000003) -> DW_OP_reg1 RDX, decl = + +# ALL-RANGES-LABEL: image lookup -v -a 0 -R a +# ALL-RANGES: Variable: id = {{.*}}, name = "x0", type = "int", valid ranges =, location = [0x0000000000000000, 0x0000000000000001) -> DW_OP_reg5 RDI, [0x0000000000000001, 0x0000000000000006) -> DW_OP_reg0 RAX, decl = +# ALL-RANGES: Variable: id = {{.*}}, name = "x1", type = "int", valid ranges =, location = , decl = +# ALL-RANGES-LABEL: image lookup -v -a 2 -R a +# ALL-RANGES: Variable: id = {{.*}}, name = "x0", type = "int", valid ranges =, location = [0x0000000000000000, 0x0000000000000001) -> DW_OP_reg5 RDI, [0x0000000000000001, 0x0000000000000006) -> DW_OP_reg0 RAX, decl = +# ALL-RANGES: Variable: id = {{.*}}, name = "x1", type = "int", valid ranges =, location = , decl = +# ALL-RANGES: Variable: id = {{.*}}, name = "x3", type = "int", valid ranges =, location = [0x0000000000000002, 0x0000000000000003) -> DW_OP_reg1 RDX, decl = + # 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 = ,