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