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