• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
LLDBSentry()54     LLDBSentry() {
55         // Initialize LLDB
56         SBDebugger::Initialize();
57     }
~LLDBSentry()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
usage()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
main(int argc,char const * argv[])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