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 if (target.HasLoadedSections()) {
287 Address symbol_containing_address;
288 if (target.ResolveLoadAddress(m_options.symbol_containing_addr,
289 symbol_containing_address)) {
290 get_ranges(symbol_containing_address);
291 }
292 } else {
293 for (lldb::ModuleSP module_sp : target.GetImages().Modules()) {
294 Address file_address;
295 if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr,
296 file_address)) {
297 get_ranges(file_address);
298 }
299 }
300 }
301
302 if (ranges.empty()) {
303 return llvm::createStringError(
304 llvm::inconvertibleErrorCode(),
305 "Could not find function bounds for address 0x%" PRIx64,
306 m_options.symbol_containing_addr);
307 }
308
309 return CheckRangeSize(std::move(ranges), "the function");
310}
311
312llvm::Expected<std::vector<AddressRange>>
314 Process *process = m_exe_ctx.GetProcessPtr();
315 StackFrame *frame = m_exe_ctx.GetFramePtr();
316 if (!frame) {
317 if (process) {
318 return llvm::createStringError(
319 "Cannot disassemble around the current function without the process "
320 "being stopped.\n");
321 }
322 return llvm::createStringError(
323 "Cannot disassemble around the current function without a selected "
324 "frame: no currently running process.\n");
325 }
326 SymbolContext sc =
327 frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol);
328 std::vector<AddressRange> ranges;
329 if (sc.function)
330 ranges = sc.function->GetAddressRanges();
331 else if (sc.symbol && sc.symbol->ValueIsAddress())
332 ranges.emplace_back(sc.symbol->GetAddress(), sc.symbol->GetByteSize());
333 else
334 ranges.emplace_back(frame->GetFrameCodeAddress(), default_disasm_byte_size);
335
336 return CheckRangeSize(std::move(ranges), "the current function");
337}
338
339llvm::Expected<std::vector<AddressRange>>
341 Process *process = m_exe_ctx.GetProcessPtr();
342 StackFrame *frame = m_exe_ctx.GetFramePtr();
343 if (!frame) {
344 if (process) {
345 return llvm::createStringError(
346 llvm::inconvertibleErrorCode(),
347 "Cannot disassemble around the current "
348 "function without the process being stopped.\n");
349 } else {
350 return llvm::createStringError(llvm::inconvertibleErrorCode(),
351 "Cannot disassemble around the current "
352 "line without a selected frame: "
353 "no currently running process.\n");
354 }
355 }
356
357 LineEntry pc_line_entry(
358 frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
359 if (pc_line_entry.IsValid())
360 return std::vector<AddressRange>{pc_line_entry.range};
361
362 // No line entry, so just disassemble around the current pc
363 m_options.show_mixed = false;
364 return GetPCRanges();
365}
366
367llvm::Expected<std::vector<AddressRange>>
369 ConstString name(m_options.func_name.c_str());
370
371 ModuleFunctionSearchOptions function_options;
372 function_options.include_symbols = true;
373 function_options.include_inlines = true;
374
375 // Find functions matching the given name.
376 SymbolContextList sc_list;
377 GetTarget().GetImages().FindFunctions(name, eFunctionNameTypeAuto,
378 function_options, sc_list);
379
380 std::vector<AddressRange> ranges;
381 llvm::Error range_errs = llvm::Error::success();
382 const uint32_t scope =
383 eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
384 const bool use_inline_block_range = true;
385 for (SymbolContext sc : sc_list.SymbolContexts()) {
386 std::vector<AddressRange> fn_ranges;
387 AddressRange range;
388 for (uint32_t range_idx = 0;
389 sc.GetAddressRange(scope, range_idx, use_inline_block_range, range);
390 ++range_idx)
391 fn_ranges.push_back(std::move(range));
392
393 if (llvm::Expected<std::vector<AddressRange>> checked_ranges =
394 CheckRangeSize(std::move(fn_ranges), "a function"))
395 llvm::move(*checked_ranges, std::back_inserter(ranges));
396 else
397 range_errs =
398 joinErrors(std::move(range_errs), checked_ranges.takeError());
399 }
400 if (ranges.empty()) {
401 if (range_errs)
402 return std::move(range_errs);
403 return llvm::createStringError(llvm::inconvertibleErrorCode(),
404 "Unable to find symbol with name '%s'.\n",
405 name.GetCString());
406 }
407 if (range_errs)
408 result.AppendWarning(toString(std::move(range_errs)));
409 return ranges;
410}
411
412llvm::Expected<std::vector<AddressRange>>
414 Process *process = m_exe_ctx.GetProcessPtr();
415 StackFrame *frame = m_exe_ctx.GetFramePtr();
416 if (!frame) {
417 if (process) {
418 return llvm::createStringError(
419 llvm::inconvertibleErrorCode(),
420 "Cannot disassemble around the current "
421 "function without the process being stopped.\n");
422 } else {
423 return llvm::createStringError(llvm::inconvertibleErrorCode(),
424 "Cannot disassemble around the current "
425 "PC without a selected frame: "
426 "no currently running process.\n");
427 }
428 }
429
430 if (m_options.num_instructions == 0) {
431 // Disassembling at the PC always disassembles some number of
432 // instructions (not the whole function).
433 m_options.num_instructions = default_disasm_num_ins;
434 }
435 return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}};
436}
437
438llvm::Expected<std::vector<AddressRange>>
440 addr_t size = 0;
441 if (m_options.end_addr != LLDB_INVALID_ADDRESS) {
442 if (m_options.end_addr <= m_options.start_addr) {
443 return llvm::createStringError(llvm::inconvertibleErrorCode(),
444 "End address before start address.");
445 }
446 size = m_options.end_addr - m_options.start_addr;
447 }
448 return std::vector<AddressRange>{{Address(m_options.start_addr), size}};
449}
450
451llvm::Expected<std::vector<AddressRange>>
466
468 CommandReturnObject &result) {
469 Target &target = GetTarget();
470
471 if (!m_options.arch.IsValid())
472 m_options.arch = target.GetArchitecture();
473
474 if (!m_options.arch.IsValid()) {
475 result.AppendError(
476 "use the --arch option or set the target architecture to disassemble");
477 return;
478 }
479
480 const char *plugin_name = m_options.GetPluginName();
481 const char *flavor_string = m_options.GetFlavorString();
482 const char *cpu_string = m_options.GetCPUString();
483 const char *features_string = m_options.GetFeaturesString();
484
486 m_options.arch, flavor_string, cpu_string, features_string, plugin_name);
487
488 if (!disassembler) {
489 if (plugin_name) {
491 "Unable to find Disassembler plug-in named '%s' that supports the "
492 "'%s' architecture.\n",
493 plugin_name, m_options.arch.GetArchitectureName());
494 } else
496 "Unable to find Disassembler plug-in for the '%s' architecture.\n",
497 m_options.arch.GetArchitectureName());
498 return;
499 } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec(
500 m_options.arch, flavor_string))
502 "invalid disassembler flavor \"%s\", using default.\n", flavor_string);
503
505
506 if (!command.empty()) {
508 "\"disassemble\" arguments are specified as options.\n");
509 const int terminal_width =
511 const bool use_color = GetCommandInterpreter().GetDebugger().GetUseColor();
513 terminal_width, use_color);
514 return;
515 }
516
517 if (m_options.show_mixed && m_options.num_lines_context == 0)
518 m_options.num_lines_context = 2;
519
520 // Always show the PC in the disassembly
521 uint32_t options = Disassembler::eOptionMarkPCAddress;
522
523 // Mark the source line for the current PC only if we are doing mixed source
524 // and assembly
525 if (m_options.show_mixed)
527
528 if (m_options.show_bytes)
530
531 if (m_options.show_control_flow_kind)
533
534 if (m_options.raw)
536
537 if (m_options.enable_variable_annotations)
539
540 llvm::Expected<std::vector<AddressRange>> ranges =
542 if (!ranges) {
543 result.AppendError(toString(ranges.takeError()));
544 return;
545 }
546
547 bool print_sc_header = ranges->size() > 1;
548 for (AddressRange cur_range : *ranges) {
550 if (m_options.num_instructions == 0) {
551 limit = {Disassembler::Limit::Bytes, cur_range.GetByteSize()};
552 if (limit.value == 0)
554 } else {
555 limit = {Disassembler::Limit::Instructions, m_options.num_instructions};
556 }
558 GetDebugger(), m_options.arch, plugin_name, flavor_string,
559 cpu_string, features_string, m_exe_ctx, cur_range.GetBaseAddress(),
560 limit, m_options.show_mixed,
561 m_options.show_mixed ? m_options.num_lines_context : 0, options,
562 result.GetOutputStream())) {
564 } else {
565 if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) {
567 "Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n",
568 m_options.symbol_containing_addr);
569 } else {
571 "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
572 cur_range.GetBaseAddress().GetLoadAddress(&target));
573 }
574 }
575 if (print_sc_header)
576 result.GetOutputStream() << "\n";
577 }
578}
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:468
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()
void void AppendError(llvm::StringRef in_string)
void AppendWarningWithFormat(const char *format,...) __attribute__((format(printf
void SetStatus(lldb::ReturnStatus status)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
void 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:386
bool GetUseColor() const
Definition Debugger.cpp:452
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:448
void FindFunctions(ConstString name, lldb::FunctionNameType name_type_mask, const ModuleFunctionSearchOptions &options, SymbolContextList &sc_list) const
ModuleIterable Modules() const
Definition ModuleList.h:537
void GenerateOptionUsage(Stream &strm, CommandObject &cmd, uint32_t screen_width, bool use_color)
Definition Options.cpp:392
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:227
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
const SymbolContext & GetSymbolContext(lldb::SymbolContextItem resolve_scope)
Provide a SymbolContext for this StackFrame's current pc value.
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:4599
const char * GetDisassemblyFlavor() const
Definition Target.cpp:4579
const char * GetDisassemblyCPU() const
Definition Target.cpp:4592
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, uint32_t stop_id=SectionLoadHistory::eStopIDNow, bool allow_section_end=false)
Definition Target.cpp:3285
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition Target.h:1014
const ArchSpec & GetArchitecture() const
Definition Target.h:1056
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
const char * toString(AppleArm64ExceptionClass EC)
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:66
bool include_inlines
Include inlined functions.
Definition Module.h:70
bool include_symbols
Include the symbol table.
Definition Module.h:68
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.