Home | History | Annotate | Download | only in lookup
      1 //===-- main.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 <getopt.h>
     11 #include <stdint.h>
     12 #include <stdlib.h>
     13 
     14 #if defined(__APPLE__)
     15 #include <LLDB/LLDB.h>
     16 #else
     17 #include "LLDB/SBBlock.h"
     18 #include "LLDB/SBCompileUnit.h"
     19 #include "LLDB/SBDebugger.h"
     20 #include "LLDB/SBFunction.h"
     21 #include "LLDB/SBModule.h"
     22 #include "LLDB/SBStream.h"
     23 #include "LLDB/SBSymbol.h"
     24 #include "LLDB/SBTarget.h"
     25 #include "LLDB/SBThread.h"
     26 #include "LLDB/SBProcess.h"
     27 #endif
     28 
     29 #include <string>
     30 
     31 using namespace lldb;
     32 
     33 //----------------------------------------------------------------------
     34 // This quick sample code shows how to create a debugger instance and
     35 // create an "i386" executable target. Then we can lookup the executable
     36 // module and resolve a file address into a section offset address,
     37 // and find all symbol context objects (if any) for that address:
     38 // compile unit, function, deepest block, line table entry and the
     39 // symbol.
     40 //
     41 // To build the program, type (while in this directory):
     42 //
     43 //    $ make
     44 //
     45 // then (for example):
     46 //
     47 //    $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/svn/ToT/build/Debug ./a.out executable_path file_address
     48 //----------------------------------------------------------------------
     49 class LLDBSentry
     50 {
     51 public:
     52     LLDBSentry() {
     53         // Initialize LLDB
     54         SBDebugger::Initialize();
     55     }
     56     ~LLDBSentry() {
     57         // Terminate LLDB
     58         SBDebugger::Terminate();
     59     }
     60 };
     61 
     62 static struct option g_long_options[] =
     63 {
     64     { "help",       no_argument,        NULL, 'h' },
     65     { "verbose",    no_argument,        NULL, 'v' },
     66 	{ "arch",		required_argument,	NULL, 'a' },
     67 	{ "platform",   required_argument,	NULL, 'p' },
     68 	{ NULL,			0,					NULL,  0  }
     69 };
     70 
     71 #define PROGRAM_NAME "lldb-lookup"
     72 void
     73 usage ()
     74 {
     75     puts (
     76     "NAME\n"
     77     "    " PROGRAM_NAME " -- symbolicate addresses using lldb.\n"
     78     "\n"
     79     "SYNOPSIS\n"
     80     "    " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] [--verbose] [--help] --] <PATH> <ADDRESS> [<ADDRESS>....]\n"
     81     "\n"
     82     "DESCRIPTION\n"
     83     "    Loads the executable pointed to by <PATH> and looks up and <ADDRESS>\n"
     84     "    arguments\n"
     85     "\n"
     86     "EXAMPLE\n"
     87     "   " PROGRAM_NAME " --arch=x86_64 -- /usr/lib/dyld 0x100000000\n"
     88     );
     89     exit(0);
     90 }
     91 int
     92 main (int argc, char const *argv[])
     93 {
     94     // Use a sentry object to properly initialize/terminate LLDB.
     95     LLDBSentry sentry;
     96 
     97     SBDebugger debugger (SBDebugger::Create());
     98 
     99     // Create a debugger instance so we can create a target
    100     if (!debugger.IsValid())
    101         fprintf (stderr, "error: failed to create a debugger object\n");
    102 
    103     bool show_usage = false;
    104     bool verbose = false;
    105     const char *arch = NULL;
    106     const char *platform = NULL;
    107     std::string short_options("h?");
    108     for (const struct option *opt = g_long_options; opt->name; ++opt)
    109     {
    110         if (isprint(opt->val))
    111         {
    112             short_options.append(1, (char)opt->val);
    113             switch (opt->has_arg)
    114             {
    115             case no_argument:
    116                 break;
    117             case required_argument:
    118                 short_options.append(1, ':');
    119                 break;
    120             case optional_argument:
    121                 short_options.append(2, ':');
    122                 break;
    123             }
    124         }
    125     }
    126 #ifdef __GLIBC__
    127     optind = 0;
    128 #else
    129     optreset = 1;
    130     optind = 1;
    131 #endif
    132     char ch;
    133 	while ((ch = getopt_long_only(argc, (char * const *)argv, short_options.c_str(), g_long_options, 0)) != -1)
    134 	{
    135 		switch (ch)
    136 		{
    137         case 0:
    138             break;
    139 
    140 		case 'a':
    141 		    if (arch != NULL)
    142 		    {
    143                 fprintf (stderr, "error: the --arch option can only be specified once\n");
    144                 exit(1);
    145 		    }
    146             arch = optarg;
    147 			break;
    148 
    149         case 'p':
    150             platform = optarg;
    151             break;
    152 
    153         case 'v':
    154             verbose = true;
    155             break;
    156 
    157 		case 'h':
    158 		case '?':
    159 		default:
    160 			show_usage = true;
    161 			break;
    162 		}
    163 	}
    164 	argc -= optind;
    165 	argv += optind;
    166 
    167     if (show_usage || argc < 2)
    168         usage();
    169 
    170     int arg_idx = 0;
    171     // The first argument is the file path we want to look something up in
    172     const char *exe_file_path = argv[arg_idx];
    173     const char *addr_cstr;
    174     const bool add_dependent_libs = false;
    175     SBError error;
    176     SBStream strm;
    177     strm.RedirectToFileHandle (stdout, false);
    178 
    179     while ((addr_cstr = argv[++arg_idx]) != NULL)
    180     {
    181         // The second argument in the address that we want to lookup
    182         lldb::addr_t file_addr = strtoull (addr_cstr, NULL, 0);
    183 
    184         // Create a target using the executable.
    185         SBTarget target = debugger.CreateTarget (exe_file_path,
    186                                                  arch,
    187                                                  platform,
    188                                                  add_dependent_libs,
    189                                                  error);
    190         if (!error.Success())
    191         {
    192             fprintf (stderr, "error: %s\n", error.GetCString());
    193             exit(1);
    194         }
    195 
    196         printf ("%sLooking up 0x%llx in '%s':\n", (arg_idx > 1) ? "\n" : "", file_addr, exe_file_path);
    197 
    198         if (target.IsValid())
    199         {
    200             // Find the executable module so we can do a lookup inside it
    201             SBFileSpec exe_file_spec (exe_file_path, true);
    202             SBModule module (target.FindModule (exe_file_spec));
    203 
    204             // Take a file virtual address and resolve it to a section offset
    205             // address that can be used to do a symbol lookup by address
    206             SBAddress addr = module.ResolveFileAddress (file_addr);
    207             bool success = addr.IsValid() && addr.GetSection().IsValid();
    208             if (success)
    209             {
    210                 // We can resolve a section offset address in the module
    211                 // and only ask for what we need. You can logical or together
    212                 // bits from the SymbolContextItem enumeration found in
    213                 // lldb-enumeration.h to request only what you want. Here we
    214                 // are asking for everything.
    215                 //
    216                 // NOTE: the less you ask for, the less LLDB will parse as
    217                 // LLDB does partial parsing on just about everything.
    218                 SBSymbolContext sc (module.ResolveSymbolContextForAddress (addr, eSymbolContextEverything));
    219 
    220                 strm.Printf ("    Address: %s + 0x%llx\n    Summary: ", addr.GetSection().GetName (), addr.GetOffset());
    221                 addr.GetDescription (strm);
    222                 strm.Printf ("\n");
    223                 if (verbose)
    224                     sc.GetDescription (strm);
    225             }
    226             else
    227             {
    228                 printf ("error: 0x%llx does not resolve to a valid file address in '%s'\n", file_addr, exe_file_path);
    229             }
    230         }
    231     }
    232 
    233     return 0;
    234 }
    235 
    236