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