1dda28197Spatrick //===-- CommandObjectDisassemble.cpp --------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "CommandObjectDisassemble.h"
10061da546Spatrick #include "lldb/Core/AddressRange.h"
11061da546Spatrick #include "lldb/Core/Disassembler.h"
12061da546Spatrick #include "lldb/Core/Module.h"
13061da546Spatrick #include "lldb/Host/OptionParser.h"
14061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
15*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
16061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
17061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
18061da546Spatrick #include "lldb/Interpreter/Options.h"
19061da546Spatrick #include "lldb/Symbol/Function.h"
20061da546Spatrick #include "lldb/Symbol/Symbol.h"
21061da546Spatrick #include "lldb/Target/SectionLoadList.h"
22061da546Spatrick #include "lldb/Target/StackFrame.h"
23061da546Spatrick #include "lldb/Target/Target.h"
24061da546Spatrick
25dda28197Spatrick static constexpr unsigned default_disasm_byte_size = 32;
26dda28197Spatrick static constexpr unsigned default_disasm_num_ins = 4;
27061da546Spatrick
28061da546Spatrick using namespace lldb;
29061da546Spatrick using namespace lldb_private;
30061da546Spatrick
31061da546Spatrick #define LLDB_OPTIONS_disassemble
32061da546Spatrick #include "CommandOptions.inc"
33061da546Spatrick
CommandOptions()34*f6aab3d8Srobert CommandObjectDisassemble::CommandOptions::CommandOptions() {
35061da546Spatrick OptionParsingStarting(nullptr);
36061da546Spatrick }
37061da546Spatrick
38061da546Spatrick CommandObjectDisassemble::CommandOptions::~CommandOptions() = default;
39061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)40061da546Spatrick Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
41061da546Spatrick uint32_t option_idx, llvm::StringRef option_arg,
42061da546Spatrick ExecutionContext *execution_context) {
43061da546Spatrick Status error;
44061da546Spatrick
45061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
46061da546Spatrick
47061da546Spatrick switch (short_option) {
48061da546Spatrick case 'm':
49061da546Spatrick show_mixed = true;
50061da546Spatrick break;
51061da546Spatrick
52061da546Spatrick case 'C':
53061da546Spatrick if (option_arg.getAsInteger(0, num_lines_context))
54061da546Spatrick error.SetErrorStringWithFormat("invalid num context lines string: \"%s\"",
55061da546Spatrick option_arg.str().c_str());
56061da546Spatrick break;
57061da546Spatrick
58061da546Spatrick case 'c':
59061da546Spatrick if (option_arg.getAsInteger(0, num_instructions))
60061da546Spatrick error.SetErrorStringWithFormat(
61061da546Spatrick "invalid num of instructions string: \"%s\"",
62061da546Spatrick option_arg.str().c_str());
63061da546Spatrick break;
64061da546Spatrick
65061da546Spatrick case 'b':
66061da546Spatrick show_bytes = true;
67061da546Spatrick break;
68061da546Spatrick
69*f6aab3d8Srobert case 'k':
70*f6aab3d8Srobert show_control_flow_kind = true;
71*f6aab3d8Srobert break;
72*f6aab3d8Srobert
73061da546Spatrick case 's': {
74061da546Spatrick start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
75061da546Spatrick LLDB_INVALID_ADDRESS, &error);
76061da546Spatrick if (start_addr != LLDB_INVALID_ADDRESS)
77061da546Spatrick some_location_specified = true;
78061da546Spatrick } break;
79061da546Spatrick case 'e': {
80061da546Spatrick end_addr = OptionArgParser::ToAddress(execution_context, option_arg,
81061da546Spatrick LLDB_INVALID_ADDRESS, &error);
82061da546Spatrick if (end_addr != LLDB_INVALID_ADDRESS)
83061da546Spatrick some_location_specified = true;
84061da546Spatrick } break;
85061da546Spatrick
86061da546Spatrick case 'n':
87dda28197Spatrick func_name.assign(std::string(option_arg));
88061da546Spatrick some_location_specified = true;
89061da546Spatrick break;
90061da546Spatrick
91061da546Spatrick case 'p':
92061da546Spatrick at_pc = true;
93061da546Spatrick some_location_specified = true;
94061da546Spatrick break;
95061da546Spatrick
96061da546Spatrick case 'l':
97061da546Spatrick frame_line = true;
98061da546Spatrick // Disassemble the current source line kind of implies showing mixed source
99061da546Spatrick // code context.
100061da546Spatrick show_mixed = true;
101061da546Spatrick some_location_specified = true;
102061da546Spatrick break;
103061da546Spatrick
104061da546Spatrick case 'P':
105dda28197Spatrick plugin_name.assign(std::string(option_arg));
106061da546Spatrick break;
107061da546Spatrick
108061da546Spatrick case 'F': {
109061da546Spatrick TargetSP target_sp =
110061da546Spatrick execution_context ? execution_context->GetTargetSP() : TargetSP();
111061da546Spatrick if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() ==
112061da546Spatrick llvm::Triple::x86 ||
113061da546Spatrick target_sp->GetArchitecture().GetTriple().getArch() ==
114061da546Spatrick llvm::Triple::x86_64)) {
115dda28197Spatrick flavor_string.assign(std::string(option_arg));
116061da546Spatrick } else
117061da546Spatrick error.SetErrorStringWithFormat("Disassembler flavors are currently only "
118061da546Spatrick "supported for x86 and x86_64 targets.");
119061da546Spatrick break;
120061da546Spatrick }
121061da546Spatrick
122061da546Spatrick case 'r':
123061da546Spatrick raw = true;
124061da546Spatrick break;
125061da546Spatrick
126061da546Spatrick case 'f':
127061da546Spatrick current_function = true;
128061da546Spatrick some_location_specified = true;
129061da546Spatrick break;
130061da546Spatrick
131061da546Spatrick case 'A':
132061da546Spatrick if (execution_context) {
133061da546Spatrick const auto &target_sp = execution_context->GetTargetSP();
134061da546Spatrick auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr;
135061da546Spatrick arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg);
136061da546Spatrick }
137061da546Spatrick break;
138061da546Spatrick
139061da546Spatrick case 'a': {
140061da546Spatrick symbol_containing_addr = OptionArgParser::ToAddress(
141061da546Spatrick execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
142061da546Spatrick if (symbol_containing_addr != LLDB_INVALID_ADDRESS) {
143061da546Spatrick some_location_specified = true;
144061da546Spatrick }
145061da546Spatrick } break;
146061da546Spatrick
147dda28197Spatrick case '\x01':
148dda28197Spatrick force = true;
149dda28197Spatrick break;
150dda28197Spatrick
151061da546Spatrick default:
152061da546Spatrick llvm_unreachable("Unimplemented option");
153061da546Spatrick }
154061da546Spatrick
155061da546Spatrick return error;
156061da546Spatrick }
157061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)158061da546Spatrick void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
159061da546Spatrick ExecutionContext *execution_context) {
160061da546Spatrick show_mixed = false;
161061da546Spatrick show_bytes = false;
162*f6aab3d8Srobert show_control_flow_kind = false;
163061da546Spatrick num_lines_context = 0;
164061da546Spatrick num_instructions = 0;
165061da546Spatrick func_name.clear();
166061da546Spatrick current_function = false;
167061da546Spatrick at_pc = false;
168061da546Spatrick frame_line = false;
169061da546Spatrick start_addr = LLDB_INVALID_ADDRESS;
170061da546Spatrick end_addr = LLDB_INVALID_ADDRESS;
171061da546Spatrick symbol_containing_addr = LLDB_INVALID_ADDRESS;
172061da546Spatrick raw = false;
173061da546Spatrick plugin_name.clear();
174061da546Spatrick
175061da546Spatrick Target *target =
176061da546Spatrick execution_context ? execution_context->GetTargetPtr() : nullptr;
177061da546Spatrick
178061da546Spatrick // This is a hack till we get the ability to specify features based on
179061da546Spatrick // architecture. For now GetDisassemblyFlavor is really only valid for x86
180061da546Spatrick // (and for the llvm assembler plugin, but I'm papering over that since that
181061da546Spatrick // is the only disassembler plugin we have...
182061da546Spatrick if (target) {
183061da546Spatrick if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 ||
184061da546Spatrick target->GetArchitecture().GetTriple().getArch() ==
185061da546Spatrick llvm::Triple::x86_64) {
186061da546Spatrick flavor_string.assign(target->GetDisassemblyFlavor());
187061da546Spatrick } else
188061da546Spatrick flavor_string.assign("default");
189061da546Spatrick
190061da546Spatrick } else
191061da546Spatrick flavor_string.assign("default");
192061da546Spatrick
193061da546Spatrick arch.Clear();
194061da546Spatrick some_location_specified = false;
195dda28197Spatrick force = false;
196061da546Spatrick }
197061da546Spatrick
OptionParsingFinished(ExecutionContext * execution_context)198061da546Spatrick Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
199061da546Spatrick ExecutionContext *execution_context) {
200061da546Spatrick if (!some_location_specified)
201061da546Spatrick current_function = true;
202061da546Spatrick return Status();
203061da546Spatrick }
204061da546Spatrick
205061da546Spatrick llvm::ArrayRef<OptionDefinition>
GetDefinitions()206061da546Spatrick CommandObjectDisassemble::CommandOptions::GetDefinitions() {
207*f6aab3d8Srobert return llvm::ArrayRef(g_disassemble_options);
208061da546Spatrick }
209061da546Spatrick
210061da546Spatrick // CommandObjectDisassemble
211061da546Spatrick
CommandObjectDisassemble(CommandInterpreter & interpreter)212061da546Spatrick CommandObjectDisassemble::CommandObjectDisassemble(
213061da546Spatrick CommandInterpreter &interpreter)
214061da546Spatrick : CommandObjectParsed(
215061da546Spatrick interpreter, "disassemble",
216061da546Spatrick "Disassemble specified instructions in the current target. "
217061da546Spatrick "Defaults to the current function for the current thread and "
218061da546Spatrick "stack frame.",
219*f6aab3d8Srobert "disassemble [<cmd-options>]", eCommandRequiresTarget) {}
220061da546Spatrick
221061da546Spatrick CommandObjectDisassemble::~CommandObjectDisassemble() = default;
222061da546Spatrick
CheckRangeSize(const AddressRange & range,llvm::StringRef what)223dda28197Spatrick llvm::Error CommandObjectDisassemble::CheckRangeSize(const AddressRange &range,
224dda28197Spatrick llvm::StringRef what) {
225dda28197Spatrick if (m_options.num_instructions > 0 || m_options.force ||
226be691f3bSpatrick range.GetByteSize() < GetDebugger().GetStopDisassemblyMaxSize())
227dda28197Spatrick return llvm::Error::success();
228dda28197Spatrick StreamString msg;
229dda28197Spatrick msg << "Not disassembling " << what << " because it is very large ";
230dda28197Spatrick range.Dump(&msg, &GetSelectedTarget(), Address::DumpStyleLoadAddress,
231dda28197Spatrick Address::DumpStyleFileAddress);
232dda28197Spatrick msg << ". To disassemble specify an instruction count limit, start/stop "
233dda28197Spatrick "addresses or use the --force option.";
234dda28197Spatrick return llvm::createStringError(llvm::inconvertibleErrorCode(),
235dda28197Spatrick msg.GetString());
236dda28197Spatrick }
237dda28197Spatrick
238dda28197Spatrick llvm::Expected<std::vector<AddressRange>>
GetContainingAddressRanges()239dda28197Spatrick CommandObjectDisassemble::GetContainingAddressRanges() {
240dda28197Spatrick std::vector<AddressRange> ranges;
241dda28197Spatrick const auto &get_range = [&](Address addr) {
242dda28197Spatrick ModuleSP module_sp(addr.GetModule());
243dda28197Spatrick SymbolContext sc;
244dda28197Spatrick bool resolve_tail_call_address = true;
245dda28197Spatrick addr.GetModule()->ResolveSymbolContextForAddress(
246dda28197Spatrick addr, eSymbolContextEverything, sc, resolve_tail_call_address);
247dda28197Spatrick if (sc.function || sc.symbol) {
248dda28197Spatrick AddressRange range;
249dda28197Spatrick sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
250dda28197Spatrick false, range);
251dda28197Spatrick ranges.push_back(range);
252dda28197Spatrick }
253dda28197Spatrick };
254dda28197Spatrick
255dda28197Spatrick Target &target = GetSelectedTarget();
256dda28197Spatrick if (!target.GetSectionLoadList().IsEmpty()) {
257dda28197Spatrick Address symbol_containing_address;
258dda28197Spatrick if (target.GetSectionLoadList().ResolveLoadAddress(
259dda28197Spatrick m_options.symbol_containing_addr, symbol_containing_address)) {
260dda28197Spatrick get_range(symbol_containing_address);
261dda28197Spatrick }
262dda28197Spatrick } else {
263dda28197Spatrick for (lldb::ModuleSP module_sp : target.GetImages().Modules()) {
264dda28197Spatrick Address file_address;
265dda28197Spatrick if (module_sp->ResolveFileAddress(m_options.symbol_containing_addr,
266dda28197Spatrick file_address)) {
267dda28197Spatrick get_range(file_address);
268dda28197Spatrick }
269dda28197Spatrick }
270dda28197Spatrick }
271dda28197Spatrick
272dda28197Spatrick if (ranges.empty()) {
273dda28197Spatrick return llvm::createStringError(
274dda28197Spatrick llvm::inconvertibleErrorCode(),
275dda28197Spatrick "Could not find function bounds for address 0x%" PRIx64,
276dda28197Spatrick m_options.symbol_containing_addr);
277dda28197Spatrick }
278dda28197Spatrick
279dda28197Spatrick if (llvm::Error err = CheckRangeSize(ranges[0], "the function"))
280dda28197Spatrick return std::move(err);
281dda28197Spatrick return ranges;
282dda28197Spatrick }
283dda28197Spatrick
284dda28197Spatrick llvm::Expected<std::vector<AddressRange>>
GetCurrentFunctionRanges()285dda28197Spatrick CommandObjectDisassemble::GetCurrentFunctionRanges() {
286*f6aab3d8Srobert Process *process = m_exe_ctx.GetProcessPtr();
287dda28197Spatrick StackFrame *frame = m_exe_ctx.GetFramePtr();
288dda28197Spatrick if (!frame) {
289*f6aab3d8Srobert if (process) {
290*f6aab3d8Srobert return llvm::createStringError(
291*f6aab3d8Srobert llvm::inconvertibleErrorCode(),
292*f6aab3d8Srobert "Cannot disassemble around the current "
293*f6aab3d8Srobert "function without the process being stopped.\n");
294*f6aab3d8Srobert } else {
295dda28197Spatrick return llvm::createStringError(llvm::inconvertibleErrorCode(),
296dda28197Spatrick "Cannot disassemble around the current "
297*f6aab3d8Srobert "function without a selected frame: "
298*f6aab3d8Srobert "no currently running process.\n");
299*f6aab3d8Srobert }
300dda28197Spatrick }
301dda28197Spatrick SymbolContext sc(
302dda28197Spatrick frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
303dda28197Spatrick AddressRange range;
304dda28197Spatrick if (sc.function)
305dda28197Spatrick range = sc.function->GetAddressRange();
306dda28197Spatrick else if (sc.symbol && sc.symbol->ValueIsAddress()) {
307dda28197Spatrick range = {sc.symbol->GetAddress(), sc.symbol->GetByteSize()};
308dda28197Spatrick } else
309dda28197Spatrick range = {frame->GetFrameCodeAddress(), default_disasm_byte_size};
310dda28197Spatrick
311dda28197Spatrick if (llvm::Error err = CheckRangeSize(range, "the current function"))
312dda28197Spatrick return std::move(err);
313dda28197Spatrick return std::vector<AddressRange>{range};
314dda28197Spatrick }
315dda28197Spatrick
316dda28197Spatrick llvm::Expected<std::vector<AddressRange>>
GetCurrentLineRanges()317dda28197Spatrick CommandObjectDisassemble::GetCurrentLineRanges() {
318*f6aab3d8Srobert Process *process = m_exe_ctx.GetProcessPtr();
319dda28197Spatrick StackFrame *frame = m_exe_ctx.GetFramePtr();
320dda28197Spatrick if (!frame) {
321*f6aab3d8Srobert if (process) {
322*f6aab3d8Srobert return llvm::createStringError(
323*f6aab3d8Srobert llvm::inconvertibleErrorCode(),
324*f6aab3d8Srobert "Cannot disassemble around the current "
325*f6aab3d8Srobert "function without the process being stopped.\n");
326*f6aab3d8Srobert } else {
327dda28197Spatrick return llvm::createStringError(llvm::inconvertibleErrorCode(),
328dda28197Spatrick "Cannot disassemble around the current "
329*f6aab3d8Srobert "line without a selected frame: "
330*f6aab3d8Srobert "no currently running process.\n");
331*f6aab3d8Srobert }
332dda28197Spatrick }
333dda28197Spatrick
334dda28197Spatrick LineEntry pc_line_entry(
335dda28197Spatrick frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
336dda28197Spatrick if (pc_line_entry.IsValid())
337dda28197Spatrick return std::vector<AddressRange>{pc_line_entry.range};
338dda28197Spatrick
339dda28197Spatrick // No line entry, so just disassemble around the current pc
340dda28197Spatrick m_options.show_mixed = false;
341dda28197Spatrick return GetPCRanges();
342dda28197Spatrick }
343dda28197Spatrick
344dda28197Spatrick llvm::Expected<std::vector<AddressRange>>
GetNameRanges(CommandReturnObject & result)345dda28197Spatrick CommandObjectDisassemble::GetNameRanges(CommandReturnObject &result) {
346dda28197Spatrick ConstString name(m_options.func_name.c_str());
347*f6aab3d8Srobert
348*f6aab3d8Srobert ModuleFunctionSearchOptions function_options;
349*f6aab3d8Srobert function_options.include_symbols = true;
350*f6aab3d8Srobert function_options.include_inlines = true;
351dda28197Spatrick
352dda28197Spatrick // Find functions matching the given name.
353dda28197Spatrick SymbolContextList sc_list;
354*f6aab3d8Srobert GetSelectedTarget().GetImages().FindFunctions(name, eFunctionNameTypeAuto,
355*f6aab3d8Srobert function_options, sc_list);
356dda28197Spatrick
357dda28197Spatrick std::vector<AddressRange> ranges;
358dda28197Spatrick llvm::Error range_errs = llvm::Error::success();
359dda28197Spatrick AddressRange range;
360dda28197Spatrick const uint32_t scope =
361dda28197Spatrick eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
362dda28197Spatrick const bool use_inline_block_range = true;
363dda28197Spatrick for (SymbolContext sc : sc_list.SymbolContexts()) {
364dda28197Spatrick for (uint32_t range_idx = 0;
365dda28197Spatrick sc.GetAddressRange(scope, range_idx, use_inline_block_range, range);
366dda28197Spatrick ++range_idx) {
367dda28197Spatrick if (llvm::Error err = CheckRangeSize(range, "a range"))
368dda28197Spatrick range_errs = joinErrors(std::move(range_errs), std::move(err));
369dda28197Spatrick else
370dda28197Spatrick ranges.push_back(range);
371dda28197Spatrick }
372dda28197Spatrick }
373dda28197Spatrick if (ranges.empty()) {
374dda28197Spatrick if (range_errs)
375dda28197Spatrick return std::move(range_errs);
376dda28197Spatrick return llvm::createStringError(llvm::inconvertibleErrorCode(),
377dda28197Spatrick "Unable to find symbol with name '%s'.\n",
378dda28197Spatrick name.GetCString());
379dda28197Spatrick }
380dda28197Spatrick if (range_errs)
381dda28197Spatrick result.AppendWarning(toString(std::move(range_errs)));
382dda28197Spatrick return ranges;
383dda28197Spatrick }
384dda28197Spatrick
385dda28197Spatrick llvm::Expected<std::vector<AddressRange>>
GetPCRanges()386dda28197Spatrick CommandObjectDisassemble::GetPCRanges() {
387*f6aab3d8Srobert Process *process = m_exe_ctx.GetProcessPtr();
388dda28197Spatrick StackFrame *frame = m_exe_ctx.GetFramePtr();
389dda28197Spatrick if (!frame) {
390*f6aab3d8Srobert if (process) {
391*f6aab3d8Srobert return llvm::createStringError(
392*f6aab3d8Srobert llvm::inconvertibleErrorCode(),
393*f6aab3d8Srobert "Cannot disassemble around the current "
394*f6aab3d8Srobert "function without the process being stopped.\n");
395*f6aab3d8Srobert } else {
396dda28197Spatrick return llvm::createStringError(llvm::inconvertibleErrorCode(),
397dda28197Spatrick "Cannot disassemble around the current "
398*f6aab3d8Srobert "PC without a selected frame: "
399*f6aab3d8Srobert "no currently running process.\n");
400*f6aab3d8Srobert }
401dda28197Spatrick }
402dda28197Spatrick
403dda28197Spatrick if (m_options.num_instructions == 0) {
404dda28197Spatrick // Disassembling at the PC always disassembles some number of
405dda28197Spatrick // instructions (not the whole function).
406dda28197Spatrick m_options.num_instructions = default_disasm_num_ins;
407dda28197Spatrick }
408dda28197Spatrick return std::vector<AddressRange>{{frame->GetFrameCodeAddress(), 0}};
409dda28197Spatrick }
410dda28197Spatrick
411dda28197Spatrick llvm::Expected<std::vector<AddressRange>>
GetStartEndAddressRanges()412dda28197Spatrick CommandObjectDisassemble::GetStartEndAddressRanges() {
413dda28197Spatrick addr_t size = 0;
414dda28197Spatrick if (m_options.end_addr != LLDB_INVALID_ADDRESS) {
415dda28197Spatrick if (m_options.end_addr <= m_options.start_addr) {
416dda28197Spatrick return llvm::createStringError(llvm::inconvertibleErrorCode(),
417dda28197Spatrick "End address before start address.");
418dda28197Spatrick }
419dda28197Spatrick size = m_options.end_addr - m_options.start_addr;
420dda28197Spatrick }
421dda28197Spatrick return std::vector<AddressRange>{{Address(m_options.start_addr), size}};
422dda28197Spatrick }
423dda28197Spatrick
424dda28197Spatrick llvm::Expected<std::vector<AddressRange>>
GetRangesForSelectedMode(CommandReturnObject & result)425dda28197Spatrick CommandObjectDisassemble::GetRangesForSelectedMode(
426dda28197Spatrick CommandReturnObject &result) {
427dda28197Spatrick if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
428dda28197Spatrick return CommandObjectDisassemble::GetContainingAddressRanges();
429dda28197Spatrick if (m_options.current_function)
430dda28197Spatrick return CommandObjectDisassemble::GetCurrentFunctionRanges();
431dda28197Spatrick if (m_options.frame_line)
432dda28197Spatrick return CommandObjectDisassemble::GetCurrentLineRanges();
433dda28197Spatrick if (!m_options.func_name.empty())
434dda28197Spatrick return CommandObjectDisassemble::GetNameRanges(result);
435dda28197Spatrick if (m_options.start_addr != LLDB_INVALID_ADDRESS)
436dda28197Spatrick return CommandObjectDisassemble::GetStartEndAddressRanges();
437dda28197Spatrick return CommandObjectDisassemble::GetPCRanges();
438dda28197Spatrick }
439dda28197Spatrick
DoExecute(Args & command,CommandReturnObject & result)440061da546Spatrick bool CommandObjectDisassemble::DoExecute(Args &command,
441061da546Spatrick CommandReturnObject &result) {
442061da546Spatrick Target *target = &GetSelectedTarget();
443061da546Spatrick
444061da546Spatrick if (!m_options.arch.IsValid())
445061da546Spatrick m_options.arch = target->GetArchitecture();
446061da546Spatrick
447061da546Spatrick if (!m_options.arch.IsValid()) {
448061da546Spatrick result.AppendError(
449061da546Spatrick "use the --arch option or set the target architecture to disassemble");
450061da546Spatrick return false;
451061da546Spatrick }
452061da546Spatrick
453061da546Spatrick const char *plugin_name = m_options.GetPluginName();
454061da546Spatrick const char *flavor_string = m_options.GetFlavorString();
455061da546Spatrick
456061da546Spatrick DisassemblerSP disassembler =
457061da546Spatrick Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
458061da546Spatrick
459061da546Spatrick if (!disassembler) {
460061da546Spatrick if (plugin_name) {
461061da546Spatrick result.AppendErrorWithFormat(
462061da546Spatrick "Unable to find Disassembler plug-in named '%s' that supports the "
463061da546Spatrick "'%s' architecture.\n",
464061da546Spatrick plugin_name, m_options.arch.GetArchitectureName());
465061da546Spatrick } else
466061da546Spatrick result.AppendErrorWithFormat(
467061da546Spatrick "Unable to find Disassembler plug-in for the '%s' architecture.\n",
468061da546Spatrick m_options.arch.GetArchitectureName());
469061da546Spatrick return false;
470061da546Spatrick } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec(
471061da546Spatrick m_options.arch, flavor_string))
472061da546Spatrick result.AppendWarningWithFormat(
473061da546Spatrick "invalid disassembler flavor \"%s\", using default.\n", flavor_string);
474061da546Spatrick
475061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
476061da546Spatrick
477061da546Spatrick if (!command.empty()) {
478061da546Spatrick result.AppendErrorWithFormat(
479061da546Spatrick "\"disassemble\" arguments are specified as options.\n");
480061da546Spatrick const int terminal_width =
481061da546Spatrick GetCommandInterpreter().GetDebugger().GetTerminalWidth();
482*f6aab3d8Srobert GetOptions()->GenerateOptionUsage(result.GetErrorStream(), *this,
483061da546Spatrick terminal_width);
484061da546Spatrick return false;
485061da546Spatrick }
486061da546Spatrick
487061da546Spatrick if (m_options.show_mixed && m_options.num_lines_context == 0)
488061da546Spatrick m_options.num_lines_context = 2;
489061da546Spatrick
490061da546Spatrick // Always show the PC in the disassembly
491061da546Spatrick uint32_t options = Disassembler::eOptionMarkPCAddress;
492061da546Spatrick
493061da546Spatrick // Mark the source line for the current PC only if we are doing mixed source
494061da546Spatrick // and assembly
495061da546Spatrick if (m_options.show_mixed)
496061da546Spatrick options |= Disassembler::eOptionMarkPCSourceLine;
497061da546Spatrick
498061da546Spatrick if (m_options.show_bytes)
499061da546Spatrick options |= Disassembler::eOptionShowBytes;
500061da546Spatrick
501*f6aab3d8Srobert if (m_options.show_control_flow_kind)
502*f6aab3d8Srobert options |= Disassembler::eOptionShowControlFlowKind;
503*f6aab3d8Srobert
504061da546Spatrick if (m_options.raw)
505061da546Spatrick options |= Disassembler::eOptionRawOuput;
506061da546Spatrick
507dda28197Spatrick llvm::Expected<std::vector<AddressRange>> ranges =
508dda28197Spatrick GetRangesForSelectedMode(result);
509dda28197Spatrick if (!ranges) {
510dda28197Spatrick result.AppendError(toString(ranges.takeError()));
511dda28197Spatrick return result.Succeeded();
512061da546Spatrick }
513061da546Spatrick
514dda28197Spatrick bool print_sc_header = ranges->size() > 1;
515dda28197Spatrick for (AddressRange cur_range : *ranges) {
516dda28197Spatrick Disassembler::Limit limit;
517061da546Spatrick if (m_options.num_instructions == 0) {
518dda28197Spatrick limit = {Disassembler::Limit::Bytes, cur_range.GetByteSize()};
519dda28197Spatrick if (limit.value == 0)
520dda28197Spatrick limit.value = default_disasm_byte_size;
521061da546Spatrick } else {
522dda28197Spatrick limit = {Disassembler::Limit::Instructions, m_options.num_instructions};
523061da546Spatrick }
524061da546Spatrick if (Disassembler::Disassemble(
525061da546Spatrick GetDebugger(), m_options.arch, plugin_name, flavor_string,
526dda28197Spatrick m_exe_ctx, cur_range.GetBaseAddress(), limit, m_options.show_mixed,
527061da546Spatrick m_options.show_mixed ? m_options.num_lines_context : 0, options,
528061da546Spatrick result.GetOutputStream())) {
529061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
530061da546Spatrick } else {
531dda28197Spatrick if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS) {
532061da546Spatrick result.AppendErrorWithFormat(
533dda28197Spatrick "Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n",
534061da546Spatrick m_options.symbol_containing_addr);
535061da546Spatrick } else {
536061da546Spatrick result.AppendErrorWithFormat(
537061da546Spatrick "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
538061da546Spatrick cur_range.GetBaseAddress().GetLoadAddress(target));
539dda28197Spatrick }
540061da546Spatrick }
541061da546Spatrick if (print_sc_header)
542dda28197Spatrick result.GetOutputStream() << "\n";
543061da546Spatrick }
544061da546Spatrick
545061da546Spatrick return result.Succeeded();
546061da546Spatrick }
547