130fdc8d8SChris Lattner //===-- CommandObjectDisassemble.cpp ----------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner // C Includes
1130fdc8d8SChris Lattner // C++ Includes
1230fdc8d8SChris Lattner // Other libraries and framework includes
1330fdc8d8SChris Lattner // Project includes
1426cac3afSEugene Zelenko #include "CommandObjectDisassemble.h"
1530fdc8d8SChris Lattner #include "lldb/Core/AddressRange.h"
161f746071SGreg Clayton #include "lldb/Core/Disassembler.h"
17801237a2SJason Molenda #include "lldb/Core/Module.h"
181f746071SGreg Clayton #include "lldb/Core/SourceManager.h"
195275aaa0SVince Harron #include "lldb/Host/StringConvert.h"
2030fdc8d8SChris Lattner #include "lldb/Interpreter/CommandCompletions.h"
2130fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h"
2230fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
2340af72e1SJim Ingham #include "lldb/Interpreter/Options.h"
241f746071SGreg Clayton #include "lldb/Symbol/Function.h"
2530fdc8d8SChris Lattner #include "lldb/Symbol/Symbol.h"
2630fdc8d8SChris Lattner #include "lldb/Target/Process.h"
27d5944cd1SGreg Clayton #include "lldb/Target/SectionLoadList.h"
28b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
2930fdc8d8SChris Lattner #include "lldb/Target/Target.h"
3030fdc8d8SChris Lattner 
3130fdc8d8SChris Lattner #define DEFAULT_DISASM_BYTE_SIZE 32
3237023b06SJim Ingham #define DEFAULT_DISASM_NUM_INS  4
3330fdc8d8SChris Lattner 
3430fdc8d8SChris Lattner using namespace lldb;
3530fdc8d8SChris Lattner using namespace lldb_private;
3630fdc8d8SChris Lattner 
37*e1cfbc79STodd Fiala CommandObjectDisassemble::CommandOptions::CommandOptions() :
38*e1cfbc79STodd Fiala     Options(),
3937023b06SJim Ingham     num_lines_context(0),
4037023b06SJim Ingham     num_instructions (0),
4132e0a750SGreg Clayton     func_name(),
421fb2e7dfSGreg Clayton     current_function (false),
4332e0a750SGreg Clayton     start_addr(),
4432e0a750SGreg Clayton     end_addr (),
4532e0a750SGreg Clayton     at_pc (false),
4632e0a750SGreg Clayton     frame_line (false),
4732e0a750SGreg Clayton     plugin_name (),
480f063ba6SJim Ingham     flavor_string(),
493555b5d7SJim Ingham     arch(),
50801237a2SJason Molenda     some_location_specified (false),
51801237a2SJason Molenda     symbol_containing_addr ()
5230fdc8d8SChris Lattner {
53*e1cfbc79STodd Fiala     OptionParsingStarting(nullptr);
5430fdc8d8SChris Lattner }
5530fdc8d8SChris Lattner 
5626cac3afSEugene Zelenko CommandObjectDisassemble::CommandOptions::~CommandOptions() = default;
5730fdc8d8SChris Lattner 
5830fdc8d8SChris Lattner Error
59*e1cfbc79STodd Fiala CommandObjectDisassemble::CommandOptions::SetOptionValue(uint32_t option_idx,
60*e1cfbc79STodd Fiala                                                          const char *option_arg,
61*e1cfbc79STodd Fiala                                             ExecutionContext *execution_context)
6230fdc8d8SChris Lattner {
6330fdc8d8SChris Lattner     Error error;
6430fdc8d8SChris Lattner 
653bcdfc0eSGreg Clayton     const int short_option = m_getopt_table[option_idx].val;
6630fdc8d8SChris Lattner 
6737023b06SJim Ingham     bool success;
6837023b06SJim Ingham 
6930fdc8d8SChris Lattner     switch (short_option)
7030fdc8d8SChris Lattner     {
7130fdc8d8SChris Lattner     case 'm':
7230fdc8d8SChris Lattner         show_mixed = true;
7330fdc8d8SChris Lattner         break;
7430fdc8d8SChris Lattner 
75357132ebSGreg Clayton     case 'C':
765275aaa0SVince Harron         num_lines_context = StringConvert::ToUInt32(option_arg, 0, 0, &success);
7737023b06SJim Ingham         if (!success)
7886edbf41SGreg Clayton             error.SetErrorStringWithFormat ("invalid num context lines string: \"%s\"", option_arg);
7937023b06SJim Ingham         break;
8037023b06SJim Ingham 
8130fdc8d8SChris Lattner     case 'c':
825275aaa0SVince Harron         num_instructions = StringConvert::ToUInt32(option_arg, 0, 0, &success);
8337023b06SJim Ingham         if (!success)
8486edbf41SGreg Clayton             error.SetErrorStringWithFormat ("invalid num of instructions string: \"%s\"", option_arg);
8530fdc8d8SChris Lattner         break;
8630fdc8d8SChris Lattner 
8730fdc8d8SChris Lattner     case 'b':
8830fdc8d8SChris Lattner         show_bytes = true;
8930fdc8d8SChris Lattner         break;
9030fdc8d8SChris Lattner 
918651121cSJim Ingham     case 's':
92b9d5df58SGreg Clayton         {
93*e1cfbc79STodd Fiala             start_addr = Args::StringToAddress(execution_context, option_arg,
94*e1cfbc79STodd Fiala                                                LLDB_INVALID_ADDRESS, &error);
95b9d5df58SGreg Clayton             if (start_addr != LLDB_INVALID_ADDRESS)
963555b5d7SJim Ingham                 some_location_specified = true;
97b9d5df58SGreg Clayton         }
988651121cSJim Ingham         break;
998651121cSJim Ingham     case 'e':
100b9d5df58SGreg Clayton         {
101*e1cfbc79STodd Fiala             end_addr = Args::StringToAddress(execution_context, option_arg,
102*e1cfbc79STodd Fiala                                              LLDB_INVALID_ADDRESS, &error);
103b9d5df58SGreg Clayton             if (end_addr != LLDB_INVALID_ADDRESS)
1043555b5d7SJim Ingham                 some_location_specified = true;
105b9d5df58SGreg Clayton         }
106b9d5df58SGreg Clayton         break;
10726cac3afSEugene Zelenko 
10830fdc8d8SChris Lattner     case 'n':
10932e0a750SGreg Clayton         func_name.assign (option_arg);
1103555b5d7SJim Ingham         some_location_specified = true;
11130fdc8d8SChris Lattner         break;
11230fdc8d8SChris Lattner 
11337023b06SJim Ingham     case 'p':
11432e0a750SGreg Clayton         at_pc = true;
1153555b5d7SJim Ingham         some_location_specified = true;
11632e0a750SGreg Clayton         break;
11732e0a750SGreg Clayton 
11832e0a750SGreg Clayton     case 'l':
11932e0a750SGreg Clayton         frame_line = true;
12032e0a750SGreg Clayton         // Disassemble the current source line kind of implies showing mixed
12132e0a750SGreg Clayton         // source code context.
12232e0a750SGreg Clayton         show_mixed = true;
1233555b5d7SJim Ingham         some_location_specified = true;
12437023b06SJim Ingham         break;
12537023b06SJim Ingham 
1261080edbcSGreg Clayton     case 'P':
12732e0a750SGreg Clayton         plugin_name.assign (option_arg);
1281080edbcSGreg Clayton         break;
1291080edbcSGreg Clayton 
1300f063ba6SJim Ingham     case 'F':
1310f063ba6SJim Ingham         {
132*e1cfbc79STodd Fiala             TargetSP target_sp = execution_context ?
133*e1cfbc79STodd Fiala                 execution_context->GetTargetSP() : TargetSP();
134*e1cfbc79STodd Fiala             if (target_sp &&
135*e1cfbc79STodd Fiala                 (target_sp->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86
136*e1cfbc79STodd Fiala                 || target_sp->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64))
1370f063ba6SJim Ingham             {
1380f063ba6SJim Ingham                 flavor_string.assign (option_arg);
1390f063ba6SJim Ingham             }
1400f063ba6SJim Ingham             else
1410f063ba6SJim Ingham                 error.SetErrorStringWithFormat("Disassembler flavors are currently only supported for x86 and x86_64 targets.");
1420f063ba6SJim Ingham             break;
1430f063ba6SJim Ingham         }
14426cac3afSEugene Zelenko 
14530fdc8d8SChris Lattner     case 'r':
14630fdc8d8SChris Lattner         raw = true;
14730fdc8d8SChris Lattner         break;
14830fdc8d8SChris Lattner 
1498ceb8ba2SJohnny Chen     case 'f':
1501fb2e7dfSGreg Clayton         current_function = true;
1513555b5d7SJim Ingham         some_location_specified = true;
1528ceb8ba2SJohnny Chen         break;
1538ceb8ba2SJohnny Chen 
154801237a2SJason Molenda     case 'A':
155*e1cfbc79STodd Fiala         if (execution_context)
156*e1cfbc79STodd Fiala         {
157*e1cfbc79STodd Fiala             auto target_sp = execution_context ?
158*e1cfbc79STodd Fiala                 execution_context->GetTargetSP() : TargetSP();
159*e1cfbc79STodd Fiala             auto platform_sp =
160*e1cfbc79STodd Fiala                 target_sp ? target_sp->GetPlatform() : PlatformSP();
161*e1cfbc79STodd Fiala             if (!arch.SetTriple (option_arg, platform_sp.get()))
16270512317SGreg Clayton                 arch.SetTriple (option_arg);
163*e1cfbc79STodd Fiala         }
164357132ebSGreg Clayton         break;
165357132ebSGreg Clayton 
166801237a2SJason Molenda     case 'a':
167801237a2SJason Molenda         {
168*e1cfbc79STodd Fiala             symbol_containing_addr =
169*e1cfbc79STodd Fiala                 Args::StringToAddress(execution_context,option_arg,
170*e1cfbc79STodd Fiala                                       LLDB_INVALID_ADDRESS, &error);
171801237a2SJason Molenda             if (symbol_containing_addr != LLDB_INVALID_ADDRESS)
172801237a2SJason Molenda             {
173801237a2SJason Molenda                 some_location_specified = true;
174801237a2SJason Molenda             }
175801237a2SJason Molenda         }
176801237a2SJason Molenda         break;
177801237a2SJason Molenda 
17830fdc8d8SChris Lattner     default:
17986edbf41SGreg Clayton         error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
18030fdc8d8SChris Lattner         break;
18130fdc8d8SChris Lattner     }
18230fdc8d8SChris Lattner 
18330fdc8d8SChris Lattner     return error;
18430fdc8d8SChris Lattner }
18530fdc8d8SChris Lattner 
18630fdc8d8SChris Lattner void
187*e1cfbc79STodd Fiala CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
188*e1cfbc79STodd Fiala                                             ExecutionContext *execution_context)
18930fdc8d8SChris Lattner {
19030fdc8d8SChris Lattner     show_mixed = false;
19130fdc8d8SChris Lattner     show_bytes = false;
19230fdc8d8SChris Lattner     num_lines_context = 0;
19337023b06SJim Ingham     num_instructions = 0;
19432e0a750SGreg Clayton     func_name.clear();
1951fb2e7dfSGreg Clayton     current_function = false;
19632e0a750SGreg Clayton     at_pc = false;
19732e0a750SGreg Clayton     frame_line = false;
19832e0a750SGreg Clayton     start_addr = LLDB_INVALID_ADDRESS;
19932e0a750SGreg Clayton     end_addr = LLDB_INVALID_ADDRESS;
200801237a2SJason Molenda     symbol_containing_addr = LLDB_INVALID_ADDRESS;
201a68c1a21SSean Callanan     raw = false;
20232e0a750SGreg Clayton     plugin_name.clear();
2030f063ba6SJim Ingham 
204*e1cfbc79STodd Fiala     Target *target =
205*e1cfbc79STodd Fiala         execution_context ? execution_context->GetTargetPtr() : nullptr;
2060f063ba6SJim Ingham 
2070f063ba6SJim Ingham     // This is a hack till we get the ability to specify features based on architecture.  For now GetDisassemblyFlavor
2080f063ba6SJim Ingham     // is really only valid for x86 (and for the llvm assembler plugin, but I'm papering over that since that is the
2090f063ba6SJim Ingham     // only disassembler plugin we have...
2100f063ba6SJim Ingham     if (target)
2110f063ba6SJim Ingham     {
2120f063ba6SJim Ingham         if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86
2130f063ba6SJim Ingham             || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64)
2140f063ba6SJim Ingham         {
2150f063ba6SJim Ingham             flavor_string.assign(target->GetDisassemblyFlavor());
2160f063ba6SJim Ingham         }
2170f063ba6SJim Ingham         else
2180f063ba6SJim Ingham             flavor_string.assign ("default");
2190f063ba6SJim Ingham 
2200f063ba6SJim Ingham     }
2210f063ba6SJim Ingham     else
2220f063ba6SJim Ingham         flavor_string.assign("default");
2230f063ba6SJim Ingham 
22432e0a750SGreg Clayton     arch.Clear();
2253555b5d7SJim Ingham     some_location_specified = false;
2263555b5d7SJim Ingham }
2273555b5d7SJim Ingham 
2283555b5d7SJim Ingham Error
229*e1cfbc79STodd Fiala CommandObjectDisassemble::CommandOptions::OptionParsingFinished(
230*e1cfbc79STodd Fiala                                             ExecutionContext *execution_context)
2313555b5d7SJim Ingham {
2323555b5d7SJim Ingham     if (!some_location_specified)
2331fb2e7dfSGreg Clayton         current_function = true;
2343555b5d7SJim Ingham     return Error();
23530fdc8d8SChris Lattner }
23630fdc8d8SChris Lattner 
237e0d378b3SGreg Clayton const OptionDefinition*
23830fdc8d8SChris Lattner CommandObjectDisassemble::CommandOptions::GetDefinitions ()
23930fdc8d8SChris Lattner {
24030fdc8d8SChris Lattner     return g_option_table;
24130fdc8d8SChris Lattner }
24230fdc8d8SChris Lattner 
243e0d378b3SGreg Clayton OptionDefinition
24430fdc8d8SChris Lattner CommandObjectDisassemble::CommandOptions::g_option_table[] =
24530fdc8d8SChris Lattner {
24626cac3afSEugene Zelenko { LLDB_OPT_SET_ALL, false, "bytes"        , 'b', OptionParser::eNoArgument        , nullptr, nullptr, 0, eArgTypeNone,        "Show opcode bytes when disassembling."},
24726cac3afSEugene Zelenko { LLDB_OPT_SET_ALL, false, "context"      , 'C', OptionParser::eRequiredArgument  , nullptr, nullptr, 0, eArgTypeNumLines,    "Number of context lines of source to show."},
24826cac3afSEugene Zelenko { LLDB_OPT_SET_ALL, false, "mixed"        , 'm', OptionParser::eNoArgument        , nullptr, nullptr, 0, eArgTypeNone,        "Enable mixed source and assembly display."},
24926cac3afSEugene Zelenko { LLDB_OPT_SET_ALL, false, "raw"          , 'r', OptionParser::eNoArgument        , nullptr, nullptr, 0, eArgTypeNone,        "Print raw disassembly with no symbol information."},
25026cac3afSEugene Zelenko { LLDB_OPT_SET_ALL, false, "plugin"       , 'P', OptionParser::eRequiredArgument  , nullptr, nullptr, 0, eArgTypePlugin,      "Name of the disassembler plugin you want to use."},
25126cac3afSEugene Zelenko { LLDB_OPT_SET_ALL, false, "flavor"       , 'F', OptionParser::eRequiredArgument  , nullptr, nullptr, 0, eArgTypeDisassemblyFlavor,        "Name of the disassembly flavor you want to use.  "
2520f063ba6SJim Ingham                                                                                                           "Currently the only valid options are default, and for Intel"
2530f063ba6SJim Ingham                                                                                                           " architectures, att and intel."},
25426cac3afSEugene Zelenko { LLDB_OPT_SET_ALL, false, "arch"         , 'A', OptionParser::eRequiredArgument  , nullptr, nullptr, 0, eArgTypeArchitecture,"Specify the architecture to use from cross disassembly."},
255357132ebSGreg Clayton { LLDB_OPT_SET_1  |
25626cac3afSEugene Zelenko   LLDB_OPT_SET_2  , true , "start-address", 's', OptionParser::eRequiredArgument  , nullptr, nullptr, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."},
25726cac3afSEugene Zelenko { LLDB_OPT_SET_1  , false, "end-address"  , 'e', OptionParser::eRequiredArgument  , nullptr, nullptr, 0, eArgTypeAddressOrExpression,  "Address at which to end disassembling."},
258357132ebSGreg Clayton { LLDB_OPT_SET_2  |
259357132ebSGreg Clayton   LLDB_OPT_SET_3  |
260357132ebSGreg Clayton   LLDB_OPT_SET_4  |
26126cac3afSEugene Zelenko   LLDB_OPT_SET_5  , false, "count"        , 'c', OptionParser::eRequiredArgument  , nullptr, nullptr, 0, eArgTypeNumLines,    "Number of instructions to display."},
26226cac3afSEugene Zelenko { LLDB_OPT_SET_3  , false, "name"         , 'n', OptionParser::eRequiredArgument  , nullptr, nullptr, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
2631fb2e7dfSGreg Clayton                                                                                                           "Disassemble entire contents of the given function name."},
26426cac3afSEugene Zelenko { LLDB_OPT_SET_4  , false, "frame"        , 'f', OptionParser::eNoArgument        , nullptr, nullptr, 0, eArgTypeNone,        "Disassemble from the start of the current frame's function."},
26526cac3afSEugene Zelenko { LLDB_OPT_SET_5  , false, "pc"           , 'p', OptionParser::eNoArgument        , nullptr, nullptr, 0, eArgTypeNone,        "Disassemble around the current pc."},
26626cac3afSEugene Zelenko { LLDB_OPT_SET_6  , false, "line"         , 'l', OptionParser::eNoArgument        , nullptr, nullptr, 0, eArgTypeNone,        "Disassemble the current frame's current source line instructions if there is debug line table information, else disassemble around the pc."},
26726cac3afSEugene Zelenko { LLDB_OPT_SET_7  , false, "address"      , 'a', OptionParser::eRequiredArgument  , nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Disassemble function containing this address."},
26826cac3afSEugene Zelenko { 0               , false, nullptr           ,   0, 0                  , nullptr, nullptr, 0, eArgTypeNone,        nullptr }
26930fdc8d8SChris Lattner };
27030fdc8d8SChris Lattner 
27130fdc8d8SChris Lattner //-------------------------------------------------------------------------
27230fdc8d8SChris Lattner // CommandObjectDisassemble
27330fdc8d8SChris Lattner //-------------------------------------------------------------------------
27430fdc8d8SChris Lattner 
2757428a18cSKate Stone CommandObjectDisassemble::CommandObjectDisassemble(CommandInterpreter &interpreter)
2767428a18cSKate Stone     : CommandObjectParsed(interpreter, "disassemble", "Disassemble specified instructions in the current target.  "
2777428a18cSKate Stone                                                       "Defaults to the current function for the current thread and "
2787428a18cSKate Stone                                                       "stack frame.",
279eb0103f2SGreg Clayton                           "disassemble [<cmd-options>]"),
280*e1cfbc79STodd Fiala       m_options()
28130fdc8d8SChris Lattner {
28230fdc8d8SChris Lattner }
28330fdc8d8SChris Lattner 
28426cac3afSEugene Zelenko CommandObjectDisassemble::~CommandObjectDisassemble() = default;
28530fdc8d8SChris Lattner 
28630fdc8d8SChris Lattner bool
2875a988416SJim Ingham CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
28830fdc8d8SChris Lattner {
289a7015092SGreg Clayton     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
29026cac3afSEugene Zelenko     if (target == nullptr)
29130fdc8d8SChris Lattner     {
292effe5c95SGreg Clayton         result.AppendError ("invalid target, create a debug target using the 'target create' command");
29330fdc8d8SChris Lattner         result.SetStatus (eReturnStatusFailed);
29430fdc8d8SChris Lattner         return false;
29530fdc8d8SChris Lattner     }
29632e0a750SGreg Clayton     if (!m_options.arch.IsValid())
29732e0a750SGreg Clayton         m_options.arch = target->GetArchitecture();
29830fdc8d8SChris Lattner 
29932e0a750SGreg Clayton     if (!m_options.arch.IsValid())
30030fdc8d8SChris Lattner     {
301125adcf0SJason Molenda         result.AppendError ("use the --arch option or set the target architecture to disassemble");
30230fdc8d8SChris Lattner         result.SetStatus (eReturnStatusFailed);
30330fdc8d8SChris Lattner         return false;
30430fdc8d8SChris Lattner     }
30530fdc8d8SChris Lattner 
3061080edbcSGreg Clayton     const char *plugin_name = m_options.GetPluginName ();
3070f063ba6SJim Ingham     const char *flavor_string = m_options.GetFlavorString();
3080f063ba6SJim Ingham 
3090f063ba6SJim Ingham     DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
31030fdc8d8SChris Lattner 
3119a028519SSean Callanan     if (!disassembler)
31230fdc8d8SChris Lattner     {
3131080edbcSGreg Clayton         if (plugin_name)
3140f063ba6SJim Ingham         {
315357132ebSGreg Clayton             result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n",
316357132ebSGreg Clayton                                           plugin_name,
31732e0a750SGreg Clayton                                           m_options.arch.GetArchitectureName());
3180f063ba6SJim Ingham         }
3191080edbcSGreg Clayton         else
320357132ebSGreg Clayton             result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n",
32132e0a750SGreg Clayton                                           m_options.arch.GetArchitectureName());
32230fdc8d8SChris Lattner         result.SetStatus (eReturnStatusFailed);
32330fdc8d8SChris Lattner         return false;
32430fdc8d8SChris Lattner     }
32526cac3afSEugene Zelenko     else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string))
3260f063ba6SJim Ingham         result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string);
32730fdc8d8SChris Lattner 
32830fdc8d8SChris Lattner     result.SetStatus (eReturnStatusSuccessFinishResult);
32930fdc8d8SChris Lattner 
330dda4f7b5SGreg Clayton     if (command.GetArgumentCount() != 0)
33130fdc8d8SChris Lattner     {
332a7015092SGreg Clayton         result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n");
333*e1cfbc79STodd Fiala         const int terminal_width =
334*e1cfbc79STodd Fiala             GetCommandInterpreter().GetDebugger().GetTerminalWidth();
335*e1cfbc79STodd Fiala         GetOptions()->GenerateOptionUsage(result.GetErrorStream(), this,
336*e1cfbc79STodd Fiala                                           terminal_width);
3378651121cSJim Ingham         result.SetStatus (eReturnStatusFailed);
3388651121cSJim Ingham         return false;
3398651121cSJim Ingham     }
3408651121cSJim Ingham 
341dda4f7b5SGreg Clayton     if (m_options.show_mixed && m_options.num_lines_context == 0)
3426dbd3983SGreg Clayton         m_options.num_lines_context = 1;
343dda4f7b5SGreg Clayton 
344b10d72f0SGreg Clayton     // Always show the PC in the disassembly
345b10d72f0SGreg Clayton     uint32_t options = Disassembler::eOptionMarkPCAddress;
3461da6f9d7SGreg Clayton 
347b10d72f0SGreg Clayton     // Mark the source line for the current PC only if we are doing mixed source and assembly
348b10d72f0SGreg Clayton     if (m_options.show_mixed)
349b10d72f0SGreg Clayton         options |= Disassembler::eOptionMarkPCSourceLine;
3501da6f9d7SGreg Clayton 
3511da6f9d7SGreg Clayton     if (m_options.show_bytes)
3521da6f9d7SGreg Clayton         options |= Disassembler::eOptionShowBytes;
3531da6f9d7SGreg Clayton 
3541da6f9d7SGreg Clayton     if (m_options.raw)
3551da6f9d7SGreg Clayton         options |= Disassembler::eOptionRawOuput;
35637023b06SJim Ingham 
35732e0a750SGreg Clayton     if (!m_options.func_name.empty())
358dda4f7b5SGreg Clayton     {
35932e0a750SGreg Clayton         ConstString name(m_options.func_name.c_str());
360dda4f7b5SGreg Clayton 
361a7015092SGreg Clayton         if (Disassembler::Disassemble(m_interpreter.GetDebugger(),
36232e0a750SGreg Clayton                                       m_options.arch,
3631080edbcSGreg Clayton                                       plugin_name,
3640f063ba6SJim Ingham                                       flavor_string,
365f9fc609fSGreg Clayton                                       m_exe_ctx,
366dda4f7b5SGreg Clayton                                       name,
36726cac3afSEugene Zelenko                                       nullptr,    // Module *
36837023b06SJim Ingham                                       m_options.num_instructions,
369dda4f7b5SGreg Clayton                                       m_options.show_mixed ? m_options.num_lines_context : 0,
3701da6f9d7SGreg Clayton                                       options,
371dda4f7b5SGreg Clayton                                       result.GetOutputStream()))
372dda4f7b5SGreg Clayton         {
373dda4f7b5SGreg Clayton             result.SetStatus (eReturnStatusSuccessFinishResult);
374dda4f7b5SGreg Clayton         }
375dda4f7b5SGreg Clayton         else
376dda4f7b5SGreg Clayton         {
377dda4f7b5SGreg Clayton             result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
378dda4f7b5SGreg Clayton             result.SetStatus (eReturnStatusFailed);
379dda4f7b5SGreg Clayton         }
380dda4f7b5SGreg Clayton     }
381dda4f7b5SGreg Clayton     else
382dda4f7b5SGreg Clayton     {
3832f2c876eSJim Ingham         std::vector<AddressRange> ranges;
38432e0a750SGreg Clayton         AddressRange range;
385b57e4a1bSJason Molenda         StackFrame *frame = m_exe_ctx.GetFramePtr();
38632e0a750SGreg Clayton         if (m_options.frame_line)
38732e0a750SGreg Clayton         {
38826cac3afSEugene Zelenko             if (frame == nullptr)
3893555b5d7SJim Ingham             {
3903555b5d7SJim Ingham                 result.AppendError ("Cannot disassemble around the current line without a selected frame.\n");
3913555b5d7SJim Ingham                 result.SetStatus (eReturnStatusFailed);
3923555b5d7SJim Ingham                 return false;
3933555b5d7SJim Ingham             }
394c14ee32dSGreg Clayton             LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
39532e0a750SGreg Clayton             if (pc_line_entry.IsValid())
39632e0a750SGreg Clayton             {
39732e0a750SGreg Clayton                 range = pc_line_entry.range;
39832e0a750SGreg Clayton             }
39932e0a750SGreg Clayton             else
40032e0a750SGreg Clayton             {
40132e0a750SGreg Clayton                 m_options.at_pc = true; // No line entry, so just disassemble around the current pc
40232e0a750SGreg Clayton                 m_options.show_mixed = false;
40332e0a750SGreg Clayton             }
40432e0a750SGreg Clayton         }
4051fb2e7dfSGreg Clayton         else if (m_options.current_function)
4063555b5d7SJim Ingham         {
40726cac3afSEugene Zelenko             if (frame == nullptr)
4083555b5d7SJim Ingham             {
4093555b5d7SJim Ingham                 result.AppendError ("Cannot disassemble around the current function without a selected frame.\n");
4103555b5d7SJim Ingham                 result.SetStatus (eReturnStatusFailed);
4113555b5d7SJim Ingham                 return false;
4123555b5d7SJim Ingham             }
413c14ee32dSGreg Clayton             Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
4143555b5d7SJim Ingham             if (symbol)
415e7612134SGreg Clayton             {
416e7612134SGreg Clayton                 range.GetBaseAddress() = symbol->GetAddress();
417e7612134SGreg Clayton                 range.SetByteSize(symbol->GetByteSize());
418e7612134SGreg Clayton             }
4193555b5d7SJim Ingham         }
42037023b06SJim Ingham 
42132e0a750SGreg Clayton         // Did the "m_options.frame_line" find a valid range already? If so
42232e0a750SGreg Clayton         // skip the rest...
42332e0a750SGreg Clayton         if (range.GetByteSize() == 0)
42432e0a750SGreg Clayton         {
42532e0a750SGreg Clayton             if (m_options.at_pc)
4268651121cSJim Ingham             {
42726cac3afSEugene Zelenko                 if (frame == nullptr)
42837023b06SJim Ingham                 {
42937023b06SJim Ingham                     result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n");
43037023b06SJim Ingham                     result.SetStatus (eReturnStatusFailed);
43137023b06SJim Ingham                     return false;
43237023b06SJim Ingham                 }
433c14ee32dSGreg Clayton                 range.GetBaseAddress() = frame->GetFrameCodeAddress();
43437023b06SJim Ingham                 if (m_options.num_instructions == 0)
43537023b06SJim Ingham                 {
43637023b06SJim Ingham                     // Disassembling at the PC always disassembles some number of instructions (not the whole function).
43737023b06SJim Ingham                     m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
43837023b06SJim Ingham                 }
4392f2c876eSJim Ingham                 ranges.push_back(range);
44037023b06SJim Ingham             }
44137023b06SJim Ingham             else
44237023b06SJim Ingham             {
44332e0a750SGreg Clayton                 range.GetBaseAddress().SetOffset (m_options.start_addr);
44432e0a750SGreg Clayton                 if (range.GetBaseAddress().IsValid())
44537023b06SJim Ingham                 {
44632e0a750SGreg Clayton                     if (m_options.end_addr != LLDB_INVALID_ADDRESS)
4478651121cSJim Ingham                     {
44832e0a750SGreg Clayton                         if (m_options.end_addr <= m_options.start_addr)
4498651121cSJim Ingham                         {
4508651121cSJim Ingham                             result.AppendErrorWithFormat ("End address before start address.\n");
4518651121cSJim Ingham                             result.SetStatus (eReturnStatusFailed);
4528651121cSJim Ingham                             return false;
4538651121cSJim Ingham                         }
45432e0a750SGreg Clayton                         range.SetByteSize (m_options.end_addr - m_options.start_addr);
45532e0a750SGreg Clayton                     }
4562f4693aaSJim Ingham                     ranges.push_back(range);
45737023b06SJim Ingham                 }
458801237a2SJason Molenda                 else
459801237a2SJason Molenda                 {
460801237a2SJason Molenda                     if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS
4612f2c876eSJim Ingham                         && target)
4622f2c876eSJim Ingham                     {
4632f2c876eSJim Ingham                         if (!target->GetSectionLoadList().IsEmpty())
464801237a2SJason Molenda                         {
465801237a2SJason Molenda                             bool failed = false;
466801237a2SJason Molenda                             Address symbol_containing_address;
467801237a2SJason Molenda                             if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address))
468801237a2SJason Molenda                             {
469801237a2SJason Molenda                                 ModuleSP module_sp (symbol_containing_address.GetModule());
470801237a2SJason Molenda                                 SymbolContext sc;
47135729bb1SAshok Thirumurthi                                 bool resolve_tail_call_address = true; // PC can be one past the address range of the function.
47235729bb1SAshok Thirumurthi                                 module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc,
47335729bb1SAshok Thirumurthi                                                                            resolve_tail_call_address);
474801237a2SJason Molenda                                 if (sc.function || sc.symbol)
475801237a2SJason Molenda                                 {
476801237a2SJason Molenda                                     sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
477801237a2SJason Molenda                                 }
478801237a2SJason Molenda                                 else
479801237a2SJason Molenda                                 {
480801237a2SJason Molenda                                     failed = true;
481801237a2SJason Molenda                                 }
482801237a2SJason Molenda                             }
483801237a2SJason Molenda                             else
484801237a2SJason Molenda                             {
485801237a2SJason Molenda                                 failed = true;
486801237a2SJason Molenda                             }
487801237a2SJason Molenda                             if (failed)
488801237a2SJason Molenda                             {
489801237a2SJason Molenda                                 result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr);
490801237a2SJason Molenda                                 result.SetStatus (eReturnStatusFailed);
491801237a2SJason Molenda                                 return false;
492801237a2SJason Molenda                             }
4932f2c876eSJim Ingham                             ranges.push_back(range);
494801237a2SJason Molenda                         }
4952f2c876eSJim Ingham                         else
4962f2c876eSJim Ingham                         {
4972f2c876eSJim Ingham                             for (lldb::ModuleSP module_sp : target->GetImages().Modules())
4982f2c876eSJim Ingham                             {
4992f2c876eSJim Ingham                                 lldb::addr_t file_addr = m_options.symbol_containing_addr;
5002f2c876eSJim Ingham                                 Address file_address;
5012f2c876eSJim Ingham                                 if (module_sp->ResolveFileAddress(file_addr, file_address))
5022f2c876eSJim Ingham                                 {
5032f2c876eSJim Ingham                                     SymbolContext sc;
5042f2c876eSJim Ingham                                     bool resolve_tail_call_address = true; // PC can be one past the address range of the function.
5052f2c876eSJim Ingham                                     module_sp->ResolveSymbolContextForAddress (file_address, eSymbolContextEverything, sc, resolve_tail_call_address);
5062f2c876eSJim Ingham                                     if (sc.function || sc.symbol)
5072f2c876eSJim Ingham                                     {
5082f2c876eSJim Ingham                                         sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
5092f2c876eSJim Ingham                                         ranges.push_back(range);
510801237a2SJason Molenda                                     }
51137023b06SJim Ingham                                 }
51237023b06SJim Ingham                             }
5132f2c876eSJim Ingham                         }
5142f2c876eSJim Ingham                     }
5152f2c876eSJim Ingham                 }
5162f2c876eSJim Ingham             }
5172f2c876eSJim Ingham         }
5182f2c876eSJim Ingham         else
5192f2c876eSJim Ingham             ranges.push_back(range);
5202f2c876eSJim Ingham 
52137023b06SJim Ingham         if (m_options.num_instructions != 0)
52237023b06SJim Ingham         {
52326cac3afSEugene Zelenko             if (ranges.empty())
52437023b06SJim Ingham             {
52537023b06SJim Ingham                 // The default action is to disassemble the current frame function.
526c14ee32dSGreg Clayton                 if (frame)
52737023b06SJim Ingham                 {
528c14ee32dSGreg Clayton                     SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
52937023b06SJim Ingham                     if (sc.function)
53032e0a750SGreg Clayton                         range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress();
531e7612134SGreg Clayton                     else if (sc.symbol && sc.symbol->ValueIsAddress())
532e7612134SGreg Clayton                         range.GetBaseAddress() = sc.symbol->GetAddress();
53337023b06SJim Ingham                     else
534c14ee32dSGreg Clayton                         range.GetBaseAddress() = frame->GetFrameCodeAddress();
53537023b06SJim Ingham                 }
53637023b06SJim Ingham 
53732e0a750SGreg Clayton                 if (!range.GetBaseAddress().IsValid())
53837023b06SJim Ingham                 {
53937023b06SJim Ingham                     result.AppendError ("invalid frame");
54037023b06SJim Ingham                     result.SetStatus (eReturnStatusFailed);
54137023b06SJim Ingham                     return false;
54237023b06SJim Ingham                 }
54337023b06SJim Ingham             }
54437023b06SJim Ingham 
5452f2c876eSJim Ingham             bool print_sc_header = ranges.size() > 1;
5462f2c876eSJim Ingham             for (AddressRange cur_range : ranges)
5472f2c876eSJim Ingham             {
54837023b06SJim Ingham                 if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
54932e0a750SGreg Clayton                                                m_options.arch,
5501080edbcSGreg Clayton                                                plugin_name,
5510f063ba6SJim Ingham                                                flavor_string,
552f9fc609fSGreg Clayton                                                m_exe_ctx,
5532f2c876eSJim Ingham                                                cur_range.GetBaseAddress(),
55437023b06SJim Ingham                                                m_options.num_instructions,
55537023b06SJim Ingham                                                m_options.show_mixed ? m_options.num_lines_context : 0,
5561da6f9d7SGreg Clayton                                                options,
55737023b06SJim Ingham                                                result.GetOutputStream()))
55837023b06SJim Ingham                 {
55937023b06SJim Ingham                     result.SetStatus (eReturnStatusSuccessFinishResult);
5608651121cSJim Ingham                 }
5618651121cSJim Ingham                 else
56237023b06SJim Ingham                 {
5632f2c876eSJim Ingham                     if (m_options.start_addr != LLDB_INVALID_ADDRESS)
564d01b2953SDaniel Malea                         result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
5652f2c876eSJim Ingham                     else if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS)
5662f2c876eSJim Ingham                         result.AppendErrorWithFormat ("Failed to disassemble memory in function at 0x%8.8" PRIx64 ".\n", m_options.symbol_containing_addr);
56737023b06SJim Ingham                     result.SetStatus (eReturnStatusFailed);
56837023b06SJim Ingham                 }
56937023b06SJim Ingham             }
5702f2c876eSJim Ingham             if (print_sc_header)
5712f2c876eSJim Ingham                 result.AppendMessage("\n");
5722f2c876eSJim Ingham         }
57337023b06SJim Ingham         else
57437023b06SJim Ingham         {
57526cac3afSEugene Zelenko             if (ranges.empty())
57630fdc8d8SChris Lattner             {
5778ceb8ba2SJohnny Chen                 // The default action is to disassemble the current frame function.
578c14ee32dSGreg Clayton                 if (frame)
57930fdc8d8SChris Lattner                 {
580c14ee32dSGreg Clayton                     SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
58130fdc8d8SChris Lattner                     if (sc.function)
582dda4f7b5SGreg Clayton                         range = sc.function->GetAddressRange();
583e7612134SGreg Clayton                     else if (sc.symbol && sc.symbol->ValueIsAddress())
584e7612134SGreg Clayton                     {
585e7612134SGreg Clayton                         range.GetBaseAddress() = sc.symbol->GetAddress();
586e7612134SGreg Clayton                         range.SetByteSize (sc.symbol->GetByteSize());
587e7612134SGreg Clayton                     }
58830fdc8d8SChris Lattner                     else
589c14ee32dSGreg Clayton                         range.GetBaseAddress() = frame->GetFrameCodeAddress();
59030fdc8d8SChris Lattner                 }
59130fdc8d8SChris Lattner                 else
59230fdc8d8SChris Lattner                 {
59330fdc8d8SChris Lattner                     result.AppendError ("invalid frame");
59430fdc8d8SChris Lattner                     result.SetStatus (eReturnStatusFailed);
59530fdc8d8SChris Lattner                     return false;
59630fdc8d8SChris Lattner                 }
5972f2c876eSJim Ingham                 ranges.push_back(range);
59830fdc8d8SChris Lattner             }
5992f2c876eSJim Ingham 
6002f2c876eSJim Ingham             bool print_sc_header = ranges.size() > 1;
6012f2c876eSJim Ingham             for (AddressRange cur_range : ranges)
6022f2c876eSJim Ingham             {
6032f2c876eSJim Ingham                 if (cur_range.GetByteSize() == 0)
6042f2c876eSJim Ingham                     cur_range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
60530fdc8d8SChris Lattner 
606a7015092SGreg Clayton                 if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
60732e0a750SGreg Clayton                                                m_options.arch,
6081080edbcSGreg Clayton                                                plugin_name,
6090f063ba6SJim Ingham                                                flavor_string,
610f9fc609fSGreg Clayton                                                m_exe_ctx,
6112f2c876eSJim Ingham                                                cur_range,
61237023b06SJim Ingham                                                m_options.num_instructions,
613dda4f7b5SGreg Clayton                                                m_options.show_mixed ? m_options.num_lines_context : 0,
6141da6f9d7SGreg Clayton                                                options,
615dda4f7b5SGreg Clayton                                                result.GetOutputStream()))
61630fdc8d8SChris Lattner                 {
617dda4f7b5SGreg Clayton                     result.SetStatus (eReturnStatusSuccessFinishResult);
61830fdc8d8SChris Lattner                 }
61930fdc8d8SChris Lattner                 else
62030fdc8d8SChris Lattner                 {
621d01b2953SDaniel Malea                     result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
62230fdc8d8SChris Lattner                     result.SetStatus (eReturnStatusFailed);
62330fdc8d8SChris Lattner                 }
6242f2c876eSJim Ingham                 if (print_sc_header)
6252f2c876eSJim Ingham                     result.AppendMessage("\n");
6262f2c876eSJim Ingham             }
62730fdc8d8SChris Lattner         }
62837023b06SJim Ingham     }
62930fdc8d8SChris Lattner 
63030fdc8d8SChris Lattner     return result.Succeeded();
63130fdc8d8SChris Lattner }
632