xref: /llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp (revision c4fb7180cbbe977f1ab1ce945a691550f8fdd1fb)
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 
9 #include "CommandObjectDisassemble.h"
10 #include "lldb/Core/AddressRange.h"
11 #include "lldb/Core/Disassembler.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Host/OptionParser.h"
14 #include "lldb/Interpreter/CommandInterpreter.h"
15 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
16 #include "lldb/Interpreter/CommandReturnObject.h"
17 #include "lldb/Interpreter/OptionArgParser.h"
18 #include "lldb/Interpreter/Options.h"
19 #include "lldb/Symbol/Function.h"
20 #include "lldb/Symbol/Symbol.h"
21 #include "lldb/Target/SectionLoadList.h"
22 #include "lldb/Target/StackFrame.h"
23 #include "lldb/Target/Target.h"
24 
25 static constexpr unsigned default_disasm_byte_size = 32;
26 static constexpr unsigned default_disasm_num_ins = 4;
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   OptionParsingStarting(nullptr);
36 }
37 
38 CommandObjectDisassemble::CommandOptions::~CommandOptions() = default;
39 
40 Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
41     uint32_t option_idx, llvm::StringRef option_arg,
42     ExecutionContext *execution_context) {
43   Status error;
44 
45   const int short_option = m_getopt_table[option_idx].val;
46 
47   switch (short_option) {
48   case 'm':
49     show_mixed = true;
50     break;
51 
52   case 'C':
53     if (option_arg.getAsInteger(0, num_lines_context))
54       error = Status::FromErrorStringWithFormat(
55           "invalid num context lines string: \"%s\"", option_arg.str().c_str());
56     break;
57 
58   case 'c':
59     if (option_arg.getAsInteger(0, num_instructions))
60       error = Status::FromErrorStringWithFormat(
61           "invalid num of instructions string: \"%s\"",
62           option_arg.str().c_str());
63     break;
64 
65   case 'b':
66     show_bytes = true;
67     break;
68 
69   case 'k':
70     show_control_flow_kind = true;
71     break;
72 
73   case 's': {
74     start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
75                                             LLDB_INVALID_ADDRESS, &error);
76     if (start_addr != LLDB_INVALID_ADDRESS)
77       some_location_specified = true;
78   } break;
79   case 'e': {
80     end_addr = OptionArgParser::ToAddress(execution_context, option_arg,
81                                           LLDB_INVALID_ADDRESS, &error);
82     if (end_addr != LLDB_INVALID_ADDRESS)
83       some_location_specified = true;
84   } break;
85 
86   case 'n':
87     func_name.assign(std::string(option_arg));
88     some_location_specified = true;
89     break;
90 
91   case 'p':
92     at_pc = true;
93     some_location_specified = 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;
101     some_location_specified = 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 = Status::FromErrorStringWithFormat(
118           "Disassembler flavors are currently only "
119           "supported for x86 and x86_64 targets.");
120     break;
121   }
122 
123   case 'X':
124     cpu_string = std::string(option_arg);
125     break;
126 
127   case 'Y':
128     features_string = std::string(option_arg);
129     break;
130 
131   case 'r':
132     raw = true;
133     break;
134 
135   case 'f':
136     current_function = true;
137     some_location_specified = true;
138     break;
139 
140   case 'A':
141     if (execution_context) {
142       const auto &target_sp = execution_context->GetTargetSP();
143       auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr;
144       arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg);
145     }
146     break;
147 
148   case 'a': {
149     symbol_containing_addr = OptionArgParser::ToAddress(
150         execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
151     if (symbol_containing_addr != LLDB_INVALID_ADDRESS) {
152       some_location_specified = true;
153     }
154   } break;
155 
156   case '\x01':
157     force = true;
158     break;
159 
160   default:
161     llvm_unreachable("Unimplemented option");
162   }
163 
164   return error;
165 }
166 
167 void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
168     ExecutionContext *execution_context) {
169   show_mixed = false;
170   show_bytes = false;
171   show_control_flow_kind = false;
172   num_lines_context = 0;
173   num_instructions = 0;
174   func_name.clear();
175   current_function = false;
176   at_pc = false;
177   frame_line = false;
178   start_addr = LLDB_INVALID_ADDRESS;
179   end_addr = LLDB_INVALID_ADDRESS;
180   symbol_containing_addr = LLDB_INVALID_ADDRESS;
181   raw = false;
182   plugin_name.clear();
183 
184   Target *target =
185       execution_context ? execution_context->GetTargetPtr() : nullptr;
186 
187   if (target) {
188     // This is a hack till we get the ability to specify features based on
189     // architecture.  For now GetDisassemblyFlavor is really only valid for x86
190     // (and for the llvm assembler plugin, but I'm papering over that since that
191     // is the only disassembler plugin we have...
192     if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 ||
193         target->GetArchitecture().GetTriple().getArch() ==
194             llvm::Triple::x86_64) {
195       flavor_string.assign(target->GetDisassemblyFlavor());
196     } else {
197       flavor_string.assign("default");
198     }
199     if (const char *cpu = target->GetDisassemblyCPU())
200       cpu_string.assign(cpu);
201     if (const char *features = target->GetDisassemblyFeatures())
202       features_string.assign(features);
203   } else {
204     flavor_string.assign("default");
205     cpu_string.assign("default");
206     features_string.assign("default");
207   }
208 
209   arch.Clear();
210   some_location_specified = false;
211   force = false;
212 }
213 
214 Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
215     ExecutionContext *execution_context) {
216   if (!some_location_specified)
217     current_function = true;
218   return Status();
219 }
220 
221 llvm::ArrayRef<OptionDefinition>
222 CommandObjectDisassemble::CommandOptions::GetDefinitions() {
223   return llvm::ArrayRef(g_disassemble_options);
224 }
225 
226 // CommandObjectDisassemble
227 
228 CommandObjectDisassemble::CommandObjectDisassemble(
229     CommandInterpreter &interpreter)
230     : CommandObjectParsed(
231           interpreter, "disassemble",
232           "Disassemble specified instructions in the current target.  "
233           "Defaults to the current function for the current thread and "
234           "stack frame.",
235           "disassemble [<cmd-options>]", eCommandRequiresTarget) {}
236 
237 CommandObjectDisassemble::~CommandObjectDisassemble() = default;
238 
239 llvm::Error CommandObjectDisassemble::CheckRangeSize(const AddressRange &range,
240                                                      llvm::StringRef what) {
241   if (m_options.num_instructions > 0 || m_options.force ||
242       range.GetByteSize() < GetDebugger().GetStopDisassemblyMaxSize())
243     return llvm::Error::success();
244   StreamString msg;
245   msg << "Not disassembling " << what << " because it is very large ";
246   range.Dump(&msg, &GetTarget(), Address::DumpStyleLoadAddress,
247              Address::DumpStyleFileAddress);
248   msg << ". To disassemble specify an instruction count limit, start/stop "
249          "addresses or use the --force option.";
250   return llvm::createStringError(llvm::inconvertibleErrorCode(),
251                                  msg.GetString());
252 }
253 
254 llvm::Expected<std::vector<AddressRange>>
255 CommandObjectDisassemble::GetContainingAddressRanges() {
256   std::vector<AddressRange> ranges;
257   const auto &get_range = [&](Address addr) {
258     ModuleSP module_sp(addr.GetModule());
259     SymbolContext sc;
260     bool resolve_tail_call_address = true;
261     addr.GetModule()->ResolveSymbolContextForAddress(
262         addr, eSymbolContextEverything, sc, resolve_tail_call_address);
263     if (sc.function || sc.symbol) {
264       AddressRange range;
265       sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
266                          false, range);
267       ranges.push_back(range);
268     }
269   };
270 
271   Target &target = GetTarget();
272   if (target.HasLoadedSections()) {
273     Address symbol_containing_address;
274     if (target.ResolveLoadAddress(m_options.symbol_containing_addr,
275                                   symbol_containing_address)) {
276       get_range(symbol_containing_address);
277     }
278   } else {
279     for (lldb::ModuleSP module_sp : target.GetImages().Modules()) {
280       Address file_address;
281       if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr,
282                                         file_address)) {
283         get_range(file_address);
284       }
285     }
286   }
287 
288   if (ranges.empty()) {
289     return llvm::createStringError(
290         llvm::inconvertibleErrorCode(),
291         "Could not find function bounds for address 0x%" PRIx64,
292         m_options.symbol_containing_addr);
293   }
294 
295   if (llvm::Error err = CheckRangeSize(ranges[0], "the function"))
296     return std::move(err);
297   return ranges;
298 }
299 
300 llvm::Expected<std::vector<AddressRange>>
301 CommandObjectDisassemble::GetCurrentFunctionRanges() {
302   Process *process = m_exe_ctx.GetProcessPtr();
303   StackFrame *frame = m_exe_ctx.GetFramePtr();
304   if (!frame) {
305     if (process) {
306       return llvm::createStringError(
307           llvm::inconvertibleErrorCode(),
308           "Cannot disassemble around the current "
309           "function without the process being stopped.\n");
310     } else {
311       return llvm::createStringError(llvm::inconvertibleErrorCode(),
312                                      "Cannot disassemble around the current "
313                                      "function without a selected frame: "
314                                      "no currently running process.\n");
315     }
316   }
317   SymbolContext sc(
318       frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
319   AddressRange range;
320   if (sc.function)
321     range = sc.function->GetAddressRange();
322   else if (sc.symbol && sc.symbol->ValueIsAddress()) {
323     range = {sc.symbol->GetAddress(), sc.symbol->GetByteSize()};
324   } else
325     range = {frame->GetFrameCodeAddress(), default_disasm_byte_size};
326 
327   if (llvm::Error err = CheckRangeSize(range, "the current function"))
328     return std::move(err);
329   return std::vector<AddressRange>{range};
330 }
331 
332 llvm::Expected<std::vector<AddressRange>>
333 CommandObjectDisassemble::GetCurrentLineRanges() {
334   Process *process = m_exe_ctx.GetProcessPtr();
335   StackFrame *frame = m_exe_ctx.GetFramePtr();
336   if (!frame) {
337     if (process) {
338       return llvm::createStringError(
339           llvm::inconvertibleErrorCode(),
340           "Cannot disassemble around the current "
341           "function without the process being stopped.\n");
342     } else {
343       return llvm::createStringError(llvm::inconvertibleErrorCode(),
344                                      "Cannot disassemble around the current "
345                                      "line without a selected frame: "
346                                      "no currently running process.\n");
347     }
348   }
349 
350   LineEntry pc_line_entry(
351       frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
352   if (pc_line_entry.IsValid())
353     return std::vector<AddressRange>{pc_line_entry.range};
354 
355   // No line entry, so just disassemble around the current pc
356   m_options.show_mixed = false;
357   return GetPCRanges();
358 }
359 
360 llvm::Expected<std::vector<AddressRange>>
361 CommandObjectDisassemble::GetNameRanges(CommandReturnObject &result) {
362   ConstString name(m_options.func_name.c_str());
363 
364   ModuleFunctionSearchOptions function_options;
365   function_options.include_symbols = true;
366   function_options.include_inlines = true;
367 
368   // Find functions matching the given name.
369   SymbolContextList sc_list;
370   GetTarget().GetImages().FindFunctions(name, eFunctionNameTypeAuto,
371                                         function_options, sc_list);
372 
373   std::vector<AddressRange> ranges;
374   llvm::Error range_errs = llvm::Error::success();
375   AddressRange range;
376   const uint32_t scope =
377       eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
378   const bool use_inline_block_range = true;
379   for (SymbolContext sc : sc_list.SymbolContexts()) {
380     for (uint32_t range_idx = 0;
381          sc.GetAddressRange(scope, range_idx, use_inline_block_range, range);
382          ++range_idx) {
383       if (llvm::Error err = CheckRangeSize(range, "a range"))
384         range_errs = joinErrors(std::move(range_errs), std::move(err));
385       else
386         ranges.push_back(range);
387     }
388   }
389   if (ranges.empty()) {
390     if (range_errs)
391       return std::move(range_errs);
392     return llvm::createStringError(llvm::inconvertibleErrorCode(),
393                                    "Unable to find symbol with name '%s'.\n",
394                                    name.GetCString());
395   }
396   if (range_errs)
397     result.AppendWarning(toString(std::move(range_errs)));
398   return ranges;
399 }
400 
401 llvm::Expected<std::vector<AddressRange>>
402 CommandObjectDisassemble::GetPCRanges() {
403   Process *process = m_exe_ctx.GetProcessPtr();
404   StackFrame *frame = m_exe_ctx.GetFramePtr();
405   if (!frame) {
406     if (process) {
407       return llvm::createStringError(
408           llvm::inconvertibleErrorCode(),
409           "Cannot disassemble around the current "
410           "function without the process being stopped.\n");
411     } else {
412       return llvm::createStringError(llvm::inconvertibleErrorCode(),
413                                      "Cannot disassemble around the current "
414                                      "PC without a selected frame: "
415                                      "no currently running process.\n");
416     }
417   }
418 
419   if (m_options.num_instructions == 0) {
420     // Disassembling at the PC always disassembles some number of
421     // instructions (not the whole function).
422     m_options.num_instructions = default_disasm_num_ins;
423   }
424   return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}};
425 }
426 
427 llvm::Expected<std::vector<AddressRange>>
428 CommandObjectDisassemble::GetStartEndAddressRanges() {
429   addr_t size = 0;
430   if (m_options.end_addr != LLDB_INVALID_ADDRESS) {
431     if (m_options.end_addr <= m_options.start_addr) {
432       return llvm::createStringError(llvm::inconvertibleErrorCode(),
433                                      "End address before start address.");
434     }
435     size = m_options.end_addr - m_options.start_addr;
436   }
437   return std::vector<AddressRange>{{Address(m_options.start_addr), size}};
438 }
439 
440 llvm::Expected<std::vector<AddressRange>>
441 CommandObjectDisassemble::GetRangesForSelectedMode(
442     CommandReturnObject &result) {
443   if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
444     return CommandObjectDisassemble::GetContainingAddressRanges();
445   if (m_options.current_function)
446     return CommandObjectDisassemble::GetCurrentFunctionRanges();
447   if (m_options.frame_line)
448     return CommandObjectDisassemble::GetCurrentLineRanges();
449   if (!m_options.func_name.empty())
450     return CommandObjectDisassemble::GetNameRanges(result);
451   if (m_options.start_addr != LLDB_INVALID_ADDRESS)
452     return CommandObjectDisassemble::GetStartEndAddressRanges();
453   return CommandObjectDisassemble::GetPCRanges();
454 }
455 
456 void CommandObjectDisassemble::DoExecute(Args &command,
457                                          CommandReturnObject &result) {
458   Target &target = GetTarget();
459 
460   if (!m_options.arch.IsValid())
461     m_options.arch = target.GetArchitecture();
462 
463   if (!m_options.arch.IsValid()) {
464     result.AppendError(
465         "use the --arch option or set the target architecture to disassemble");
466     return;
467   }
468 
469   const char *plugin_name = m_options.GetPluginName();
470   const char *flavor_string = m_options.GetFlavorString();
471   const char *cpu_string = m_options.GetCPUString();
472   const char *features_string = m_options.GetFeaturesString();
473 
474   DisassemblerSP disassembler = Disassembler::FindPlugin(
475       m_options.arch, flavor_string, cpu_string, features_string, plugin_name);
476 
477   if (!disassembler) {
478     if (plugin_name) {
479       result.AppendErrorWithFormat(
480           "Unable to find Disassembler plug-in named '%s' that supports the "
481           "'%s' architecture.\n",
482           plugin_name, m_options.arch.GetArchitectureName());
483     } else
484       result.AppendErrorWithFormat(
485           "Unable to find Disassembler plug-in for the '%s' architecture.\n",
486           m_options.arch.GetArchitectureName());
487     return;
488   } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec(
489                                              m_options.arch, flavor_string))
490     result.AppendWarningWithFormat(
491         "invalid disassembler flavor \"%s\", using default.\n", flavor_string);
492 
493   result.SetStatus(eReturnStatusSuccessFinishResult);
494 
495   if (!command.empty()) {
496     result.AppendErrorWithFormat(
497         "\"disassemble\" arguments are specified as options.\n");
498     const int terminal_width =
499         GetCommandInterpreter().GetDebugger().GetTerminalWidth();
500     GetOptions()->GenerateOptionUsage(result.GetErrorStream(), *this,
501                                       terminal_width);
502     return;
503   }
504 
505   if (m_options.show_mixed && m_options.num_lines_context == 0)
506     m_options.num_lines_context = 2;
507 
508   // Always show the PC in the disassembly
509   uint32_t options = Disassembler::eOptionMarkPCAddress;
510 
511   // Mark the source line for the current PC only if we are doing mixed source
512   // and assembly
513   if (m_options.show_mixed)
514     options |= Disassembler::eOptionMarkPCSourceLine;
515 
516   if (m_options.show_bytes)
517     options |= Disassembler::eOptionShowBytes;
518 
519   if (m_options.show_control_flow_kind)
520     options |= Disassembler::eOptionShowControlFlowKind;
521 
522   if (m_options.raw)
523     options |= Disassembler::eOptionRawOuput;
524 
525   llvm::Expected<std::vector<AddressRange>> ranges =
526       GetRangesForSelectedMode(result);
527   if (!ranges) {
528     result.AppendError(toString(ranges.takeError()));
529     return;
530   }
531 
532   bool print_sc_header = ranges->size() > 1;
533   for (AddressRange cur_range : *ranges) {
534     Disassembler::Limit limit;
535     if (m_options.num_instructions == 0) {
536       limit = {Disassembler::Limit::Bytes, cur_range.GetByteSize()};
537       if (limit.value == 0)
538         limit.value = default_disasm_byte_size;
539     } else {
540       limit = {Disassembler::Limit::Instructions, m_options.num_instructions};
541     }
542     if (Disassembler::Disassemble(
543             GetDebugger(), m_options.arch, plugin_name, flavor_string,
544             cpu_string, features_string, m_exe_ctx, cur_range.GetBaseAddress(),
545             limit, m_options.show_mixed,
546             m_options.show_mixed ? m_options.num_lines_context : 0, options,
547             result.GetOutputStream())) {
548       result.SetStatus(eReturnStatusSuccessFinishResult);
549     } else {
550       if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) {
551         result.AppendErrorWithFormat(
552             "Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n",
553             m_options.symbol_containing_addr);
554       } else {
555         result.AppendErrorWithFormat(
556             "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
557             cur_range.GetBaseAddress().GetLoadAddress(&target));
558       }
559     }
560     if (print_sc_header)
561       result.GetOutputStream() << "\n";
562   }
563 }
564