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