]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Commands / CommandObjectDisassemble.cpp
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
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/Core/SourceManager.h"
14 #include "lldb/Host/OptionParser.h"
15 #include "lldb/Interpreter/CommandCompletions.h"
16 #include "lldb/Interpreter/CommandInterpreter.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Interpreter/OptionArgParser.h"
19 #include "lldb/Interpreter/Options.h"
20 #include "lldb/Symbol/Function.h"
21 #include "lldb/Symbol/Symbol.h"
22 #include "lldb/Target/Process.h"
23 #include "lldb/Target/SectionLoadList.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 |
48   LLDB_OPT_SET_3 |
49   LLDB_OPT_SET_4 |
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
68 CommandObjectDisassemble::CommandOptions::~CommandOptions() = default;
69
70 Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
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))
90       error.SetErrorStringWithFormat(
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);
102     if (start_addr != LLDB_INVALID_ADDRESS)
103       some_location_specified = true;
104   } break;
105   case 'e': {
106     end_addr = OptionArgParser::ToAddress(execution_context, option_arg,
107                                           LLDB_INVALID_ADDRESS, &error);
108     if (end_addr != LLDB_INVALID_ADDRESS)
109       some_location_specified = true;
110   } break;
111
112   case 'n':
113     func_name.assign(option_arg);
114     some_location_specified = true;
115     break;
116
117   case 'p':
118     at_pc = true;
119     some_location_specified = 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;
127     some_location_specified = 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;
154     some_location_specified = 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': {
166     symbol_containing_addr = OptionArgParser::ToAddress(
167         execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
168     if (symbol_containing_addr != LLDB_INVALID_ADDRESS) {
169       some_location_specified = true;
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
182 void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
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;
192   start_addr = LLDB_INVALID_ADDRESS;
193   end_addr = LLDB_INVALID_ADDRESS;
194   symbol_containing_addr = LLDB_INVALID_ADDRESS;
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
220 Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
221     ExecutionContext *execution_context) {
222   if (!some_location_specified)
223     current_function = true;
224   return Status();
225 }
226
227 llvm::ArrayRef<OptionDefinition>
228 CommandObjectDisassemble::CommandOptions::GetDefinitions() {
229   return llvm::makeArrayRef(g_disassemble_options);
230 }
231
232 // CommandObjectDisassemble
233
234 CommandObjectDisassemble::CommandObjectDisassemble(
235     CommandInterpreter &interpreter)
236     : CommandObjectParsed(
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
244 CommandObjectDisassemble::~CommandObjectDisassemble() = default;
245
246 bool CommandObjectDisassemble::DoExecute(Args &command,
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");
252     result.SetStatus(eReturnStatusFailed);
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");
261     result.SetStatus(eReturnStatusFailed);
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",
280           m_options.arch.GetArchitectureName());
281     result.SetStatus(eReturnStatusFailed);
282     return false;
283   } else if (flavor_string != nullptr &&
284              !disassembler->FlavorValidForArchSpec(m_options.arch,
285                                                    flavor_string))
286     result.AppendWarningWithFormat(
287         "invalid disassembler flavor \"%s\", using default.\n", flavor_string);
288
289   result.SetStatus(eReturnStatusSuccessFinishResult);
290
291   if (!command.empty()) {
292     result.AppendErrorWithFormat(
293         "\"disassemble\" arguments are specified as options.\n");
294     const int terminal_width =
295         GetCommandInterpreter().GetDebugger().GetTerminalWidth();
296     GetOptions()->GenerateOptionUsage(result.GetErrorStream(), this,
297                                       terminal_width);
298     result.SetStatus(eReturnStatusFailed);
299     return false;
300   }
301
302   if (m_options.show_mixed && m_options.num_lines_context == 0)
303     m_options.num_lines_context = 2;
304
305   // Always show the PC in the disassembly
306   uint32_t options = Disassembler::eOptionMarkPCAddress;
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)
311     options |= Disassembler::eOptionMarkPCSourceLine;
312
313   if (m_options.show_bytes)
314     options |= Disassembler::eOptionShowBytes;
315
316   if (m_options.raw)
317     options |= Disassembler::eOptionRawOuput;
318
319   if (!m_options.func_name.empty()) {
320     ConstString name(m_options.func_name.c_str());
321
322     if (Disassembler::Disassemble(
323             GetDebugger(), m_options.arch, plugin_name, flavor_string,
324             m_exe_ctx, name,
325             nullptr, // Module *
326             m_options.num_instructions, m_options.show_mixed,
327             m_options.show_mixed ? m_options.num_lines_context : 0, options,
328             result.GetOutputStream())) {
329       result.SetStatus(eReturnStatusSuccessFinishResult);
330     } else {
331       result.AppendErrorWithFormat("Unable to find symbol with name '%s'.\n",
332                                    name.GetCString());
333       result.SetStatus(eReturnStatusFailed);
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");
343         result.SetStatus(eReturnStatusFailed);
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");
359         result.SetStatus(eReturnStatusFailed);
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");
376           result.SetStatus(eReturnStatusFailed);
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).
383           m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
384         }
385         ranges.push_back(range);
386       } else {
387         range.GetBaseAddress().SetOffset(m_options.start_addr);
388         if (range.GetBaseAddress().IsValid()) {
389           if (m_options.end_addr != LLDB_INVALID_ADDRESS) {
390             if (m_options.end_addr <= m_options.start_addr) {
391               result.AppendErrorWithFormat(
392                   "End address before start address.\n");
393               result.SetStatus(eReturnStatusFailed);
394               return false;
395             }
396             range.SetByteSize(m_options.end_addr - m_options.start_addr);
397           }
398           ranges.push_back(range);
399         } else {
400           if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS &&
401               target) {
402             if (!target->GetSectionLoadList().IsEmpty()) {
403               bool failed = false;
404               Address symbol_containing_address;
405               if (target->GetSectionLoadList().ResolveLoadAddress(
406                       m_options.symbol_containing_addr,
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",
430                     m_options.symbol_containing_addr);
431                 result.SetStatus(eReturnStatusFailed);
432                 return false;
433               }
434               ranges.push_back(range);
435             } else {
436               for (lldb::ModuleSP module_sp : target->GetImages().Modules()) {
437                 lldb::addr_t file_addr = m_options.symbol_containing_addr;
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");
479           result.SetStatus(eReturnStatusFailed);
480           return false;
481         }
482       }
483
484       bool print_sc_header = ranges.size() > 1;
485       for (AddressRange cur_range : ranges) {
486         if (Disassembler::Disassemble(
487                 GetDebugger(), m_options.arch, plugin_name, flavor_string,
488                 m_exe_ctx, cur_range.GetBaseAddress(),
489                 m_options.num_instructions, m_options.show_mixed,
490                 m_options.show_mixed ? m_options.num_lines_context : 0, options,
491                 result.GetOutputStream())) {
492           result.SetStatus(eReturnStatusSuccessFinishResult);
493         } else {
494           if (m_options.start_addr != LLDB_INVALID_ADDRESS)
495             result.AppendErrorWithFormat(
496                 "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
497                 m_options.start_addr);
498           else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
499             result.AppendErrorWithFormat(
500                 "Failed to disassemble memory in function at 0x%8.8" PRIx64
501                 ".\n",
502                 m_options.symbol_containing_addr);
503           result.SetStatus(eReturnStatusFailed);
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");
523           result.SetStatus(eReturnStatusFailed);
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
534         if (Disassembler::Disassemble(
535                 GetDebugger(), m_options.arch, plugin_name, flavor_string,
536                 m_exe_ctx, cur_range, m_options.num_instructions,
537                 m_options.show_mixed,
538                 m_options.show_mixed ? m_options.num_lines_context : 0, options,
539                 result.GetOutputStream())) {
540           result.SetStatus(eReturnStatusSuccessFinishResult);
541         } else {
542           result.AppendErrorWithFormat(
543               "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
544               m_options.start_addr);
545           result.SetStatus(eReturnStatusFailed);
546         }
547         if (print_sc_header)
548           result.AppendMessage("\n");
549       }
550     }
551   }
552
553   return result.Succeeded();
554 }