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