1cfca06d7SDimitry Andric //===-- CommandObjectDisassemble.cpp --------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9f3fbd1c0SDimitry Andric #include "CommandObjectDisassemble.h"
10f034231aSEd Maste #include "lldb/Core/AddressRange.h"
11f034231aSEd Maste #include "lldb/Core/Disassembler.h"
12f034231aSEd Maste #include "lldb/Core/Module.h"
1374a628f7SDimitry Andric #include "lldb/Host/OptionParser.h"
14f034231aSEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
154b4fe385SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
16f034231aSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
17f73363f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
18f034231aSEd Maste #include "lldb/Interpreter/Options.h"
19f034231aSEd Maste #include "lldb/Symbol/Function.h"
20f034231aSEd Maste #include "lldb/Symbol/Symbol.h"
21866dcdacSEd Maste #include "lldb/Target/SectionLoadList.h"
22f034231aSEd Maste #include "lldb/Target/StackFrame.h"
23f034231aSEd Maste #include "lldb/Target/Target.h"
24f034231aSEd Maste
25cfca06d7SDimitry Andric static constexpr unsigned default_disasm_byte_size = 32;
26cfca06d7SDimitry Andric static constexpr unsigned default_disasm_num_ins = 4;
27f034231aSEd Maste
28f034231aSEd Maste using namespace lldb;
29f034231aSEd Maste using namespace lldb_private;
30f034231aSEd Maste
31ead24645SDimitry Andric #define LLDB_OPTIONS_disassemble
32ead24645SDimitry Andric #include "CommandOptions.inc"
3314f1b3e8SDimitry Andric
CommandOptions()346f8fc217SDimitry Andric CommandObjectDisassemble::CommandOptions::CommandOptions() {
3514f1b3e8SDimitry Andric OptionParsingStarting(nullptr);
36f034231aSEd Maste }
37f034231aSEd Maste
38f3fbd1c0SDimitry Andric CommandObjectDisassemble::CommandOptions::~CommandOptions() = default;
39f034231aSEd Maste
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)40b76161e4SDimitry Andric Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
4114f1b3e8SDimitry Andric uint32_t option_idx, llvm::StringRef option_arg,
4214f1b3e8SDimitry Andric ExecutionContext *execution_context) {
43b76161e4SDimitry Andric Status error;
44f034231aSEd Maste
45f034231aSEd Maste const int short_option = m_getopt_table[option_idx].val;
46f034231aSEd Maste
4714f1b3e8SDimitry Andric switch (short_option) {
48f034231aSEd Maste case 'm':
49f034231aSEd Maste show_mixed = true;
50f034231aSEd Maste break;
51f034231aSEd Maste
52f034231aSEd Maste case 'C':
5314f1b3e8SDimitry Andric if (option_arg.getAsInteger(0, num_lines_context))
5414f1b3e8SDimitry Andric error.SetErrorStringWithFormat("invalid num context lines string: \"%s\"",
5514f1b3e8SDimitry Andric option_arg.str().c_str());
56f034231aSEd Maste break;
57f034231aSEd Maste
58f034231aSEd Maste case 'c':
5914f1b3e8SDimitry Andric if (option_arg.getAsInteger(0, num_instructions))
6014f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
6114f1b3e8SDimitry Andric "invalid num of instructions string: \"%s\"",
6214f1b3e8SDimitry Andric option_arg.str().c_str());
63f034231aSEd Maste break;
64f034231aSEd Maste
65f034231aSEd Maste case 'b':
66f034231aSEd Maste show_bytes = true;
67f034231aSEd Maste break;
68f034231aSEd Maste
691f917f69SDimitry Andric case 'k':
701f917f69SDimitry Andric show_control_flow_kind = true;
711f917f69SDimitry Andric break;
721f917f69SDimitry Andric
7314f1b3e8SDimitry Andric case 's': {
74f73363f1SDimitry Andric start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
7514f1b3e8SDimitry Andric LLDB_INVALID_ADDRESS, &error);
76f034231aSEd Maste if (start_addr != LLDB_INVALID_ADDRESS)
77f034231aSEd Maste some_location_specified = true;
7814f1b3e8SDimitry Andric } break;
7914f1b3e8SDimitry Andric case 'e': {
80f73363f1SDimitry Andric end_addr = OptionArgParser::ToAddress(execution_context, option_arg,
8114f1b3e8SDimitry Andric LLDB_INVALID_ADDRESS, &error);
82f034231aSEd Maste if (end_addr != LLDB_INVALID_ADDRESS)
83f034231aSEd Maste some_location_specified = true;
8414f1b3e8SDimitry Andric } break;
85f3fbd1c0SDimitry Andric
86f034231aSEd Maste case 'n':
87cfca06d7SDimitry Andric func_name.assign(std::string(option_arg));
88f034231aSEd Maste some_location_specified = true;
89f034231aSEd Maste break;
90f034231aSEd Maste
91f034231aSEd Maste case 'p':
92f034231aSEd Maste at_pc = true;
93f034231aSEd Maste some_location_specified = true;
94f034231aSEd Maste break;
95f034231aSEd Maste
96f034231aSEd Maste case 'l':
97f034231aSEd Maste frame_line = true;
98f73363f1SDimitry Andric // Disassemble the current source line kind of implies showing mixed source
99f73363f1SDimitry Andric // code context.
100f034231aSEd Maste show_mixed = true;
101f034231aSEd Maste some_location_specified = true;
102f034231aSEd Maste break;
103f034231aSEd Maste
104f034231aSEd Maste case 'P':
105cfca06d7SDimitry Andric plugin_name.assign(std::string(option_arg));
106f034231aSEd Maste break;
107f034231aSEd Maste
10814f1b3e8SDimitry Andric case 'F': {
10914f1b3e8SDimitry Andric TargetSP target_sp =
11014f1b3e8SDimitry Andric execution_context ? execution_context->GetTargetSP() : TargetSP();
11114f1b3e8SDimitry Andric if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() ==
11214f1b3e8SDimitry Andric llvm::Triple::x86 ||
11314f1b3e8SDimitry Andric target_sp->GetArchitecture().GetTriple().getArch() ==
11414f1b3e8SDimitry Andric llvm::Triple::x86_64)) {
115cfca06d7SDimitry Andric flavor_string.assign(std::string(option_arg));
11614f1b3e8SDimitry Andric } else
11714f1b3e8SDimitry Andric error.SetErrorStringWithFormat("Disassembler flavors are currently only "
11814f1b3e8SDimitry Andric "supported for x86 and x86_64 targets.");
119f034231aSEd Maste break;
120f034231aSEd Maste }
121f3fbd1c0SDimitry Andric
122f034231aSEd Maste case 'r':
123f034231aSEd Maste raw = true;
124f034231aSEd Maste break;
125f034231aSEd Maste
126f034231aSEd Maste case 'f':
127f034231aSEd Maste current_function = true;
128f034231aSEd Maste some_location_specified = true;
129f034231aSEd Maste break;
130f034231aSEd Maste
131f034231aSEd Maste case 'A':
13214f1b3e8SDimitry Andric if (execution_context) {
133f73363f1SDimitry Andric const auto &target_sp = execution_context->GetTargetSP();
134f73363f1SDimitry Andric auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr;
135f73363f1SDimitry Andric arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg);
13614f1b3e8SDimitry Andric }
137f034231aSEd Maste break;
138f034231aSEd Maste
13914f1b3e8SDimitry Andric case 'a': {
140f73363f1SDimitry Andric symbol_containing_addr = OptionArgParser::ToAddress(
14114f1b3e8SDimitry Andric execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
14214f1b3e8SDimitry Andric if (symbol_containing_addr != LLDB_INVALID_ADDRESS) {
143f034231aSEd Maste some_location_specified = true;
144f034231aSEd Maste }
14514f1b3e8SDimitry Andric } break;
146f034231aSEd Maste
147cfca06d7SDimitry Andric case '\x01':
148cfca06d7SDimitry Andric force = true;
149cfca06d7SDimitry Andric break;
150cfca06d7SDimitry Andric
151f034231aSEd Maste default:
152ead24645SDimitry Andric llvm_unreachable("Unimplemented option");
153f034231aSEd Maste }
154f034231aSEd Maste
155f034231aSEd Maste return error;
156f034231aSEd Maste }
157f034231aSEd Maste
OptionParsingStarting(ExecutionContext * execution_context)15814f1b3e8SDimitry Andric void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
15914f1b3e8SDimitry Andric ExecutionContext *execution_context) {
160f034231aSEd Maste show_mixed = false;
161f034231aSEd Maste show_bytes = false;
1621f917f69SDimitry Andric show_control_flow_kind = false;
163f034231aSEd Maste num_lines_context = 0;
164f034231aSEd Maste num_instructions = 0;
165f034231aSEd Maste func_name.clear();
166f034231aSEd Maste current_function = false;
167f034231aSEd Maste at_pc = false;
168f034231aSEd Maste frame_line = false;
169f034231aSEd Maste start_addr = LLDB_INVALID_ADDRESS;
170f034231aSEd Maste end_addr = LLDB_INVALID_ADDRESS;
171f034231aSEd Maste symbol_containing_addr = LLDB_INVALID_ADDRESS;
172f034231aSEd Maste raw = false;
173f034231aSEd Maste plugin_name.clear();
174f034231aSEd Maste
17514f1b3e8SDimitry Andric Target *target =
17614f1b3e8SDimitry Andric execution_context ? execution_context->GetTargetPtr() : nullptr;
177f034231aSEd Maste
17814f1b3e8SDimitry Andric // This is a hack till we get the ability to specify features based on
179f73363f1SDimitry Andric // architecture. For now GetDisassemblyFlavor is really only valid for x86
180f73363f1SDimitry Andric // (and for the llvm assembler plugin, but I'm papering over that since that
181f73363f1SDimitry Andric // is the only disassembler plugin we have...
18214f1b3e8SDimitry Andric if (target) {
18314f1b3e8SDimitry Andric if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 ||
18414f1b3e8SDimitry Andric target->GetArchitecture().GetTriple().getArch() ==
18514f1b3e8SDimitry Andric llvm::Triple::x86_64) {
186f034231aSEd Maste flavor_string.assign(target->GetDisassemblyFlavor());
18714f1b3e8SDimitry Andric } else
188f034231aSEd Maste flavor_string.assign("default");
189f034231aSEd Maste
19014f1b3e8SDimitry Andric } else
191f034231aSEd Maste flavor_string.assign("default");
192f034231aSEd Maste
193f034231aSEd Maste arch.Clear();
194f034231aSEd Maste some_location_specified = false;
195cfca06d7SDimitry Andric force = false;
196f034231aSEd Maste }
197f034231aSEd Maste
OptionParsingFinished(ExecutionContext * execution_context)198b76161e4SDimitry Andric Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
19914f1b3e8SDimitry Andric ExecutionContext *execution_context) {
200f034231aSEd Maste if (!some_location_specified)
201f034231aSEd Maste current_function = true;
202b76161e4SDimitry Andric return Status();
203f034231aSEd Maste }
204f034231aSEd Maste
20514f1b3e8SDimitry Andric llvm::ArrayRef<OptionDefinition>
GetDefinitions()20614f1b3e8SDimitry Andric CommandObjectDisassemble::CommandOptions::GetDefinitions() {
207e3b55780SDimitry Andric return llvm::ArrayRef(g_disassemble_options);
208f034231aSEd Maste }
209f034231aSEd Maste
210f034231aSEd Maste // CommandObjectDisassemble
211f034231aSEd Maste
CommandObjectDisassemble(CommandInterpreter & interpreter)21214f1b3e8SDimitry Andric CommandObjectDisassemble::CommandObjectDisassemble(
21314f1b3e8SDimitry Andric CommandInterpreter &interpreter)
21414f1b3e8SDimitry Andric : CommandObjectParsed(
21514f1b3e8SDimitry Andric interpreter, "disassemble",
21614f1b3e8SDimitry Andric "Disassemble specified instructions in the current target. "
217f3fbd1c0SDimitry Andric "Defaults to the current function for the current thread and "
218f3fbd1c0SDimitry Andric "stack frame.",
21908e8dd7bSDimitry Andric "disassemble [<cmd-options>]", eCommandRequiresTarget) {}
220f034231aSEd Maste
221f3fbd1c0SDimitry Andric CommandObjectDisassemble::~CommandObjectDisassemble() = default;
222f034231aSEd Maste
CheckRangeSize(const AddressRange & range,llvm::StringRef what)223cfca06d7SDimitry Andric llvm::Error CommandObjectDisassemble::CheckRangeSize(const AddressRange &range,
224cfca06d7SDimitry Andric llvm::StringRef what) {
225cfca06d7SDimitry Andric if (m_options.num_instructions > 0 || m_options.force ||
226344a3780SDimitry Andric range.GetByteSize() < GetDebugger().GetStopDisassemblyMaxSize())
227cfca06d7SDimitry Andric return llvm::Error::success();
228cfca06d7SDimitry Andric StreamString msg;
229cfca06d7SDimitry Andric msg << "Not disassembling " << what << " because it is very large ";
230cfca06d7SDimitry Andric range.Dump(&msg, &GetSelectedTarget(), Address::DumpStyleLoadAddress,
231cfca06d7SDimitry Andric Address::DumpStyleFileAddress);
232cfca06d7SDimitry Andric msg << ". To disassemble specify an instruction count limit, start/stop "
233cfca06d7SDimitry Andric "addresses or use the --force option.";
234cfca06d7SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(),
235cfca06d7SDimitry Andric msg.GetString());
236cfca06d7SDimitry Andric }
237cfca06d7SDimitry Andric
238cfca06d7SDimitry Andric llvm::Expected<std::vector<AddressRange>>
GetContainingAddressRanges()239cfca06d7SDimitry Andric CommandObjectDisassemble::GetContainingAddressRanges() {
240cfca06d7SDimitry Andric std::vector<AddressRange> ranges;
241cfca06d7SDimitry Andric const auto &get_range = [&](Address addr) {
242cfca06d7SDimitry Andric ModuleSP module_sp(addr.GetModule());
243cfca06d7SDimitry Andric SymbolContext sc;
244cfca06d7SDimitry Andric bool resolve_tail_call_address = true;
245cfca06d7SDimitry Andric addr.GetModule()->ResolveSymbolContextForAddress(
246cfca06d7SDimitry Andric addr, eSymbolContextEverything, sc, resolve_tail_call_address);
247cfca06d7SDimitry Andric if (sc.function || sc.symbol) {
248cfca06d7SDimitry Andric AddressRange range;
249cfca06d7SDimitry Andric sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
250cfca06d7SDimitry Andric false, range);
251cfca06d7SDimitry Andric ranges.push_back(range);
252cfca06d7SDimitry Andric }
253cfca06d7SDimitry Andric };
254cfca06d7SDimitry Andric
255cfca06d7SDimitry Andric Target &target = GetSelectedTarget();
256cfca06d7SDimitry Andric if (!target.GetSectionLoadList().IsEmpty()) {
257cfca06d7SDimitry Andric Address symbol_containing_address;
258cfca06d7SDimitry Andric if (target.GetSectionLoadList().ResolveLoadAddress(
259cfca06d7SDimitry Andric m_options.symbol_containing_addr, symbol_containing_address)) {
260cfca06d7SDimitry Andric get_range(symbol_containing_address);
261cfca06d7SDimitry Andric }
262cfca06d7SDimitry Andric } else {
263cfca06d7SDimitry Andric for (lldb::ModuleSP module_sp : target.GetImages().Modules()) {
264cfca06d7SDimitry Andric Address file_address;
265cfca06d7SDimitry Andric if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr,
266cfca06d7SDimitry Andric file_address)) {
267cfca06d7SDimitry Andric get_range(file_address);
268cfca06d7SDimitry Andric }
269cfca06d7SDimitry Andric }
270cfca06d7SDimitry Andric }
271cfca06d7SDimitry Andric
272cfca06d7SDimitry Andric if (ranges.empty()) {
273cfca06d7SDimitry Andric return llvm::createStringError(
274cfca06d7SDimitry Andric llvm::inconvertibleErrorCode(),
275cfca06d7SDimitry Andric "Could not find function bounds for address 0x%" PRIx64,
276cfca06d7SDimitry Andric m_options.symbol_containing_addr);
277cfca06d7SDimitry Andric }
278cfca06d7SDimitry Andric
279cfca06d7SDimitry Andric if (llvm::Error err = CheckRangeSize(ranges[0], "the function"))
280cfca06d7SDimitry Andric return std::move(err);
281cfca06d7SDimitry Andric return ranges;
282cfca06d7SDimitry Andric }
283cfca06d7SDimitry Andric
284cfca06d7SDimitry Andric llvm::Expected<std::vector<AddressRange>>
GetCurrentFunctionRanges()285cfca06d7SDimitry Andric CommandObjectDisassemble::GetCurrentFunctionRanges() {
286145449b1SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
287cfca06d7SDimitry Andric StackFrame *frame = m_exe_ctx.GetFramePtr();
288cfca06d7SDimitry Andric if (!frame) {
289145449b1SDimitry Andric if (process) {
290145449b1SDimitry Andric return llvm::createStringError(
291145449b1SDimitry Andric llvm::inconvertibleErrorCode(),
292145449b1SDimitry Andric "Cannot disassemble around the current "
293145449b1SDimitry Andric "function without the process being stopped.\n");
294145449b1SDimitry Andric } else {
295cfca06d7SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(),
296cfca06d7SDimitry Andric "Cannot disassemble around the current "
297145449b1SDimitry Andric "function without a selected frame: "
298145449b1SDimitry Andric "no currently running process.\n");
299145449b1SDimitry Andric }
300cfca06d7SDimitry Andric }
301cfca06d7SDimitry Andric SymbolContext sc(
302cfca06d7SDimitry Andric frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
303cfca06d7SDimitry Andric AddressRange range;
304cfca06d7SDimitry Andric if (sc.function)
305cfca06d7SDimitry Andric range = sc.function->GetAddressRange();
306cfca06d7SDimitry Andric else if (sc.symbol && sc.symbol->ValueIsAddress()) {
307cfca06d7SDimitry Andric range = {sc.symbol->GetAddress(), sc.symbol->GetByteSize()};
308cfca06d7SDimitry Andric } else
309cfca06d7SDimitry Andric range = {frame->GetFrameCodeAddress(), default_disasm_byte_size};
310cfca06d7SDimitry Andric
311cfca06d7SDimitry Andric if (llvm::Error err = CheckRangeSize(range, "the current function"))
312cfca06d7SDimitry Andric return std::move(err);
313cfca06d7SDimitry Andric return std::vector<AddressRange>{range};
314cfca06d7SDimitry Andric }
315cfca06d7SDimitry Andric
316cfca06d7SDimitry Andric llvm::Expected<std::vector<AddressRange>>
GetCurrentLineRanges()317cfca06d7SDimitry Andric CommandObjectDisassemble::GetCurrentLineRanges() {
318145449b1SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
319cfca06d7SDimitry Andric StackFrame *frame = m_exe_ctx.GetFramePtr();
320cfca06d7SDimitry Andric if (!frame) {
321145449b1SDimitry Andric if (process) {
322145449b1SDimitry Andric return llvm::createStringError(
323145449b1SDimitry Andric llvm::inconvertibleErrorCode(),
324145449b1SDimitry Andric "Cannot disassemble around the current "
325145449b1SDimitry Andric "function without the process being stopped.\n");
326145449b1SDimitry Andric } else {
327cfca06d7SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(),
328cfca06d7SDimitry Andric "Cannot disassemble around the current "
329145449b1SDimitry Andric "line without a selected frame: "
330145449b1SDimitry Andric "no currently running process.\n");
331145449b1SDimitry Andric }
332cfca06d7SDimitry Andric }
333cfca06d7SDimitry Andric
334cfca06d7SDimitry Andric LineEntry pc_line_entry(
335cfca06d7SDimitry Andric frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
336cfca06d7SDimitry Andric if (pc_line_entry.IsValid())
337cfca06d7SDimitry Andric return std::vector<AddressRange>{pc_line_entry.range};
338cfca06d7SDimitry Andric
339cfca06d7SDimitry Andric // No line entry, so just disassemble around the current pc
340cfca06d7SDimitry Andric m_options.show_mixed = false;
341cfca06d7SDimitry Andric return GetPCRanges();
342cfca06d7SDimitry Andric }
343cfca06d7SDimitry Andric
344cfca06d7SDimitry Andric llvm::Expected<std::vector<AddressRange>>
GetNameRanges(CommandReturnObject & result)345cfca06d7SDimitry Andric CommandObjectDisassemble::GetNameRanges(CommandReturnObject &result) {
346cfca06d7SDimitry Andric ConstString name(m_options.func_name.c_str());
347c0981da4SDimitry Andric
348c0981da4SDimitry Andric ModuleFunctionSearchOptions function_options;
349c0981da4SDimitry Andric function_options.include_symbols = true;
350c0981da4SDimitry Andric function_options.include_inlines = true;
351cfca06d7SDimitry Andric
352cfca06d7SDimitry Andric // Find functions matching the given name.
353cfca06d7SDimitry Andric SymbolContextList sc_list;
354c0981da4SDimitry Andric GetSelectedTarget().GetImages().FindFunctions(name, eFunctionNameTypeAuto,
355c0981da4SDimitry Andric function_options, sc_list);
356cfca06d7SDimitry Andric
357cfca06d7SDimitry Andric std::vector<AddressRange> ranges;
358cfca06d7SDimitry Andric llvm::Error range_errs = llvm::Error::success();
359cfca06d7SDimitry Andric AddressRange range;
360cfca06d7SDimitry Andric const uint32_t scope =
361cfca06d7SDimitry Andric eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
362cfca06d7SDimitry Andric const bool use_inline_block_range = true;
363cfca06d7SDimitry Andric for (SymbolContext sc : sc_list.SymbolContexts()) {
364cfca06d7SDimitry Andric for (uint32_t range_idx = 0;
365cfca06d7SDimitry Andric sc.GetAddressRange(scope, range_idx, use_inline_block_range, range);
366cfca06d7SDimitry Andric ++range_idx) {
367cfca06d7SDimitry Andric if (llvm::Error err = CheckRangeSize(range, "a range"))
368cfca06d7SDimitry Andric range_errs = joinErrors(std::move(range_errs), std::move(err));
369cfca06d7SDimitry Andric else
370cfca06d7SDimitry Andric ranges.push_back(range);
371cfca06d7SDimitry Andric }
372cfca06d7SDimitry Andric }
373cfca06d7SDimitry Andric if (ranges.empty()) {
374cfca06d7SDimitry Andric if (range_errs)
375cfca06d7SDimitry Andric return std::move(range_errs);
376cfca06d7SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(),
377cfca06d7SDimitry Andric "Unable to find symbol with name '%s'.\n",
378cfca06d7SDimitry Andric name.GetCString());
379cfca06d7SDimitry Andric }
380cfca06d7SDimitry Andric if (range_errs)
381cfca06d7SDimitry Andric result.AppendWarning(toString(std::move(range_errs)));
382cfca06d7SDimitry Andric return ranges;
383cfca06d7SDimitry Andric }
384cfca06d7SDimitry Andric
385cfca06d7SDimitry Andric llvm::Expected<std::vector<AddressRange>>
GetPCRanges()386cfca06d7SDimitry Andric CommandObjectDisassemble::GetPCRanges() {
387145449b1SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
388cfca06d7SDimitry Andric StackFrame *frame = m_exe_ctx.GetFramePtr();
389cfca06d7SDimitry Andric if (!frame) {
390145449b1SDimitry Andric if (process) {
391145449b1SDimitry Andric return llvm::createStringError(
392145449b1SDimitry Andric llvm::inconvertibleErrorCode(),
393145449b1SDimitry Andric "Cannot disassemble around the current "
394145449b1SDimitry Andric "function without the process being stopped.\n");
395145449b1SDimitry Andric } else {
396cfca06d7SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(),
397cfca06d7SDimitry Andric "Cannot disassemble around the current "
398145449b1SDimitry Andric "PC without a selected frame: "
399145449b1SDimitry Andric "no currently running process.\n");
400145449b1SDimitry Andric }
401cfca06d7SDimitry Andric }
402cfca06d7SDimitry Andric
403cfca06d7SDimitry Andric if (m_options.num_instructions == 0) {
404cfca06d7SDimitry Andric // Disassembling at the PC always disassembles some number of
405cfca06d7SDimitry Andric // instructions (not the whole function).
406cfca06d7SDimitry Andric m_options.num_instructions = default_disasm_num_ins;
407cfca06d7SDimitry Andric }
408cfca06d7SDimitry Andric return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}};
409cfca06d7SDimitry Andric }
410cfca06d7SDimitry Andric
411cfca06d7SDimitry Andric llvm::Expected<std::vector<AddressRange>>
GetStartEndAddressRanges()412cfca06d7SDimitry Andric CommandObjectDisassemble::GetStartEndAddressRanges() {
413cfca06d7SDimitry Andric addr_t size = 0;
414cfca06d7SDimitry Andric if (m_options.end_addr != LLDB_INVALID_ADDRESS) {
415cfca06d7SDimitry Andric if (m_options.end_addr <= m_options.start_addr) {
416cfca06d7SDimitry Andric return llvm::createStringError(llvm::inconvertibleErrorCode(),
417cfca06d7SDimitry Andric "End address before start address.");
418cfca06d7SDimitry Andric }
419cfca06d7SDimitry Andric size = m_options.end_addr - m_options.start_addr;
420cfca06d7SDimitry Andric }
421cfca06d7SDimitry Andric return std::vector<AddressRange>{{Address(m_options.start_addr), size}};
422cfca06d7SDimitry Andric }
423cfca06d7SDimitry Andric
424cfca06d7SDimitry Andric llvm::Expected<std::vector<AddressRange>>
GetRangesForSelectedMode(CommandReturnObject & result)425cfca06d7SDimitry Andric CommandObjectDisassemble::GetRangesForSelectedMode(
426cfca06d7SDimitry Andric CommandReturnObject &result) {
427cfca06d7SDimitry Andric if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
428cfca06d7SDimitry Andric return CommandObjectDisassemble::GetContainingAddressRanges();
429cfca06d7SDimitry Andric if (m_options.current_function)
430cfca06d7SDimitry Andric return CommandObjectDisassemble::GetCurrentFunctionRanges();
431cfca06d7SDimitry Andric if (m_options.frame_line)
432cfca06d7SDimitry Andric return CommandObjectDisassemble::GetCurrentLineRanges();
433cfca06d7SDimitry Andric if (!m_options.func_name.empty())
434cfca06d7SDimitry Andric return CommandObjectDisassemble::GetNameRanges(result);
435cfca06d7SDimitry Andric if (m_options.start_addr != LLDB_INVALID_ADDRESS)
436cfca06d7SDimitry Andric return CommandObjectDisassemble::GetStartEndAddressRanges();
437cfca06d7SDimitry Andric return CommandObjectDisassemble::GetPCRanges();
438cfca06d7SDimitry Andric }
439cfca06d7SDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)440b1c73532SDimitry Andric void CommandObjectDisassemble::DoExecute(Args &command,
44114f1b3e8SDimitry Andric CommandReturnObject &result) {
442ead24645SDimitry Andric Target *target = &GetSelectedTarget();
443ead24645SDimitry Andric
444f034231aSEd Maste if (!m_options.arch.IsValid())
445f034231aSEd Maste m_options.arch = target->GetArchitecture();
446f034231aSEd Maste
44714f1b3e8SDimitry Andric if (!m_options.arch.IsValid()) {
44814f1b3e8SDimitry Andric result.AppendError(
44914f1b3e8SDimitry Andric "use the --arch option or set the target architecture to disassemble");
450b1c73532SDimitry Andric return;
451f034231aSEd Maste }
452f034231aSEd Maste
453f034231aSEd Maste const char *plugin_name = m_options.GetPluginName();
454f034231aSEd Maste const char *flavor_string = m_options.GetFlavorString();
455f034231aSEd Maste
45614f1b3e8SDimitry Andric DisassemblerSP disassembler =
45714f1b3e8SDimitry Andric Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
458f034231aSEd Maste
45914f1b3e8SDimitry Andric if (!disassembler) {
46014f1b3e8SDimitry Andric if (plugin_name) {
46114f1b3e8SDimitry Andric result.AppendErrorWithFormat(
46214f1b3e8SDimitry Andric "Unable to find Disassembler plug-in named '%s' that supports the "
46314f1b3e8SDimitry Andric "'%s' architecture.\n",
46414f1b3e8SDimitry Andric plugin_name, m_options.arch.GetArchitectureName());
46514f1b3e8SDimitry Andric } else
46614f1b3e8SDimitry Andric result.AppendErrorWithFormat(
46714f1b3e8SDimitry Andric "Unable to find Disassembler plug-in for the '%s' architecture.\n",
468f034231aSEd Maste m_options.arch.GetArchitectureName());
469b1c73532SDimitry Andric return;
470706b4fc4SDimitry Andric } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec(
471706b4fc4SDimitry Andric m_options.arch, flavor_string))
47214f1b3e8SDimitry Andric result.AppendWarningWithFormat(
47314f1b3e8SDimitry Andric "invalid disassembler flavor \"%s\", using default.\n", flavor_string);
474f034231aSEd Maste
475f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
476f034231aSEd Maste
47714f1b3e8SDimitry Andric if (!command.empty()) {
47814f1b3e8SDimitry Andric result.AppendErrorWithFormat(
47914f1b3e8SDimitry Andric "\"disassemble\" arguments are specified as options.\n");
48014f1b3e8SDimitry Andric const int terminal_width =
48114f1b3e8SDimitry Andric GetCommandInterpreter().GetDebugger().GetTerminalWidth();
482145449b1SDimitry Andric GetOptions()->GenerateOptionUsage(result.GetErrorStream(), *this,
48314f1b3e8SDimitry Andric terminal_width);
484b1c73532SDimitry Andric return;
485f034231aSEd Maste }
486f034231aSEd Maste
487f034231aSEd Maste if (m_options.show_mixed && m_options.num_lines_context == 0)
48814f1b3e8SDimitry Andric m_options.num_lines_context = 2;
489f034231aSEd Maste
490f034231aSEd Maste // Always show the PC in the disassembly
491f034231aSEd Maste uint32_t options = Disassembler::eOptionMarkPCAddress;
492f034231aSEd Maste
49314f1b3e8SDimitry Andric // Mark the source line for the current PC only if we are doing mixed source
49414f1b3e8SDimitry Andric // and assembly
495f034231aSEd Maste if (m_options.show_mixed)
496f034231aSEd Maste options |= Disassembler::eOptionMarkPCSourceLine;
497f034231aSEd Maste
498f034231aSEd Maste if (m_options.show_bytes)
499f034231aSEd Maste options |= Disassembler::eOptionShowBytes;
500f034231aSEd Maste
5011f917f69SDimitry Andric if (m_options.show_control_flow_kind)
5021f917f69SDimitry Andric options |= Disassembler::eOptionShowControlFlowKind;
5031f917f69SDimitry Andric
504f034231aSEd Maste if (m_options.raw)
505f034231aSEd Maste options |= Disassembler::eOptionRawOuput;
506f034231aSEd Maste
507cfca06d7SDimitry Andric llvm::Expected<std::vector<AddressRange>> ranges =
508cfca06d7SDimitry Andric GetRangesForSelectedMode(result);
509cfca06d7SDimitry Andric if (!ranges) {
510cfca06d7SDimitry Andric result.AppendError(toString(ranges.takeError()));
511b1c73532SDimitry Andric return;
512f034231aSEd Maste }
513f034231aSEd Maste
514cfca06d7SDimitry Andric bool print_sc_header = ranges->size() > 1;
515cfca06d7SDimitry Andric for (AddressRange cur_range : *ranges) {
516cfca06d7SDimitry Andric Disassembler::Limit limit;
51714f1b3e8SDimitry Andric if (m_options.num_instructions == 0) {
518cfca06d7SDimitry Andric limit = {Disassembler::Limit::Bytes, cur_range.GetByteSize()};
519cfca06d7SDimitry Andric if (limit.value == 0)
520cfca06d7SDimitry Andric limit.value = default_disasm_byte_size;
52114f1b3e8SDimitry Andric } else {
522cfca06d7SDimitry Andric limit = {Disassembler::Limit::Instructions, m_options.num_instructions};
523f034231aSEd Maste }
52414f1b3e8SDimitry Andric if (Disassembler::Disassemble(
5255f29bb8aSDimitry Andric GetDebugger(), m_options.arch, plugin_name, flavor_string,
526cfca06d7SDimitry Andric m_exe_ctx, cur_range.GetBaseAddress(), limit, m_options.show_mixed,
52714f1b3e8SDimitry Andric m_options.show_mixed ? m_options.num_lines_context : 0, options,
52814f1b3e8SDimitry Andric result.GetOutputStream())) {
529f034231aSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
53014f1b3e8SDimitry Andric } else {
531cfca06d7SDimitry Andric if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) {
53214f1b3e8SDimitry Andric result.AppendErrorWithFormat(
533cfca06d7SDimitry Andric "Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n",
53414f1b3e8SDimitry Andric m_options.symbol_containing_addr);
53514f1b3e8SDimitry Andric } else {
53614f1b3e8SDimitry Andric result.AppendErrorWithFormat(
53714f1b3e8SDimitry Andric "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
538ead24645SDimitry Andric cur_range.GetBaseAddress().GetLoadAddress(target));
539cfca06d7SDimitry Andric }
540f034231aSEd Maste }
5410cac4ca3SEd Maste if (print_sc_header)
542cfca06d7SDimitry Andric result.GetOutputStream() << "\n";
543f034231aSEd Maste }
544f034231aSEd Maste }
545