diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp index 5b131fe86dedb..70e687e19ac6d 100644 --- a/lldb/source/Commands/CommandObjectDisassemble.cpp +++ b/lldb/source/Commands/CommandObjectDisassemble.cpp @@ -21,6 +21,7 @@ #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" +#include static constexpr unsigned default_disasm_byte_size = 32; static constexpr unsigned default_disasm_num_ins = 4; @@ -236,25 +237,31 @@ CommandObjectDisassemble::CommandObjectDisassemble( CommandObjectDisassemble::~CommandObjectDisassemble() = default; -llvm::Error CommandObjectDisassemble::CheckRangeSize(const AddressRange &range, - llvm::StringRef what) { +llvm::Expected> +CommandObjectDisassemble::CheckRangeSize(std::vector ranges, + llvm::StringRef what) { + addr_t total_range_size = 0; + for (const AddressRange &r : ranges) + total_range_size += r.GetByteSize(); + if (m_options.num_instructions > 0 || m_options.force || - range.GetByteSize() < GetDebugger().GetStopDisassemblyMaxSize()) - return llvm::Error::success(); + total_range_size < GetDebugger().GetStopDisassemblyMaxSize()) + return ranges; + StreamString msg; msg << "Not disassembling " << what << " because it is very large "; - range.Dump(&msg, &GetTarget(), Address::DumpStyleLoadAddress, - Address::DumpStyleFileAddress); + for (const AddressRange &r : ranges) + r.Dump(&msg, &GetTarget(), Address::DumpStyleLoadAddress, + Address::DumpStyleFileAddress); msg << ". To disassemble specify an instruction count limit, start/stop " "addresses or use the --force option."; - return llvm::createStringError(llvm::inconvertibleErrorCode(), - msg.GetString()); + return llvm::createStringError(msg.GetString()); } llvm::Expected> CommandObjectDisassemble::GetContainingAddressRanges() { std::vector ranges; - const auto &get_range = [&](Address addr) { + const auto &get_ranges = [&](Address addr) { ModuleSP module_sp(addr.GetModule()); SymbolContext sc; bool resolve_tail_call_address = true; @@ -262,9 +269,11 @@ CommandObjectDisassemble::GetContainingAddressRanges() { addr, eSymbolContextEverything, sc, resolve_tail_call_address); if (sc.function || sc.symbol) { AddressRange range; - sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, - false, range); - ranges.push_back(range); + for (uint32_t idx = 0; + sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, + idx, false, range); + ++idx) + ranges.push_back(range); } }; @@ -273,14 +282,14 @@ CommandObjectDisassemble::GetContainingAddressRanges() { Address symbol_containing_address; if (target.ResolveLoadAddress(m_options.symbol_containing_addr, symbol_containing_address)) { - get_range(symbol_containing_address); + get_ranges(symbol_containing_address); } } else { for (lldb::ModuleSP module_sp : target.GetImages().Modules()) { Address file_address; if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr, file_address)) { - get_range(file_address); + get_ranges(file_address); } } } @@ -292,9 +301,7 @@ CommandObjectDisassemble::GetContainingAddressRanges() { m_options.symbol_containing_addr); } - if (llvm::Error err = CheckRangeSize(ranges[0], "the function")) - return std::move(err); - return ranges; + return CheckRangeSize(std::move(ranges), "the function"); } llvm::Expected> @@ -304,29 +311,24 @@ CommandObjectDisassemble::GetCurrentFunctionRanges() { if (!frame) { if (process) { return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "Cannot disassemble around the current " - "function without the process being stopped.\n"); - } else { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Cannot disassemble around the current " - "function without a selected frame: " - "no currently running process.\n"); + "Cannot disassemble around the current function without the process " + "being stopped.\n"); } + return llvm::createStringError( + "Cannot disassemble around the current function without a selected " + "frame: no currently running process.\n"); } - SymbolContext sc( - frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); - AddressRange range; + SymbolContext sc = + frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol); + std::vector ranges; if (sc.function) - range = sc.function->GetAddressRange(); - else if (sc.symbol && sc.symbol->ValueIsAddress()) { - range = {sc.symbol->GetAddress(), sc.symbol->GetByteSize()}; - } else - range = {frame->GetFrameCodeAddress(), default_disasm_byte_size}; - - if (llvm::Error err = CheckRangeSize(range, "the current function")) - return std::move(err); - return std::vector{range}; + ranges = sc.function->GetAddressRanges(); + else if (sc.symbol && sc.symbol->ValueIsAddress()) + ranges.emplace_back(sc.symbol->GetAddress(), sc.symbol->GetByteSize()); + else + ranges.emplace_back(frame->GetFrameCodeAddress(), default_disasm_byte_size); + + return CheckRangeSize(std::move(ranges), "the current function"); } llvm::Expected> @@ -372,19 +374,23 @@ CommandObjectDisassemble::GetNameRanges(CommandReturnObject &result) { std::vector ranges; llvm::Error range_errs = llvm::Error::success(); - AddressRange range; const uint32_t scope = eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol; const bool use_inline_block_range = true; for (SymbolContext sc : sc_list.SymbolContexts()) { + std::vector fn_ranges; + AddressRange range; for (uint32_t range_idx = 0; sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); - ++range_idx) { - if (llvm::Error err = CheckRangeSize(range, "a range")) - range_errs = joinErrors(std::move(range_errs), std::move(err)); - else - ranges.push_back(range); - } + ++range_idx) + fn_ranges.push_back(std::move(range)); + + if (llvm::Expected> checked_ranges = + CheckRangeSize(std::move(fn_ranges), "a function")) + llvm::move(*checked_ranges, std::back_inserter(ranges)); + else + range_errs = + joinErrors(std::move(range_errs), checked_ranges.takeError()); } if (ranges.empty()) { if (range_errs) diff --git a/lldb/source/Commands/CommandObjectDisassemble.h b/lldb/source/Commands/CommandObjectDisassemble.h index f9cba1e5ae9cb..4fbcd72d1c042 100644 --- a/lldb/source/Commands/CommandObjectDisassemble.h +++ b/lldb/source/Commands/CommandObjectDisassemble.h @@ -100,7 +100,8 @@ class CommandObjectDisassemble : public CommandObjectParsed { llvm::Expected> GetPCRanges(); llvm::Expected> GetStartEndAddressRanges(); - llvm::Error CheckRangeSize(const AddressRange &range, llvm::StringRef what); + llvm::Expected> + CheckRangeSize(std::vector ranges, llvm::StringRef what); CommandOptions m_options; }; diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp index 19f4f91e29d25..4725df52ff559 100644 --- a/lldb/source/Symbol/SymbolContext.cpp +++ b/lldb/source/Symbol/SymbolContext.cpp @@ -351,8 +351,8 @@ bool SymbolContext::GetAddressRange(uint32_t scope, uint32_t range_idx, } if ((scope & eSymbolContextFunction) && (function != nullptr)) { - if (range_idx == 0) { - range = function->GetAddressRange(); + if (range_idx < function->GetAddressRanges().size()) { + range = function->GetAddressRanges()[range_idx]; return true; } } diff --git a/lldb/test/Shell/Commands/command-disassemble.s b/lldb/test/Shell/Commands/command-disassemble.s index 1625f80468eb1..951d96cefd4b9 100644 --- a/lldb/test/Shell/Commands/command-disassemble.s +++ b/lldb/test/Shell/Commands/command-disassemble.s @@ -82,20 +82,25 @@ # CHECK-NEXT: (lldb) disassemble --name case2 # CHECK-NEXT: command-disassemble.s.tmp`n1::case2: # CHECK-NEXT: command-disassemble.s.tmp[0x2044] <+0>: int $0x32 -# CHECK-NEXT: warning: Not disassembling a range because it is very large [0x0000000000002046-0x0000000000004046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option. +# CHECK-NEXT: warning: Not disassembling a function because it is very large [0x0000000000002046-0x0000000000004046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option. # CHECK-NEXT: (lldb) disassemble --name case3 -# CHECK-NEXT: error: Not disassembling a range because it is very large [0x0000000000004046-0x0000000000006046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option. -# CHECK-NEXT: Not disassembling a range because it is very large [0x0000000000006046-0x0000000000008046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option. +# CHECK-NEXT: error: Not disassembling a function because it is very large [0x0000000000006046-0x0000000000007046)[0x0000000000009046-0x000000000000a046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option. +# CHECK-NEXT: Not disassembling a function because it is very large [0x0000000000004046-0x0000000000006046). To disassemble specify an instruction count limit, start/stop addresses or use the --force option. # CHECK-NEXT: (lldb) disassemble --name case3 --count 3 +# CHECK-NEXT: command-disassemble.s.tmp`n2::case3: +# CHECK-NEXT: command-disassemble.s.tmp[0x6046] <-12288>: int $0x2a +# CHECK-NEXT: command-disassemble.s.tmp[0x6048] <-12286>: int $0x2a +# CHECK-NEXT: command-disassemble.s.tmp[0x604a] <-12284>: int $0x2a +# CHECK-EMPTY: +# CHECK-NEXT: command-disassemble.s.tmp`n2::case3: +# CHECK-NEXT: command-disassemble.s.tmp[0x9046] <+0>: int $0x2a +# CHECK-NEXT: command-disassemble.s.tmp[0x9048] <+2>: int $0x2a +# CHECK-NEXT: command-disassemble.s.tmp[0x904a] <+4>: int $0x2a +# CHECK-EMPTY: # CHECK-NEXT: command-disassemble.s.tmp`n1::case3: # CHECK-NEXT: command-disassemble.s.tmp[0x4046] <+0>: int $0x2a # CHECK-NEXT: command-disassemble.s.tmp[0x4048] <+2>: int $0x2a # CHECK-NEXT: command-disassemble.s.tmp[0x404a] <+4>: int $0x2a -# CHECK-EMPTY: -# CHECK-NEXT: command-disassemble.s.tmp`n2::case3: -# CHECK-NEXT: command-disassemble.s.tmp[0x6046] <+0>: int $0x2a -# CHECK-NEXT: command-disassemble.s.tmp[0x6048] <+2>: int $0x2a -# CHECK-NEXT: command-disassemble.s.tmp[0x604a] <+4>: int $0x2a # CHECK-EMPTY: @@ -158,8 +163,97 @@ _ZN2n15case3Ev: .rept 0x1000 int $42 .endr + .size _ZN2n15case3Ev, .-_ZN2n15case3Ev -_ZN2n25case3Ev: +.L_ZN2n25case3Ev.__part.1: + .rept 0x800 + int $42 + .endr +.L_ZN2n25case3Ev.__part.1_end: + +.Lpadding: .rept 0x1000 int $42 .endr + +_ZN2n25case3Ev: + .rept 0x800 + int $42 + .endr +.L_ZN2n25case3Ev_end: + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 8 # DW_FORM_string + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 57 # DW_TAG_namespace + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 0 # DW_CHILDREN_no + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 110 # DW_AT_linkage_name + .byte 8 # DW_FORM_string + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev DW_TAG_compile_unit + .asciz "Hand-written DWARF" # DW_AT_producer + .short 29 # DW_AT_language + .quad 0 # DW_AT_low_pc + .long .Ldebug_ranges0 # DW_AT_ranges + .byte 2 # Abbrev DW_TAG_namespace + .asciz "n2" # DW_AT_name + .byte 3 # Abbrev DW_TAG_subprogram + .long .Ldebug_ranges0 # DW_AT_ranges + .asciz "case3" # DW_AT_name + .asciz "_ZN2n25case3Ev" # DW_AT_linkage_name + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + + .section .debug_rnglists,"",@progbits + .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length +.Ldebug_list_header_start0: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 2 # Offset entry count +.Lrnglists_table_base0: + .long .Ldebug_ranges0-.Lrnglists_table_base0 +.Ldebug_ranges0: + .byte 6 # DW_RLE_start_end + .quad _ZN2n25case3Ev + .quad .L_ZN2n25case3Ev_end + .byte 6 # DW_RLE_start_end + .quad .L_ZN2n25case3Ev.__part.1 + .quad .L_ZN2n25case3Ev.__part.1_end + .byte 0 # DW_RLE_end_of_list +.Ldebug_list_header_end0: