LLDB mainline
CommandObjectDisassemble.cpp
Go to the documentation of this file.
1//===-- CommandObjectDisassemble.cpp --------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
12#include "lldb/Core/Module.h"
20#include "lldb/Symbol/Symbol.h"
23#include "lldb/Target/Target.h"
24#include <iterator>
25
26static constexpr unsigned default_disasm_byte_size = 32;
27static constexpr unsigned default_disasm_num_ins = 4;
28
29using namespace lldb;
30using namespace lldb_private;
31
32#define LLDB_OPTIONS_disassemble
33#include "CommandOptions.inc"
34
38
40
42 uint32_t option_idx, llvm::StringRef option_arg,
43 ExecutionContext *execution_context) {
45
46 const int short_option = m_getopt_table[option_idx].val;
47
48 switch (short_option) {
49 case 'm':
50 show_mixed = true;
51 break;
52
53 case 'C':
54 if (option_arg.getAsInteger(0, num_lines_context))
56 "invalid num context lines string: \"%s\"", option_arg.str().c_str());
57 break;
58
59 case 'c':
60 if (option_arg.getAsInteger(0, num_instructions))
62 "invalid num of instructions string: \"%s\"",
63 option_arg.str().c_str());
64 break;
65
66 case 'b':
67 show_bytes = true;
68 break;
69
70 case 'k':
72 break;
73
74 case 's': {
75 start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
79 } break;
80 case 'e': {
81 end_addr = OptionArgParser::ToAddress(execution_context, option_arg,
85 } break;
86
87 case 'n':
88 func_name.assign(std::string(option_arg));
90 break;
91
92 case 'p':
93 at_pc = true;
95 break;
96
97 case 'l':
98 frame_line = true;
99 // Disassemble the current source line kind of implies showing mixed source
100 // code context.
101 show_mixed = true;
103 break;
104
105 case 'P':
106 plugin_name.assign(std::string(option_arg));
107 break;
108
109 case 'F': {
110 TargetSP target_sp =
111 execution_context ? execution_context->GetTargetSP() : TargetSP();
112 if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() ==
113 llvm::Triple::x86 ||
114 target_sp->GetArchitecture().GetTriple().getArch() ==
115 llvm::Triple::x86_64)) {
116 flavor_string.assign(std::string(option_arg));
117 } else
119 "Disassembler flavors are currently only "
120 "supported for x86 and x86_64 targets.");
121 break;
122 }
123
124 case 'X':
125 cpu_string = std::string(option_arg);
126 break;
127
128 case 'Y':
129 features_string = std::string(option_arg);
130 break;
131
132 case 'r':
133 raw = true;
134 break;
135
136 case 'f':
137 current_function = true;
139 break;
140
141 case 'A':
142 if (execution_context) {
143 const auto &target_sp = execution_context->GetTargetSP();
144 auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr;
145 arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg);
146 }
147 break;
148
149 case 'a': {
151 execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
154 }
155 } break;
156
157 case 'v':
159 break;
160
161 case '\x01':
162 force = true;
163 break;
164
165 default:
166 llvm_unreachable("Unimplemented option");
167 }
168
169 return error;
170}
171
173 ExecutionContext *execution_context) {
174 show_mixed = false;
175 show_bytes = false;
179 func_name.clear();
180 current_function = false;
181 at_pc = false;
182 frame_line = false;
186 raw = false;
188 plugin_name.clear();
189
190 Target *target =
191 execution_context ? execution_context->GetTargetPtr() : nullptr;
192
193 if (target) {
194 // This is a hack till we get the ability to specify features based on
195 // architecture. For now GetDisassemblyFlavor is really only valid for x86
196 // (and for the llvm assembler plugin, but I'm papering over that since that
197 // is the only disassembler plugin we have...
198 if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 ||
199 target->GetArchitecture().GetTriple().getArch() ==
200 llvm::Triple::x86_64) {
201 flavor_string.assign(target->GetDisassemblyFlavor());
202 } else {
203 flavor_string.assign("default");
204 }
205 if (const char *cpu = target->GetDisassemblyCPU())
206 cpu_string.assign(cpu);
207 if (const char *features = target->GetDisassemblyFeatures())
208 features_string.assign(features);
209 } else {
210 flavor_string.assign("default");
211 cpu_string.assign("default");
212 features_string.assign("default");
213 }
214
215 arch.Clear();
217 force = false;
218}
219
226
227llvm::ArrayRef<OptionDefinition>
229 return llvm::ArrayRef(g_disassemble_options);
230}
231
232// CommandObjectDisassemble
233
235 CommandInterpreter &interpreter)
237 interpreter, "disassemble",
238 "Disassemble specified instructions in the current target. "
239 "Defaults to the current function for the current thread and "
240 "stack frame.",
241 "disassemble [<cmd-options>]", eCommandRequiresTarget) {}
242
244
245llvm::Expected<std::vector<AddressRange>>
246CommandObjectDisassemble::CheckRangeSize(std::vector<AddressRange> ranges,
247 llvm::StringRef what) {
248 addr_t total_range_size = 0;
249 for (const AddressRange &r : ranges)
250 total_range_size += r.GetByteSize();
251
252 if (m_options.num_instructions > 0 || m_options.force ||
253 total_range_size < GetDebugger().GetStopDisassemblyMaxSize())
254 return ranges;
255
256 StreamString msg;
257 msg << "not disassembling " << what << " because it is very large ";
258 for (const AddressRange &r : ranges)
261 msg << ". To disassemble specify an instruction count limit, start/stop "
262 "addresses or use the --force option";
263 return llvm::createStringError(msg.GetString());
264}
265
266llvm::Expected<std::vector<AddressRange>>
268 std::vector<AddressRange> ranges;
269 const auto &get_ranges = [&](Address addr) {
270 ModuleSP module_sp(addr.GetModule());
271 SymbolContext sc;
272 bool resolve_tail_call_address = true;
273 addr.GetModule()->ResolveSymbolContextForAddress(
274 addr, eSymbolContextEverything, sc, resolve_tail_call_address);
275 if (sc.function || sc.symbol) {
276 AddressRange range;
277 for (uint32_t idx = 0;
278 sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol,
279 idx, false, range);
280 ++idx)
281 ranges.push_back(range);
282 }
283 };
284
285 Target *target = GetTarget();
286 assert(target && "target guaranteed by eCommandRequiresTarget");
287 if (target->HasLoadedSections()) {
288 Address symbol_containing_address;
289 if (target->ResolveLoadAddress(m_options.symbol_containing_addr,
290 symbol_containing_address)) {
291 get_ranges(symbol_containing_address);
292 }
293 } else {
294 for (lldb::ModuleSP module_sp : target->GetImages().Modules()) {
295 Address file_address;
296 if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr,
297 file_address)) {
298 get_ranges(file_address);
299 }
300 }
301 }
302
303 if (ranges.empty()) {
304 return llvm::createStringError(
305 llvm::inconvertibleErrorCode(),
306 "Could not find function bounds for address 0x%" PRIx64,
307 m_options.symbol_containing_addr);
308 }
309
310 return CheckRangeSize(std::move(ranges), "the function");
311}
312
313llvm::Expected<std::vector<AddressRange>>
315 Process *process = m_exe_ctx.GetProcessPtr();
316 StackFrame *frame = m_exe_ctx.GetFramePtr();
317 if (!frame) {
318 if (process) {
319 return llvm::createStringError(
320 "Cannot disassemble around the current function without the process "
321 "being stopped.\n");
322 }
323 return llvm::createStringError(
324 "Cannot disassemble around the current function without a selected "
325 "frame: no currently running process.\n");
326 }
327 SymbolContext sc =
328 frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol);
329 std::vector<AddressRange> ranges;
330 if (sc.function)
331 ranges = sc.function->GetAddressRanges();
332 else if (sc.symbol && sc.symbol->ValueIsAddress())
333 ranges.emplace_back(sc.symbol->GetAddress(), sc.symbol->GetByteSize());
334 else
335 ranges.emplace_back(frame->GetFrameCodeAddress(), default_disasm_byte_size);
336
337 return CheckRangeSize(std::move(ranges), "the current function");
338}
339
340llvm::Expected<std::vector<AddressRange>>
342 Process *process = m_exe_ctx.GetProcessPtr();
343 StackFrame *frame = m_exe_ctx.GetFramePtr();
344 if (!frame) {
345 if (process) {
346 return llvm::createStringError(
347 llvm::inconvertibleErrorCode(),
348 "Cannot disassemble around the current "
349 "function without the process being stopped.\n");
350 } else {
351 return llvm::createStringError(llvm::inconvertibleErrorCode(),
352 "Cannot disassemble around the current "
353 "line without a selected frame: "
354 "no currently running process.\n");
355 }
356 }
357
358 LineEntry pc_line_entry(
359 frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
360 if (pc_line_entry.IsValid())
361 return std::vector<AddressRange>{pc_line_entry.range};
362
363 // No line entry, so just disassemble around the current pc
364 m_options.show_mixed = false;
365 return GetPCRanges();
366}
367
368llvm::Expected<std::vector<AddressRange>>
370 ConstString name(m_options.func_name);
371
372 ModuleFunctionSearchOptions function_options;
373 function_options.include_symbols = true;
374 function_options.include_inlines = true;
375
376 // Find functions matching the given name.
377 SymbolContextList sc_list;
378 GetTarget()->GetImages().FindFunctions(name, eFunctionNameTypeAuto,
379 function_options, sc_list);
380
381 std::vector<AddressRange> ranges;
382 llvm::Error range_errs = llvm::Error::success();
383 const uint32_t scope =
384 eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
385 const bool use_inline_block_range = true;
386 for (SymbolContext sc : sc_list.SymbolContexts()) {
387 std::vector<AddressRange> fn_ranges;
388 AddressRange range;
389 for (uint32_t range_idx = 0;
390 sc.GetAddressRange(scope, range_idx, use_inline_block_range, range);
391 ++range_idx)
392 fn_ranges.push_back(std::move(range));
393
394 if (llvm::Expected<std::vector<AddressRange>> checked_ranges =
395 CheckRangeSize(std::move(fn_ranges), "a function"))
396 llvm::move(*checked_ranges, std::back_inserter(ranges));
397 else
398 range_errs =
399 joinErrors(std::move(range_errs), checked_ranges.takeError());
400 }
401 if (ranges.empty()) {
402 if (range_errs)
403 return std::move(range_errs);
404 return llvm::createStringError(llvm::inconvertibleErrorCode(),
405 "Unable to find symbol with name '%s'.\n",
406 name.GetCString());
407 }
408 if (range_errs)
409 result.AppendWarning(toString(std::move(range_errs)));
410 return ranges;
411}
412
413llvm::Expected<std::vector<AddressRange>>
415 Process *process = m_exe_ctx.GetProcessPtr();
416 StackFrame *frame = m_exe_ctx.GetFramePtr();
417 if (!frame) {
418 if (process) {
419 return llvm::createStringError(
420 llvm::inconvertibleErrorCode(),
421 "Cannot disassemble around the current "
422 "function without the process being stopped.\n");
423 } else {
424 return llvm::createStringError(llvm::inconvertibleErrorCode(),
425 "Cannot disassemble around the current "
426 "PC without a selected frame: "
427 "no currently running process.\n");
428 }
429 }
430
431 if (m_options.num_instructions == 0) {
432 // Disassembling at the PC always disassembles some number of
433 // instructions (not the whole function).
434 m_options.num_instructions = default_disasm_num_ins;
435 }
436 return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}};
437}
438
439llvm::Expected<std::vector<AddressRange>>
441 addr_t size = 0;
442 if (m_options.end_addr != LLDB_INVALID_ADDRESS) {
443 if (m_options.end_addr <= m_options.start_addr) {
444 return llvm::createStringError(llvm::inconvertibleErrorCode(),
445 "End address before start address.");
446 }
447 size = m_options.end_addr - m_options.start_addr;
448 }
449 return std::vector<AddressRange>{{Address(m_options.start_addr), size}};
450}
451
452llvm::Expected<std::vector<AddressRange>>
467
469 CommandReturnObject &result) {
470 Target *target = GetTarget();
471 assert(target && "target guaranteed by eCommandRequiresTarget");
472 if (!m_options.arch.IsValid())
473 m_options.arch = target->GetArchitecture();
474
475 if (!m_options.arch.IsValid()) {
476 result.AppendError(
477 "use the --arch option or set the target architecture to disassemble");
478 return;
479 }
480
481 const char *plugin_name = m_options.GetPluginName();
482 const char *flavor_string = m_options.GetFlavorString();
483 const char *cpu_string = m_options.GetCPUString();
484 const char *features_string = m_options.GetFeaturesString();
485
487 m_options.arch, flavor_string, cpu_string, features_string, plugin_name);
488
489 if (!disassembler) {
490 if (plugin_name) {
492 "Unable to find Disassembler plug-in named '%s' that supports the "
493 "'%s' architecture",
494 plugin_name, m_options.arch.GetArchitectureName());
495 } else
497 "Unable to find Disassembler plug-in for the '%s' architecture",
498 m_options.arch.GetArchitectureName());
499 return;
500 } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec(
501 m_options.arch, flavor_string))
503 "invalid disassembler flavor \"{0}\", using default", flavor_string);
504
506
507 if (!command.empty()) {
509 "\"disassemble\" arguments are specified as options");
510 const int terminal_width =
512 const bool use_color = GetCommandInterpreter().GetDebugger().GetUseColor();
514 terminal_width, use_color);
515 return;
516 }
517
518 if (m_options.show_mixed && m_options.num_lines_context == 0)
519 m_options.num_lines_context = 2;
520
521 // Always show the PC in the disassembly
522 uint32_t options = Disassembler::eOptionMarkPCAddress;
523
524 // Mark the source line for the current PC only if we are doing mixed source
525 // and assembly
526 if (m_options.show_mixed)
528
529 if (m_options.show_bytes)
531
532 if (m_options.show_control_flow_kind)
534
535 if (m_options.raw)
537
538 if (m_options.enable_variable_annotations)
540
541 llvm::Expected<std::vector<AddressRange>> ranges =
543 if (!ranges) {
544 result.AppendError(toString(ranges.takeError()));
545 return;
546 }
547
548 bool print_sc_header = ranges->size() > 1;
549 for (AddressRange cur_range : *ranges) {
551 if (m_options.num_instructions == 0) {
552 limit = {Disassembler::Limit::Bytes, cur_range.GetByteSize()};
553 if (limit.value == 0)
555 } else {
556 limit = {Disassembler::Limit::Instructions, m_options.num_instructions};
557 }
559 GetDebugger(), m_options.arch, plugin_name, flavor_string,
560 cpu_string, features_string, m_exe_ctx, cur_range.GetBaseAddress(),
561 limit, m_options.show_mixed,
562 m_options.show_mixed ? m_options.num_lines_context : 0, options,
563 result.GetOutputStream())) {
565 } else {
566 if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) {
568 "Failed to disassemble memory in function at 0x%8.8" PRIx64,
569 m_options.symbol_containing_addr);
570 } else {
572 "Failed to disassemble memory at 0x%8.8" PRIx64,
573 cur_range.GetBaseAddress().GetLoadAddress(target));
574 }
575 }
576 if (print_sc_header)
577 result.GetOutputStream() << "\n";
578 }
579}
static constexpr unsigned default_disasm_num_ins
static constexpr unsigned default_disasm_byte_size
static llvm::raw_ostream & error(Stream &strm)
A section + offset based address range class.
A section + offset based address class.
Definition Address.h:62
@ DumpStyleFileAddress
Display as the file address (if any).
Definition Address.h:87
@ DumpStyleLoadAddress
Display as the load address (if resolved).
Definition Address.h:99
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:460
A command line argument class.
Definition Args.h:33
bool empty() const
Definition Args.h:122
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
void OptionParsingStarting(ExecutionContext *execution_context) override
Status OptionParsingFinished(ExecutionContext *execution_context) override
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
llvm::Expected< std::vector< AddressRange > > GetCurrentFunctionRanges()
void DoExecute(Args &command, CommandReturnObject &result) override
llvm::Expected< std::vector< AddressRange > > GetStartEndAddressRanges()
CommandObjectDisassemble(CommandInterpreter &interpreter)
llvm::Expected< std::vector< AddressRange > > GetNameRanges(CommandReturnObject &result)
llvm::Expected< std::vector< AddressRange > > GetPCRanges()
llvm::Expected< std::vector< AddressRange > > CheckRangeSize(std::vector< AddressRange > ranges, llvm::StringRef what)
llvm::Expected< std::vector< AddressRange > > GetCurrentLineRanges()
llvm::Expected< std::vector< AddressRange > > GetContainingAddressRanges()
llvm::Expected< std::vector< AddressRange > > GetRangesForSelectedMode(CommandReturnObject &result)
CommandObjectParsed(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
CommandInterpreter & GetCommandInterpreter()
Target * GetTarget()
Get the target this command should operate on.
void AppendError(llvm::StringRef in_string)
void AppendWarningWithFormatv(const char *format, Args &&...args)
void SetStatus(lldb::ReturnStatus status)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
void AppendWarning(llvm::StringRef in_string)
A uniqued constant string class.
Definition ConstString.h:40
const char * GetCString() const
Get the string value as a C string.
uint64_t GetTerminalWidth() const
Definition Debugger.cpp:459
bool GetUseColor() const
Definition Debugger.cpp:525
static lldb::DisassemblerSP FindPlugin(const ArchSpec &arch, const char *flavor, const char *cpu, const char *features, const char *plugin_name)
static bool Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, const char *flavor, const char *cpu, const char *features, const ExecutionContext &exe_ctx, const Address &start, Limit limit, bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
const lldb::TargetSP & GetTargetSP() const
Get accessor to get the target shared pointer.
Target * GetTargetPtr() const
Returns a pointer to the target object.
AddressRanges GetAddressRanges()
Definition Function.h:440
void FindFunctions(ConstString name, lldb::FunctionNameType name_type_mask, const ModuleFunctionSearchOptions &options, SymbolContextList &sc_list) const
ModuleIterable Modules() const
Definition ModuleList.h:570
void GenerateOptionUsage(Stream &strm, CommandObject &cmd, uint32_t screen_width, bool use_color)
Definition Options.cpp:351
std::vector< Option > m_getopt_table
Definition Options.h:198
static ArchSpec GetAugmentedArchSpec(Platform *platform, llvm::StringRef triple)
Augments the triple either with information from platform or the host system (if platform is null).
Definition Platform.cpp:321
A plug-in interface definition class for debugging a process.
Definition Process.h:357
This base class provides an interface to stack frames.
Definition StackFrame.h:44
virtual const SymbolContext & GetSymbolContext(lldb::SymbolContextItem resolve_scope)
Provide a SymbolContext for this StackFrame's current pc value.
virtual const Address & GetFrameCodeAddress()
Get an Address for the current pc value in this StackFrame.
An error handling class.
Definition Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
llvm::StringRef GetString() const
Defines a list of symbol context objects.
SymbolContextIterable SymbolContexts()
Defines a symbol context baton that can be handed other debug core functions.
Function * function
The Function for a given query.
bool GetAddressRange(uint32_t scope, uint32_t range_idx, bool use_inline_block_range, AddressRange &range) const
Get the address range contained within a symbol context.
Symbol * symbol
The Symbol for a given query.
LineEntry line_entry
The LineEntry for a given query.
bool ValueIsAddress() const
Definition Symbol.cpp:165
lldb::addr_t GetByteSize() const
Definition Symbol.cpp:431
Address GetAddress() const
Definition Symbol.h:89
const char * GetDisassemblyFeatures() const
Definition Target.cpp:5282
const char * GetDisassemblyFlavor() const
Definition Target.cpp:5262
const char * GetDisassemblyCPU() const
Definition Target.cpp:5275
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, uint32_t stop_id=SectionLoadHistory::eStopIDNow, bool allow_section_end=false)
Definition Target.cpp:3448
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition Target.h:1241
const ArchSpec & GetArchitecture() const
Definition Target.h:1283
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
std::string toString(FormatterBytecode::OpCodes op)
std::shared_ptr< lldb_private::Disassembler > DisassemblerSP
@ eReturnStatusSuccessFinishResult
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::Module > ModuleSP
A line table entry class.
Definition LineEntry.h:21
bool IsValid() const
Check if a line entry object is valid.
Definition LineEntry.cpp:35
AddressRange range
The section offset address range for this line entry.
Definition LineEntry.h:137
Options used by Module::FindFunctions.
Definition Module.h:67
bool include_inlines
Include inlined functions.
Definition Module.h:71
bool include_symbols
Include the symbol table.
Definition Module.h:69
static lldb::addr_t ToAddress(const ExecutionContext *exe_ctx, llvm::StringRef s, lldb::addr_t fail_value, Status *error_ptr)
Try to parse an address.