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