CommandObjectDisassemble.cpp revision 4968ad817597891cc02c195d4b3e7c3cde1fc391
1//===-- CommandObjectDisassemble.cpp ----------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/lldb-python.h"
11
12#include "CommandObjectDisassemble.h"
13
14// C Includes
15// C++ Includes
16// Other libraries and framework includes
17// Project includes
18#include "lldb/Core/AddressRange.h"
19#include "lldb/Core/Disassembler.h"
20#include "lldb/Core/SourceManager.h"
21#include "lldb/Interpreter/Args.h"
22#include "lldb/Interpreter/CommandCompletions.h"
23#include "lldb/Interpreter/CommandInterpreter.h"
24#include "lldb/Interpreter/CommandReturnObject.h"
25#include "lldb/Interpreter/Options.h"
26#include "lldb/Symbol/Function.h"
27#include "lldb/Symbol/Symbol.h"
28#include "lldb/Target/Process.h"
29#include "lldb/Target/StackFrame.h"
30#include "lldb/Target/Target.h"
31
32#define DEFAULT_DISASM_BYTE_SIZE 32
33#define DEFAULT_DISASM_NUM_INS  4
34
35using namespace lldb;
36using namespace lldb_private;
37
38CommandObjectDisassemble::CommandOptions::CommandOptions (CommandInterpreter &interpreter) :
39    Options(interpreter),
40    num_lines_context(0),
41    num_instructions (0),
42    func_name(),
43    current_function (false),
44    start_addr(),
45    end_addr (),
46    at_pc (false),
47    frame_line (false),
48    plugin_name (),
49    arch(),
50    some_location_specified (false)
51{
52    OptionParsingStarting();
53}
54
55CommandObjectDisassemble::CommandOptions::~CommandOptions ()
56{
57}
58
59Error
60CommandObjectDisassemble::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
61{
62    Error error;
63
64    const int short_option = m_getopt_table[option_idx].val;
65
66    bool success;
67
68    switch (short_option)
69    {
70    case 'm':
71        show_mixed = true;
72        break;
73
74    case 'C':
75        num_lines_context = Args::StringToUInt32(option_arg, 0, 0, &success);
76        if (!success)
77            error.SetErrorStringWithFormat ("invalid num context lines string: \"%s\"", option_arg);
78        break;
79
80    case 'c':
81        num_instructions = Args::StringToUInt32(option_arg, 0, 0, &success);
82        if (!success)
83            error.SetErrorStringWithFormat ("invalid num of instructions string: \"%s\"", option_arg);
84        break;
85
86    case 'b':
87        show_bytes = true;
88        break;
89
90    case 's':
91        {
92            ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
93            start_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
94            if (start_addr != LLDB_INVALID_ADDRESS)
95                some_location_specified = true;
96        }
97        break;
98    case 'e':
99        {
100            ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
101            end_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
102            if (end_addr != LLDB_INVALID_ADDRESS)
103                some_location_specified = true;
104        }
105        break;
106    case 'n':
107        func_name.assign (option_arg);
108        some_location_specified = true;
109        break;
110
111    case 'p':
112        at_pc = true;
113        some_location_specified = true;
114        break;
115
116    case 'l':
117        frame_line = true;
118        // Disassemble the current source line kind of implies showing mixed
119        // source code context.
120        show_mixed = true;
121        some_location_specified = true;
122        break;
123
124    case 'P':
125        plugin_name.assign (option_arg);
126        break;
127
128    case 'r':
129        raw = true;
130        break;
131
132    case 'f':
133        current_function = true;
134        some_location_specified = true;
135        break;
136
137    case 'a':
138        if (!arch.SetTriple (option_arg, m_interpreter.GetPlatform (true).get()))
139            arch.SetTriple (option_arg);
140        break;
141
142    default:
143        error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
144        break;
145    }
146
147    return error;
148}
149
150void
151CommandObjectDisassemble::CommandOptions::OptionParsingStarting ()
152{
153    show_mixed = false;
154    show_bytes = false;
155    num_lines_context = 0;
156    num_instructions = 0;
157    func_name.clear();
158    current_function = false;
159    at_pc = false;
160    frame_line = false;
161    start_addr = LLDB_INVALID_ADDRESS;
162    end_addr = LLDB_INVALID_ADDRESS;
163    raw = false;
164    plugin_name.clear();
165    arch.Clear();
166    some_location_specified = false;
167}
168
169Error
170CommandObjectDisassemble::CommandOptions::OptionParsingFinished ()
171{
172    if (!some_location_specified)
173        current_function = true;
174    return Error();
175
176}
177
178const OptionDefinition*
179CommandObjectDisassemble::CommandOptions::GetDefinitions ()
180{
181    return g_option_table;
182}
183
184OptionDefinition
185CommandObjectDisassemble::CommandOptions::g_option_table[] =
186{
187{ LLDB_OPT_SET_ALL, false, "bytes"        , 'b', no_argument        , NULL, 0, eArgTypeNone,        "Show opcode bytes when disassembling."},
188{ LLDB_OPT_SET_ALL, false, "context"      , 'C', required_argument  , NULL, 0, eArgTypeNumLines,    "Number of context lines of source to show."},
189{ LLDB_OPT_SET_ALL, false, "mixed"        , 'm', no_argument        , NULL, 0, eArgTypeNone,        "Enable mixed source and assembly display."},
190{ LLDB_OPT_SET_ALL, false, "raw"          , 'r', no_argument        , NULL, 0, eArgTypeNone,        "Print raw disassembly with no symbol information."},
191{ LLDB_OPT_SET_ALL, false, "plugin"       , 'P', required_argument  , NULL, 0, eArgTypePlugin,      "Name of the disassembler plugin you want to use."},
192{ LLDB_OPT_SET_ALL, false, "arch"         , 'a', required_argument  , NULL, 0, eArgTypeArchitecture,"Specify the architecture to use from cross disassembly."},
193{ LLDB_OPT_SET_1  |
194  LLDB_OPT_SET_2  , true , "start-address", 's', required_argument  , NULL, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."},
195{ LLDB_OPT_SET_1  , false, "end-address"  , 'e', required_argument  , NULL, 0, eArgTypeAddressOrExpression,  "Address at which to end disassembling."},
196{ LLDB_OPT_SET_2  |
197  LLDB_OPT_SET_3  |
198  LLDB_OPT_SET_4  |
199  LLDB_OPT_SET_5  , false, "count"        , 'c', required_argument  , NULL, 0, eArgTypeNumLines,    "Number of instructions to display."},
200{ LLDB_OPT_SET_3  , false, "name"         , 'n', required_argument  , NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
201                                                                                                    "Disassemble entire contents of the given function name."},
202{ LLDB_OPT_SET_4  , false, "frame"        , 'f', no_argument        , NULL, 0, eArgTypeNone,        "Disassemble from the start of the current frame's function."},
203{ LLDB_OPT_SET_5  , false, "pc"           , 'p', no_argument        , NULL, 0, eArgTypeNone,        "Disassemble around the current pc."},
204{ LLDB_OPT_SET_6  , false, "line"         , 'l', no_argument        , NULL, 0, eArgTypeNone,        "Disassemble the current frame's current source line instructions if there debug line table information, else disasemble around the pc."},
205{ 0               , false, NULL           ,   0, 0                  , NULL, 0, eArgTypeNone,        NULL }
206};
207
208
209
210//-------------------------------------------------------------------------
211// CommandObjectDisassemble
212//-------------------------------------------------------------------------
213
214CommandObjectDisassemble::CommandObjectDisassemble (CommandInterpreter &interpreter) :
215    CommandObjectParsed (interpreter,
216                         "disassemble",
217                         "Disassemble bytes in the current function, or elsewhere in the executable program as specified by the user.",
218                         "disassemble [<cmd-options>]"),
219    m_options (interpreter)
220{
221}
222
223CommandObjectDisassemble::~CommandObjectDisassemble()
224{
225}
226
227bool
228CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
229{
230    Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
231    if (target == NULL)
232    {
233        result.AppendError ("invalid target, create a debug target using the 'target create' command");
234        result.SetStatus (eReturnStatusFailed);
235        return false;
236    }
237    if (!m_options.arch.IsValid())
238        m_options.arch = target->GetArchitecture();
239
240    if (!m_options.arch.IsValid())
241    {
242        result.AppendError ("use the --arch option or set the target architecure to disassemble");
243        result.SetStatus (eReturnStatusFailed);
244        return false;
245    }
246
247    const char *plugin_name = m_options.GetPluginName ();
248    DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, plugin_name);
249
250    if (!disassembler)
251    {
252        if (plugin_name)
253            result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n",
254                                          plugin_name,
255                                          m_options.arch.GetArchitectureName());
256        else
257            result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n",
258                                          m_options.arch.GetArchitectureName());
259        result.SetStatus (eReturnStatusFailed);
260        return false;
261    }
262
263    result.SetStatus (eReturnStatusSuccessFinishResult);
264
265    if (command.GetArgumentCount() != 0)
266    {
267        result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n");
268        GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this);
269        result.SetStatus (eReturnStatusFailed);
270        return false;
271    }
272
273    if (m_options.show_mixed && m_options.num_lines_context == 0)
274        m_options.num_lines_context = 1;
275
276    // Always show the PC in the disassembly
277    uint32_t options = Disassembler::eOptionMarkPCAddress;
278
279    // Mark the source line for the current PC only if we are doing mixed source and assembly
280    if (m_options.show_mixed)
281        options |= Disassembler::eOptionMarkPCSourceLine;
282
283    if (m_options.show_bytes)
284        options |= Disassembler::eOptionShowBytes;
285
286    if (m_options.raw)
287        options |= Disassembler::eOptionRawOuput;
288
289    if (!m_options.func_name.empty())
290    {
291        ConstString name(m_options.func_name.c_str());
292
293        if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
294                                       m_options.arch,
295                                       plugin_name,
296                                       m_exe_ctx,
297                                       name,
298                                       NULL,    // Module *
299                                       m_options.num_instructions,
300                                       m_options.show_mixed ? m_options.num_lines_context : 0,
301                                       options,
302                                       result.GetOutputStream()))
303        {
304            result.SetStatus (eReturnStatusSuccessFinishResult);
305        }
306        else
307        {
308            result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
309            result.SetStatus (eReturnStatusFailed);
310        }
311    }
312    else
313    {
314        AddressRange range;
315        StackFrame *frame = m_exe_ctx.GetFramePtr();
316        if (m_options.frame_line)
317        {
318            if (frame == NULL)
319            {
320                result.AppendError ("Cannot disassemble around the current line without a selected frame.\n");
321                result.SetStatus (eReturnStatusFailed);
322                return false;
323            }
324            LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
325            if (pc_line_entry.IsValid())
326            {
327                range = pc_line_entry.range;
328            }
329            else
330            {
331                m_options.at_pc = true; // No line entry, so just disassemble around the current pc
332                m_options.show_mixed = false;
333            }
334        }
335        else if (m_options.current_function)
336        {
337            if (frame == NULL)
338            {
339                result.AppendError ("Cannot disassemble around the current function without a selected frame.\n");
340                result.SetStatus (eReturnStatusFailed);
341                return false;
342            }
343            Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
344            if (symbol)
345            {
346                range.GetBaseAddress() = symbol->GetAddress();
347                range.SetByteSize(symbol->GetByteSize());
348            }
349        }
350
351        // Did the "m_options.frame_line" find a valid range already? If so
352        // skip the rest...
353        if (range.GetByteSize() == 0)
354        {
355            if (m_options.at_pc)
356            {
357                if (frame == NULL)
358                {
359                    result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n");
360                    result.SetStatus (eReturnStatusFailed);
361                    return false;
362                }
363                range.GetBaseAddress() = frame->GetFrameCodeAddress();
364                if (m_options.num_instructions == 0)
365                {
366                    // Disassembling at the PC always disassembles some number of instructions (not the whole function).
367                    m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
368                }
369            }
370            else
371            {
372                range.GetBaseAddress().SetOffset (m_options.start_addr);
373                if (range.GetBaseAddress().IsValid())
374                {
375                    if (m_options.end_addr != LLDB_INVALID_ADDRESS)
376                    {
377                        if (m_options.end_addr <= m_options.start_addr)
378                        {
379                            result.AppendErrorWithFormat ("End address before start address.\n");
380                            result.SetStatus (eReturnStatusFailed);
381                            return false;
382                        }
383                        range.SetByteSize (m_options.end_addr - m_options.start_addr);
384                    }
385                }
386            }
387        }
388
389        if (m_options.num_instructions != 0)
390        {
391            if (!range.GetBaseAddress().IsValid())
392            {
393                // The default action is to disassemble the current frame function.
394                if (frame)
395                {
396                    SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
397                    if (sc.function)
398                        range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress();
399                    else if (sc.symbol && sc.symbol->ValueIsAddress())
400                        range.GetBaseAddress() = sc.symbol->GetAddress();
401                    else
402                        range.GetBaseAddress() = frame->GetFrameCodeAddress();
403                }
404
405                if (!range.GetBaseAddress().IsValid())
406                {
407                    result.AppendError ("invalid frame");
408                    result.SetStatus (eReturnStatusFailed);
409                    return false;
410                }
411            }
412
413            if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
414                                           m_options.arch,
415                                           plugin_name,
416                                           m_exe_ctx,
417                                           range.GetBaseAddress(),
418                                           m_options.num_instructions,
419                                           m_options.show_mixed ? m_options.num_lines_context : 0,
420                                           options,
421                                           result.GetOutputStream()))
422            {
423                result.SetStatus (eReturnStatusSuccessFinishResult);
424            }
425            else
426            {
427                result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
428                result.SetStatus (eReturnStatusFailed);
429            }
430        }
431        else
432        {
433            if (!range.GetBaseAddress().IsValid())
434            {
435                // The default action is to disassemble the current frame function.
436                if (frame)
437                {
438                    SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
439                    if (sc.function)
440                        range = sc.function->GetAddressRange();
441                    else if (sc.symbol && sc.symbol->ValueIsAddress())
442                    {
443                        range.GetBaseAddress() = sc.symbol->GetAddress();
444                        range.SetByteSize (sc.symbol->GetByteSize());
445                    }
446                    else
447                        range.GetBaseAddress() = frame->GetFrameCodeAddress();
448                }
449                else
450                {
451                    result.AppendError ("invalid frame");
452                    result.SetStatus (eReturnStatusFailed);
453                    return false;
454                }
455            }
456            if (range.GetByteSize() == 0)
457                range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
458
459            if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
460                                           m_options.arch,
461                                           plugin_name,
462                                           m_exe_ctx,
463                                           range,
464                                           m_options.num_instructions,
465                                           m_options.show_mixed ? m_options.num_lines_context : 0,
466                                           options,
467                                           result.GetOutputStream()))
468            {
469                result.SetStatus (eReturnStatusSuccessFinishResult);
470            }
471            else
472            {
473                result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
474                result.SetStatus (eReturnStatusFailed);
475            }
476        }
477    }
478
479    return result.Succeeded();
480}
481