Skip to content

[lldb] Implement (SB)Function::GetInstructions for discontinuous functions #122933

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions lldb/include/lldb/Core/Disassembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion lldb/source/API/SBFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions lldb/source/API/SBInstructionList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -165,10 +169,14 @@ bool SBInstructionList::GetDescription(Stream &sref) {
addr, eSymbolContextEverything, sc);
}

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,
&format, 0);
sref.EOL();
next_addr = addr;
next_addr->Slide(inst->GetOpcode().GetByteSize());
}
return true;
}
Expand Down
27 changes: 11 additions & 16 deletions lldb/source/Core/Disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {};

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Symbol/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
11 changes: 11 additions & 0 deletions lldb/test/Shell/ScriptInterpreter/Python/sb_function_ranges.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Loading