CommandObjectDisassemble.cpp revision 24943d2ee8bfaa7cf5893e4709143924157a5c1e
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 "CommandObjectDisassemble.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Core/AddressRange.h"
17#include "lldb/Core/Args.h"
18#include "lldb/Interpreter/CommandCompletions.h"
19#include "lldb/Interpreter/CommandInterpreter.h"
20#include "lldb/Interpreter/CommandReturnObject.h"
21#include "lldb/Core/Disassembler.h"
22#include "lldb/Core/Options.h"
23#include "lldb/Core/SourceManager.h"
24#include "lldb/Target/StackFrame.h"
25#include "lldb/Symbol/Symbol.h"
26#include "lldb/Target/Process.h"
27#include "lldb/Target/Target.h"
28
29#define DEFAULT_DISASM_BYTE_SIZE 32
30
31using namespace lldb;
32using namespace lldb_private;
33
34CommandObjectDisassemble::CommandOptions::CommandOptions () :
35    Options(),
36    m_func_name(),
37    m_load_addr()
38{
39    ResetOptionValues();
40}
41
42CommandObjectDisassemble::CommandOptions::~CommandOptions ()
43{
44}
45
46Error
47CommandObjectDisassemble::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
48{
49    Error error;
50
51    char short_option = (char) m_getopt_table[option_idx].val;
52
53    switch (short_option)
54    {
55    case 'm':
56        show_mixed = true;
57        break;
58
59    case 'c':
60        num_lines_context = Args::StringToUInt32(option_arg, 0, 0);
61        break;
62
63    case 'b':
64        show_bytes = true;
65        break;
66
67    case 'a':
68        m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 0);
69        if (m_load_addr == LLDB_INVALID_ADDRESS)
70            m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 16);
71
72        if (m_load_addr == LLDB_INVALID_ADDRESS)
73            error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", optarg);
74        break;
75
76    case 'n':
77        m_func_name = option_arg;
78        break;
79
80    case 'r':
81        raw = true;
82        break;
83
84    default:
85        error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
86        break;
87    }
88
89    return error;
90}
91
92void
93CommandObjectDisassemble::CommandOptions::ResetOptionValues ()
94{
95    Options::ResetOptionValues();
96    show_mixed = false;
97    show_bytes = false;
98    num_lines_context = 0;
99    m_func_name.clear();
100    m_load_addr = LLDB_INVALID_ADDRESS;
101}
102
103const lldb::OptionDefinition*
104CommandObjectDisassemble::CommandOptions::GetDefinitions ()
105{
106    return g_option_table;
107}
108
109lldb::OptionDefinition
110CommandObjectDisassemble::CommandOptions::g_option_table[] =
111{
112{ 0, false, "bytes",    'b', no_argument,       NULL, 0, NULL,             "Show opcode bytes when disassembling."},
113{ 0, false, "context",  'c', required_argument, NULL, 0, "<num-lines>",    "Number of context lines of source to show."},
114{ 0, false, "mixed",    'm', no_argument,       NULL, 0, NULL,             "Enable mixed source and assembly display."},
115{ 0, false, "raw",      'r', no_argument,       NULL, 0, NULL,             "Print raw disassembly with no symbol information."},
116
117{ 1, false, "address",  'a', required_argument, NULL, 0, "<address>",      "Address to start disassembling."},
118{ 1, false, "bytes",    'b', no_argument,       NULL, 0, NULL,             "Show opcode bytes when disassembling."},
119{ 1, false, "context",  'c', required_argument, NULL, 0, "<num-lines>",    "Number of context lines of source to show."},
120{ 1, false, "mixed",    'm', no_argument,       NULL, 0, NULL,             "Enable mixed source and assembly display."},
121{ 1, false, "raw",      'r', no_argument,       NULL, 0, NULL,             "Print raw disassembly with no symbol information."},
122
123{ 2, false, "name",     'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, "<function-name>",             "Disassemble entire contents of the given function name."},
124{ 2, false, "bytes",    'b', no_argument,       NULL, 0, NULL,             "Show opcode bytes when disassembling."},
125{ 2, false, "context",  'c', required_argument, NULL, 0, "<num-lines>",    "Number of context lines of source to show."},
126{ 2, false, "mixed",    'm', no_argument,       NULL, 0, NULL,             "Enable mixed source and assembly display."},
127{ 2, false, "raw",      'r', no_argument,       NULL, 0, NULL,             "Print raw disassembly with no symbol information."},
128
129{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
130};
131
132
133
134//-------------------------------------------------------------------------
135// CommandObjectDisassemble
136//-------------------------------------------------------------------------
137
138CommandObjectDisassemble::CommandObjectDisassemble () :
139    CommandObject ("disassemble",
140                     "Disassemble bytes in the current function or anywhere in the inferior program.",
141                     "disassemble [[<start-addr> [<end-addr>]] | <function-name>] [<cmd-options>]")
142{
143}
144
145CommandObjectDisassemble::~CommandObjectDisassemble()
146{
147}
148
149void
150CommandObjectDisassemble::Disassemble
151(
152    CommandContext *context,
153    CommandInterpreter *interpreter,
154    CommandReturnObject &result,
155    Disassembler *disassembler,
156    const SymbolContextList &sc_list
157)
158{
159    const size_t count = sc_list.GetSize();
160    SymbolContext sc;
161    AddressRange range;
162    for (size_t i=0; i<count; ++i)
163    {
164        if (sc_list.GetContextAtIndex(i, sc) == false)
165            break;
166        if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, range))
167        {
168            lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(context->GetExecutionContext().process);
169            if (addr != LLDB_INVALID_ADDRESS)
170            {
171                lldb::addr_t end_addr = addr + range.GetByteSize();
172                Disassemble (context, interpreter, result, disassembler, addr, end_addr);
173            }
174        }
175    }
176}
177
178void
179CommandObjectDisassemble::Disassemble
180(
181    CommandContext *context,
182    CommandInterpreter *interpreter,
183    CommandReturnObject &result,
184    Disassembler *disassembler,
185    lldb::addr_t addr,
186    lldb::addr_t end_addr
187)
188{
189    if (addr == LLDB_INVALID_ADDRESS)
190        return;
191
192    if (end_addr == LLDB_INVALID_ADDRESS || addr >= end_addr)
193        end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
194
195    ExecutionContext exe_ctx (context->GetExecutionContext());
196    DataExtractor data;
197    size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, eAddressTypeLoad, addr, end_addr - addr, data);
198    if (bytes_disassembled == 0)
199    {
200        // Nothing got disassembled...
201    }
202    else
203    {
204        // We got some things disassembled...
205        size_t num_instructions = disassembler->GetInstructionList().GetSize();
206        uint32_t offset = 0;
207        Stream &output_stream = result.GetOutputStream();
208        SymbolContext sc;
209        SymbolContext prev_sc;
210        AddressRange sc_range;
211        if (m_options.show_mixed)
212            output_stream.IndentMore ();
213
214        for (size_t i=0; i<num_instructions; ++i)
215        {
216            Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i);
217            if (inst)
218            {
219                lldb::addr_t curr_addr = addr + offset;
220                if (m_options.show_mixed)
221                {
222                    Process *process = context->GetExecutionContext().process;
223                    if (!sc_range.ContainsLoadAddress (curr_addr, process))
224                    {
225                        prev_sc = sc;
226                        Address curr_so_addr;
227                        if (process && process->ResolveLoadAddress (curr_addr, curr_so_addr))
228                        {
229                            if (curr_so_addr.GetSection())
230                            {
231                                Module *module = curr_so_addr.GetSection()->GetModule();
232                                uint32_t resolved_mask = module->ResolveSymbolContextForAddress(curr_so_addr, eSymbolContextEverything, sc);
233                                if (resolved_mask)
234                                {
235                                    sc.GetAddressRange (eSymbolContextEverything, sc_range);
236                                    if (sc != prev_sc)
237                                    {
238                                        if (offset != 0)
239                                            output_stream.EOL();
240
241                                        sc.DumpStopContext(&output_stream, process, curr_so_addr);
242                                        output_stream.EOL();
243                                        if (sc.comp_unit && sc.line_entry.IsValid())
244                                        {
245                                            interpreter->GetSourceManager().DisplaySourceLinesWithLineNumbers (
246                                                    sc.line_entry.file,
247                                                    sc.line_entry.line,
248                                                    m_options.num_lines_context,
249                                                    m_options.num_lines_context,
250                                                    m_options.num_lines_context ? "->" : "",
251                                                    &output_stream);
252                                        }
253                                    }
254                                }
255                            }
256                        }
257                    }
258                }
259                if (m_options.show_mixed)
260                    output_stream.IndentMore ();
261                output_stream.Indent();
262                size_t inst_byte_size = inst->GetByteSize();
263                inst->Dump(&output_stream, curr_addr, m_options.show_bytes ? &data : NULL, offset, exe_ctx, m_options.raw);
264                output_stream.EOL();
265                offset += inst_byte_size;
266                if (m_options.show_mixed)
267                    output_stream.IndentLess ();
268            }
269            else
270            {
271                break;
272            }
273        }
274        if (m_options.show_mixed)
275            output_stream.IndentLess ();
276
277    }
278}
279
280bool
281CommandObjectDisassemble::Execute
282(
283    Args& command,
284    CommandContext *context,
285    CommandInterpreter *interpreter,
286    CommandReturnObject &result
287)
288{
289    Target *target = context->GetTarget();
290    if (target == NULL)
291    {
292        result.AppendError ("invalid target, set executable file using 'file' command");
293        result.SetStatus (eReturnStatusFailed);
294        return false;
295    }
296
297    ArchSpec arch(target->GetArchitecture());
298    if (!arch.IsValid())
299    {
300        result.AppendError ("target needs valid architecure in order to be able to disassemble");
301        result.SetStatus (eReturnStatusFailed);
302        return false;
303    }
304
305    Disassembler *disassembler = Disassembler::FindPlugin(arch);
306
307    if (disassembler == NULL)
308    {
309        result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for %s architecture.\n", arch.AsCString());
310        result.SetStatus (eReturnStatusFailed);
311        return false;
312    }
313
314    result.SetStatus (eReturnStatusSuccessFinishResult);
315
316    lldb::addr_t addr = LLDB_INVALID_ADDRESS;
317    lldb::addr_t end_addr = LLDB_INVALID_ADDRESS;
318    ConstString name;
319    const size_t argc = command.GetArgumentCount();
320    if (argc == 0 && m_options.m_load_addr != LLDB_INVALID_ADDRESS)
321    {
322        addr = m_options.m_load_addr;
323        end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
324    } else if (argc == 0 && !m_options.m_func_name.empty())
325    {
326        ConstString tmpname(m_options.m_func_name.c_str());
327        name = tmpname;
328    } else if (argc == 0)
329    {
330        ExecutionContext exe_ctx(context->GetExecutionContext());
331        if (exe_ctx.frame)
332        {
333            SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
334            if (sc.function)
335            {
336                addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(exe_ctx.process);
337                if (addr != LLDB_INVALID_ADDRESS)
338                    end_addr = addr + sc.function->GetAddressRange().GetByteSize();
339            }
340            else if (sc.symbol && sc.symbol->GetAddressRangePtr())
341            {
342                addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(exe_ctx.process);
343                if (addr != LLDB_INVALID_ADDRESS)
344                {
345                    end_addr = addr + sc.symbol->GetAddressRangePtr()->GetByteSize();
346                    if (addr == end_addr)
347                        end_addr += DEFAULT_DISASM_BYTE_SIZE;
348                }
349            }
350            else
351            {
352                addr = exe_ctx.frame->GetPC().GetLoadAddress(exe_ctx.process);
353                if (addr != LLDB_INVALID_ADDRESS)
354                    end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
355            }
356        }
357        else
358        {
359            result.AppendError ("invalid frame");
360            result.SetStatus (eReturnStatusFailed);
361            return false;
362        }
363    }
364    else if (argc == 1)
365    {
366        const char *arg = command.GetArgumentAtIndex(0);
367        addr = Args::StringToAddress (arg);
368        if (addr == LLDB_INVALID_ADDRESS)
369        {
370            // Lookup function or symbol name?
371            ConstString tmpname(arg);
372            name = tmpname;
373        }
374        else
375        {
376            end_addr = addr + DEFAULT_DISASM_BYTE_SIZE;
377        }
378    }
379    else if (argc >= 1 && argc <= 2)
380    {
381        addr = Args::StringToAddress (command.GetArgumentAtIndex(0));
382        if (addr == LLDB_INVALID_ADDRESS)
383        {
384            result.AppendErrorWithFormat ("Unable to parse address '%s'.\n", command.GetArgumentAtIndex(0));
385            result.SetStatus (eReturnStatusFailed);
386            return false;
387        }
388        end_addr = Args::StringToAddress (command.GetArgumentAtIndex(1), addr);
389        if (end_addr == LLDB_INVALID_ADDRESS)
390        {
391            result.AppendErrorWithFormat ("Unable to parse address '%s'.\n", command.GetArgumentAtIndex(1));
392            result.SetStatus (eReturnStatusFailed);
393            return false;
394        }
395    }
396
397    if (!name.IsEmpty())
398    {
399        SymbolContextList sc_list;
400
401        if (target->GetImages().FindFunctions(name, sc_list))
402        {
403            Disassemble (context, interpreter, result, disassembler, sc_list);
404        }
405        else if (target->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeCode, sc_list))
406        {
407            Disassemble (context, interpreter, result, disassembler, sc_list);
408        }
409        else
410        {
411            result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
412            result.SetStatus (eReturnStatusFailed);
413            return false;
414        }
415    }
416
417    if (addr < end_addr)
418    {
419        Disassemble (context, interpreter, result, disassembler, addr, end_addr);
420    }
421
422    if (addr == LLDB_INVALID_ADDRESS && name.IsEmpty())
423    {
424        result.AppendError ("No recognizable address of function name provided");
425        result.SetStatus (eReturnStatusFailed);
426        return false;
427    }
428    {
429        return result.Succeeded();
430    }
431}
432