1ac7ddfbfSEd Maste //===-- CommandObjectDisassemble.cpp ----------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste //                     The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste 
104bb0738eSEd Maste #include "CommandObjectDisassemble.h"
11ac7ddfbfSEd Maste #include "lldb/Core/AddressRange.h"
12ac7ddfbfSEd Maste #include "lldb/Core/Disassembler.h"
13ac7ddfbfSEd Maste #include "lldb/Core/Module.h"
14ac7ddfbfSEd Maste #include "lldb/Core/SourceManager.h"
15f678e45dSDimitry Andric #include "lldb/Host/OptionParser.h"
16ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandCompletions.h"
17ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
18ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
194ba319b5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
20ac7ddfbfSEd Maste #include "lldb/Interpreter/Options.h"
21ac7ddfbfSEd Maste #include "lldb/Symbol/Function.h"
22ac7ddfbfSEd Maste #include "lldb/Symbol/Symbol.h"
23ac7ddfbfSEd Maste #include "lldb/Target/Process.h"
2412b93ac6SEd Maste #include "lldb/Target/SectionLoadList.h"
25ac7ddfbfSEd Maste #include "lldb/Target/StackFrame.h"
26ac7ddfbfSEd Maste #include "lldb/Target/Target.h"
27ac7ddfbfSEd Maste 
28ac7ddfbfSEd Maste #define DEFAULT_DISASM_BYTE_SIZE 32
29ac7ddfbfSEd Maste #define DEFAULT_DISASM_NUM_INS 4
30ac7ddfbfSEd Maste 
31ac7ddfbfSEd Maste using namespace lldb;
32ac7ddfbfSEd Maste using namespace lldb_private;
33ac7ddfbfSEd Maste 
34*b5893f02SDimitry Andric static constexpr OptionDefinition g_disassemble_options[] = {
35435933ddSDimitry Andric     // clang-format off
36*b5893f02SDimitry Andric   { LLDB_OPT_SET_ALL, false, "bytes",         'b', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Show opcode bytes when disassembling." },
37*b5893f02SDimitry Andric   { LLDB_OPT_SET_ALL, false, "context",       'C', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeNumLines,            "Number of context lines of source to show." },
38*b5893f02SDimitry Andric   { LLDB_OPT_SET_ALL, false, "mixed",         'm', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Enable mixed source and assembly display." },
39*b5893f02SDimitry Andric   { LLDB_OPT_SET_ALL, false, "raw",           'r', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Print raw disassembly with no symbol information." },
40*b5893f02SDimitry Andric   { LLDB_OPT_SET_ALL, false, "plugin",        'P', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypePlugin,              "Name of the disassembler plugin you want to use." },
41*b5893f02SDimitry Andric   { LLDB_OPT_SET_ALL, false, "flavor",        'F', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeDisassemblyFlavor,   "Name of the disassembly flavor you want to use.  "
42435933ddSDimitry Andric   "Currently the only valid options are default, and for Intel "
43435933ddSDimitry Andric   "architectures, att and intel." },
44*b5893f02SDimitry Andric   { LLDB_OPT_SET_ALL, false, "arch",          'A', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeArchitecture,        "Specify the architecture to use from cross disassembly." },
45435933ddSDimitry Andric   { LLDB_OPT_SET_1 |
46*b5893f02SDimitry Andric   LLDB_OPT_SET_2,   true,  "start-address", 's', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeAddressOrExpression, "Address at which to start disassembling." },
47*b5893f02SDimitry Andric   { LLDB_OPT_SET_1,   false, "end-address",   'e', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeAddressOrExpression, "Address at which to end disassembling." },
48435933ddSDimitry Andric   { LLDB_OPT_SET_2 |
49435933ddSDimitry Andric   LLDB_OPT_SET_3 |
50435933ddSDimitry Andric   LLDB_OPT_SET_4 |
51*b5893f02SDimitry Andric   LLDB_OPT_SET_5,   false, "count",         'c', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeNumLines,            "Number of instructions to display." },
52*b5893f02SDimitry Andric   { LLDB_OPT_SET_3,   false, "name",          'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,        "Disassemble entire contents of the given function name." },
53*b5893f02SDimitry Andric   { LLDB_OPT_SET_4,   false, "frame",         'f', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Disassemble from the start of the current frame's function." },
54*b5893f02SDimitry Andric   { LLDB_OPT_SET_5,   false, "pc",            'p', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Disassemble around the current pc." },
55*b5893f02SDimitry Andric   { LLDB_OPT_SET_6,   false, "line",          'l', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,                "Disassemble the current frame's current source line instructions if there is debug line "
56435933ddSDimitry Andric   "table information, else disassemble around the pc." },
57*b5893f02SDimitry Andric   { LLDB_OPT_SET_7,   false, "address",       'a', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypeAddressOrExpression, "Disassemble function containing this address." },
58435933ddSDimitry Andric     // clang-format on
59435933ddSDimitry Andric };
60435933ddSDimitry Andric 
CommandOptions()61435933ddSDimitry Andric CommandObjectDisassemble::CommandOptions::CommandOptions()
62435933ddSDimitry Andric     : Options(), num_lines_context(0), num_instructions(0), func_name(),
63435933ddSDimitry Andric       current_function(false), start_addr(), end_addr(), at_pc(false),
64435933ddSDimitry Andric       frame_line(false), plugin_name(), flavor_string(), arch(),
65435933ddSDimitry Andric       some_location_specified(false), symbol_containing_addr() {
66435933ddSDimitry Andric   OptionParsingStarting(nullptr);
67ac7ddfbfSEd Maste }
68ac7ddfbfSEd Maste 
694bb0738eSEd Maste CommandObjectDisassemble::CommandOptions::~CommandOptions() = default;
70ac7ddfbfSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)715517e702SDimitry Andric Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
72435933ddSDimitry Andric     uint32_t option_idx, llvm::StringRef option_arg,
73435933ddSDimitry Andric     ExecutionContext *execution_context) {
745517e702SDimitry Andric   Status error;
75ac7ddfbfSEd Maste 
76ac7ddfbfSEd Maste   const int short_option = m_getopt_table[option_idx].val;
77ac7ddfbfSEd Maste 
78435933ddSDimitry Andric   switch (short_option) {
79ac7ddfbfSEd Maste   case 'm':
80ac7ddfbfSEd Maste     show_mixed = true;
81ac7ddfbfSEd Maste     break;
82ac7ddfbfSEd Maste 
83ac7ddfbfSEd Maste   case 'C':
84435933ddSDimitry Andric     if (option_arg.getAsInteger(0, num_lines_context))
85435933ddSDimitry Andric       error.SetErrorStringWithFormat("invalid num context lines string: \"%s\"",
86435933ddSDimitry Andric                                      option_arg.str().c_str());
87ac7ddfbfSEd Maste     break;
88ac7ddfbfSEd Maste 
89ac7ddfbfSEd Maste   case 'c':
90435933ddSDimitry Andric     if (option_arg.getAsInteger(0, num_instructions))
91435933ddSDimitry Andric       error.SetErrorStringWithFormat(
92435933ddSDimitry Andric           "invalid num of instructions string: \"%s\"",
93435933ddSDimitry Andric           option_arg.str().c_str());
94ac7ddfbfSEd Maste     break;
95ac7ddfbfSEd Maste 
96ac7ddfbfSEd Maste   case 'b':
97ac7ddfbfSEd Maste     show_bytes = true;
98ac7ddfbfSEd Maste     break;
99ac7ddfbfSEd Maste 
100435933ddSDimitry Andric   case 's': {
1014ba319b5SDimitry Andric     start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
102435933ddSDimitry Andric                                             LLDB_INVALID_ADDRESS, &error);
103ac7ddfbfSEd Maste     if (start_addr != LLDB_INVALID_ADDRESS)
104ac7ddfbfSEd Maste       some_location_specified = true;
105435933ddSDimitry Andric   } break;
106435933ddSDimitry Andric   case 'e': {
1074ba319b5SDimitry Andric     end_addr = OptionArgParser::ToAddress(execution_context, option_arg,
108435933ddSDimitry Andric                                           LLDB_INVALID_ADDRESS, &error);
109ac7ddfbfSEd Maste     if (end_addr != LLDB_INVALID_ADDRESS)
110ac7ddfbfSEd Maste       some_location_specified = true;
111435933ddSDimitry Andric   } break;
1124bb0738eSEd Maste 
113ac7ddfbfSEd Maste   case 'n':
114ac7ddfbfSEd Maste     func_name.assign(option_arg);
115ac7ddfbfSEd Maste     some_location_specified = true;
116ac7ddfbfSEd Maste     break;
117ac7ddfbfSEd Maste 
118ac7ddfbfSEd Maste   case 'p':
119ac7ddfbfSEd Maste     at_pc = true;
120ac7ddfbfSEd Maste     some_location_specified = true;
121ac7ddfbfSEd Maste     break;
122ac7ddfbfSEd Maste 
123ac7ddfbfSEd Maste   case 'l':
124ac7ddfbfSEd Maste     frame_line = true;
1254ba319b5SDimitry Andric     // Disassemble the current source line kind of implies showing mixed source
1264ba319b5SDimitry Andric     // code context.
127ac7ddfbfSEd Maste     show_mixed = true;
128ac7ddfbfSEd Maste     some_location_specified = true;
129ac7ddfbfSEd Maste     break;
130ac7ddfbfSEd Maste 
131ac7ddfbfSEd Maste   case 'P':
132ac7ddfbfSEd Maste     plugin_name.assign(option_arg);
133ac7ddfbfSEd Maste     break;
134ac7ddfbfSEd Maste 
135435933ddSDimitry Andric   case 'F': {
136435933ddSDimitry Andric     TargetSP target_sp =
137435933ddSDimitry Andric         execution_context ? execution_context->GetTargetSP() : TargetSP();
138435933ddSDimitry Andric     if (target_sp && (target_sp->GetArchitecture().GetTriple().getArch() ==
139435933ddSDimitry Andric                           llvm::Triple::x86 ||
140435933ddSDimitry Andric                       target_sp->GetArchitecture().GetTriple().getArch() ==
141435933ddSDimitry Andric                           llvm::Triple::x86_64)) {
142ac7ddfbfSEd Maste       flavor_string.assign(option_arg);
143435933ddSDimitry Andric     } else
144435933ddSDimitry Andric       error.SetErrorStringWithFormat("Disassembler flavors are currently only "
145435933ddSDimitry Andric                                      "supported for x86 and x86_64 targets.");
146ac7ddfbfSEd Maste     break;
147ac7ddfbfSEd Maste   }
1484bb0738eSEd Maste 
149ac7ddfbfSEd Maste   case 'r':
150ac7ddfbfSEd Maste     raw = true;
151ac7ddfbfSEd Maste     break;
152ac7ddfbfSEd Maste 
153ac7ddfbfSEd Maste   case 'f':
154ac7ddfbfSEd Maste     current_function = true;
155ac7ddfbfSEd Maste     some_location_specified = true;
156ac7ddfbfSEd Maste     break;
157ac7ddfbfSEd Maste 
158ac7ddfbfSEd Maste   case 'A':
159435933ddSDimitry Andric     if (execution_context) {
1604ba319b5SDimitry Andric       const auto &target_sp = execution_context->GetTargetSP();
1614ba319b5SDimitry Andric       auto platform_ptr = target_sp ? target_sp->GetPlatform().get() : nullptr;
1624ba319b5SDimitry Andric       arch = Platform::GetAugmentedArchSpec(platform_ptr, option_arg);
163435933ddSDimitry Andric     }
164ac7ddfbfSEd Maste     break;
165ac7ddfbfSEd Maste 
166435933ddSDimitry Andric   case 'a': {
1674ba319b5SDimitry Andric     symbol_containing_addr = OptionArgParser::ToAddress(
168435933ddSDimitry Andric         execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
169435933ddSDimitry Andric     if (symbol_containing_addr != LLDB_INVALID_ADDRESS) {
170ac7ddfbfSEd Maste       some_location_specified = true;
171ac7ddfbfSEd Maste     }
172435933ddSDimitry Andric   } break;
173ac7ddfbfSEd Maste 
174ac7ddfbfSEd Maste   default:
175435933ddSDimitry Andric     error.SetErrorStringWithFormat("unrecognized short option '%c'",
176435933ddSDimitry Andric                                    short_option);
177ac7ddfbfSEd Maste     break;
178ac7ddfbfSEd Maste   }
179ac7ddfbfSEd Maste 
180ac7ddfbfSEd Maste   return error;
181ac7ddfbfSEd Maste }
182ac7ddfbfSEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)183435933ddSDimitry Andric void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
184435933ddSDimitry Andric     ExecutionContext *execution_context) {
185ac7ddfbfSEd Maste   show_mixed = false;
186ac7ddfbfSEd Maste   show_bytes = false;
187ac7ddfbfSEd Maste   num_lines_context = 0;
188ac7ddfbfSEd Maste   num_instructions = 0;
189ac7ddfbfSEd Maste   func_name.clear();
190ac7ddfbfSEd Maste   current_function = false;
191ac7ddfbfSEd Maste   at_pc = false;
192ac7ddfbfSEd Maste   frame_line = false;
193ac7ddfbfSEd Maste   start_addr = LLDB_INVALID_ADDRESS;
194ac7ddfbfSEd Maste   end_addr = LLDB_INVALID_ADDRESS;
195ac7ddfbfSEd Maste   symbol_containing_addr = LLDB_INVALID_ADDRESS;
196ac7ddfbfSEd Maste   raw = false;
197ac7ddfbfSEd Maste   plugin_name.clear();
198ac7ddfbfSEd Maste 
199435933ddSDimitry Andric   Target *target =
200435933ddSDimitry Andric       execution_context ? execution_context->GetTargetPtr() : nullptr;
201ac7ddfbfSEd Maste 
202435933ddSDimitry Andric   // This is a hack till we get the ability to specify features based on
2034ba319b5SDimitry Andric   // architecture.  For now GetDisassemblyFlavor is really only valid for x86
2044ba319b5SDimitry Andric   // (and for the llvm assembler plugin, but I'm papering over that since that
2054ba319b5SDimitry Andric   // is the only disassembler plugin we have...
206435933ddSDimitry Andric   if (target) {
207435933ddSDimitry Andric     if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86 ||
208435933ddSDimitry Andric         target->GetArchitecture().GetTriple().getArch() ==
209435933ddSDimitry Andric             llvm::Triple::x86_64) {
210ac7ddfbfSEd Maste       flavor_string.assign(target->GetDisassemblyFlavor());
211435933ddSDimitry Andric     } else
212ac7ddfbfSEd Maste       flavor_string.assign("default");
213ac7ddfbfSEd Maste 
214435933ddSDimitry Andric   } else
215ac7ddfbfSEd Maste     flavor_string.assign("default");
216ac7ddfbfSEd Maste 
217ac7ddfbfSEd Maste   arch.Clear();
218ac7ddfbfSEd Maste   some_location_specified = false;
219ac7ddfbfSEd Maste }
220ac7ddfbfSEd Maste 
OptionParsingFinished(ExecutionContext * execution_context)2215517e702SDimitry Andric Status CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
222435933ddSDimitry Andric     ExecutionContext *execution_context) {
223ac7ddfbfSEd Maste   if (!some_location_specified)
224ac7ddfbfSEd Maste     current_function = true;
2255517e702SDimitry Andric   return Status();
226ac7ddfbfSEd Maste }
227ac7ddfbfSEd Maste 
228435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition>
GetDefinitions()229435933ddSDimitry Andric CommandObjectDisassemble::CommandOptions::GetDefinitions() {
230435933ddSDimitry Andric   return llvm::makeArrayRef(g_disassemble_options);
231ac7ddfbfSEd Maste }
232ac7ddfbfSEd Maste 
233ac7ddfbfSEd Maste //-------------------------------------------------------------------------
234ac7ddfbfSEd Maste // CommandObjectDisassemble
235ac7ddfbfSEd Maste //-------------------------------------------------------------------------
236ac7ddfbfSEd Maste 
CommandObjectDisassemble(CommandInterpreter & interpreter)237435933ddSDimitry Andric CommandObjectDisassemble::CommandObjectDisassemble(
238435933ddSDimitry Andric     CommandInterpreter &interpreter)
239435933ddSDimitry Andric     : CommandObjectParsed(
240435933ddSDimitry Andric           interpreter, "disassemble",
241435933ddSDimitry Andric           "Disassemble specified instructions in the current target.  "
2424bb0738eSEd Maste           "Defaults to the current function for the current thread and "
2434bb0738eSEd Maste           "stack frame.",
244ac7ddfbfSEd Maste           "disassemble [<cmd-options>]"),
245435933ddSDimitry Andric       m_options() {}
246ac7ddfbfSEd Maste 
2474bb0738eSEd Maste CommandObjectDisassemble::~CommandObjectDisassemble() = default;
248ac7ddfbfSEd Maste 
DoExecute(Args & command,CommandReturnObject & result)249435933ddSDimitry Andric bool CommandObjectDisassemble::DoExecute(Args &command,
250435933ddSDimitry Andric                                          CommandReturnObject &result) {
251ac7ddfbfSEd Maste   Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
252435933ddSDimitry Andric   if (target == nullptr) {
253435933ddSDimitry Andric     result.AppendError("invalid target, create a debug target using the "
254435933ddSDimitry Andric                        "'target create' command");
255ac7ddfbfSEd Maste     result.SetStatus(eReturnStatusFailed);
256ac7ddfbfSEd Maste     return false;
257ac7ddfbfSEd Maste   }
258ac7ddfbfSEd Maste   if (!m_options.arch.IsValid())
259ac7ddfbfSEd Maste     m_options.arch = target->GetArchitecture();
260ac7ddfbfSEd Maste 
261435933ddSDimitry Andric   if (!m_options.arch.IsValid()) {
262435933ddSDimitry Andric     result.AppendError(
263435933ddSDimitry Andric         "use the --arch option or set the target architecture to disassemble");
264ac7ddfbfSEd Maste     result.SetStatus(eReturnStatusFailed);
265ac7ddfbfSEd Maste     return false;
266ac7ddfbfSEd Maste   }
267ac7ddfbfSEd Maste 
268ac7ddfbfSEd Maste   const char *plugin_name = m_options.GetPluginName();
269ac7ddfbfSEd Maste   const char *flavor_string = m_options.GetFlavorString();
270ac7ddfbfSEd Maste 
271435933ddSDimitry Andric   DisassemblerSP disassembler =
272435933ddSDimitry Andric       Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
273ac7ddfbfSEd Maste 
274435933ddSDimitry Andric   if (!disassembler) {
275435933ddSDimitry Andric     if (plugin_name) {
276435933ddSDimitry Andric       result.AppendErrorWithFormat(
277435933ddSDimitry Andric           "Unable to find Disassembler plug-in named '%s' that supports the "
278435933ddSDimitry Andric           "'%s' architecture.\n",
279435933ddSDimitry Andric           plugin_name, m_options.arch.GetArchitectureName());
280435933ddSDimitry Andric     } else
281435933ddSDimitry Andric       result.AppendErrorWithFormat(
282435933ddSDimitry Andric           "Unable to find Disassembler plug-in for the '%s' architecture.\n",
283ac7ddfbfSEd Maste           m_options.arch.GetArchitectureName());
284ac7ddfbfSEd Maste     result.SetStatus(eReturnStatusFailed);
285ac7ddfbfSEd Maste     return false;
286435933ddSDimitry Andric   } else if (flavor_string != nullptr &&
287435933ddSDimitry Andric              !disassembler->FlavorValidForArchSpec(m_options.arch,
288435933ddSDimitry Andric                                                    flavor_string))
289435933ddSDimitry Andric     result.AppendWarningWithFormat(
290435933ddSDimitry Andric         "invalid disassembler flavor \"%s\", using default.\n", flavor_string);
291ac7ddfbfSEd Maste 
292ac7ddfbfSEd Maste   result.SetStatus(eReturnStatusSuccessFinishResult);
293ac7ddfbfSEd Maste 
294435933ddSDimitry Andric   if (!command.empty()) {
295435933ddSDimitry Andric     result.AppendErrorWithFormat(
296435933ddSDimitry Andric         "\"disassemble\" arguments are specified as options.\n");
297435933ddSDimitry Andric     const int terminal_width =
298435933ddSDimitry Andric         GetCommandInterpreter().GetDebugger().GetTerminalWidth();
299435933ddSDimitry Andric     GetOptions()->GenerateOptionUsage(result.GetErrorStream(), this,
300435933ddSDimitry Andric                                       terminal_width);
301ac7ddfbfSEd Maste     result.SetStatus(eReturnStatusFailed);
302ac7ddfbfSEd Maste     return false;
303ac7ddfbfSEd Maste   }
304ac7ddfbfSEd Maste 
305ac7ddfbfSEd Maste   if (m_options.show_mixed && m_options.num_lines_context == 0)
306435933ddSDimitry Andric     m_options.num_lines_context = 2;
307ac7ddfbfSEd Maste 
308ac7ddfbfSEd Maste   // Always show the PC in the disassembly
309ac7ddfbfSEd Maste   uint32_t options = Disassembler::eOptionMarkPCAddress;
310ac7ddfbfSEd Maste 
311435933ddSDimitry Andric   // Mark the source line for the current PC only if we are doing mixed source
312435933ddSDimitry Andric   // and assembly
313ac7ddfbfSEd Maste   if (m_options.show_mixed)
314ac7ddfbfSEd Maste     options |= Disassembler::eOptionMarkPCSourceLine;
315ac7ddfbfSEd Maste 
316ac7ddfbfSEd Maste   if (m_options.show_bytes)
317ac7ddfbfSEd Maste     options |= Disassembler::eOptionShowBytes;
318ac7ddfbfSEd Maste 
319ac7ddfbfSEd Maste   if (m_options.raw)
320ac7ddfbfSEd Maste     options |= Disassembler::eOptionRawOuput;
321ac7ddfbfSEd Maste 
322435933ddSDimitry Andric   if (!m_options.func_name.empty()) {
323ac7ddfbfSEd Maste     ConstString name(m_options.func_name.c_str());
324ac7ddfbfSEd Maste 
325435933ddSDimitry Andric     if (Disassembler::Disassemble(
326435933ddSDimitry Andric             m_interpreter.GetDebugger(), m_options.arch, plugin_name,
327435933ddSDimitry Andric             flavor_string, m_exe_ctx, name,
3284bb0738eSEd Maste             nullptr, // Module *
329435933ddSDimitry Andric             m_options.num_instructions, m_options.show_mixed,
330435933ddSDimitry Andric             m_options.show_mixed ? m_options.num_lines_context : 0, options,
331435933ddSDimitry Andric             result.GetOutputStream())) {
332ac7ddfbfSEd Maste       result.SetStatus(eReturnStatusSuccessFinishResult);
333435933ddSDimitry Andric     } else {
334435933ddSDimitry Andric       result.AppendErrorWithFormat("Unable to find symbol with name '%s'.\n",
335435933ddSDimitry Andric                                    name.GetCString());
336ac7ddfbfSEd Maste       result.SetStatus(eReturnStatusFailed);
337ac7ddfbfSEd Maste     }
338435933ddSDimitry Andric   } else {
3390127ef0fSEd Maste     std::vector<AddressRange> ranges;
340ac7ddfbfSEd Maste     AddressRange range;
341ac7ddfbfSEd Maste     StackFrame *frame = m_exe_ctx.GetFramePtr();
342435933ddSDimitry Andric     if (m_options.frame_line) {
343435933ddSDimitry Andric       if (frame == nullptr) {
344435933ddSDimitry Andric         result.AppendError("Cannot disassemble around the current line without "
345435933ddSDimitry Andric                            "a selected frame.\n");
346ac7ddfbfSEd Maste         result.SetStatus(eReturnStatusFailed);
347ac7ddfbfSEd Maste         return false;
348ac7ddfbfSEd Maste       }
349435933ddSDimitry Andric       LineEntry pc_line_entry(
350435933ddSDimitry Andric           frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
351435933ddSDimitry Andric       if (pc_line_entry.IsValid()) {
352ac7ddfbfSEd Maste         range = pc_line_entry.range;
353435933ddSDimitry Andric       } else {
354435933ddSDimitry Andric         m_options.at_pc =
355435933ddSDimitry Andric             true; // No line entry, so just disassemble around the current pc
356ac7ddfbfSEd Maste         m_options.show_mixed = false;
357ac7ddfbfSEd Maste       }
358435933ddSDimitry Andric     } else if (m_options.current_function) {
359435933ddSDimitry Andric       if (frame == nullptr) {
360435933ddSDimitry Andric         result.AppendError("Cannot disassemble around the current function "
361435933ddSDimitry Andric                            "without a selected frame.\n");
362ac7ddfbfSEd Maste         result.SetStatus(eReturnStatusFailed);
363ac7ddfbfSEd Maste         return false;
364ac7ddfbfSEd Maste       }
365ac7ddfbfSEd Maste       Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
366435933ddSDimitry Andric       if (symbol) {
367ac7ddfbfSEd Maste         range.GetBaseAddress() = symbol->GetAddress();
368ac7ddfbfSEd Maste         range.SetByteSize(symbol->GetByteSize());
369ac7ddfbfSEd Maste       }
370ac7ddfbfSEd Maste     }
371ac7ddfbfSEd Maste 
3724ba319b5SDimitry Andric     // Did the "m_options.frame_line" find a valid range already? If so skip
3734ba319b5SDimitry Andric     // the rest...
374435933ddSDimitry Andric     if (range.GetByteSize() == 0) {
375435933ddSDimitry Andric       if (m_options.at_pc) {
376435933ddSDimitry Andric         if (frame == nullptr) {
377435933ddSDimitry Andric           result.AppendError("Cannot disassemble around the current PC without "
378435933ddSDimitry Andric                              "a selected frame.\n");
379ac7ddfbfSEd Maste           result.SetStatus(eReturnStatusFailed);
380ac7ddfbfSEd Maste           return false;
381ac7ddfbfSEd Maste         }
382ac7ddfbfSEd Maste         range.GetBaseAddress() = frame->GetFrameCodeAddress();
383435933ddSDimitry Andric         if (m_options.num_instructions == 0) {
384435933ddSDimitry Andric           // Disassembling at the PC always disassembles some number of
385435933ddSDimitry Andric           // instructions (not the whole function).
386ac7ddfbfSEd Maste           m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
387ac7ddfbfSEd Maste         }
3880127ef0fSEd Maste         ranges.push_back(range);
389435933ddSDimitry Andric       } else {
390ac7ddfbfSEd Maste         range.GetBaseAddress().SetOffset(m_options.start_addr);
391435933ddSDimitry Andric         if (range.GetBaseAddress().IsValid()) {
392435933ddSDimitry Andric           if (m_options.end_addr != LLDB_INVALID_ADDRESS) {
393435933ddSDimitry Andric             if (m_options.end_addr <= m_options.start_addr) {
394435933ddSDimitry Andric               result.AppendErrorWithFormat(
395435933ddSDimitry Andric                   "End address before start address.\n");
396ac7ddfbfSEd Maste               result.SetStatus(eReturnStatusFailed);
397ac7ddfbfSEd Maste               return false;
398ac7ddfbfSEd Maste             }
399ac7ddfbfSEd Maste             range.SetByteSize(m_options.end_addr - m_options.start_addr);
400ac7ddfbfSEd Maste           }
4010127ef0fSEd Maste           ranges.push_back(range);
402435933ddSDimitry Andric         } else {
403435933ddSDimitry Andric           if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS &&
404435933ddSDimitry Andric               target) {
405435933ddSDimitry Andric             if (!target->GetSectionLoadList().IsEmpty()) {
406ac7ddfbfSEd Maste               bool failed = false;
407ac7ddfbfSEd Maste               Address symbol_containing_address;
408435933ddSDimitry Andric               if (target->GetSectionLoadList().ResolveLoadAddress(
409435933ddSDimitry Andric                       m_options.symbol_containing_addr,
410435933ddSDimitry Andric                       symbol_containing_address)) {
411ac7ddfbfSEd Maste                 ModuleSP module_sp(symbol_containing_address.GetModule());
412ac7ddfbfSEd Maste                 SymbolContext sc;
413435933ddSDimitry Andric                 bool resolve_tail_call_address = true; // PC can be one past the
414435933ddSDimitry Andric                                                        // address range of the
415435933ddSDimitry Andric                                                        // function.
416435933ddSDimitry Andric                 module_sp->ResolveSymbolContextForAddress(
417435933ddSDimitry Andric                     symbol_containing_address, eSymbolContextEverything, sc,
41835617911SEd Maste                     resolve_tail_call_address);
419435933ddSDimitry Andric                 if (sc.function || sc.symbol) {
420435933ddSDimitry Andric                   sc.GetAddressRange(eSymbolContextFunction |
421435933ddSDimitry Andric                                          eSymbolContextSymbol,
422435933ddSDimitry Andric                                      0, false, range);
423435933ddSDimitry Andric                 } else {
424ac7ddfbfSEd Maste                   failed = true;
425ac7ddfbfSEd Maste                 }
426435933ddSDimitry Andric               } else {
427ac7ddfbfSEd Maste                 failed = true;
428ac7ddfbfSEd Maste               }
429435933ddSDimitry Andric               if (failed) {
430435933ddSDimitry Andric                 result.AppendErrorWithFormat(
431435933ddSDimitry Andric                     "Could not find function bounds for address 0x%" PRIx64
432435933ddSDimitry Andric                     "\n",
433435933ddSDimitry Andric                     m_options.symbol_containing_addr);
434ac7ddfbfSEd Maste                 result.SetStatus(eReturnStatusFailed);
435ac7ddfbfSEd Maste                 return false;
436ac7ddfbfSEd Maste               }
4370127ef0fSEd Maste               ranges.push_back(range);
438435933ddSDimitry Andric             } else {
439435933ddSDimitry Andric               for (lldb::ModuleSP module_sp : target->GetImages().Modules()) {
4400127ef0fSEd Maste                 lldb::addr_t file_addr = m_options.symbol_containing_addr;
4410127ef0fSEd Maste                 Address file_address;
442435933ddSDimitry Andric                 if (module_sp->ResolveFileAddress(file_addr, file_address)) {
4430127ef0fSEd Maste                   SymbolContext sc;
444435933ddSDimitry Andric                   bool resolve_tail_call_address = true; // PC can be one past
445435933ddSDimitry Andric                                                          // the address range of
446435933ddSDimitry Andric                                                          // the function.
447435933ddSDimitry Andric                   module_sp->ResolveSymbolContextForAddress(
448435933ddSDimitry Andric                       file_address, eSymbolContextEverything, sc,
449435933ddSDimitry Andric                       resolve_tail_call_address);
450435933ddSDimitry Andric                   if (sc.function || sc.symbol) {
451435933ddSDimitry Andric                     sc.GetAddressRange(eSymbolContextFunction |
452435933ddSDimitry Andric                                            eSymbolContextSymbol,
453435933ddSDimitry Andric                                        0, false, range);
4540127ef0fSEd Maste                     ranges.push_back(range);
455ac7ddfbfSEd Maste                   }
456ac7ddfbfSEd Maste                 }
457ac7ddfbfSEd Maste               }
4580127ef0fSEd Maste             }
4590127ef0fSEd Maste           }
4600127ef0fSEd Maste         }
4610127ef0fSEd Maste       }
462435933ddSDimitry Andric     } else
4630127ef0fSEd Maste       ranges.push_back(range);
4640127ef0fSEd Maste 
465435933ddSDimitry Andric     if (m_options.num_instructions != 0) {
466435933ddSDimitry Andric       if (ranges.empty()) {
467ac7ddfbfSEd Maste         // The default action is to disassemble the current frame function.
468435933ddSDimitry Andric         if (frame) {
469435933ddSDimitry Andric           SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction |
470435933ddSDimitry Andric                                                    eSymbolContextSymbol));
471ac7ddfbfSEd Maste           if (sc.function)
472435933ddSDimitry Andric             range.GetBaseAddress() =
473435933ddSDimitry Andric                 sc.function->GetAddressRange().GetBaseAddress();
474ac7ddfbfSEd Maste           else if (sc.symbol && sc.symbol->ValueIsAddress())
475ac7ddfbfSEd Maste             range.GetBaseAddress() = sc.symbol->GetAddress();
476ac7ddfbfSEd Maste           else
477ac7ddfbfSEd Maste             range.GetBaseAddress() = frame->GetFrameCodeAddress();
478ac7ddfbfSEd Maste         }
479ac7ddfbfSEd Maste 
480435933ddSDimitry Andric         if (!range.GetBaseAddress().IsValid()) {
481ac7ddfbfSEd Maste           result.AppendError("invalid frame");
482ac7ddfbfSEd Maste           result.SetStatus(eReturnStatusFailed);
483ac7ddfbfSEd Maste           return false;
484ac7ddfbfSEd Maste         }
485ac7ddfbfSEd Maste       }
486ac7ddfbfSEd Maste 
4870127ef0fSEd Maste       bool print_sc_header = ranges.size() > 1;
488435933ddSDimitry Andric       for (AddressRange cur_range : ranges) {
489435933ddSDimitry Andric         if (Disassembler::Disassemble(
490435933ddSDimitry Andric                 m_interpreter.GetDebugger(), m_options.arch, plugin_name,
491435933ddSDimitry Andric                 flavor_string, m_exe_ctx, cur_range.GetBaseAddress(),
492435933ddSDimitry Andric                 m_options.num_instructions, m_options.show_mixed,
493435933ddSDimitry Andric                 m_options.show_mixed ? m_options.num_lines_context : 0, options,
494435933ddSDimitry Andric                 result.GetOutputStream())) {
495ac7ddfbfSEd Maste           result.SetStatus(eReturnStatusSuccessFinishResult);
496435933ddSDimitry Andric         } else {
4970127ef0fSEd Maste           if (m_options.start_addr != LLDB_INVALID_ADDRESS)
498435933ddSDimitry Andric             result.AppendErrorWithFormat(
499435933ddSDimitry Andric                 "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
500435933ddSDimitry Andric                 m_options.start_addr);
5010127ef0fSEd Maste           else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
502435933ddSDimitry Andric             result.AppendErrorWithFormat(
503435933ddSDimitry Andric                 "Failed to disassemble memory in function at 0x%8.8" PRIx64
504435933ddSDimitry Andric                 ".\n",
505435933ddSDimitry Andric                 m_options.symbol_containing_addr);
506ac7ddfbfSEd Maste           result.SetStatus(eReturnStatusFailed);
507ac7ddfbfSEd Maste         }
508ac7ddfbfSEd Maste       }
5090127ef0fSEd Maste       if (print_sc_header)
5100127ef0fSEd Maste         result.AppendMessage("\n");
511435933ddSDimitry Andric     } else {
512435933ddSDimitry Andric       if (ranges.empty()) {
513ac7ddfbfSEd Maste         // The default action is to disassemble the current frame function.
514435933ddSDimitry Andric         if (frame) {
515435933ddSDimitry Andric           SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction |
516435933ddSDimitry Andric                                                    eSymbolContextSymbol));
517ac7ddfbfSEd Maste           if (sc.function)
518ac7ddfbfSEd Maste             range = sc.function->GetAddressRange();
519435933ddSDimitry Andric           else if (sc.symbol && sc.symbol->ValueIsAddress()) {
520ac7ddfbfSEd Maste             range.GetBaseAddress() = sc.symbol->GetAddress();
521ac7ddfbfSEd Maste             range.SetByteSize(sc.symbol->GetByteSize());
522435933ddSDimitry Andric           } else
523ac7ddfbfSEd Maste             range.GetBaseAddress() = frame->GetFrameCodeAddress();
524435933ddSDimitry Andric         } else {
525ac7ddfbfSEd Maste           result.AppendError("invalid frame");
526ac7ddfbfSEd Maste           result.SetStatus(eReturnStatusFailed);
527ac7ddfbfSEd Maste           return false;
528ac7ddfbfSEd Maste         }
5290127ef0fSEd Maste         ranges.push_back(range);
530ac7ddfbfSEd Maste       }
5310127ef0fSEd Maste 
5320127ef0fSEd Maste       bool print_sc_header = ranges.size() > 1;
533435933ddSDimitry Andric       for (AddressRange cur_range : ranges) {
5340127ef0fSEd Maste         if (cur_range.GetByteSize() == 0)
5350127ef0fSEd Maste           cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
536ac7ddfbfSEd Maste 
537435933ddSDimitry Andric         if (Disassembler::Disassemble(
538435933ddSDimitry Andric                 m_interpreter.GetDebugger(), m_options.arch, plugin_name,
539435933ddSDimitry Andric                 flavor_string, m_exe_ctx, cur_range, m_options.num_instructions,
540435933ddSDimitry Andric                 m_options.show_mixed,
541435933ddSDimitry Andric                 m_options.show_mixed ? m_options.num_lines_context : 0, options,
542435933ddSDimitry Andric                 result.GetOutputStream())) {
543ac7ddfbfSEd Maste           result.SetStatus(eReturnStatusSuccessFinishResult);
544435933ddSDimitry Andric         } else {
545435933ddSDimitry Andric           result.AppendErrorWithFormat(
546435933ddSDimitry Andric               "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n",
547435933ddSDimitry Andric               m_options.start_addr);
548ac7ddfbfSEd Maste           result.SetStatus(eReturnStatusFailed);
549ac7ddfbfSEd Maste         }
5500127ef0fSEd Maste         if (print_sc_header)
5510127ef0fSEd Maste           result.AppendMessage("\n");
5520127ef0fSEd Maste       }
553ac7ddfbfSEd Maste     }
554ac7ddfbfSEd Maste   }
555ac7ddfbfSEd Maste 
556ac7ddfbfSEd Maste   return result.Succeeded();
557ac7ddfbfSEd Maste }
558