Home | History | Annotate | Download | only in Commands
      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/Module.h"
     21 #include "lldb/Core/SourceManager.h"
     22 #include "lldb/Interpreter/Args.h"
     23 #include "lldb/Interpreter/CommandCompletions.h"
     24 #include "lldb/Interpreter/CommandInterpreter.h"
     25 #include "lldb/Interpreter/CommandReturnObject.h"
     26 #include "lldb/Interpreter/Options.h"
     27 #include "lldb/Symbol/Function.h"
     28 #include "lldb/Symbol/Symbol.h"
     29 #include "lldb/Target/Process.h"
     30 #include "lldb/Target/StackFrame.h"
     31 #include "lldb/Target/Target.h"
     32 
     33 #define DEFAULT_DISASM_BYTE_SIZE 32
     34 #define DEFAULT_DISASM_NUM_INS  4
     35 
     36 using namespace lldb;
     37 using namespace lldb_private;
     38 
     39 CommandObjectDisassemble::CommandOptions::CommandOptions (CommandInterpreter &interpreter) :
     40     Options(interpreter),
     41     num_lines_context(0),
     42     num_instructions (0),
     43     func_name(),
     44     current_function (false),
     45     start_addr(),
     46     end_addr (),
     47     at_pc (false),
     48     frame_line (false),
     49     plugin_name (),
     50     flavor_string(),
     51     arch(),
     52     some_location_specified (false),
     53     symbol_containing_addr ()
     54 {
     55     OptionParsingStarting();
     56 }
     57 
     58 CommandObjectDisassemble::CommandOptions::~CommandOptions ()
     59 {
     60 }
     61 
     62 Error
     63 CommandObjectDisassemble::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
     64 {
     65     Error error;
     66 
     67     const int short_option = m_getopt_table[option_idx].val;
     68 
     69     bool success;
     70 
     71     switch (short_option)
     72     {
     73     case 'm':
     74         show_mixed = true;
     75         break;
     76 
     77     case 'C':
     78         num_lines_context = Args::StringToUInt32(option_arg, 0, 0, &success);
     79         if (!success)
     80             error.SetErrorStringWithFormat ("invalid num context lines string: \"%s\"", option_arg);
     81         break;
     82 
     83     case 'c':
     84         num_instructions = Args::StringToUInt32(option_arg, 0, 0, &success);
     85         if (!success)
     86             error.SetErrorStringWithFormat ("invalid num of instructions string: \"%s\"", option_arg);
     87         break;
     88 
     89     case 'b':
     90         show_bytes = true;
     91         break;
     92 
     93     case 's':
     94         {
     95             ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
     96             start_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
     97             if (start_addr != LLDB_INVALID_ADDRESS)
     98                 some_location_specified = true;
     99         }
    100         break;
    101     case 'e':
    102         {
    103             ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
    104             end_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
    105             if (end_addr != LLDB_INVALID_ADDRESS)
    106                 some_location_specified = true;
    107         }
    108         break;
    109     case 'n':
    110         func_name.assign (option_arg);
    111         some_location_specified = true;
    112         break;
    113 
    114     case 'p':
    115         at_pc = true;
    116         some_location_specified = true;
    117         break;
    118 
    119     case 'l':
    120         frame_line = true;
    121         // Disassemble the current source line kind of implies showing mixed
    122         // source code context.
    123         show_mixed = true;
    124         some_location_specified = true;
    125         break;
    126 
    127     case 'P':
    128         plugin_name.assign (option_arg);
    129         break;
    130 
    131     case 'F':
    132         {
    133             Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
    134             if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86
    135                 || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64)
    136             {
    137                 flavor_string.assign (option_arg);
    138             }
    139             else
    140                 error.SetErrorStringWithFormat("Disassembler flavors are currently only supported for x86 and x86_64 targets.");
    141             break;
    142         }
    143     case 'r':
    144         raw = true;
    145         break;
    146 
    147     case 'f':
    148         current_function = true;
    149         some_location_specified = true;
    150         break;
    151 
    152     case 'A':
    153         if (!arch.SetTriple (option_arg, m_interpreter.GetPlatform (true).get()))
    154             arch.SetTriple (option_arg);
    155         break;
    156 
    157     case 'a':
    158         {
    159             ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
    160             symbol_containing_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
    161             if (symbol_containing_addr != LLDB_INVALID_ADDRESS)
    162             {
    163                 some_location_specified = true;
    164             }
    165         }
    166         break;
    167 
    168     default:
    169         error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
    170         break;
    171     }
    172 
    173     return error;
    174 }
    175 
    176 void
    177 CommandObjectDisassemble::CommandOptions::OptionParsingStarting ()
    178 {
    179     show_mixed = false;
    180     show_bytes = false;
    181     num_lines_context = 0;
    182     num_instructions = 0;
    183     func_name.clear();
    184     current_function = false;
    185     at_pc = false;
    186     frame_line = false;
    187     start_addr = LLDB_INVALID_ADDRESS;
    188     end_addr = LLDB_INVALID_ADDRESS;
    189     symbol_containing_addr = LLDB_INVALID_ADDRESS;
    190     raw = false;
    191     plugin_name.clear();
    192 
    193     Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
    194 
    195     // This is a hack till we get the ability to specify features based on architecture.  For now GetDisassemblyFlavor
    196     // is really only valid for x86 (and for the llvm assembler plugin, but I'm papering over that since that is the
    197     // only disassembler plugin we have...
    198     if (target)
    199     {
    200         if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86
    201             || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64)
    202         {
    203             flavor_string.assign(target->GetDisassemblyFlavor());
    204         }
    205         else
    206             flavor_string.assign ("default");
    207 
    208     }
    209     else
    210         flavor_string.assign("default");
    211 
    212     arch.Clear();
    213     some_location_specified = false;
    214 }
    215 
    216 Error
    217 CommandObjectDisassemble::CommandOptions::OptionParsingFinished ()
    218 {
    219     if (!some_location_specified)
    220         current_function = true;
    221     return Error();
    222 
    223 }
    224 
    225 const OptionDefinition*
    226 CommandObjectDisassemble::CommandOptions::GetDefinitions ()
    227 {
    228     return g_option_table;
    229 }
    230 
    231 OptionDefinition
    232 CommandObjectDisassemble::CommandOptions::g_option_table[] =
    233 {
    234 { LLDB_OPT_SET_ALL, false, "bytes"        , 'b', no_argument        , NULL, 0, eArgTypeNone,        "Show opcode bytes when disassembling."},
    235 { LLDB_OPT_SET_ALL, false, "context"      , 'C', required_argument  , NULL, 0, eArgTypeNumLines,    "Number of context lines of source to show."},
    236 { LLDB_OPT_SET_ALL, false, "mixed"        , 'm', no_argument        , NULL, 0, eArgTypeNone,        "Enable mixed source and assembly display."},
    237 { LLDB_OPT_SET_ALL, false, "raw"          , 'r', no_argument        , NULL, 0, eArgTypeNone,        "Print raw disassembly with no symbol information."},
    238 { LLDB_OPT_SET_ALL, false, "plugin"       , 'P', required_argument  , NULL, 0, eArgTypePlugin,      "Name of the disassembler plugin you want to use."},
    239 { LLDB_OPT_SET_ALL, false, "flavor"       , 'F', required_argument  , NULL, 0, eArgTypeDisassemblyFlavor,        "Name of the disassembly flavor you want to use.  "
    240                                                                                                     "Currently the only valid options are default, and for Intel"
    241                                                                                                     " architectures, att and intel."},
    242 { LLDB_OPT_SET_ALL, false, "arch"         , 'A', required_argument  , NULL, 0, eArgTypeArchitecture,"Specify the architecture to use from cross disassembly."},
    243 { LLDB_OPT_SET_1  |
    244   LLDB_OPT_SET_2  , true , "start-address", 's', required_argument  , NULL, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."},
    245 { LLDB_OPT_SET_1  , false, "end-address"  , 'e', required_argument  , NULL, 0, eArgTypeAddressOrExpression,  "Address at which to end disassembling."},
    246 { LLDB_OPT_SET_2  |
    247   LLDB_OPT_SET_3  |
    248   LLDB_OPT_SET_4  |
    249   LLDB_OPT_SET_5  , false, "count"        , 'c', required_argument  , NULL, 0, eArgTypeNumLines,    "Number of instructions to display."},
    250 { LLDB_OPT_SET_3  , false, "name"         , 'n', required_argument  , NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
    251                                                                                                     "Disassemble entire contents of the given function name."},
    252 { LLDB_OPT_SET_4  , false, "frame"        , 'f', no_argument        , NULL, 0, eArgTypeNone,        "Disassemble from the start of the current frame's function."},
    253 { LLDB_OPT_SET_5  , false, "pc"           , 'p', no_argument        , NULL, 0, eArgTypeNone,        "Disassemble around the current pc."},
    254 { 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."},
    255 { LLDB_OPT_SET_7  , false, "address"      , 'a', required_argument  , NULL, 0, eArgTypeAddressOrExpression, "Disassemble function containing this address."},
    256 { 0               , false, NULL           ,   0, 0                  , NULL, 0, eArgTypeNone,        NULL }
    257 };
    258 
    259 
    260 
    261 //-------------------------------------------------------------------------
    262 // CommandObjectDisassemble
    263 //-------------------------------------------------------------------------
    264 
    265 CommandObjectDisassemble::CommandObjectDisassemble (CommandInterpreter &interpreter) :
    266     CommandObjectParsed (interpreter,
    267                          "disassemble",
    268                          "Disassemble bytes in the current function, or elsewhere in the executable program as specified by the user.",
    269                          "disassemble [<cmd-options>]"),
    270     m_options (interpreter)
    271 {
    272 }
    273 
    274 CommandObjectDisassemble::~CommandObjectDisassemble()
    275 {
    276 }
    277 
    278 bool
    279 CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
    280 {
    281     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
    282     if (target == NULL)
    283     {
    284         result.AppendError ("invalid target, create a debug target using the 'target create' command");
    285         result.SetStatus (eReturnStatusFailed);
    286         return false;
    287     }
    288     if (!m_options.arch.IsValid())
    289         m_options.arch = target->GetArchitecture();
    290 
    291     if (!m_options.arch.IsValid())
    292     {
    293         result.AppendError ("use the --arch option or set the target architecure to disassemble");
    294         result.SetStatus (eReturnStatusFailed);
    295         return false;
    296     }
    297 
    298     const char *plugin_name = m_options.GetPluginName ();
    299     const char *flavor_string = m_options.GetFlavorString();
    300 
    301     DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
    302 
    303     if (!disassembler)
    304     {
    305         if (plugin_name)
    306         {
    307             result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n",
    308                                           plugin_name,
    309                                           m_options.arch.GetArchitectureName());
    310         }
    311         else
    312             result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n",
    313                                           m_options.arch.GetArchitectureName());
    314         result.SetStatus (eReturnStatusFailed);
    315         return false;
    316     }
    317     else if (flavor_string != NULL && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string))
    318         result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string);
    319 
    320     result.SetStatus (eReturnStatusSuccessFinishResult);
    321 
    322     if (command.GetArgumentCount() != 0)
    323     {
    324         result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n");
    325         GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this);
    326         result.SetStatus (eReturnStatusFailed);
    327         return false;
    328     }
    329 
    330     if (m_options.show_mixed && m_options.num_lines_context == 0)
    331         m_options.num_lines_context = 1;
    332 
    333     // Always show the PC in the disassembly
    334     uint32_t options = Disassembler::eOptionMarkPCAddress;
    335 
    336     // Mark the source line for the current PC only if we are doing mixed source and assembly
    337     if (m_options.show_mixed)
    338         options |= Disassembler::eOptionMarkPCSourceLine;
    339 
    340     if (m_options.show_bytes)
    341         options |= Disassembler::eOptionShowBytes;
    342 
    343     if (m_options.raw)
    344         options |= Disassembler::eOptionRawOuput;
    345 
    346     if (!m_options.func_name.empty())
    347     {
    348         ConstString name(m_options.func_name.c_str());
    349 
    350         if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
    351                                        m_options.arch,
    352                                        plugin_name,
    353                                        flavor_string,
    354                                        m_exe_ctx,
    355                                        name,
    356                                        NULL,    // Module *
    357                                        m_options.num_instructions,
    358                                        m_options.show_mixed ? m_options.num_lines_context : 0,
    359                                        options,
    360                                        result.GetOutputStream()))
    361         {
    362             result.SetStatus (eReturnStatusSuccessFinishResult);
    363         }
    364         else
    365         {
    366             result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
    367             result.SetStatus (eReturnStatusFailed);
    368         }
    369     }
    370     else
    371     {
    372         AddressRange range;
    373         StackFrame *frame = m_exe_ctx.GetFramePtr();
    374         if (m_options.frame_line)
    375         {
    376             if (frame == NULL)
    377             {
    378                 result.AppendError ("Cannot disassemble around the current line without a selected frame.\n");
    379                 result.SetStatus (eReturnStatusFailed);
    380                 return false;
    381             }
    382             LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
    383             if (pc_line_entry.IsValid())
    384             {
    385                 range = pc_line_entry.range;
    386             }
    387             else
    388             {
    389                 m_options.at_pc = true; // No line entry, so just disassemble around the current pc
    390                 m_options.show_mixed = false;
    391             }
    392         }
    393         else if (m_options.current_function)
    394         {
    395             if (frame == NULL)
    396             {
    397                 result.AppendError ("Cannot disassemble around the current function without a selected frame.\n");
    398                 result.SetStatus (eReturnStatusFailed);
    399                 return false;
    400             }
    401             Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
    402             if (symbol)
    403             {
    404                 range.GetBaseAddress() = symbol->GetAddress();
    405                 range.SetByteSize(symbol->GetByteSize());
    406             }
    407         }
    408 
    409         // Did the "m_options.frame_line" find a valid range already? If so
    410         // skip the rest...
    411         if (range.GetByteSize() == 0)
    412         {
    413             if (m_options.at_pc)
    414             {
    415                 if (frame == NULL)
    416                 {
    417                     result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n");
    418                     result.SetStatus (eReturnStatusFailed);
    419                     return false;
    420                 }
    421                 range.GetBaseAddress() = frame->GetFrameCodeAddress();
    422                 if (m_options.num_instructions == 0)
    423                 {
    424                     // Disassembling at the PC always disassembles some number of instructions (not the whole function).
    425                     m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
    426                 }
    427             }
    428             else
    429             {
    430                 range.GetBaseAddress().SetOffset (m_options.start_addr);
    431                 if (range.GetBaseAddress().IsValid())
    432                 {
    433                     if (m_options.end_addr != LLDB_INVALID_ADDRESS)
    434                     {
    435                         if (m_options.end_addr <= m_options.start_addr)
    436                         {
    437                             result.AppendErrorWithFormat ("End address before start address.\n");
    438                             result.SetStatus (eReturnStatusFailed);
    439                             return false;
    440                         }
    441                         range.SetByteSize (m_options.end_addr - m_options.start_addr);
    442                     }
    443                 }
    444                 else
    445                 {
    446                     if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS
    447                         && target
    448                         && !target->GetSectionLoadList().IsEmpty())
    449                     {
    450                         bool failed = false;
    451                         Address symbol_containing_address;
    452                         if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address))
    453                         {
    454                             ModuleSP module_sp (symbol_containing_address.GetModule());
    455                             SymbolContext sc;
    456                             module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc);
    457                             if (sc.function || sc.symbol)
    458                             {
    459                                 sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
    460                             }
    461                             else
    462                             {
    463                                 failed = true;
    464                             }
    465                         }
    466                         else
    467                         {
    468                             failed = true;
    469                         }
    470                         if (failed)
    471                         {
    472                             result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr);
    473                             result.SetStatus (eReturnStatusFailed);
    474                             return false;
    475                         }
    476                     }
    477                 }
    478             }
    479         }
    480 
    481         if (m_options.num_instructions != 0)
    482         {
    483             if (!range.GetBaseAddress().IsValid())
    484             {
    485                 // The default action is to disassemble the current frame function.
    486                 if (frame)
    487                 {
    488                     SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
    489                     if (sc.function)
    490                         range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress();
    491                     else if (sc.symbol && sc.symbol->ValueIsAddress())
    492                         range.GetBaseAddress() = sc.symbol->GetAddress();
    493                     else
    494                         range.GetBaseAddress() = frame->GetFrameCodeAddress();
    495                 }
    496 
    497                 if (!range.GetBaseAddress().IsValid())
    498                 {
    499                     result.AppendError ("invalid frame");
    500                     result.SetStatus (eReturnStatusFailed);
    501                     return false;
    502                 }
    503             }
    504 
    505             if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
    506                                            m_options.arch,
    507                                            plugin_name,
    508                                            flavor_string,
    509                                            m_exe_ctx,
    510                                            range.GetBaseAddress(),
    511                                            m_options.num_instructions,
    512                                            m_options.show_mixed ? m_options.num_lines_context : 0,
    513                                            options,
    514                                            result.GetOutputStream()))
    515             {
    516                 result.SetStatus (eReturnStatusSuccessFinishResult);
    517             }
    518             else
    519             {
    520                 result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
    521                 result.SetStatus (eReturnStatusFailed);
    522             }
    523         }
    524         else
    525         {
    526             if (!range.GetBaseAddress().IsValid())
    527             {
    528                 // The default action is to disassemble the current frame function.
    529                 if (frame)
    530                 {
    531                     SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
    532                     if (sc.function)
    533                         range = sc.function->GetAddressRange();
    534                     else if (sc.symbol && sc.symbol->ValueIsAddress())
    535                     {
    536                         range.GetBaseAddress() = sc.symbol->GetAddress();
    537                         range.SetByteSize (sc.symbol->GetByteSize());
    538                     }
    539                     else
    540                         range.GetBaseAddress() = frame->GetFrameCodeAddress();
    541                 }
    542                 else
    543                 {
    544                     result.AppendError ("invalid frame");
    545                     result.SetStatus (eReturnStatusFailed);
    546                     return false;
    547                 }
    548             }
    549             if (range.GetByteSize() == 0)
    550                 range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
    551 
    552             if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
    553                                            m_options.arch,
    554                                            plugin_name,
    555                                            flavor_string,
    556                                            m_exe_ctx,
    557                                            range,
    558                                            m_options.num_instructions,
    559                                            m_options.show_mixed ? m_options.num_lines_context : 0,
    560                                            options,
    561                                            result.GetOutputStream()))
    562             {
    563                 result.SetStatus (eReturnStatusSuccessFinishResult);
    564             }
    565             else
    566             {
    567                 result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
    568                 result.SetStatus (eReturnStatusFailed);
    569             }
    570         }
    571     }
    572 
    573     return result.Succeeded();
    574 }
    575