xref: /llvm-project/lldb/examples/functions/main.cpp (revision 8b3af63b8993e45b1783853a3fcf6f36bfbed81b)
107a1d37bSGreg Clayton //===-- main.cpp ------------------------------------------------*- C++ -*-===//
207a1d37bSGreg Clayton //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
607a1d37bSGreg Clayton //
707a1d37bSGreg Clayton //===----------------------------------------------------------------------===//
807a1d37bSGreg Clayton 
98ccc7f69SGreg Clayton #include <getopt.h>
1007a1d37bSGreg Clayton #include <stdint.h>
1107a1d37bSGreg Clayton #include <stdlib.h>
1207a1d37bSGreg Clayton 
131767a73bSGreg Clayton #if defined(__APPLE__)
1407a1d37bSGreg Clayton #include <LLDB/LLDB.h>
151767a73bSGreg Clayton #else
161767a73bSGreg Clayton #include "LLDB/SBBlock.h"
171767a73bSGreg Clayton #include "LLDB/SBCompileUnit.h"
181767a73bSGreg Clayton #include "LLDB/SBDebugger.h"
191767a73bSGreg Clayton #include "LLDB/SBFunction.h"
201767a73bSGreg Clayton #include "LLDB/SBModule.h"
21b9c1b51eSKate Stone #include "LLDB/SBProcess.h"
221767a73bSGreg Clayton #include "LLDB/SBStream.h"
231767a73bSGreg Clayton #include "LLDB/SBSymbol.h"
241767a73bSGreg Clayton #include "LLDB/SBTarget.h"
251767a73bSGreg Clayton #include "LLDB/SBThread.h"
261767a73bSGreg Clayton #endif
2707a1d37bSGreg Clayton 
288ccc7f69SGreg Clayton #include <string>
298ccc7f69SGreg Clayton 
3007a1d37bSGreg Clayton using namespace lldb;
3107a1d37bSGreg Clayton 
3207a1d37bSGreg Clayton // This quick sample code shows how to create a debugger instance and
3307a1d37bSGreg Clayton // create an executable target without adding dependent shared
3407a1d37bSGreg Clayton // libraries. It will then set a regular expression breakpoint to get
3507a1d37bSGreg Clayton // breakpoint locations for all functions in the module, and use the
3607a1d37bSGreg Clayton // locations to extract the symbol context for each location. Then it
3707a1d37bSGreg Clayton // dumps all // information about the function: its name, file address
3807a1d37bSGreg Clayton // range, the return type (if any), and all argument types.
3907a1d37bSGreg Clayton //
4007a1d37bSGreg Clayton // To build the program, type (while in this directory):
4107a1d37bSGreg Clayton //
4207a1d37bSGreg Clayton //    $ make
4307a1d37bSGreg Clayton //
4407a1d37bSGreg Clayton // then to run this on MacOSX, specify the path to your LLDB.framework
4507a1d37bSGreg Clayton // library using the DYLD_FRAMEWORK_PATH option and run the executable
4607a1d37bSGreg Clayton //
47b9c1b51eSKate Stone //    $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/tot/build/Debug ./a.out
48b9c1b51eSKate Stone //    executable_path1 [executable_path2 ...]
49b9c1b51eSKate Stone class LLDBSentry {
5007a1d37bSGreg Clayton public:
LLDBSentry()5107a1d37bSGreg Clayton   LLDBSentry() {
5207a1d37bSGreg Clayton     // Initialize LLDB
5307a1d37bSGreg Clayton     SBDebugger::Initialize();
5407a1d37bSGreg Clayton   }
~LLDBSentry()5507a1d37bSGreg Clayton   ~LLDBSentry() {
5607a1d37bSGreg Clayton     // Terminate LLDB
5707a1d37bSGreg Clayton     SBDebugger::Terminate();
5807a1d37bSGreg Clayton   }
5907a1d37bSGreg Clayton };
608ccc7f69SGreg Clayton 
61b9c1b51eSKate Stone static struct option g_long_options[] = {
628ccc7f69SGreg Clayton     {"arch", required_argument, NULL, 'a'},
638ccc7f69SGreg Clayton     {"canonical", no_argument, NULL, 'c'},
648ccc7f69SGreg Clayton     {"extern", no_argument, NULL, 'x'},
658ccc7f69SGreg Clayton     {"help", no_argument, NULL, 'h'},
668ccc7f69SGreg Clayton     {"platform", required_argument, NULL, 'p'},
678ccc7f69SGreg Clayton     {"verbose", no_argument, NULL, 'v'},
68b9c1b51eSKate Stone     {NULL, 0, NULL, 0}};
698ccc7f69SGreg Clayton 
708ccc7f69SGreg Clayton #define PROGRAM_NAME "lldb-functions"
usage()71b9c1b51eSKate Stone void usage() {
72b9c1b51eSKate Stone   puts("NAME\n"
73b9c1b51eSKate Stone        "    " PROGRAM_NAME
74b9c1b51eSKate Stone        " -- extract all function signatures from one or more binaries.\n"
758ccc7f69SGreg Clayton        "\n"
768ccc7f69SGreg Clayton        "SYNOPSIS\n"
77b9c1b51eSKate Stone        "    " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] "
78b9c1b51eSKate Stone                            "[--verbose] [--help] [--canonical] --] <PATH> "
79b9c1b51eSKate Stone                            "[<PATH>....]\n"
808ccc7f69SGreg Clayton        "\n"
818ccc7f69SGreg Clayton        "DESCRIPTION\n"
82b9c1b51eSKate Stone        "    Loads the executable pointed to by <PATH> and dumps complete "
83b9c1b51eSKate Stone        "signatures for all functions that have debug information.\n"
848ccc7f69SGreg Clayton        "\n"
858ccc7f69SGreg Clayton        "EXAMPLE\n"
86b9c1b51eSKate Stone        "   " PROGRAM_NAME " --arch=x86_64 /usr/lib/dyld\n");
878ccc7f69SGreg Clayton   exit(0);
888ccc7f69SGreg Clayton }
main(int argc,char const * argv[])89b9c1b51eSKate Stone int main(int argc, char const *argv[]) {
9007a1d37bSGreg Clayton   // Use a sentry object to properly initialize/terminate LLDB.
9107a1d37bSGreg Clayton   LLDBSentry sentry;
9207a1d37bSGreg Clayton 
938ccc7f69SGreg Clayton   SBDebugger debugger(SBDebugger::Create());
9407a1d37bSGreg Clayton 
958ccc7f69SGreg Clayton   // Create a debugger instance so we can create a target
968ccc7f69SGreg Clayton   if (!debugger.IsValid())
978ccc7f69SGreg Clayton     fprintf(stderr, "error: failed to create a debugger object\n");
988ccc7f69SGreg Clayton 
998ccc7f69SGreg Clayton   bool show_usage = false;
1008ccc7f69SGreg Clayton   bool verbose = false;
1018ccc7f69SGreg Clayton   bool canonical = false;
1028ccc7f69SGreg Clayton   bool external_only = false;
1038ccc7f69SGreg Clayton   const char *arch = NULL;
1048ccc7f69SGreg Clayton   const char *platform = NULL;
1058ccc7f69SGreg Clayton   std::string short_options("h?");
106b9c1b51eSKate Stone   for (const struct option *opt = g_long_options; opt->name; ++opt) {
107b9c1b51eSKate Stone     if (isprint(opt->val)) {
1088ccc7f69SGreg Clayton       short_options.append(1, (char)opt->val);
109b9c1b51eSKate Stone       switch (opt->has_arg) {
1108ccc7f69SGreg Clayton       case no_argument:
1118ccc7f69SGreg Clayton         break;
1128ccc7f69SGreg Clayton       case required_argument:
1138ccc7f69SGreg Clayton         short_options.append(1, ':');
1148ccc7f69SGreg Clayton         break;
1158ccc7f69SGreg Clayton       case optional_argument:
1168ccc7f69SGreg Clayton         short_options.append(2, ':');
1178ccc7f69SGreg Clayton         break;
1188ccc7f69SGreg Clayton       }
1198ccc7f69SGreg Clayton     }
1208ccc7f69SGreg Clayton   }
1218ccc7f69SGreg Clayton #ifdef __GLIBC__
1228ccc7f69SGreg Clayton   optind = 0;
1238ccc7f69SGreg Clayton #else
1248ccc7f69SGreg Clayton   optreset = 1;
1258ccc7f69SGreg Clayton   optind = 1;
1268ccc7f69SGreg Clayton #endif
1278ccc7f69SGreg Clayton   char ch;
128b9c1b51eSKate Stone   while ((ch = getopt_long_only(argc, (char *const *)argv,
129b9c1b51eSKate Stone                                 short_options.c_str(), g_long_options, 0)) !=
130b9c1b51eSKate Stone          -1) {
131b9c1b51eSKate Stone     switch (ch) {
1328ccc7f69SGreg Clayton     case 0:
1338ccc7f69SGreg Clayton       break;
1348ccc7f69SGreg Clayton 
1358ccc7f69SGreg Clayton     case 'a':
136b9c1b51eSKate Stone       if (arch != NULL) {
137b9c1b51eSKate Stone         fprintf(stderr,
138b9c1b51eSKate Stone                 "error: the --arch option can only be specified once\n");
1398ccc7f69SGreg Clayton         exit(1);
1408ccc7f69SGreg Clayton       }
1418ccc7f69SGreg Clayton       arch = optarg;
1428ccc7f69SGreg Clayton       break;
1438ccc7f69SGreg Clayton 
1448ccc7f69SGreg Clayton     case 'c':
1458ccc7f69SGreg Clayton       canonical = true;
1468ccc7f69SGreg Clayton       break;
1478ccc7f69SGreg Clayton 
1488ccc7f69SGreg Clayton     case 'x':
1498ccc7f69SGreg Clayton       external_only = true;
1508ccc7f69SGreg Clayton       break;
1518ccc7f69SGreg Clayton 
1528ccc7f69SGreg Clayton     case 'p':
1538ccc7f69SGreg Clayton       platform = optarg;
1548ccc7f69SGreg Clayton       break;
1558ccc7f69SGreg Clayton 
1568ccc7f69SGreg Clayton     case 'v':
1578ccc7f69SGreg Clayton       verbose = true;
1588ccc7f69SGreg Clayton       break;
1598ccc7f69SGreg Clayton 
1608ccc7f69SGreg Clayton     case 'h':
1618ccc7f69SGreg Clayton     case '?':
1628ccc7f69SGreg Clayton     default:
1638ccc7f69SGreg Clayton       show_usage = true;
1648ccc7f69SGreg Clayton       break;
1658ccc7f69SGreg Clayton     }
1668ccc7f69SGreg Clayton   }
1678ccc7f69SGreg Clayton   argc -= optind;
1688ccc7f69SGreg Clayton   argv += optind;
1698ccc7f69SGreg Clayton 
17007a1d37bSGreg Clayton   const bool add_dependent_libs = false;
17107a1d37bSGreg Clayton   SBError error;
172b9c1b51eSKate Stone   for (int arg_idx = 0; arg_idx < argc; ++arg_idx) {
17307a1d37bSGreg Clayton     // The first argument is the file path we want to look something up in
17407a1d37bSGreg Clayton     const char *exe_file_path = argv[arg_idx];
17507a1d37bSGreg Clayton 
17607a1d37bSGreg Clayton     // Create a target using the executable.
177b9c1b51eSKate Stone     SBTarget target = debugger.CreateTarget(exe_file_path, arch, platform,
178b9c1b51eSKate Stone                                             add_dependent_libs, error);
17907a1d37bSGreg Clayton 
180b9c1b51eSKate Stone     if (error.Success()) {
181b9c1b51eSKate Stone       if (target.IsValid()) {
18207a1d37bSGreg Clayton         SBFileSpec exe_file_spec(exe_file_path, true);
18307a1d37bSGreg Clayton         SBModule module(target.FindModule(exe_file_spec));
18407a1d37bSGreg Clayton         SBFileSpecList comp_unit_list;
18507a1d37bSGreg Clayton 
186b9c1b51eSKate Stone         if (module.IsValid()) {
18707a1d37bSGreg Clayton           char command[1024];
18807a1d37bSGreg Clayton           lldb::SBCommandReturnObject command_result;
189b9c1b51eSKate Stone           snprintf(command, sizeof(command), "add-dsym --uuid %s",
190b9c1b51eSKate Stone                    module.GetUUIDString());
191b9c1b51eSKate Stone           debugger.GetCommandInterpreter().HandleCommand(command,
192b9c1b51eSKate Stone                                                          command_result);
193b9c1b51eSKate Stone           if (!command_result.Succeeded()) {
194b9c1b51eSKate Stone             fprintf(stderr, "error: couldn't locate debug symbols for '%s'\n",
195b9c1b51eSKate Stone                     exe_file_path);
19607a1d37bSGreg Clayton             exit(1);
19707a1d37bSGreg Clayton           }
19807a1d37bSGreg Clayton 
19907a1d37bSGreg Clayton           SBFileSpecList module_list;
20007a1d37bSGreg Clayton           module_list.Append(exe_file_spec);
201b9c1b51eSKate Stone           SBBreakpoint bp =
202b9c1b51eSKate Stone               target.BreakpointCreateByRegex(".", module_list, comp_unit_list);
20307a1d37bSGreg Clayton 
20407a1d37bSGreg Clayton           const size_t num_locations = bp.GetNumLocations();
205b9c1b51eSKate Stone           for (uint32_t bp_loc_idx = 0; bp_loc_idx < num_locations;
206b9c1b51eSKate Stone                ++bp_loc_idx) {
20707a1d37bSGreg Clayton             SBBreakpointLocation bp_loc = bp.GetLocationAtIndex(bp_loc_idx);
208b9c1b51eSKate Stone             SBSymbolContext sc(
209b9c1b51eSKate Stone                 bp_loc.GetAddress().GetSymbolContext(eSymbolContextEverything));
210b9c1b51eSKate Stone             if (sc.IsValid()) {
211b9c1b51eSKate Stone               if (sc.GetBlock().GetContainingInlinedBlock().IsValid()) {
21207a1d37bSGreg Clayton                 // Skip inlined functions
21307a1d37bSGreg Clayton                 continue;
21407a1d37bSGreg Clayton               }
21507a1d37bSGreg Clayton               SBFunction function(sc.GetFunction());
216b9c1b51eSKate Stone               if (function.IsValid()) {
21707a1d37bSGreg Clayton                 addr_t lo_pc = function.GetStartAddress().GetFileAddress();
218b9c1b51eSKate Stone                 if (lo_pc == LLDB_INVALID_ADDRESS) {
219b9c1b51eSKate Stone                   // Skip functions that don't have concrete instances in the
220b9c1b51eSKate Stone                   // binary
22107a1d37bSGreg Clayton                   continue;
22207a1d37bSGreg Clayton                 }
22307a1d37bSGreg Clayton                 addr_t hi_pc = function.GetEndAddress().GetFileAddress();
2248ccc7f69SGreg Clayton                 const char *func_demangled_name = function.GetName();
2258ccc7f69SGreg Clayton                 const char *func_mangled_name = function.GetMangledName();
22607a1d37bSGreg Clayton 
2278ccc7f69SGreg Clayton                 bool dump = true;
228b9c1b51eSKate Stone                 const bool is_objc_method = ((func_demangled_name[0] == '-') ||
229b9c1b51eSKate Stone                                              (func_demangled_name[0] == '+')) &&
230b9c1b51eSKate Stone                                             (func_demangled_name[1] == '[');
231b9c1b51eSKate Stone                 if (external_only) {
2328ccc7f69SGreg Clayton                   // Dump all objective C methods, or external symbols
2338ccc7f69SGreg Clayton                   dump = is_objc_method;
2348ccc7f69SGreg Clayton                   if (!dump)
2358ccc7f69SGreg Clayton                     dump = sc.GetSymbol().IsExternal();
2368ccc7f69SGreg Clayton                 }
2378ccc7f69SGreg Clayton 
238b9c1b51eSKate Stone                 if (dump) {
239b9c1b51eSKate Stone                   if (verbose) {
2408ccc7f69SGreg Clayton                     printf("\n   name: %s\n", func_demangled_name);
2418ccc7f69SGreg Clayton                     if (func_mangled_name)
2428ccc7f69SGreg Clayton                       printf("mangled: %s\n", func_mangled_name);
243b9c1b51eSKate Stone                     printf("  range: [0x%16.16llx - 0x%16.16llx)\n   type: ",
244b9c1b51eSKate Stone                            lo_pc, hi_pc);
245b9c1b51eSKate Stone                   } else {
2468ccc7f69SGreg Clayton                     printf("[0x%16.16llx - 0x%16.16llx) ", lo_pc, hi_pc);
24707a1d37bSGreg Clayton                   }
2488ccc7f69SGreg Clayton                   SBType function_type = function.GetType();
2498ccc7f69SGreg Clayton                   SBType return_type = function_type.GetFunctionReturnType();
25007a1d37bSGreg Clayton 
2518ccc7f69SGreg Clayton                   if (canonical)
2528ccc7f69SGreg Clayton                     return_type = return_type.GetCanonicalType();
25307a1d37bSGreg Clayton 
254b9c1b51eSKate Stone                   if (func_mangled_name && func_mangled_name[0] == '_' &&
255b9c1b51eSKate Stone                       func_mangled_name[1] == 'Z') {
256b9c1b51eSKate Stone                     printf("%s %s\n", return_type.GetName(),
257b9c1b51eSKate Stone                            func_demangled_name);
258b9c1b51eSKate Stone                   } else {
259b9c1b51eSKate Stone                     SBTypeList function_args =
260b9c1b51eSKate Stone                         function_type.GetFunctionArgumentTypes();
26107a1d37bSGreg Clayton                     const size_t num_function_args = function_args.GetSize();
2628ccc7f69SGreg Clayton 
263b9c1b51eSKate Stone                     if (is_objc_method) {
2648ccc7f69SGreg Clayton                       const char *class_name_start = func_demangled_name + 2;
2658ccc7f69SGreg Clayton 
266b9c1b51eSKate Stone                       if (num_function_args == 0) {
267b9c1b51eSKate Stone                         printf("%c(%s)[%s\n", func_demangled_name[0],
268b9c1b51eSKate Stone                                return_type.GetName(), class_name_start);
269b9c1b51eSKate Stone                       } else {
270b9c1b51eSKate Stone                         const char *class_name_end =
271b9c1b51eSKate Stone                             strchr(class_name_start, ' ');
272b9c1b51eSKate Stone                         const int class_name_len =
273b9c1b51eSKate Stone                             class_name_end - class_name_start;
274b9c1b51eSKate Stone                         printf("%c(%s)[%*.*s", func_demangled_name[0],
275b9c1b51eSKate Stone                                return_type.GetName(), class_name_len,
276b9c1b51eSKate Stone                                class_name_len, class_name_start);
2778ccc7f69SGreg Clayton 
2788ccc7f69SGreg Clayton                         const char *selector_pos = class_name_end + 1;
279b9c1b51eSKate Stone                         for (uint32_t function_arg_idx = 0;
280b9c1b51eSKate Stone                              function_arg_idx < num_function_args;
281b9c1b51eSKate Stone                              ++function_arg_idx) {
282b9c1b51eSKate Stone                           const char *selector_end =
283b9c1b51eSKate Stone                               strchr(selector_pos, ':') + 1;
2848ccc7f69SGreg Clayton                           const int selector_len = selector_end - selector_pos;
285b9c1b51eSKate Stone                           SBType function_arg_type =
286b9c1b51eSKate Stone                               function_args.GetTypeAtIndex(function_arg_idx);
2878ccc7f69SGreg Clayton 
2888ccc7f69SGreg Clayton                           if (canonical)
289b9c1b51eSKate Stone                             function_arg_type =
290b9c1b51eSKate Stone                                 function_arg_type.GetCanonicalType();
2918ccc7f69SGreg Clayton 
292b9c1b51eSKate Stone                           printf(" %*.*s", selector_len, selector_len,
293b9c1b51eSKate Stone                                  selector_pos);
294b9c1b51eSKate Stone                           if (function_arg_type.IsValid()) {
2958ccc7f69SGreg Clayton                             printf("(%s)", function_arg_type.GetName());
296b9c1b51eSKate Stone                           } else {
2978ccc7f69SGreg Clayton                             printf("(?)");
2988ccc7f69SGreg Clayton                           }
2998ccc7f69SGreg Clayton                           selector_pos = selector_end;
3008ccc7f69SGreg Clayton                         }
3018ccc7f69SGreg Clayton                         printf("]\n");
3028ccc7f69SGreg Clayton                       }
303b9c1b51eSKate Stone                     } else {
3048ccc7f69SGreg Clayton                       printf("%s ", return_type.GetName());
3058ccc7f69SGreg Clayton                       if (strchr(func_demangled_name, '('))
3068ccc7f69SGreg Clayton                         printf("(*)(");
3078ccc7f69SGreg Clayton                       else
3088ccc7f69SGreg Clayton                         printf("%s(", func_demangled_name);
3098ccc7f69SGreg Clayton 
310b9c1b51eSKate Stone                       for (uint32_t function_arg_idx = 0;
311b9c1b51eSKate Stone                            function_arg_idx < num_function_args;
312b9c1b51eSKate Stone                            ++function_arg_idx) {
313b9c1b51eSKate Stone                         SBType function_arg_type =
314b9c1b51eSKate Stone                             function_args.GetTypeAtIndex(function_arg_idx);
3158ccc7f69SGreg Clayton 
3168ccc7f69SGreg Clayton                         if (canonical)
317b9c1b51eSKate Stone                           function_arg_type =
318b9c1b51eSKate Stone                               function_arg_type.GetCanonicalType();
3198ccc7f69SGreg Clayton 
320b9c1b51eSKate Stone                         if (function_arg_type.IsValid()) {
321b9c1b51eSKate Stone                           printf("%s%s", function_arg_idx > 0 ? ", " : "",
322b9c1b51eSKate Stone                                  function_arg_type.GetName());
323b9c1b51eSKate Stone                         } else {
3248ccc7f69SGreg Clayton                           printf("%s???", function_arg_idx > 0 ? ", " : "");
32507a1d37bSGreg Clayton                         }
32607a1d37bSGreg Clayton                       }
3278ccc7f69SGreg Clayton                       printf(")\n");
3288ccc7f69SGreg Clayton                     }
3298ccc7f69SGreg Clayton                   }
3308ccc7f69SGreg Clayton                 }
33107a1d37bSGreg Clayton               }
33207a1d37bSGreg Clayton             }
33307a1d37bSGreg Clayton           }
33407a1d37bSGreg Clayton         }
33507a1d37bSGreg Clayton       }
336b9c1b51eSKate Stone     } else {
33707a1d37bSGreg Clayton       fprintf(stderr, "error: %s\n", error.GetCString());
33807a1d37bSGreg Clayton       exit(1);
33907a1d37bSGreg Clayton     }
34007a1d37bSGreg Clayton   }
34107a1d37bSGreg Clayton 
34207a1d37bSGreg Clayton   return 0;
34307a1d37bSGreg Clayton }
344