[LoongArch][Clang] Make the parameters and return value of {x,}vorn.v builti ns ...
[llvm-project.git] / lldb / source / Commands / CommandObjectDisassemble.cpp
blob6db4b2665bd84ac52b8b9fa656f97701a2c4d643
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 //===----------------------------------------------------------------------===//
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"
25 static constexpr unsigned default_disasm_byte_size = 32;
26 static constexpr unsigned default_disasm_num_ins = 4;
28 using namespace lldb;
29 using namespace lldb_private;
31 #define LLDB_OPTIONS_disassemble
32 #include "CommandOptions.inc"
34 CommandObjectDisassemble::CommandOptions::CommandOptions() {
35 OptionParsingStarting(nullptr);
38 CommandObjectDisassemble::CommandOptions::~CommandOptions() = default;
40 Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
41 uint32_t option_idx, llvm::StringRef option_arg,
42 ExecutionContext *execution_context) {
43 Status error;
45 const int short_option = m_getopt_table[option_idx].val;
47 switch (short_option) {
48 case 'm':
49 show_mixed = true;
50 break;
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;
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;
65 case 'b':
66 show_bytes = true;
67 break;
69 case 'k':
70 show_control_flow_kind = true;
71 break;
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;
86 case 'n':
87 func_name.assign(std::string(option_arg));
88 some_location_specified = true;
89 break;
91 case 'p':
92 at_pc = true;
93 some_location_specified = true;
94 break;
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;
104 case 'P':
105 plugin_name.assign(std::string(option_arg));
106 break;
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;
123 case 'X':
124 cpu_string = std::string(option_arg);
125 break;
127 case 'Y':
128 features_string = std::string(option_arg);
129 break;
131 case 'r':
132 raw = true;
133 break;
135 case 'f':
136 current_function = true;
137 some_location_specified = true;
138 break;
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);
146 break;
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;
154 } break;
156 case '\x01':
157 force = true;
158 break;
160 default:
161 llvm_unreachable("Unimplemented option");
164 return error;
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();
184 Target *target =
185 execution_context ? execution_context->GetTargetPtr() : nullptr;
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");
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");
209 arch.Clear();
210 some_location_specified = false;
211 force = false;
214 Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
215 ExecutionContext *execution_context) {
216 if (!some_location_specified)
217 current_function = true;
218 return Status();
221 llvm::ArrayRef<OptionDefinition>
222 CommandObjectDisassemble::CommandOptions::GetDefinitions() {
223 return llvm::ArrayRef(g_disassemble_options);
226 // CommandObjectDisassemble
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) {}
237 CommandObjectDisassemble::~CommandObjectDisassemble() = default;
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());
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);
271 Target &target = GetTarget();
272 if (!target.GetSectionLoadList().IsEmpty()) {
273 Address symbol_containing_address;
274 if (target.GetSectionLoadList().ResolveLoadAddress(
275 m_options.symbol_containing_addr, symbol_containing_address)) {
276 get_range(symbol_containing_address);
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);
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);
295 if (llvm::Error err = CheckRangeSize(ranges[0], "the function"))
296 return std::move(err);
297 return ranges;
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");
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};
327 if (llvm::Error err = CheckRangeSize(range, "the current function"))
328 return std::move(err);
329 return std::vector<AddressRange>{range};
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");
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};
355 // No line entry, so just disassemble around the current pc
356 m_options.show_mixed = false;
357 return GetPCRanges();
360 llvm::Expected<std::vector<AddressRange>>
361 CommandObjectDisassemble::GetNameRanges(CommandReturnObject &result) {
362 ConstString name(m_options.func_name.c_str());
364 ModuleFunctionSearchOptions function_options;
365 function_options.include_symbols = true;
366 function_options.include_inlines = true;
368 // Find functions matching the given name.
369 SymbolContextList sc_list;
370 GetTarget().GetImages().FindFunctions(name, eFunctionNameTypeAuto,
371 function_options, sc_list);
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);
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());
396 if (range_errs)
397 result.AppendWarning(toString(std::move(range_errs)));
398 return ranges;
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");
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;
424 return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}};
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.");
435 size = m_options.end_addr - m_options.start_addr;
437 return std::vector<AddressRange>{{Address(m_options.start_addr), size}};
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();
456 void CommandObjectDisassemble::DoExecute(Args &command,
457 CommandReturnObject &result) {
458 Target &target = GetTarget();
460 if (!m_options.arch.IsValid())
461 m_options.arch = target.GetArchitecture();
463 if (!m_options.arch.IsValid()) {
464 result.AppendError(
465 "use the --arch option or set the target architecture to disassemble");
466 return;
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();
474 DisassemblerSP disassembler = Disassembler::FindPlugin(
475 m_options.arch, flavor_string, cpu_string, features_string, plugin_name);
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);
493 result.SetStatus(eReturnStatusSuccessFinishResult);
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;
505 if (m_options.show_mixed && m_options.num_lines_context == 0)
506 m_options.num_lines_context = 2;
508 // Always show the PC in the disassembly
509 uint32_t options = Disassembler::eOptionMarkPCAddress;
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;
516 if (m_options.show_bytes)
517 options |= Disassembler::eOptionShowBytes;
519 if (m_options.show_control_flow_kind)
520 options |= Disassembler::eOptionShowControlFlowKind;
522 if (m_options.raw)
523 options |= Disassembler::eOptionRawOuput;
525 llvm::Expected<std::vector<AddressRange>> ranges =
526 GetRangesForSelectedMode(result);
527 if (!ranges) {
528 result.AppendError(toString(ranges.takeError()));
529 return;
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};
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));
560 if (print_sc_header)
561 result.GetOutputStream() << "\n";