1 //===-- CommandObjectDisassemble.cpp --------------------------------------===//
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
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;
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
) {
45 const int short_option
= m_getopt_table
[option_idx
].val
;
47 switch (short_option
) {
53 if (option_arg
.getAsInteger(0, num_lines_context
))
54 error
.SetErrorStringWithFormat("invalid num context lines string: \"%s\"",
55 option_arg
.str().c_str());
59 if (option_arg
.getAsInteger(0, num_instructions
))
60 error
.SetErrorStringWithFormat(
61 "invalid num of instructions string: \"%s\"",
62 option_arg
.str().c_str());
70 show_control_flow_kind
= true;
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;
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;
87 func_name
.assign(std::string(option_arg
));
88 some_location_specified
= true;
93 some_location_specified
= true;
98 // Disassemble the current source line kind of implies showing mixed source
101 some_location_specified
= true;
105 plugin_name
.assign(std::string(option_arg
));
110 execution_context
? execution_context
->GetTargetSP() : TargetSP();
111 if (target_sp
&& (target_sp
->GetArchitecture().GetTriple().getArch() ==
113 target_sp
->GetArchitecture().GetTriple().getArch() ==
114 llvm::Triple::x86_64
)) {
115 flavor_string
.assign(std::string(option_arg
));
117 error
.SetErrorStringWithFormat("Disassembler flavors are currently only "
118 "supported for x86 and x86_64 targets.");
127 current_function
= true;
128 some_location_specified
= true;
132 if (execution_context
) {
133 const auto &target_sp
= execution_context
->GetTargetSP();
134 auto platform_ptr
= target_sp
? target_sp
->GetPlatform().get() : nullptr;
135 arch
= Platform::GetAugmentedArchSpec(platform_ptr
, option_arg
);
140 symbol_containing_addr
= OptionArgParser::ToAddress(
141 execution_context
, option_arg
, LLDB_INVALID_ADDRESS
, &error
);
142 if (symbol_containing_addr
!= LLDB_INVALID_ADDRESS
) {
143 some_location_specified
= true;
152 llvm_unreachable("Unimplemented option");
158 void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
159 ExecutionContext
*execution_context
) {
162 show_control_flow_kind
= false;
163 num_lines_context
= 0;
164 num_instructions
= 0;
166 current_function
= false;
169 start_addr
= LLDB_INVALID_ADDRESS
;
170 end_addr
= LLDB_INVALID_ADDRESS
;
171 symbol_containing_addr
= LLDB_INVALID_ADDRESS
;
176 execution_context
? execution_context
->GetTargetPtr() : nullptr;
178 // This is a hack till we get the ability to specify features based on
179 // architecture. For now GetDisassemblyFlavor is really only valid for x86
180 // (and for the llvm assembler plugin, but I'm papering over that since that
181 // is the only disassembler plugin we have...
183 if (target
->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86
||
184 target
->GetArchitecture().GetTriple().getArch() ==
185 llvm::Triple::x86_64
) {
186 flavor_string
.assign(target
->GetDisassemblyFlavor());
188 flavor_string
.assign("default");
191 flavor_string
.assign("default");
194 some_location_specified
= false;
198 Status
CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
199 ExecutionContext
*execution_context
) {
200 if (!some_location_specified
)
201 current_function
= true;
205 llvm::ArrayRef
<OptionDefinition
>
206 CommandObjectDisassemble::CommandOptions::GetDefinitions() {
207 return llvm::ArrayRef(g_disassemble_options
);
210 // CommandObjectDisassemble
212 CommandObjectDisassemble::CommandObjectDisassemble(
213 CommandInterpreter
&interpreter
)
214 : CommandObjectParsed(
215 interpreter
, "disassemble",
216 "Disassemble specified instructions in the current target. "
217 "Defaults to the current function for the current thread and "
219 "disassemble [<cmd-options>]", eCommandRequiresTarget
) {}
221 CommandObjectDisassemble::~CommandObjectDisassemble() = default;
223 llvm::Error
CommandObjectDisassemble::CheckRangeSize(const AddressRange
&range
,
224 llvm::StringRef what
) {
225 if (m_options
.num_instructions
> 0 || m_options
.force
||
226 range
.GetByteSize() < GetDebugger().GetStopDisassemblyMaxSize())
227 return llvm::Error::success();
229 msg
<< "Not disassembling " << what
<< " because it is very large ";
230 range
.Dump(&msg
, &GetSelectedTarget(), Address::DumpStyleLoadAddress
,
231 Address::DumpStyleFileAddress
);
232 msg
<< ". To disassemble specify an instruction count limit, start/stop "
233 "addresses or use the --force option.";
234 return llvm::createStringError(llvm::inconvertibleErrorCode(),
238 llvm::Expected
<std::vector
<AddressRange
>>
239 CommandObjectDisassemble::GetContainingAddressRanges() {
240 std::vector
<AddressRange
> ranges
;
241 const auto &get_range
= [&](Address addr
) {
242 ModuleSP
module_sp(addr
.GetModule());
244 bool resolve_tail_call_address
= true;
245 addr
.GetModule()->ResolveSymbolContextForAddress(
246 addr
, eSymbolContextEverything
, sc
, resolve_tail_call_address
);
247 if (sc
.function
|| sc
.symbol
) {
249 sc
.GetAddressRange(eSymbolContextFunction
| eSymbolContextSymbol
, 0,
251 ranges
.push_back(range
);
255 Target
&target
= GetSelectedTarget();
256 if (!target
.GetSectionLoadList().IsEmpty()) {
257 Address symbol_containing_address
;
258 if (target
.GetSectionLoadList().ResolveLoadAddress(
259 m_options
.symbol_containing_addr
, symbol_containing_address
)) {
260 get_range(symbol_containing_address
);
263 for (lldb::ModuleSP module_sp
: target
.GetImages().Modules()) {
264 Address file_address
;
265 if (module_sp
->ResolveFileAddress(m_options
.symbol_containing_addr
,
267 get_range(file_address
);
272 if (ranges
.empty()) {
273 return llvm::createStringError(
274 llvm::inconvertibleErrorCode(),
275 "Could not find function bounds for address 0x%" PRIx64
,
276 m_options
.symbol_containing_addr
);
279 if (llvm::Error err
= CheckRangeSize(ranges
[0], "the function"))
280 return std::move(err
);
284 llvm::Expected
<std::vector
<AddressRange
>>
285 CommandObjectDisassemble::GetCurrentFunctionRanges() {
286 Process
*process
= m_exe_ctx
.GetProcessPtr();
287 StackFrame
*frame
= m_exe_ctx
.GetFramePtr();
290 return llvm::createStringError(
291 llvm::inconvertibleErrorCode(),
292 "Cannot disassemble around the current "
293 "function without the process being stopped.\n");
295 return llvm::createStringError(llvm::inconvertibleErrorCode(),
296 "Cannot disassemble around the current "
297 "function without a selected frame: "
298 "no currently running process.\n");
302 frame
->GetSymbolContext(eSymbolContextFunction
| eSymbolContextSymbol
));
305 range
= sc
.function
->GetAddressRange();
306 else if (sc
.symbol
&& sc
.symbol
->ValueIsAddress()) {
307 range
= {sc
.symbol
->GetAddress(), sc
.symbol
->GetByteSize()};
309 range
= {frame
->GetFrameCodeAddress(), default_disasm_byte_size
};
311 if (llvm::Error err
= CheckRangeSize(range
, "the current function"))
312 return std::move(err
);
313 return std::vector
<AddressRange
>{range
};
316 llvm::Expected
<std::vector
<AddressRange
>>
317 CommandObjectDisassemble::GetCurrentLineRanges() {
318 Process
*process
= m_exe_ctx
.GetProcessPtr();
319 StackFrame
*frame
= m_exe_ctx
.GetFramePtr();
322 return llvm::createStringError(
323 llvm::inconvertibleErrorCode(),
324 "Cannot disassemble around the current "
325 "function without the process being stopped.\n");
327 return llvm::createStringError(llvm::inconvertibleErrorCode(),
328 "Cannot disassemble around the current "
329 "line without a selected frame: "
330 "no currently running process.\n");
334 LineEntry
pc_line_entry(
335 frame
->GetSymbolContext(eSymbolContextLineEntry
).line_entry
);
336 if (pc_line_entry
.IsValid())
337 return std::vector
<AddressRange
>{pc_line_entry
.range
};
339 // No line entry, so just disassemble around the current pc
340 m_options
.show_mixed
= false;
341 return GetPCRanges();
344 llvm::Expected
<std::vector
<AddressRange
>>
345 CommandObjectDisassemble::GetNameRanges(CommandReturnObject
&result
) {
346 ConstString
name(m_options
.func_name
.c_str());
348 ModuleFunctionSearchOptions function_options
;
349 function_options
.include_symbols
= true;
350 function_options
.include_inlines
= true;
352 // Find functions matching the given name.
353 SymbolContextList sc_list
;
354 GetSelectedTarget().GetImages().FindFunctions(name
, eFunctionNameTypeAuto
,
355 function_options
, sc_list
);
357 std::vector
<AddressRange
> ranges
;
358 llvm::Error range_errs
= llvm::Error::success();
360 const uint32_t scope
=
361 eSymbolContextBlock
| eSymbolContextFunction
| eSymbolContextSymbol
;
362 const bool use_inline_block_range
= true;
363 for (SymbolContext sc
: sc_list
.SymbolContexts()) {
364 for (uint32_t range_idx
= 0;
365 sc
.GetAddressRange(scope
, range_idx
, use_inline_block_range
, range
);
367 if (llvm::Error err
= CheckRangeSize(range
, "a range"))
368 range_errs
= joinErrors(std::move(range_errs
), std::move(err
));
370 ranges
.push_back(range
);
373 if (ranges
.empty()) {
375 return std::move(range_errs
);
376 return llvm::createStringError(llvm::inconvertibleErrorCode(),
377 "Unable to find symbol with name '%s'.\n",
381 result
.AppendWarning(toString(std::move(range_errs
)));
385 llvm::Expected
<std::vector
<AddressRange
>>
386 CommandObjectDisassemble::GetPCRanges() {
387 Process
*process
= m_exe_ctx
.GetProcessPtr();
388 StackFrame
*frame
= m_exe_ctx
.GetFramePtr();
391 return llvm::createStringError(
392 llvm::inconvertibleErrorCode(),
393 "Cannot disassemble around the current "
394 "function without the process being stopped.\n");
396 return llvm::createStringError(llvm::inconvertibleErrorCode(),
397 "Cannot disassemble around the current "
398 "PC without a selected frame: "
399 "no currently running process.\n");
403 if (m_options
.num_instructions
== 0) {
404 // Disassembling at the PC always disassembles some number of
405 // instructions (not the whole function).
406 m_options
.num_instructions
= default_disasm_num_ins
;
408 return std::vector
<AddressRange
>{{frame
->GetFrameCodeAddress(), 0}};
411 llvm::Expected
<std::vector
<AddressRange
>>
412 CommandObjectDisassemble::GetStartEndAddressRanges() {
414 if (m_options
.end_addr
!= LLDB_INVALID_ADDRESS
) {
415 if (m_options
.end_addr
<= m_options
.start_addr
) {
416 return llvm::createStringError(llvm::inconvertibleErrorCode(),
417 "End address before start address.");
419 size
= m_options
.end_addr
- m_options
.start_addr
;
421 return std::vector
<AddressRange
>{{Address(m_options
.start_addr
), size
}};
424 llvm::Expected
<std::vector
<AddressRange
>>
425 CommandObjectDisassemble::GetRangesForSelectedMode(
426 CommandReturnObject
&result
) {
427 if (m_options
.symbol_containing_addr
!= LLDB_INVALID_ADDRESS
)
428 return CommandObjectDisassemble::GetContainingAddressRanges();
429 if (m_options
.current_function
)
430 return CommandObjectDisassemble::GetCurrentFunctionRanges();
431 if (m_options
.frame_line
)
432 return CommandObjectDisassemble::GetCurrentLineRanges();
433 if (!m_options
.func_name
.empty())
434 return CommandObjectDisassemble::GetNameRanges(result
);
435 if (m_options
.start_addr
!= LLDB_INVALID_ADDRESS
)
436 return CommandObjectDisassemble::GetStartEndAddressRanges();
437 return CommandObjectDisassemble::GetPCRanges();
440 void CommandObjectDisassemble::DoExecute(Args
&command
,
441 CommandReturnObject
&result
) {
442 Target
*target
= &GetSelectedTarget();
444 if (!m_options
.arch
.IsValid())
445 m_options
.arch
= target
->GetArchitecture();
447 if (!m_options
.arch
.IsValid()) {
449 "use the --arch option or set the target architecture to disassemble");
453 const char *plugin_name
= m_options
.GetPluginName();
454 const char *flavor_string
= m_options
.GetFlavorString();
456 DisassemblerSP disassembler
=
457 Disassembler::FindPlugin(m_options
.arch
, flavor_string
, plugin_name
);
461 result
.AppendErrorWithFormat(
462 "Unable to find Disassembler plug-in named '%s' that supports the "
463 "'%s' architecture.\n",
464 plugin_name
, m_options
.arch
.GetArchitectureName());
466 result
.AppendErrorWithFormat(
467 "Unable to find Disassembler plug-in for the '%s' architecture.\n",
468 m_options
.arch
.GetArchitectureName());
470 } else if (flavor_string
!= nullptr && !disassembler
->FlavorValidForArchSpec(
471 m_options
.arch
, flavor_string
))
472 result
.AppendWarningWithFormat(
473 "invalid disassembler flavor \"%s\", using default.\n", flavor_string
);
475 result
.SetStatus(eReturnStatusSuccessFinishResult
);
477 if (!command
.empty()) {
478 result
.AppendErrorWithFormat(
479 "\"disassemble\" arguments are specified as options.\n");
480 const int terminal_width
=
481 GetCommandInterpreter().GetDebugger().GetTerminalWidth();
482 GetOptions()->GenerateOptionUsage(result
.GetErrorStream(), *this,
487 if (m_options
.show_mixed
&& m_options
.num_lines_context
== 0)
488 m_options
.num_lines_context
= 2;
490 // Always show the PC in the disassembly
491 uint32_t options
= Disassembler::eOptionMarkPCAddress
;
493 // Mark the source line for the current PC only if we are doing mixed source
495 if (m_options
.show_mixed
)
496 options
|= Disassembler::eOptionMarkPCSourceLine
;
498 if (m_options
.show_bytes
)
499 options
|= Disassembler::eOptionShowBytes
;
501 if (m_options
.show_control_flow_kind
)
502 options
|= Disassembler::eOptionShowControlFlowKind
;
505 options
|= Disassembler::eOptionRawOuput
;
507 llvm::Expected
<std::vector
<AddressRange
>> ranges
=
508 GetRangesForSelectedMode(result
);
510 result
.AppendError(toString(ranges
.takeError()));
514 bool print_sc_header
= ranges
->size() > 1;
515 for (AddressRange cur_range
: *ranges
) {
516 Disassembler::Limit limit
;
517 if (m_options
.num_instructions
== 0) {
518 limit
= {Disassembler::Limit::Bytes
, cur_range
.GetByteSize()};
519 if (limit
.value
== 0)
520 limit
.value
= default_disasm_byte_size
;
522 limit
= {Disassembler::Limit::Instructions
, m_options
.num_instructions
};
524 if (Disassembler::Disassemble(
525 GetDebugger(), m_options
.arch
, plugin_name
, flavor_string
,
526 m_exe_ctx
, cur_range
.GetBaseAddress(), limit
, m_options
.show_mixed
,
527 m_options
.show_mixed
? m_options
.num_lines_context
: 0, options
,
528 result
.GetOutputStream())) {
529 result
.SetStatus(eReturnStatusSuccessFinishResult
);
531 if (m_options
.symbol_containing_addr
!= LLDB_INVALID_ADDRESS
) {
532 result
.AppendErrorWithFormat(
533 "Failed to disassemble memory in function at 0x%8.8" PRIx64
".\n",
534 m_options
.symbol_containing_addr
);
536 result
.AppendErrorWithFormat(
537 "Failed to disassemble memory at 0x%8.8" PRIx64
".\n",
538 cur_range
.GetBaseAddress().GetLoadAddress(target
));
542 result
.GetOutputStream() << "\n";