LLDB  mainline
CommandObjectDisassemble.cpp
Go to the documentation of this file.
1 //===-- CommandObjectDisassemble.cpp ----------------------------*- C++ -*-===//
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 
10 #include "lldb/Core/AddressRange.h"
11 #include "lldb/Core/Disassembler.h"
12 #include "lldb/Core/Module.h"
14 #include "lldb/Host/OptionParser.h"
20 #include "lldb/Symbol/Function.h"
21 #include "lldb/Symbol/Symbol.h"
22 #include "lldb/Target/Process.h"
24 #include "lldb/Target/StackFrame.h"
25 #include "lldb/Target/Target.h"
26 
27 #define DEFAULT_DISASM_BYTE_SIZE 32
28 #define DEFAULT_DISASM_NUM_INS 4
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 static constexpr OptionDefinition g_disassemble_options[] = {
34  // clang-format off
35  { LLDB_OPT_SET_ALL, false, "bytes", 'b', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Show opcode bytes when disassembling." },
36  { LLDB_OPT_SET_ALL, false, "context", 'C', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeNumLines, "Number of context lines of source to show." },
37  { LLDB_OPT_SET_ALL, false, "mixed", 'm', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Enable mixed source and assembly display." },
38  { LLDB_OPT_SET_ALL, false, "raw", 'r', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Print raw disassembly with no symbol information." },
39  { LLDB_OPT_SET_ALL, false, "plugin", 'P', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePlugin, "Name of the disassembler plugin you want to use." },
40  { LLDB_OPT_SET_ALL, false, "flavor", 'F', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeDisassemblyFlavor, "Name of the disassembly flavor you want to use. "
41  "Currently the only valid options are default, and for Intel "
42  "architectures, att and intel." },
43  { LLDB_OPT_SET_ALL, false, "arch", 'A', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeArchitecture, "Specify the architecture to use from cross disassembly." },
44  { LLDB_OPT_SET_1 |
45  LLDB_OPT_SET_2, true, "start-address", 's', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddressOrExpression, "Address at which to start disassembling." },
46  { LLDB_OPT_SET_1, false, "end-address", 'e', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddressOrExpression, "Address at which to end disassembling." },
47  { LLDB_OPT_SET_2 |
50  LLDB_OPT_SET_5, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeNumLines, "Number of instructions to display." },
51  { LLDB_OPT_SET_3, false, "name", 'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, "Disassemble entire contents of the given function name." },
52  { LLDB_OPT_SET_4, false, "frame", 'f', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Disassemble from the start of the current frame's function." },
53  { LLDB_OPT_SET_5, false, "pc", 'p', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Disassemble around the current pc." },
54  { LLDB_OPT_SET_6, false, "line", 'l', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Disassemble the current frame's current source line instructions if there is debug line "
55  "table information, else disassemble around the pc." },
56  { LLDB_OPT_SET_7, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddressOrExpression, "Disassemble function containing this address." },
57  // clang-format on
58 };
59 
60 CommandObjectDisassemble::CommandOptions::CommandOptions()
61  : Options(), num_lines_context(0), num_instructions(0), func_name(),
62  current_function(false), start_addr(), end_addr(), at_pc(false),
63  frame_line(false), plugin_name(), flavor_string(), arch(),
64  some_location_specified(false), symbol_containing_addr() {
65  OptionParsingStarting(nullptr);
66 }
67 
69 
71  uint32_t option_idx, llvm::StringRef option_arg,
72  ExecutionContext *execution_context) {
73  Status error;
74 
75  const int short_option = m_getopt_table[option_idx].val;
76 
77  switch (short_option) {
78  case 'm':
79  show_mixed = true;
80  break;
81 
82  case 'C':
83  if (option_arg.getAsInteger(0, num_lines_context))
84  error.SetErrorStringWithFormat("invalid num context lines string: \"%s\"",
85  option_arg.str().c_str());
86  break;
87 
88  case 'c':
89  if (option_arg.getAsInteger(0, num_instructions))
91  "invalid num of instructions string: \"%s\"",
92  option_arg.str().c_str());
93  break;
94 
95  case 'b':
96  show_bytes = true;
97  break;
98 
99  case 's': {
100  start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
101  LLDB_INVALID_ADDRESS, &error);
104  } break;
105  case 'e': {
106  end_addr = OptionArgParser::ToAddress(execution_context, option_arg,
107  LLDB_INVALID_ADDRESS, &error);
110  } break;
111 
112  case 'n':
113  func_name.assign(option_arg);
115  break;
116 
117  case 'p':
118  at_pc = true;
120  break;
121 
122  case 'l':
123  frame_line = true;
124  // Disassemble the current source line kind of implies showing mixed source
125  // code context.
126  show_mixed = true;
128  break;
129 
130  case 'P':
131  plugin_name.assign(option_arg);
132  break;
133 
134  case 'F': {
135  TargetSP target_sp =
136  execution_context ? execution_context->GetTargetSP() : TargetSP();
137  if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() ==
138  llvm::Triple::x86 ||
139  target_sp->GetArchitecture().GetTriple().getArch() ==
140  llvm::Triple::x86_64)) {
141  flavor_string.assign(option_arg);
142  } else
143  error.SetErrorStringWithFormat("Disassembler flavors are currently only "
144  "supported for x86 and x86_64 targets.");
145  break;
146  }
147 
148  case 'r':
149  raw = true;
150  break;
151 
152  case 'f':
153  current_function = true;
155  break;
156 
157  case 'A':
158  if (execution_context) {
159  const auto &target_sp = execution_context->GetTargetSP();
160  auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr;
161  arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg);
162  }
163  break;
164 
165  case 'a': {
167  execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
170  }
171  } break;
172 
173  default:
174  error.SetErrorStringWithFormat("unrecognized short option '%c'",
175  short_option);
176  break;
177  }
178 
179  return error;
180 }
181 
183  ExecutionContext *execution_context) {
184  show_mixed = false;
185  show_bytes = false;
186  num_lines_context = 0;
187  num_instructions = 0;
188  func_name.clear();
189  current_function = false;
190  at_pc = false;
191  frame_line = false;
195  raw = false;
196  plugin_name.clear();
197 
198  Target *target =
199  execution_context ? execution_context->GetTargetPtr() : nullptr;
200 
201  // This is a hack till we get the ability to specify features based on
202  // architecture. For now GetDisassemblyFlavor is really only valid for x86
203  // (and for the llvm assembler plugin, but I'm papering over that since that
204  // is the only disassembler plugin we have...
205  if (target) {
206  if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 ||
207  target->GetArchitecture().GetTriple().getArch() ==
208  llvm::Triple::x86_64) {
209  flavor_string.assign(target->GetDisassemblyFlavor());
210  } else
211  flavor_string.assign("default");
212 
213  } else
214  flavor_string.assign("default");
215 
216  arch.Clear();
217  some_location_specified = false;
218 }
219 
221  ExecutionContext *execution_context) {
223  current_function = true;
224  return Status();
225 }
226 
227 llvm::ArrayRef<OptionDefinition>
229  return llvm::makeArrayRef(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>]"),
242  m_options() {}
243 
245 
247  CommandReturnObject &result) {
248  Target *target = GetDebugger().GetSelectedTarget().get();
249  if (target == nullptr) {
250  result.AppendError("invalid target, create a debug target using the "
251  "'target create' command");
253  return false;
254  }
255  if (!m_options.arch.IsValid())
256  m_options.arch = target->GetArchitecture();
257 
258  if (!m_options.arch.IsValid()) {
259  result.AppendError(
260  "use the --arch option or set the target architecture to disassemble");
262  return false;
263  }
264 
265  const char *plugin_name = m_options.GetPluginName();
266  const char *flavor_string = m_options.GetFlavorString();
267 
268  DisassemblerSP disassembler =
269  Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
270 
271  if (!disassembler) {
272  if (plugin_name) {
273  result.AppendErrorWithFormat(
274  "Unable to find Disassembler plug-in named '%s' that supports the "
275  "'%s' architecture.\n",
276  plugin_name, m_options.arch.GetArchitectureName());
277  } else
278  result.AppendErrorWithFormat(
279  "Unable to find Disassembler plug-in for the '%s' architecture.\n",
282  return false;
283  } else if (flavor_string != nullptr &&
284  !disassembler->FlavorValidForArchSpec(m_options.arch,
285  flavor_string))
287  "invalid disassembler flavor \"%s\", using default.\n", flavor_string);
288 
290 
291  if (!command.empty()) {
292  result.AppendErrorWithFormat(
293  "\"disassemble\" arguments are specified as options.\n");
294  const int terminal_width =
297  terminal_width);
299  return false;
300  }
301 
304 
305  // Always show the PC in the disassembly
307 
308  // Mark the source line for the current PC only if we are doing mixed source
309  // and assembly
310  if (m_options.show_mixed)
312 
313  if (m_options.show_bytes)
315 
316  if (m_options.raw)
318 
319  if (!m_options.func_name.empty()) {
320  ConstString name(m_options.func_name.c_str());
321 
323  GetDebugger(), m_options.arch, plugin_name, flavor_string,
324  m_exe_ctx, name,
325  nullptr, // Module *
328  result.GetOutputStream())) {
330  } else {
331  result.AppendErrorWithFormat("Unable to find symbol with name '%s'.\n",
332  name.GetCString());
334  }
335  } else {
336  std::vector<AddressRange> ranges;
337  AddressRange range;
338  StackFrame *frame = m_exe_ctx.GetFramePtr();
339  if (m_options.frame_line) {
340  if (frame == nullptr) {
341  result.AppendError("Cannot disassemble around the current line without "
342  "a selected frame.\n");
344  return false;
345  }
346  LineEntry pc_line_entry(
347  frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
348  if (pc_line_entry.IsValid()) {
349  range = pc_line_entry.range;
350  } else {
351  m_options.at_pc =
352  true; // No line entry, so just disassemble around the current pc
353  m_options.show_mixed = false;
354  }
355  } else if (m_options.current_function) {
356  if (frame == nullptr) {
357  result.AppendError("Cannot disassemble around the current function "
358  "without a selected frame.\n");
360  return false;
361  }
362  Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
363  if (symbol) {
364  range.GetBaseAddress() = symbol->GetAddress();
365  range.SetByteSize(symbol->GetByteSize());
366  }
367  }
368 
369  // Did the "m_options.frame_line" find a valid range already? If so skip
370  // the rest...
371  if (range.GetByteSize() == 0) {
372  if (m_options.at_pc) {
373  if (frame == nullptr) {
374  result.AppendError("Cannot disassemble around the current PC without "
375  "a selected frame.\n");
377  return false;
378  }
379  range.GetBaseAddress() = frame->GetFrameCodeAddress();
380  if (m_options.num_instructions == 0) {
381  // Disassembling at the PC always disassembles some number of
382  // instructions (not the whole function).
384  }
385  ranges.push_back(range);
386  } else {
388  if (range.GetBaseAddress().IsValid()) {
391  result.AppendErrorWithFormat(
392  "End address before start address.\n");
394  return false;
395  }
397  }
398  ranges.push_back(range);
399  } else {
401  target) {
402  if (!target->GetSectionLoadList().IsEmpty()) {
403  bool failed = false;
404  Address symbol_containing_address;
407  symbol_containing_address)) {
408  ModuleSP module_sp(symbol_containing_address.GetModule());
409  SymbolContext sc;
410  bool resolve_tail_call_address = true; // PC can be one past the
411  // address range of the
412  // function.
413  module_sp->ResolveSymbolContextForAddress(
414  symbol_containing_address, eSymbolContextEverything, sc,
415  resolve_tail_call_address);
416  if (sc.function || sc.symbol) {
417  sc.GetAddressRange(eSymbolContextFunction |
418  eSymbolContextSymbol,
419  0, false, range);
420  } else {
421  failed = true;
422  }
423  } else {
424  failed = true;
425  }
426  if (failed) {
427  result.AppendErrorWithFormat(
428  "Could not find function bounds for address 0x%" PRIx64
429  "\n",
432  return false;
433  }
434  ranges.push_back(range);
435  } else {
436  for (lldb::ModuleSP module_sp : target->GetImages().Modules()) {
438  Address file_address;
439  if (module_sp->ResolveFileAddress(file_addr, file_address)) {
440  SymbolContext sc;
441  bool resolve_tail_call_address = true; // PC can be one past
442  // the address range of
443  // the function.
444  module_sp->ResolveSymbolContextForAddress(
445  file_address, eSymbolContextEverything, sc,
446  resolve_tail_call_address);
447  if (sc.function || sc.symbol) {
448  sc.GetAddressRange(eSymbolContextFunction |
449  eSymbolContextSymbol,
450  0, false, range);
451  ranges.push_back(range);
452  }
453  }
454  }
455  }
456  }
457  }
458  }
459  } else
460  ranges.push_back(range);
461 
462  if (m_options.num_instructions != 0) {
463  if (ranges.empty()) {
464  // The default action is to disassemble the current frame function.
465  if (frame) {
466  SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction |
467  eSymbolContextSymbol));
468  if (sc.function)
469  range.GetBaseAddress() =
470  sc.function->GetAddressRange().GetBaseAddress();
471  else if (sc.symbol && sc.symbol->ValueIsAddress())
472  range.GetBaseAddress() = sc.symbol->GetAddress();
473  else
474  range.GetBaseAddress() = frame->GetFrameCodeAddress();
475  }
476 
477  if (!range.GetBaseAddress().IsValid()) {
478  result.AppendError("invalid frame");
480  return false;
481  }
482  }
483 
484  bool print_sc_header = ranges.size() > 1;
485  for (AddressRange cur_range : ranges) {
487  GetDebugger(), m_options.arch, plugin_name, flavor_string,
488  m_exe_ctx, cur_range.GetBaseAddress(),
491  result.GetOutputStream())) {
493  } else {
495  result.AppendErrorWithFormat(
496  "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
499  result.AppendErrorWithFormat(
500  "Failed to disassemble memory in function at 0x%8.8" PRIx64
501  ".\n",
504  }
505  }
506  if (print_sc_header)
507  result.AppendMessage("\n");
508  } else {
509  if (ranges.empty()) {
510  // The default action is to disassemble the current frame function.
511  if (frame) {
512  SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction |
513  eSymbolContextSymbol));
514  if (sc.function)
515  range = sc.function->GetAddressRange();
516  else if (sc.symbol && sc.symbol->ValueIsAddress()) {
517  range.GetBaseAddress() = sc.symbol->GetAddress();
518  range.SetByteSize(sc.symbol->GetByteSize());
519  } else
520  range.GetBaseAddress() = frame->GetFrameCodeAddress();
521  } else {
522  result.AppendError("invalid frame");
524  return false;
525  }
526  ranges.push_back(range);
527  }
528 
529  bool print_sc_header = ranges.size() > 1;
530  for (AddressRange cur_range : ranges) {
531  if (cur_range.GetByteSize() == 0)
532  cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
533 
535  GetDebugger(), m_options.arch, plugin_name, flavor_string,
539  result.GetOutputStream())) {
541  } else {
542  result.AppendErrorWithFormat(
543  "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
546  }
547  if (print_sc_header)
548  result.AppendMessage("\n");
549  }
550  }
551  }
552 
553  return result.Succeeded();
554 }
A line table entry class.
Definition: LineEntry.h:20
A command line argument class.
Definition: Args.h:32
bool empty() const
Definition: Args.h:113
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
lldb::addr_t GetByteSize() const
Get accessor for the byte size of this range.
Definition: AddressRange.h:232
const ArchSpec & GetArchitecture() const
Definition: Target.h:941
Defines a symbol context baton that can be handed other debug core functions.
Definition: SymbolContext.h:33
const lldb::TargetSP & GetTargetSP() const
Get accessor to get the target shared pointer.
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
static constexpr OptionDefinition g_disassemble_options[]
bool DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectDisassemble(CommandInterpreter &interpreter)
static bool Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, const char *flavor, const ExecutionContext &exe_ctx, const AddressRange &range, uint32_t num_instructions, 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.
Address GetAddress() const
Definition: Symbol.h:72
bool IsValid() const
Tests if this ArchSpec is valid.
Definition: ArchSpec.h:329
bool SetOffset(lldb::addr_t offset)
Set accessor for the offset.
Definition: Address.h:419
StackFrame * GetFramePtr() const
Returns a pointer to the frame object.
Symbol * symbol
The Symbol for a given query.
std::vector< Option > m_getopt_table
Definition: Options.h:209
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:431
static lldb::DisassemblerSP FindPlugin(const ArchSpec &arch, const char *flavor, const char *plugin_name)
void Clear()
Clears the object state.
Definition: ArchSpec.cpp:580
const SymbolContext & GetSymbolContext(lldb::SymbolContextItem resolve_scope)
Provide a SymbolContext for this StackFrame&#39;s current pc value.
Definition: StackFrame.cpp:267
#define LLDB_OPT_SET_3
Definition: lldb-defines.h:113
Function * function
The Function for a given query.
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition: ArchSpec.cpp:591
lldb::addr_t GetByteSize() const
Definition: Symbol.cpp:408
Target * GetTargetPtr() const
Returns a pointer to the target object.
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
void OptionParsingStarting(ExecutionContext *execution_context) override
uint32_t GetTerminalWidth() const
Definition: Debugger.cpp:442
SectionLoadList & GetSectionLoadList()
Definition: Target.h:1012
void AppendMessage(llvm::StringRef in_string)
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, bool allow_section_end=false) const
const char * GetDisassemblyFlavor() const
Definition: Target.cpp:3796
#define LLDB_OPT_SET_4
Definition: lldb-defines.h:114
Status OptionParsingFinished(ExecutionContext *execution_context) override
A section + offset based address class.
Definition: Address.h:80
bool IsValid() const
Check if the object state is valid.
Definition: Address.h:343
static lldb::addr_t ToAddress(const ExecutionContext *exe_ctx, llvm::StringRef s, lldb::addr_t fail_value, Status *error)
ModuleIterable Modules()
Definition: ModuleList.h:559
#define LLDB_OPT_SET_2
Definition: lldb-defines.h:112
ExecutionContext m_exe_ctx
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition: Target.h:899
A command line option parsing protocol class.
Definition: Options.h:62
CommandInterpreter & GetCommandInterpreter()
void void AppendError(llvm::StringRef in_string)
uint64_t addr_t
Definition: lldb-types.h:83
A uniqued constant string class.
Definition: ConstString.h:38
lldb::ModuleSP GetModule() const
Get accessor for the module for this address.
Definition: Address.cpp:264
#define LLDB_OPT_SET_7
Definition: lldb-defines.h:117
LineEntry line_entry
The LineEntry for a given query.
Definition: SBAddress.h:15
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
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.
#define LLDB_OPT_SET_ALL
Definition: lldb-defines.h:110
#define DEFAULT_DISASM_NUM_INS
Address & GetBaseAddress()
Get accessor for the base address of the range.
Definition: AddressRange.h:220
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
Definition: Status.cpp:255
#define DEFAULT_DISASM_BYTE_SIZE
#define LLDB_OPT_SET_1
Definition: lldb-defines.h:111
lldb::TargetSP GetSelectedTarget()
Definition: Debugger.h:167
void AppendWarningWithFormat(const char *format,...) __attribute__((format(printf
#define LLDB_OPT_SET_5
Definition: lldb-defines.h:115
A section + offset based address range class.
Definition: AddressRange.h:32
#define LLDB_OPT_SET_6
Definition: lldb-defines.h:116
void SetStatus(lldb::ReturnStatus status)
This base class provides an interface to stack frames.
Definition: StackFrame.h:40
void GenerateOptionUsage(Stream &strm, CommandObject *cmd, uint32_t screen_width)
Definition: Options.cpp:393
const Address & GetFrameCodeAddress()
Get an Address for the current pc value in this StackFrame.
Definition: StackFrame.cpp:181
An error handling class.
Definition: Status.h:44
void SetByteSize(lldb::addr_t byte_size)
Set accessor for the byte size of this range.
Definition: AddressRange.h:248
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:372