]> 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 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "CommandObjectDisassemble.h"
11 #include "lldb/Core/AddressRange.h"
12 #include "lldb/Core/Disassembler.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/SourceManager.h"
15 #include "lldb/Host/OptionParser.h"
16 #include "lldb/Interpreter/CommandCompletions.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Interpreter/CommandReturnObject.h"
19 #include "lldb/Interpreter/OptionArgParser.h"
20 #include "lldb/Interpreter/Options.h"
21 #include "lldb/Symbol/Function.h"
22 #include "lldb/Symbol/Symbol.h"
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/SectionLoadList.h"
25 #include "lldb/Target/StackFrame.h"
26 #include "lldb/Target/Target.h"
27
28 #define DEFAULT_DISASM_BYTE_SIZE 32
29 #define DEFAULT_DISASM_NUM_INS 4
30
31 using namespace lldb;
32 using namespace lldb_private;
33
34 static constexpr OptionDefinition g_disassemble_options[] = {
35     // clang-format off
36   { LLDB_OPT_SET_ALL, false, "bytes",         'b', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Show opcode bytes when disassembling." },
37   { LLDB_OPT_SET_ALL, false, "context",       'C', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeNumLines,            "Number of context lines of source to show." },
38   { LLDB_OPT_SET_ALL, false, "mixed",         'm', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Enable mixed source and assembly display." },
39   { LLDB_OPT_SET_ALL, false, "raw",           'r', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Print raw disassembly with no symbol information." },
40   { LLDB_OPT_SET_ALL, false, "plugin",        'P', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypePlugin,              "Name of the disassembler plugin you want to use." },
41   { LLDB_OPT_SET_ALL, false, "flavor",        'F', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeDisassemblyFlavor,   "Name of the disassembly flavor you want to use.  "
42   "Currently the only valid options are default, and for Intel "
43   "architectures, att and intel." },
44   { LLDB_OPT_SET_ALL, false, "arch",          'A', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeArchitecture,        "Specify the architecture to use from cross disassembly." },
45   { LLDB_OPT_SET_1 |
46   LLDB_OPT_SET_2,   true,  "start-address", 's', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeAddressOrExpression, "Address at which to start disassembling." },
47   { LLDB_OPT_SET_1,   false, "end-address",   'e', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeAddressOrExpression, "Address at which to end disassembling." },
48   { LLDB_OPT_SET_2 |
49   LLDB_OPT_SET_3 |
50   LLDB_OPT_SET_4 |
51   LLDB_OPT_SET_5,   false, "count",         'c', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeNumLines,            "Number of instructions to display." },
52   { LLDB_OPT_SET_3,   false, "name",          'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,        "Disassemble entire contents of the given function name." },
53   { LLDB_OPT_SET_4,   false, "frame",         'f', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Disassemble from the start of the current frame's function." },
54   { LLDB_OPT_SET_5,   false, "pc",            'p', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Disassemble around the current pc." },
55   { 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 "
56   "table information, else disassemble around the pc." },
57   { LLDB_OPT_SET_7,   false, "address",       'a', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeAddressOrExpression, "Disassemble function containing this address." },
58     // clang-format on
59 };
60
61 CommandObjectDisassemble::CommandOptions::CommandOptions()
62     : Options(), num_lines_context(0), num_instructions(0), func_name(),
63       current_function(false), start_addr(), end_addr(), at_pc(false),
64       frame_line(false), plugin_name(), flavor_string(), arch(),
65       some_location_specified(false), symbol_containing_addr() {
66   OptionParsingStarting(nullptr);
67 }
68
69 CommandObjectDisassemble::CommandOptions::~CommandOptions() = default;
70
71 Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
72     uint32_t option_idx, llvm::StringRef option_arg,
73     ExecutionContext *execution_context) {
74   Status error;
75
76   const int short_option = m_getopt_table[option_idx].val;
77
78   switch (short_option) {
79   case 'm':
80     show_mixed = true;
81     break;
82
83   case 'C':
84     if (option_arg.getAsInteger(0, num_lines_context))
85       error.SetErrorStringWithFormat("invalid num context lines string: \"%s\"",
86                                      option_arg.str().c_str());
87     break;
88
89   case 'c':
90     if (option_arg.getAsInteger(0, num_instructions))
91       error.SetErrorStringWithFormat(
92           "invalid num of instructions string: \"%s\"",
93           option_arg.str().c_str());
94     break;
95
96   case 'b':
97     show_bytes = true;
98     break;
99
100   case 's': {
101     start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
102                                             LLDB_INVALID_ADDRESS, &error);
103     if (start_addr != LLDB_INVALID_ADDRESS)
104       some_location_specified = true;
105   } break;
106   case 'e': {
107     end_addr = OptionArgParser::ToAddress(execution_context, option_arg,
108                                           LLDB_INVALID_ADDRESS, &error);
109     if (end_addr != LLDB_INVALID_ADDRESS)
110       some_location_specified = true;
111   } break;
112
113   case 'n':
114     func_name.assign(option_arg);
115     some_location_specified = true;
116     break;
117
118   case 'p':
119     at_pc = true;
120     some_location_specified = true;
121     break;
122
123   case 'l':
124     frame_line = true;
125     // Disassemble the current source line kind of implies showing mixed source
126     // code context.
127     show_mixed = true;
128     some_location_specified = true;
129     break;
130
131   case 'P':
132     plugin_name.assign(option_arg);
133     break;
134
135   case 'F': {
136     TargetSP target_sp =
137         execution_context ? execution_context->GetTargetSP() : TargetSP();
138     if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() ==
139                           llvm::Triple::x86 ||
140                       target_sp->GetArchitecture().GetTriple().getArch() ==
141                           llvm::Triple::x86_64)) {
142       flavor_string.assign(option_arg);
143     } else
144       error.SetErrorStringWithFormat("Disassembler flavors are currently only "
145                                      "supported for x86 and x86_64 targets.");
146     break;
147   }
148
149   case 'r':
150     raw = true;
151     break;
152
153   case 'f':
154     current_function = true;
155     some_location_specified = true;
156     break;
157
158   case 'A':
159     if (execution_context) {
160       const auto &target_sp = execution_context->GetTargetSP();
161       auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr;
162       arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg);
163     }
164     break;
165
166   case 'a': {
167     symbol_containing_addr = OptionArgParser::ToAddress(
168         execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
169     if (symbol_containing_addr != LLDB_INVALID_ADDRESS) {
170       some_location_specified = true;
171     }
172   } break;
173
174   default:
175     error.SetErrorStringWithFormat("unrecognized short option '%c'",
176                                    short_option);
177     break;
178   }
179
180   return error;
181 }
182
183 void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
184     ExecutionContext *execution_context) {
185   show_mixed = false;
186   show_bytes = false;
187   num_lines_context = 0;
188   num_instructions = 0;
189   func_name.clear();
190   current_function = false;
191   at_pc = false;
192   frame_line = false;
193   start_addr = LLDB_INVALID_ADDRESS;
194   end_addr = LLDB_INVALID_ADDRESS;
195   symbol_containing_addr = LLDB_INVALID_ADDRESS;
196   raw = false;
197   plugin_name.clear();
198
199   Target *target =
200       execution_context ? execution_context->GetTargetPtr() : nullptr;
201
202   // This is a hack till we get the ability to specify features based on
203   // architecture.  For now GetDisassemblyFlavor is really only valid for x86
204   // (and for the llvm assembler plugin, but I'm papering over that since that
205   // is the only disassembler plugin we have...
206   if (target) {
207     if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 ||
208         target->GetArchitecture().GetTriple().getArch() ==
209             llvm::Triple::x86_64) {
210       flavor_string.assign(target->GetDisassemblyFlavor());
211     } else
212       flavor_string.assign("default");
213
214   } else
215     flavor_string.assign("default");
216
217   arch.Clear();
218   some_location_specified = false;
219 }
220
221 Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
222     ExecutionContext *execution_context) {
223   if (!some_location_specified)
224     current_function = true;
225   return Status();
226 }
227
228 llvm::ArrayRef<OptionDefinition>
229 CommandObjectDisassemble::CommandOptions::GetDefinitions() {
230   return llvm::makeArrayRef(g_disassemble_options);
231 }
232
233 //-------------------------------------------------------------------------
234 // CommandObjectDisassemble
235 //-------------------------------------------------------------------------
236
237 CommandObjectDisassemble::CommandObjectDisassemble(
238     CommandInterpreter &interpreter)
239     : CommandObjectParsed(
240           interpreter, "disassemble",
241           "Disassemble specified instructions in the current target.  "
242           "Defaults to the current function for the current thread and "
243           "stack frame.",
244           "disassemble [<cmd-options>]"),
245       m_options() {}
246
247 CommandObjectDisassemble::~CommandObjectDisassemble() = default;
248
249 bool CommandObjectDisassemble::DoExecute(Args &command,
250                                          CommandReturnObject &result) {
251   Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
252   if (target == nullptr) {
253     result.AppendError("invalid target, create a debug target using the "
254                        "'target create' command");
255     result.SetStatus(eReturnStatusFailed);
256     return false;
257   }
258   if (!m_options.arch.IsValid())
259     m_options.arch = target->GetArchitecture();
260
261   if (!m_options.arch.IsValid()) {
262     result.AppendError(
263         "use the --arch option or set the target architecture to disassemble");
264     result.SetStatus(eReturnStatusFailed);
265     return false;
266   }
267
268   const char *plugin_name = m_options.GetPluginName();
269   const char *flavor_string = m_options.GetFlavorString();
270
271   DisassemblerSP disassembler =
272       Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
273
274   if (!disassembler) {
275     if (plugin_name) {
276       result.AppendErrorWithFormat(
277           "Unable to find Disassembler plug-in named '%s' that supports the "
278           "'%s' architecture.\n",
279           plugin_name, m_options.arch.GetArchitectureName());
280     } else
281       result.AppendErrorWithFormat(
282           "Unable to find Disassembler plug-in for the '%s' architecture.\n",
283           m_options.arch.GetArchitectureName());
284     result.SetStatus(eReturnStatusFailed);
285     return false;
286   } else if (flavor_string != nullptr &&
287              !disassembler->FlavorValidForArchSpec(m_options.arch,
288                                                    flavor_string))
289     result.AppendWarningWithFormat(
290         "invalid disassembler flavor \"%s\", using default.\n", flavor_string);
291
292   result.SetStatus(eReturnStatusSuccessFinishResult);
293
294   if (!command.empty()) {
295     result.AppendErrorWithFormat(
296         "\"disassemble\" arguments are specified as options.\n");
297     const int terminal_width =
298         GetCommandInterpreter().GetDebugger().GetTerminalWidth();
299     GetOptions()->GenerateOptionUsage(result.GetErrorStream(), this,
300                                       terminal_width);
301     result.SetStatus(eReturnStatusFailed);
302     return false;
303   }
304
305   if (m_options.show_mixed && m_options.num_lines_context == 0)
306     m_options.num_lines_context = 2;
307
308   // Always show the PC in the disassembly
309   uint32_t options = Disassembler::eOptionMarkPCAddress;
310
311   // Mark the source line for the current PC only if we are doing mixed source
312   // and assembly
313   if (m_options.show_mixed)
314     options |= Disassembler::eOptionMarkPCSourceLine;
315
316   if (m_options.show_bytes)
317     options |= Disassembler::eOptionShowBytes;
318
319   if (m_options.raw)
320     options |= Disassembler::eOptionRawOuput;
321
322   if (!m_options.func_name.empty()) {
323     ConstString name(m_options.func_name.c_str());
324
325     if (Disassembler::Disassemble(
326             m_interpreter.GetDebugger(), m_options.arch, plugin_name,
327             flavor_string, m_exe_ctx, name,
328             nullptr, // Module *
329             m_options.num_instructions, m_options.show_mixed,
330             m_options.show_mixed ? m_options.num_lines_context : 0, options,
331             result.GetOutputStream())) {
332       result.SetStatus(eReturnStatusSuccessFinishResult);
333     } else {
334       result.AppendErrorWithFormat("Unable to find symbol with name '%s'.\n",
335                                    name.GetCString());
336       result.SetStatus(eReturnStatusFailed);
337     }
338   } else {
339     std::vector<AddressRange> ranges;
340     AddressRange range;
341     StackFrame *frame = m_exe_ctx.GetFramePtr();
342     if (m_options.frame_line) {
343       if (frame == nullptr) {
344         result.AppendError("Cannot disassemble around the current line without "
345                            "a selected frame.\n");
346         result.SetStatus(eReturnStatusFailed);
347         return false;
348       }
349       LineEntry pc_line_entry(
350           frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
351       if (pc_line_entry.IsValid()) {
352         range = pc_line_entry.range;
353       } else {
354         m_options.at_pc =
355             true; // No line entry, so just disassemble around the current pc
356         m_options.show_mixed = false;
357       }
358     } else if (m_options.current_function) {
359       if (frame == nullptr) {
360         result.AppendError("Cannot disassemble around the current function "
361                            "without a selected frame.\n");
362         result.SetStatus(eReturnStatusFailed);
363         return false;
364       }
365       Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
366       if (symbol) {
367         range.GetBaseAddress() = symbol->GetAddress();
368         range.SetByteSize(symbol->GetByteSize());
369       }
370     }
371
372     // Did the "m_options.frame_line" find a valid range already? If so skip
373     // the rest...
374     if (range.GetByteSize() == 0) {
375       if (m_options.at_pc) {
376         if (frame == nullptr) {
377           result.AppendError("Cannot disassemble around the current PC without "
378                              "a selected frame.\n");
379           result.SetStatus(eReturnStatusFailed);
380           return false;
381         }
382         range.GetBaseAddress() = frame->GetFrameCodeAddress();
383         if (m_options.num_instructions == 0) {
384           // Disassembling at the PC always disassembles some number of
385           // instructions (not the whole function).
386           m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
387         }
388         ranges.push_back(range);
389       } else {
390         range.GetBaseAddress().SetOffset(m_options.start_addr);
391         if (range.GetBaseAddress().IsValid()) {
392           if (m_options.end_addr != LLDB_INVALID_ADDRESS) {
393             if (m_options.end_addr <= m_options.start_addr) {
394               result.AppendErrorWithFormat(
395                   "End address before start address.\n");
396               result.SetStatus(eReturnStatusFailed);
397               return false;
398             }
399             range.SetByteSize(m_options.end_addr - m_options.start_addr);
400           }
401           ranges.push_back(range);
402         } else {
403           if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS &&
404               target) {
405             if (!target->GetSectionLoadList().IsEmpty()) {
406               bool failed = false;
407               Address symbol_containing_address;
408               if (target->GetSectionLoadList().ResolveLoadAddress(
409                       m_options.symbol_containing_addr,
410                       symbol_containing_address)) {
411                 ModuleSP module_sp(symbol_containing_address.GetModule());
412                 SymbolContext sc;
413                 bool resolve_tail_call_address = true; // PC can be one past the
414                                                        // address range of the
415                                                        // function.
416                 module_sp->ResolveSymbolContextForAddress(
417                     symbol_containing_address, eSymbolContextEverything, sc,
418                     resolve_tail_call_address);
419                 if (sc.function || sc.symbol) {
420                   sc.GetAddressRange(eSymbolContextFunction |
421                                          eSymbolContextSymbol,
422                                      0, false, range);
423                 } else {
424                   failed = true;
425                 }
426               } else {
427                 failed = true;
428               }
429               if (failed) {
430                 result.AppendErrorWithFormat(
431                     "Could not find function bounds for address 0x%" PRIx64
432                     "\n",
433                     m_options.symbol_containing_addr);
434                 result.SetStatus(eReturnStatusFailed);
435                 return false;
436               }
437               ranges.push_back(range);
438             } else {
439               for (lldb::ModuleSP module_sp : target->GetImages().Modules()) {
440                 lldb::addr_t file_addr = m_options.symbol_containing_addr;
441                 Address file_address;
442                 if (module_sp->ResolveFileAddress(file_addr, file_address)) {
443                   SymbolContext sc;
444                   bool resolve_tail_call_address = true; // PC can be one past
445                                                          // the address range of
446                                                          // the function.
447                   module_sp->ResolveSymbolContextForAddress(
448                       file_address, eSymbolContextEverything, sc,
449                       resolve_tail_call_address);
450                   if (sc.function || sc.symbol) {
451                     sc.GetAddressRange(eSymbolContextFunction |
452                                            eSymbolContextSymbol,
453                                        0, false, range);
454                     ranges.push_back(range);
455                   }
456                 }
457               }
458             }
459           }
460         }
461       }
462     } else
463       ranges.push_back(range);
464
465     if (m_options.num_instructions != 0) {
466       if (ranges.empty()) {
467         // The default action is to disassemble the current frame function.
468         if (frame) {
469           SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction |
470                                                    eSymbolContextSymbol));
471           if (sc.function)
472             range.GetBaseAddress() =
473                 sc.function->GetAddressRange().GetBaseAddress();
474           else if (sc.symbol && sc.symbol->ValueIsAddress())
475             range.GetBaseAddress() = sc.symbol->GetAddress();
476           else
477             range.GetBaseAddress() = frame->GetFrameCodeAddress();
478         }
479
480         if (!range.GetBaseAddress().IsValid()) {
481           result.AppendError("invalid frame");
482           result.SetStatus(eReturnStatusFailed);
483           return false;
484         }
485       }
486
487       bool print_sc_header = ranges.size() > 1;
488       for (AddressRange cur_range : ranges) {
489         if (Disassembler::Disassemble(
490                 m_interpreter.GetDebugger(), m_options.arch, plugin_name,
491                 flavor_string, m_exe_ctx, cur_range.GetBaseAddress(),
492                 m_options.num_instructions, m_options.show_mixed,
493                 m_options.show_mixed ? m_options.num_lines_context : 0, options,
494                 result.GetOutputStream())) {
495           result.SetStatus(eReturnStatusSuccessFinishResult);
496         } else {
497           if (m_options.start_addr != LLDB_INVALID_ADDRESS)
498             result.AppendErrorWithFormat(
499                 "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
500                 m_options.start_addr);
501           else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
502             result.AppendErrorWithFormat(
503                 "Failed to disassemble memory in function at 0x%8.8" PRIx64
504                 ".\n",
505                 m_options.symbol_containing_addr);
506           result.SetStatus(eReturnStatusFailed);
507         }
508       }
509       if (print_sc_header)
510         result.AppendMessage("\n");
511     } else {
512       if (ranges.empty()) {
513         // The default action is to disassemble the current frame function.
514         if (frame) {
515           SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction |
516                                                    eSymbolContextSymbol));
517           if (sc.function)
518             range = sc.function->GetAddressRange();
519           else if (sc.symbol && sc.symbol->ValueIsAddress()) {
520             range.GetBaseAddress() = sc.symbol->GetAddress();
521             range.SetByteSize(sc.symbol->GetByteSize());
522           } else
523             range.GetBaseAddress() = frame->GetFrameCodeAddress();
524         } else {
525           result.AppendError("invalid frame");
526           result.SetStatus(eReturnStatusFailed);
527           return false;
528         }
529         ranges.push_back(range);
530       }
531
532       bool print_sc_header = ranges.size() > 1;
533       for (AddressRange cur_range : ranges) {
534         if (cur_range.GetByteSize() == 0)
535           cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
536
537         if (Disassembler::Disassemble(
538                 m_interpreter.GetDebugger(), m_options.arch, plugin_name,
539                 flavor_string, m_exe_ctx, cur_range, m_options.num_instructions,
540                 m_options.show_mixed,
541                 m_options.show_mixed ? m_options.num_lines_context : 0, options,
542                 result.GetOutputStream())) {
543           result.SetStatus(eReturnStatusSuccessFinishResult);
544         } else {
545           result.AppendErrorWithFormat(
546               "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
547               m_options.start_addr);
548           result.SetStatus(eReturnStatusFailed);
549         }
550         if (print_sc_header)
551           result.AppendMessage("\n");
552       }
553     }
554   }
555
556   return result.Succeeded();
557 }