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