xref: /src/contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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