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 
10 #include "lldb/Core/AddressRange.h"
11 #include "lldb/Core/Disassembler.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Host/OptionParser.h"
18 #include "lldb/Symbol/Function.h"
19 #include "lldb/Symbol/Symbol.h"
21 #include "lldb/Target/StackFrame.h"
22 #include "lldb/Target/Target.h"
23 
24 static constexpr unsigned default_disasm_byte_size = 32;
25 static constexpr unsigned default_disasm_num_ins = 4;
26 static constexpr unsigned large_function_threshold = 8000;
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 #define LLDB_OPTIONS_disassemble
32 #include "CommandOptions.inc"
33 
34 CommandObjectDisassemble::CommandOptions::CommandOptions()
35  : Options(), num_lines_context(0), num_instructions(0), func_name(),
36  current_function(false), start_addr(), end_addr(), at_pc(false),
37  frame_line(false), plugin_name(), flavor_string(), arch(),
38  some_location_specified(false), symbol_containing_addr() {
39  OptionParsingStarting(nullptr);
40 }
41 
43 
45  uint32_t option_idx, llvm::StringRef option_arg,
46  ExecutionContext *execution_context) {
47  Status error;
48 
49  const int short_option = m_getopt_table[option_idx].val;
50 
51  switch (short_option) {
52  case 'm':
53  show_mixed = true;
54  break;
55 
56  case 'C':
57  if (option_arg.getAsInteger(0, num_lines_context))
58  error.SetErrorStringWithFormat("invalid num context lines string: \"%s\"",
59  option_arg.str().c_str());
60  break;
61 
62  case 'c':
63  if (option_arg.getAsInteger(0, num_instructions))
65  "invalid num of instructions string: \"%s\"",
66  option_arg.str().c_str());
67  break;
68 
69  case 'b':
70  show_bytes = true;
71  break;
72 
73  case 's': {
74  start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
75  LLDB_INVALID_ADDRESS, &error);
78  } break;
79  case 'e': {
80  end_addr = OptionArgParser::ToAddress(execution_context, option_arg,
81  LLDB_INVALID_ADDRESS, &error);
84  } break;
85 
86  case 'n':
87  func_name.assign(std::string(option_arg));
89  break;
90 
91  case 'p':
92  at_pc = true;
94  break;
95 
96  case 'l':
97  frame_line = true;
98  // Disassemble the current source line kind of implies showing mixed source
99  // code context.
100  show_mixed = true;
102  break;
103 
104  case 'P':
105  plugin_name.assign(std::string(option_arg));
106  break;
107 
108  case 'F': {
109  TargetSP target_sp =
110  execution_context ? execution_context->GetTargetSP() : TargetSP();
111  if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() ==
112  llvm::Triple::x86 ||
113  target_sp->GetArchitecture().GetTriple().getArch() ==
114  llvm::Triple::x86_64)) {
115  flavor_string.assign(std::string(option_arg));
116  } else
117  error.SetErrorStringWithFormat("Disassembler flavors are currently only "
118  "supported for x86 and x86_64 targets.");
119  break;
120  }
121 
122  case 'r':
123  raw = true;
124  break;
125 
126  case 'f':
127  current_function = true;
129  break;
130 
131  case 'A':
132  if (execution_context) {
133  const auto &target_sp = execution_context->GetTargetSP();
134  auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr;
135  arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg);
136  }
137  break;
138 
139  case 'a': {
141  execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
144  }
145  } break;
146 
147  case '\x01':
148  force = true;
149  break;
150 
151  default:
152  llvm_unreachable("Unimplemented option");
153  }
154 
155  return error;
156 }
157 
159  ExecutionContext *execution_context) {
160  show_mixed = false;
161  show_bytes = false;
162  num_lines_context = 0;
163  num_instructions = 0;
164  func_name.clear();
165  current_function = false;
166  at_pc = false;
167  frame_line = false;
171  raw = false;
172  plugin_name.clear();
173 
174  Target *target =
175  execution_context ? execution_context->GetTargetPtr() : nullptr;
176 
177  // This is a hack till we get the ability to specify features based on
178  // architecture. For now GetDisassemblyFlavor is really only valid for x86
179  // (and for the llvm assembler plugin, but I'm papering over that since that
180  // is the only disassembler plugin we have...
181  if (target) {
182  if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 ||
183  target->GetArchitecture().GetTriple().getArch() ==
184  llvm::Triple::x86_64) {
185  flavor_string.assign(target->GetDisassemblyFlavor());
186  } else
187  flavor_string.assign("default");
188 
189  } else
190  flavor_string.assign("default");
191 
192  arch.Clear();
193  some_location_specified = false;
194  force = false;
195 }
196 
198  ExecutionContext *execution_context) {
200  current_function = true;
201  return Status();
202 }
203 
204 llvm::ArrayRef<OptionDefinition>
206  return llvm::makeArrayRef(g_disassemble_options);
207 }
208 
209 // CommandObjectDisassemble
210 
212  CommandInterpreter &interpreter)
214  interpreter, "disassemble",
215  "Disassemble specified instructions in the current target. "
216  "Defaults to the current function for the current thread and "
217  "stack frame.",
218  "disassemble [<cmd-options>]", eCommandRequiresTarget),
219  m_options() {}
220 
222 
224  llvm::StringRef what) {
227  return llvm::Error::success();
228  StreamString msg;
229  msg << "Not disassembling " << what << " because it is very large ";
232  msg << ". To disassemble specify an instruction count limit, start/stop "
233  "addresses or use the --force option.";
234  return llvm::createStringError(llvm::inconvertibleErrorCode(),
235  msg.GetString());
236 }
237 
238 llvm::Expected<std::vector<AddressRange>>
240  std::vector<AddressRange> ranges;
241  const auto &get_range = [&](Address addr) {
242  ModuleSP module_sp(addr.GetModule());
243  SymbolContext sc;
244  bool resolve_tail_call_address = true;
245  addr.GetModule()->ResolveSymbolContextForAddress(
246  addr, eSymbolContextEverything, sc, resolve_tail_call_address);
247  if (sc.function || sc.symbol) {
248  AddressRange range;
249  sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
250  false, range);
251  ranges.push_back(range);
252  }
253  };
254 
255  Target &target = GetSelectedTarget();
256  if (!target.GetSectionLoadList().IsEmpty()) {
257  Address symbol_containing_address;
259  m_options.symbol_containing_addr, symbol_containing_address)) {
260  get_range(symbol_containing_address);
261  }
262  } else {
263  for (lldb::ModuleSP module_sp : target.GetImages().Modules()) {
264  Address file_address;
265  if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr,
266  file_address)) {
267  get_range(file_address);
268  }
269  }
270  }
271 
272  if (ranges.empty()) {
273  return llvm::createStringError(
274  llvm::inconvertibleErrorCode(),
275  "Could not find function bounds for address 0x%" PRIx64,
277  }
278 
279  if (llvm::Error err = CheckRangeSize(ranges[0], "the function"))
280  return std::move(err);
281  return ranges;
282 }
283 
284 llvm::Expected<std::vector<AddressRange>>
286  StackFrame *frame = m_exe_ctx.GetFramePtr();
287  if (!frame) {
288  return llvm::createStringError(llvm::inconvertibleErrorCode(),
289  "Cannot disassemble around the current "
290  "function without a selected frame.\n");
291  }
292  SymbolContext sc(
293  frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
294  AddressRange range;
295  if (sc.function)
296  range = sc.function->GetAddressRange();
297  else if (sc.symbol && sc.symbol->ValueIsAddress()) {
298  range = {sc.symbol->GetAddress(), sc.symbol->GetByteSize()};
299  } else
300  range = {frame->GetFrameCodeAddress(), default_disasm_byte_size};
301 
302  if (llvm::Error err = CheckRangeSize(range, "the current function"))
303  return std::move(err);
304  return std::vector<AddressRange>{range};
305 }
306 
307 llvm::Expected<std::vector<AddressRange>>
309  StackFrame *frame = m_exe_ctx.GetFramePtr();
310  if (!frame) {
311  return llvm::createStringError(llvm::inconvertibleErrorCode(),
312  "Cannot disassemble around the current "
313  "line without a selected frame.\n");
314  }
315 
316  LineEntry pc_line_entry(
317  frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
318  if (pc_line_entry.IsValid())
319  return std::vector<AddressRange>{pc_line_entry.range};
320 
321  // No line entry, so just disassemble around the current pc
322  m_options.show_mixed = false;
323  return GetPCRanges();
324 }
325 
326 llvm::Expected<std::vector<AddressRange>>
328  ConstString name(m_options.func_name.c_str());
329  const bool include_symbols = true;
330  const bool include_inlines = true;
331 
332  // Find functions matching the given name.
333  SymbolContextList sc_list;
335  name, eFunctionNameTypeAuto, include_symbols, include_inlines, sc_list);
336 
337  std::vector<AddressRange> ranges;
338  llvm::Error range_errs = llvm::Error::success();
339  AddressRange range;
340  const uint32_t scope =
341  eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
342  const bool use_inline_block_range = true;
343  for (SymbolContext sc : sc_list.SymbolContexts()) {
344  for (uint32_t range_idx = 0;
345  sc.GetAddressRange(scope, range_idx, use_inline_block_range, range);
346  ++range_idx) {
347  if (llvm::Error err = CheckRangeSize(range, "a range"))
348  range_errs = joinErrors(std::move(range_errs), std::move(err));
349  else
350  ranges.push_back(range);
351  }
352  }
353  if (ranges.empty()) {
354  if (range_errs)
355  return std::move(range_errs);
356  return llvm::createStringError(llvm::inconvertibleErrorCode(),
357  "Unable to find symbol with name '%s'.\n",
358  name.GetCString());
359  }
360  if (range_errs)
361  result.AppendWarning(toString(std::move(range_errs)));
362  return ranges;
363 }
364 
365 llvm::Expected<std::vector<AddressRange>>
367  StackFrame *frame = m_exe_ctx.GetFramePtr();
368  if (!frame) {
369  return llvm::createStringError(llvm::inconvertibleErrorCode(),
370  "Cannot disassemble around the current "
371  "PC without a selected frame.\n");
372  }
373 
374  if (m_options.num_instructions == 0) {
375  // Disassembling at the PC always disassembles some number of
376  // instructions (not the whole function).
378  }
379  return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}};
380 }
381 
382 llvm::Expected<std::vector<AddressRange>>
384  addr_t size = 0;
387  return llvm::createStringError(llvm::inconvertibleErrorCode(),
388  "End address before start address.");
389  }
391  }
392  return std::vector<AddressRange>{{Address(m_options.start_addr), size}};
393 }
394 
395 llvm::Expected<std::vector<AddressRange>>
397  CommandReturnObject &result) {
402  if (m_options.frame_line)
404  if (!m_options.func_name.empty())
409 }
410 
412  CommandReturnObject &result) {
413  Target *target = &GetSelectedTarget();
414 
415  if (!m_options.arch.IsValid())
416  m_options.arch = target->GetArchitecture();
417 
418  if (!m_options.arch.IsValid()) {
419  result.AppendError(
420  "use the --arch option or set the target architecture to disassemble");
422  return false;
423  }
424 
425  const char *plugin_name = m_options.GetPluginName();
426  const char *flavor_string = m_options.GetFlavorString();
427 
428  DisassemblerSP disassembler =
429  Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
430 
431  if (!disassembler) {
432  if (plugin_name) {
433  result.AppendErrorWithFormat(
434  "Unable to find Disassembler plug-in named '%s' that supports the "
435  "'%s' architecture.\n",
436  plugin_name, m_options.arch.GetArchitectureName());
437  } else
438  result.AppendErrorWithFormat(
439  "Unable to find Disassembler plug-in for the '%s' architecture.\n",
442  return false;
443  } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec(
444  m_options.arch, flavor_string))
446  "invalid disassembler flavor \"%s\", using default.\n", flavor_string);
447 
449 
450  if (!command.empty()) {
451  result.AppendErrorWithFormat(
452  "\"disassemble\" arguments are specified as options.\n");
453  const int terminal_width =
456  terminal_width);
458  return false;
459  }
460 
463 
464  // Always show the PC in the disassembly
466 
467  // Mark the source line for the current PC only if we are doing mixed source
468  // and assembly
469  if (m_options.show_mixed)
471 
472  if (m_options.show_bytes)
474 
475  if (m_options.raw)
477 
478  llvm::Expected<std::vector<AddressRange>> ranges =
479  GetRangesForSelectedMode(result);
480  if (!ranges) {
481  result.AppendError(toString(ranges.takeError()));
483  return result.Succeeded();
484  }
485 
486  bool print_sc_header = ranges->size() > 1;
487  for (AddressRange cur_range : *ranges) {
488  Disassembler::Limit limit;
489  if (m_options.num_instructions == 0) {
490  limit = {Disassembler::Limit::Bytes, cur_range.GetByteSize()};
491  if (limit.value == 0)
493  } else {
495  }
497  GetDebugger(), m_options.arch, plugin_name, flavor_string,
498  m_exe_ctx, cur_range.GetBaseAddress(), limit, m_options.show_mixed,
500  result.GetOutputStream())) {
502  } else {
504  result.AppendErrorWithFormat(
505  "Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n",
507  } else {
508  result.AppendErrorWithFormat(
509  "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
510  cur_range.GetBaseAddress().GetLoadAddress(target));
511  }
513  }
514  if (print_sc_header)
515  result.GetOutputStream() << "\n";
516  }
517 
518  return result.Succeeded();
519 }
A line table entry class.
Definition: LineEntry.h:20
A command line argument class.
Definition: Args.h:33
bool empty() const
Definition: Args.h:118
Defines a list of symbol context objects.
A class that represents a running process on the host machine.
lldb::addr_t GetByteSize() const
Get accessor for the byte size of this range.
Definition: AddressRange.h:222
llvm::Expected< std::vector< AddressRange > > GetPCRanges()
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
llvm::Error CheckRangeSize(const AddressRange &range, llvm::StringRef what)
llvm::Error Error
bool DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectDisassemble(CommandInterpreter &interpreter)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool IsValid() const
Tests if this ArchSpec is valid.
Definition: ArchSpec.h:332
void FindFunctions(ConstString name, lldb::FunctionNameType name_type_mask, bool include_symbols, bool include_inlines, SymbolContextList &sc_list) const
StackFrame * GetFramePtr() const
Returns a pointer to the frame object.
std::vector< Option > m_getopt_table
Definition: Options.h:202
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:434
static lldb::DisassemblerSP FindPlugin(const ArchSpec &arch, const char *flavor, const char *plugin_name)
void Clear()
Clears the object state.
Definition: ArchSpec.cpp:574
const SymbolContext & GetSymbolContext(lldb::SymbolContextItem resolve_scope)
Provide a SymbolContext for this StackFrame&#39;s current pc value.
Definition: StackFrame.cpp:274
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition: ArchSpec.cpp:585
static constexpr unsigned default_disasm_byte_size
Target * GetTargetPtr() const
Returns a pointer to the target object.
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
void AppendWarning(llvm::StringRef in_string)
llvm::StringRef toString(Record::Kind K)
llvm::Expected< std::vector< AddressRange > > GetCurrentFunctionRanges()
void OptionParsingStarting(ExecutionContext *execution_context) override
uint32_t GetTerminalWidth() const
Definition: Debugger.cpp:311
SectionLoadList & GetSectionLoadList()
Definition: Target.h:1012
static constexpr unsigned large_function_threshold
static constexpr unsigned default_disasm_num_ins
llvm::StringRef GetString() const
bool ResolveLoadAddress(lldb::addr_t load_addr, Address &so_addr, bool allow_section_end=false) const
const char * GetDisassemblyFlavor() const
Definition: Target.cpp:3567
SymbolContextIterable SymbolContexts()
llvm::Expected< std::vector< AddressRange > > GetContainingAddressRanges()
Status OptionParsingFinished(ExecutionContext *execution_context) override
A section + offset based address class.
Definition: Address.h:59
static lldb::addr_t ToAddress(const ExecutionContext *exe_ctx, llvm::StringRef s, lldb::addr_t fail_value, Status *error)
ModuleIterable Modules()
Definition: ModuleList.h:489
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
llvm::Expected< std::vector< AddressRange > > GetCurrentLineRanges()
llvm::Expected< std::vector< AddressRange > > GetRangesForSelectedMode(CommandReturnObject &result)
Display as the load address (if resolved).
Definition: Address.h:96
A uniqued constant string class.
Definition: ConstString.h:40
llvm::Expected< std::vector< AddressRange > > GetStartEndAddressRanges()
bool Dump(Stream *s, Target *target, Address::DumpStyle style, Address::DumpStyle fallback_style=Address::DumpStyleInvalid) const
Dump a description of this object to a Stream.
LineEntry line_entry
The LineEntry for a given query.
Definition: SBAddress.h:15
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
static bool Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, const char *flavor, 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)
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:256
void AppendWarningWithFormat(const char *format,...) __attribute__((format(printf
A section + offset based address range class.
Definition: AddressRange.h:25
llvm::Expected< std::vector< AddressRange > > GetNameRanges(CommandReturnObject &result)
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
AddressRange range
The section offset address range for this line entry.
Definition: LineEntry.h:139
const Address & GetFrameCodeAddress()
Get an Address for the current pc value in this StackFrame.
Definition: StackFrame.cpp:188
An error handling class.
Definition: Status.h:44
Display as the file address (if any).
Definition: Address.h:84
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:382