Home | History | Annotate | Download | only in functions
      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 executable target without adding dependent shared
     36 // libraries. It will then set a regular expression breakpoint to get
     37 // breakpoint locations for all functions in the module, and use the
     38 // locations to extract the symbol context for each location. Then it
     39 // dumps all // information about the function: its name, file address
     40 // range, the return type (if any), and all argument types.
     41 //
     42 // To build the program, type (while in this directory):
     43 //
     44 //    $ make
     45 //
     46 // then to run this on MacOSX, specify the path to your LLDB.framework
     47 // library using the DYLD_FRAMEWORK_PATH option and run the executable
     48 //
     49 //    $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/tot/build/Debug ./a.out executable_path1 [executable_path2 ...]
     50 //----------------------------------------------------------------------
     51 class LLDBSentry
     52 {
     53 public:
     54     LLDBSentry() {
     55         // Initialize LLDB
     56         SBDebugger::Initialize();
     57     }
     58     ~LLDBSentry() {
     59         // Terminate LLDB
     60         SBDebugger::Terminate();
     61     }
     62 };
     63 
     64 static struct option g_long_options[] =
     65 {
     66 	{ "arch",		required_argument,	NULL, 'a' },
     67 	{ "canonical",  no_argument,	    NULL, 'c' },
     68 	{ "extern",     no_argument,	    NULL, 'x' },
     69     { "help",       no_argument,        NULL, 'h' },
     70 	{ "platform",   required_argument,	NULL, 'p' },
     71     { "verbose",    no_argument,        NULL, 'v' },
     72 	{ NULL,			0,					NULL,  0  }
     73 };
     74 
     75 #define PROGRAM_NAME "lldb-functions"
     76 void
     77 usage ()
     78 {
     79     puts (
     80     "NAME\n"
     81     "    " PROGRAM_NAME " -- extract all function signatures from one or more binaries.\n"
     82     "\n"
     83     "SYNOPSIS\n"
     84     "    " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] [--verbose] [--help] [--canonical] --] <PATH> [<PATH>....]\n"
     85     "\n"
     86     "DESCRIPTION\n"
     87     "    Loads the executable pointed to by <PATH> and dumps complete signatures for all functions that have debug information.\n"
     88     "\n"
     89     "EXAMPLE\n"
     90     "   " PROGRAM_NAME " --arch=x86_64 /usr/lib/dyld\n"
     91     );
     92     exit(0);
     93 }
     94 int
     95 main (int argc, char const *argv[])
     96 {
     97     // Use a sentry object to properly initialize/terminate LLDB.
     98     LLDBSentry sentry;
     99 
    100     SBDebugger debugger (SBDebugger::Create());
    101 
    102     // Create a debugger instance so we can create a target
    103     if (!debugger.IsValid())
    104         fprintf (stderr, "error: failed to create a debugger object\n");
    105 
    106     bool show_usage = false;
    107     bool verbose = false;
    108     bool canonical = false;
    109     bool external_only = false;
    110     const char *arch = NULL;
    111     const char *platform = NULL;
    112     std::string short_options("h?");
    113     for (const struct option *opt = g_long_options; opt->name; ++opt)
    114     {
    115         if (isprint(opt->val))
    116         {
    117             short_options.append(1, (char)opt->val);
    118             switch (opt->has_arg)
    119             {
    120             case no_argument:
    121                 break;
    122             case required_argument:
    123                 short_options.append(1, ':');
    124                 break;
    125             case optional_argument:
    126                 short_options.append(2, ':');
    127                 break;
    128             }
    129         }
    130     }
    131 #ifdef __GLIBC__
    132     optind = 0;
    133 #else
    134     optreset = 1;
    135     optind = 1;
    136 #endif
    137     char ch;
    138 	while ((ch = getopt_long_only(argc, (char * const *)argv, short_options.c_str(), g_long_options, 0)) != -1)
    139 	{
    140 		switch (ch)
    141 		{
    142         case 0:
    143             break;
    144 
    145 		case 'a':
    146 		    if (arch != NULL)
    147 		    {
    148                 fprintf (stderr, "error: the --arch option can only be specified once\n");
    149                 exit(1);
    150 		    }
    151             arch = optarg;
    152 			break;
    153 
    154         case 'c':
    155             canonical = true;
    156             break;
    157 
    158         case 'x':
    159             external_only = true;
    160             break;
    161 
    162         case 'p':
    163             platform = optarg;
    164             break;
    165 
    166         case 'v':
    167             verbose = true;
    168             break;
    169 
    170 		case 'h':
    171 		case '?':
    172 		default:
    173 			show_usage = true;
    174 			break;
    175 		}
    176 	}
    177 	argc -= optind;
    178 	argv += optind;
    179 
    180     const bool add_dependent_libs = false;
    181     SBError error;
    182     for (int arg_idx = 0; arg_idx < argc; ++arg_idx)
    183     {
    184         // The first argument is the file path we want to look something up in
    185         const char *exe_file_path = argv[arg_idx];
    186 
    187         // Create a target using the executable.
    188         SBTarget target = debugger.CreateTarget (exe_file_path,
    189                                                  arch,
    190                                                  platform,
    191                                                  add_dependent_libs,
    192                                                  error);
    193 
    194         if (error.Success())
    195         {
    196             if (target.IsValid())
    197             {
    198                 SBFileSpec exe_file_spec (exe_file_path, true);
    199                 SBModule module (target.FindModule (exe_file_spec));
    200                 SBFileSpecList comp_unit_list;
    201 
    202                 if (module.IsValid())
    203                 {
    204                     char command[1024];
    205                     lldb::SBCommandReturnObject command_result;
    206                     snprintf (command, sizeof(command), "add-dsym --uuid %s", module.GetUUIDString());
    207                     debugger.GetCommandInterpreter().HandleCommand (command, command_result);
    208                     if (!command_result.Succeeded())
    209                     {
    210                         fprintf (stderr, "error: couldn't locate debug symbols for '%s'\n", exe_file_path);
    211                         exit(1);
    212                     }
    213 
    214                     SBFileSpecList module_list;
    215                     module_list.Append(exe_file_spec);
    216                     SBBreakpoint bp = target.BreakpointCreateByRegex (".", module_list, comp_unit_list);
    217 
    218                     const size_t num_locations = bp.GetNumLocations();
    219                     for (uint32_t bp_loc_idx=0; bp_loc_idx<num_locations; ++bp_loc_idx)
    220                     {
    221                         SBBreakpointLocation bp_loc = bp.GetLocationAtIndex(bp_loc_idx);
    222                         SBSymbolContext sc (bp_loc.GetAddress().GetSymbolContext(eSymbolContextEverything));
    223                         if (sc.IsValid())
    224                         {
    225                             if (sc.GetBlock().GetContainingInlinedBlock().IsValid())
    226                             {
    227                                 // Skip inlined functions
    228                                 continue;
    229                             }
    230                             SBFunction function (sc.GetFunction());
    231                             if (function.IsValid())
    232                             {
    233                                 addr_t lo_pc = function.GetStartAddress().GetFileAddress();
    234                                 if (lo_pc == LLDB_INVALID_ADDRESS)
    235                                 {
    236                                     // Skip functions that don't have concrete instances in the binary
    237                                     continue;
    238                                 }
    239                                 addr_t hi_pc = function.GetEndAddress().GetFileAddress();
    240                                 const char *func_demangled_name = function.GetName();
    241                                 const char *func_mangled_name = function.GetMangledName();
    242 
    243                                 bool dump = true;
    244                                 const bool is_objc_method = ((func_demangled_name[0] == '-') || (func_demangled_name[0] == '+')) && (func_demangled_name[1] == '[');
    245                                 if (external_only)
    246                                 {
    247                                     // Dump all objective C methods, or external symbols
    248                                     dump = is_objc_method;
    249                                     if (!dump)
    250                                         dump = sc.GetSymbol().IsExternal();
    251                                 }
    252 
    253                                 if (dump)
    254                                 {
    255                                     if (verbose)
    256                                     {
    257                                         printf ("\n   name: %s\n", func_demangled_name);
    258                                         if (func_mangled_name)
    259                                             printf ("mangled: %s\n", func_mangled_name);
    260                                         printf ("  range: [0x%16.16llx - 0x%16.16llx)\n   type: ", lo_pc, hi_pc);
    261                                     }
    262                                     else
    263                                     {
    264                                         printf ("[0x%16.16llx - 0x%16.16llx) ", lo_pc, hi_pc);
    265                                     }
    266                                     SBType function_type = function.GetType();
    267                                     SBType return_type = function_type.GetFunctionReturnType();
    268 
    269                                     if (canonical)
    270                                         return_type = return_type.GetCanonicalType();
    271 
    272                                     if (func_mangled_name &&
    273                                         func_mangled_name[0] == '_' &&
    274                                         func_mangled_name[1] == 'Z')
    275                                     {
    276                                         printf ("%s %s\n", return_type.GetName(), func_demangled_name);
    277                                     }
    278                                     else
    279                                     {
    280                                         SBTypeList function_args = function_type.GetFunctionArgumentTypes();
    281                                         const size_t num_function_args = function_args.GetSize();
    282 
    283                                         if (is_objc_method)
    284                                         {
    285                                             const char *class_name_start = func_demangled_name + 2;
    286 
    287                                             if (num_function_args == 0)
    288                                             {
    289                                                 printf("%c(%s)[%s\n", func_demangled_name[0], return_type.GetName(), class_name_start);
    290                                             }
    291                                             else
    292                                             {
    293                                                 const char *class_name_end = strchr(class_name_start,' ');
    294                                                 const int class_name_len = class_name_end - class_name_start;
    295                                                 printf ("%c(%s)[%*.*s", func_demangled_name[0], return_type.GetName(), class_name_len, class_name_len, class_name_start);
    296 
    297                                                 const char *selector_pos = class_name_end + 1;
    298                                                 for (uint32_t function_arg_idx = 0; function_arg_idx < num_function_args; ++function_arg_idx)
    299                                                 {
    300                                                     const char *selector_end = strchr(selector_pos, ':') + 1;
    301                                                     const int selector_len = selector_end - selector_pos;
    302                                                     SBType function_arg_type = function_args.GetTypeAtIndex(function_arg_idx);
    303 
    304                                                     if (canonical)
    305                                                         function_arg_type = function_arg_type.GetCanonicalType();
    306 
    307                                                     printf (" %*.*s", selector_len, selector_len, selector_pos);
    308                                                     if (function_arg_type.IsValid())
    309                                                     {
    310                                                         printf ("(%s)", function_arg_type.GetName());
    311                                                     }
    312                                                     else
    313                                                     {
    314                                                         printf ("(?)");
    315                                                     }
    316                                                     selector_pos = selector_end;
    317                                                 }
    318                                                 printf ("]\n");
    319                                             }
    320                                         }
    321                                         else
    322                                         {
    323                                             printf ("%s ", return_type.GetName());
    324                                             if (strchr (func_demangled_name, '('))
    325                                                 printf ("(*)(");
    326                                             else
    327                                                 printf ("%s(", func_demangled_name);
    328 
    329                                             for (uint32_t function_arg_idx = 0; function_arg_idx < num_function_args; ++function_arg_idx)
    330                                             {
    331                                                 SBType function_arg_type = function_args.GetTypeAtIndex(function_arg_idx);
    332 
    333                                                 if (canonical)
    334                                                     function_arg_type = function_arg_type.GetCanonicalType();
    335 
    336                                                 if (function_arg_type.IsValid())
    337                                                 {
    338                                                     printf ("%s%s", function_arg_idx > 0 ? ", " : "", function_arg_type.GetName());
    339                                                 }
    340                                                 else
    341                                                 {
    342                                                     printf ("%s???", function_arg_idx > 0 ? ", " : "");
    343                                                 }
    344                                             }
    345                                             printf (")\n");
    346                                         }
    347                                     }
    348                                 }
    349                             }
    350                         }
    351                     }
    352                 }
    353             }
    354         }
    355         else
    356         {
    357             fprintf (stderr, "error: %s\n", error.GetCString());
    358             exit(1);
    359         }
    360     }
    361 
    362     return 0;
    363 }
    364 
    365