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
31using 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//----------------------------------------------------------------------
51class LLDBSentry
52{
53public:
54    LLDBSentry() {
55        // Initialize LLDB
56        SBDebugger::Initialize();
57    }
58    ~LLDBSentry() {
59        // Terminate LLDB
60        SBDebugger::Terminate();
61    }
62};
63
64static 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"
76void
77usage ()
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}
94int
95main (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