https://github.com/labath updated https://github.com/llvm/llvm-project/pull/122933
>From dd5dba70fe99d2510e9e1903b7f1f9a141f1572d Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Tue, 14 Jan 2025 17:17:28 +0100 Subject: [PATCH 1/2] [lldb] Implement (SB)Function::GetInstructions for discontinuous functions The main change is to permit the disassembler class to process/store multiple (discontinuous) ranges of addresses. The result is not ambiguous because each instruction knows its size (in addition to its address), so we can check for discontinuity by looking at whether the next instruction begins where the previous ends. This patch doesn't handle the "disassemble" CLI command, which uses a more elaborate mechanism for dissassembling and printing instructions. --- lldb/include/lldb/Core/Disassembler.h | 11 ++++++-- lldb/source/API/SBFunction.cpp | 2 +- lldb/source/API/SBInstructionList.cpp | 8 ++++++ lldb/source/Core/Disassembler.cpp | 27 ++++++++----------- lldb/source/Symbol/Function.cpp | 2 +- .../Python/sb_function_ranges.s | 11 ++++++++ 6 files changed, 41 insertions(+), 20 deletions(-) diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h index e0ad4316e02497..21bacb14f9b25b 100644 --- a/lldb/include/lldb/Core/Disassembler.h +++ b/lldb/include/lldb/Core/Disassembler.h @@ -428,7 +428,7 @@ class Disassembler : public std::enable_shared_from_this<Disassembler>, static lldb::DisassemblerSP DisassembleRange(const ArchSpec &arch, const char *plugin_name, const char *flavor, const char *cpu, const char *features, - Target &target, const AddressRange &disasm_range, + Target &target, llvm::ArrayRef<AddressRange> disasm_ranges, bool force_live_memory = false); static lldb::DisassemblerSP @@ -460,7 +460,11 @@ class Disassembler : public std::enable_shared_from_this<Disassembler>, size_t ParseInstructions(Target &target, Address address, Limit limit, Stream *error_strm_ptr, - bool force_live_memory = false); + bool force_live_memory = false) { + m_instruction_list.Clear(); + return AppendInstructions(target, address, limit, error_strm_ptr, + force_live_memory); + } virtual size_t DecodeInstructions(const Address &base_addr, const DataExtractor &data, @@ -480,6 +484,9 @@ class Disassembler : public std::enable_shared_from_this<Disassembler>, const char *flavor) = 0; protected: + size_t AppendInstructions(Target &target, Address address, Limit limit, + Stream *error_strm_ptr, bool force_live_memory); + // SourceLine and SourceLinesToDisplay structures are only used in the mixed // source and assembly display methods internal to this class. diff --git a/lldb/source/API/SBFunction.cpp b/lldb/source/API/SBFunction.cpp index 414eccc357c0e4..d07594c2e8c010 100644 --- a/lldb/source/API/SBFunction.cpp +++ b/lldb/source/API/SBFunction.cpp @@ -127,7 +127,7 @@ SBInstructionList SBFunction::GetInstructions(SBTarget target, sb_instructions.SetDisassembler(Disassembler::DisassembleRange( module_sp->GetArchitecture(), nullptr, flavor, target_sp->GetDisassemblyCPU(), target_sp->GetDisassemblyFeatures(), - *target_sp, m_opaque_ptr->GetAddressRange(), force_live_memory)); + *target_sp, m_opaque_ptr->GetAddressRanges(), force_live_memory)); } } return sb_instructions; diff --git a/lldb/source/API/SBInstructionList.cpp b/lldb/source/API/SBInstructionList.cpp index 3f37b984cb4627..5747ae0366ec30 100644 --- a/lldb/source/API/SBInstructionList.cpp +++ b/lldb/source/API/SBInstructionList.cpp @@ -151,6 +151,10 @@ bool SBInstructionList::GetDescription(Stream &sref) { FormatEntity::Parse("${addr}: ", format); SymbolContext sc; SymbolContext prev_sc; + + // Expected address of the next instruction. Used to print an empty line + // for non-contiguous blocks of insns. + std::optional<Address> next_addr; for (size_t i = 0; i < num_instructions; ++i) { Instruction *inst = m_opaque_sp->GetInstructionList().GetInstructionAtIndex(i).get(); @@ -165,10 +169,14 @@ bool SBInstructionList::GetDescription(Stream &sref) { addr, eSymbolContextEverything, sc); } + if (next_addr && addr != next_addr) + sref.EOL(); inst->Dump(&sref, max_opcode_byte_size, true, false, /*show_control_flow_kind=*/false, nullptr, &sc, &prev_sc, &format, 0); sref.EOL(); + next_addr = addr; + next_addr->Slide(inst->GetOpcode().GetByteSize()); } return true; } diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp index 68e52144eb6ef8..ed6a008a29fef5 100644 --- a/lldb/source/Core/Disassembler.cpp +++ b/lldb/source/Core/Disassembler.cpp @@ -123,22 +123,19 @@ static Address ResolveAddress(Target &target, const Address &addr) { lldb::DisassemblerSP Disassembler::DisassembleRange( const ArchSpec &arch, const char *plugin_name, const char *flavor, const char *cpu, const char *features, Target &target, - const AddressRange &range, bool force_live_memory) { - if (range.GetByteSize() <= 0) - return {}; - - if (!range.GetBaseAddress().IsValid()) - return {}; - + llvm::ArrayRef<AddressRange> disasm_ranges, bool force_live_memory) { lldb::DisassemblerSP disasm_sp = Disassembler::FindPluginForTarget( target, arch, flavor, cpu, features, plugin_name); if (!disasm_sp) return {}; - const size_t bytes_disassembled = disasm_sp->ParseInstructions( - target, range.GetBaseAddress(), {Limit::Bytes, range.GetByteSize()}, - nullptr, force_live_memory); + size_t bytes_disassembled = 0; + for (const AddressRange &range : disasm_ranges) { + bytes_disassembled += disasm_sp->AppendInstructions( + target, range.GetBaseAddress(), {Limit::Bytes, range.GetByteSize()}, + nullptr, force_live_memory); + } if (bytes_disassembled == 0) return {}; @@ -1092,11 +1089,9 @@ InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr, return GetIndexOfInstructionAtAddress(address); } -size_t Disassembler::ParseInstructions(Target &target, Address start, - Limit limit, Stream *error_strm_ptr, - bool force_live_memory) { - m_instruction_list.Clear(); - +size_t Disassembler::AppendInstructions(Target &target, Address start, + Limit limit, Stream *error_strm_ptr, + bool force_live_memory) { if (!start.IsValid()) return 0; @@ -1129,7 +1124,7 @@ size_t Disassembler::ParseInstructions(Target &target, Address start, return DecodeInstructions(start, data, 0, limit.kind == Limit::Instructions ? limit.value : UINT32_MAX, - false, data_from_file); + /*append=*/true, data_from_file); } // Disassembler copy constructor diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp index c9523281dc5659..15879f05a0ff0c 100644 --- a/lldb/source/Symbol/Function.cpp +++ b/lldb/source/Symbol/Function.cpp @@ -488,7 +488,7 @@ lldb::DisassemblerSP Function::GetInstructions(const ExecutionContext &exe_ctx, if (module_sp && exe_ctx.HasTargetScope()) { return Disassembler::DisassembleRange( module_sp->GetArchitecture(), nullptr, nullptr, nullptr, flavor, - exe_ctx.GetTargetRef(), GetAddressRange(), !prefer_file_cache); + exe_ctx.GetTargetRef(), GetAddressRanges(), !prefer_file_cache); } return lldb::DisassemblerSP(); } diff --git a/lldb/test/Shell/ScriptInterpreter/Python/sb_function_ranges.s b/lldb/test/Shell/ScriptInterpreter/Python/sb_function_ranges.s index a9e4104f2aaf76..2e2bc52cd3ff99 100644 --- a/lldb/test/Shell/ScriptInterpreter/Python/sb_function_ranges.s +++ b/lldb/test/Shell/ScriptInterpreter/Python/sb_function_ranges.s @@ -6,6 +6,16 @@ # CHECK: Found 1 function(s). # CHECK: foo: [input.o[0x0-0xe), input.o[0x14-0x1c)] +# CHECK-NEXT: input.o[0x0]: cmpl $0x0, %edi +# CHECK-NEXT: input.o[0x3]: je 0x14 +# CHECK-NEXT: input.o[0x5]: jmp 0x7 +# CHECK-NEXT: input.o[0x7]: callq 0xe +# CHECK-NEXT: input.o[0xc]: jmp 0x1b +# CHECK-EMPTY: +# CHECK-NEXT: input.o[0x14]: callq 0x19 +# CHECK-NEXT: input.o[0x19]: jmp 0x1b +# CHECK-NEXT: input.o[0x1b]: retq + #--- script.py import lldb @@ -17,6 +27,7 @@ def __lldb_init_module(debugger, internal_dict): for ctx in sym_ctxs: fn = ctx.function print(f"{fn.name}: {fn.GetRanges()}") + print(fn.GetInstructions(target)) #--- input.s # An example of a function which has been split into two parts. Roughly >From 49a7bd2db6cb4010fa31107c7607f1c2f6454664 Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Wed, 15 Jan 2025 10:25:10 +0100 Subject: [PATCH 2/2] deref optional --- lldb/source/API/SBInstructionList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/API/SBInstructionList.cpp b/lldb/source/API/SBInstructionList.cpp index 5747ae0366ec30..c18204375dff15 100644 --- a/lldb/source/API/SBInstructionList.cpp +++ b/lldb/source/API/SBInstructionList.cpp @@ -169,7 +169,7 @@ bool SBInstructionList::GetDescription(Stream &sref) { addr, eSymbolContextEverything, sc); } - if (next_addr && addr != next_addr) + if (next_addr && *next_addr != addr) sref.EOL(); inst->Dump(&sref, max_opcode_byte_size, true, false, /*show_control_flow_kind=*/false, nullptr, &sc, &prev_sc, _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits