1 //===-- main.cpp ------------------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
13 #if defined(__APPLE__)
14 #include <LLDB/LLDB.h>
16 #include "LLDB/SBBlock.h"
17 #include "LLDB/SBCompileUnit.h"
18 #include "LLDB/SBDebugger.h"
19 #include "LLDB/SBFunction.h"
20 #include "LLDB/SBModule.h"
21 #include "LLDB/SBProcess.h"
22 #include "LLDB/SBStream.h"
23 #include "LLDB/SBSymbol.h"
24 #include "LLDB/SBTarget.h"
25 #include "LLDB/SBThread.h"
32 // This quick sample code shows how to create a debugger instance and
33 // create an executable target without adding dependent shared
34 // libraries. It will then set a regular expression breakpoint to get
35 // breakpoint locations for all functions in the module, and use the
36 // locations to extract the symbol context for each location. Then it
37 // dumps all // information about the function: its name, file address
38 // range, the return type (if any), and all argument types.
40 // To build the program, type (while in this directory):
44 // then to run this on MacOSX, specify the path to your LLDB.framework
45 // library using the DYLD_FRAMEWORK_PATH option and run the executable
47 // $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/tot/build/Debug ./a.out
48 // executable_path1 [executable_path2 ...]
53 SBDebugger::Initialize();
57 SBDebugger::Terminate();
61 static struct option g_long_options
[] = {
62 {"arch", required_argument
, NULL
, 'a'},
63 {"canonical", no_argument
, NULL
, 'c'},
64 {"extern", no_argument
, NULL
, 'x'},
65 {"help", no_argument
, NULL
, 'h'},
66 {"platform", required_argument
, NULL
, 'p'},
67 {"verbose", no_argument
, NULL
, 'v'},
70 #define PROGRAM_NAME "lldb-functions"
74 " -- extract all function signatures from one or more binaries.\n"
77 " " PROGRAM_NAME
" [[--arch=<ARCH>] [--platform=<PLATFORM>] "
78 "[--verbose] [--help] [--canonical] --] <PATH> "
82 " Loads the executable pointed to by <PATH> and dumps complete "
83 "signatures for all functions that have debug information.\n"
86 " " PROGRAM_NAME
" --arch=x86_64 /usr/lib/dyld\n");
89 int main(int argc
, char const *argv
[]) {
90 // Use a sentry object to properly initialize/terminate LLDB.
93 SBDebugger
debugger(SBDebugger::Create());
95 // Create a debugger instance so we can create a target
96 if (!debugger
.IsValid())
97 fprintf(stderr
, "error: failed to create a debugger object\n");
99 bool show_usage
= false;
100 bool verbose
= false;
101 bool canonical
= false;
102 bool external_only
= false;
103 const char *arch
= NULL
;
104 const char *platform
= NULL
;
105 std::string
short_options("h?");
106 for (const struct option
*opt
= g_long_options
; opt
->name
; ++opt
) {
107 if (isprint(opt
->val
)) {
108 short_options
.append(1, (char)opt
->val
);
109 switch (opt
->has_arg
) {
112 case required_argument
:
113 short_options
.append(1, ':');
115 case optional_argument
:
116 short_options
.append(2, ':');
128 while ((ch
= getopt_long_only(argc
, (char *const *)argv
,
129 short_options
.c_str(), g_long_options
, 0)) !=
138 "error: the --arch option can only be specified once\n");
149 external_only
= true;
170 const bool add_dependent_libs
= false;
172 for (int arg_idx
= 0; arg_idx
< argc
; ++arg_idx
) {
173 // The first argument is the file path we want to look something up in
174 const char *exe_file_path
= argv
[arg_idx
];
176 // Create a target using the executable.
177 SBTarget target
= debugger
.CreateTarget(exe_file_path
, arch
, platform
,
178 add_dependent_libs
, error
);
180 if (error
.Success()) {
181 if (target
.IsValid()) {
182 SBFileSpec
exe_file_spec(exe_file_path
, true);
183 SBModule
module(target
.FindModule(exe_file_spec
));
184 SBFileSpecList comp_unit_list
;
186 if (module
.IsValid()) {
188 lldb::SBCommandReturnObject command_result
;
189 snprintf(command
, sizeof(command
), "add-dsym --uuid %s",
190 module
.GetUUIDString());
191 debugger
.GetCommandInterpreter().HandleCommand(command
,
193 if (!command_result
.Succeeded()) {
194 fprintf(stderr
, "error: couldn't locate debug symbols for '%s'\n",
199 SBFileSpecList module_list
;
200 module_list
.Append(exe_file_spec
);
202 target
.BreakpointCreateByRegex(".", module_list
, comp_unit_list
);
204 const size_t num_locations
= bp
.GetNumLocations();
205 for (uint32_t bp_loc_idx
= 0; bp_loc_idx
< num_locations
;
207 SBBreakpointLocation bp_loc
= bp
.GetLocationAtIndex(bp_loc_idx
);
209 bp_loc
.GetAddress().GetSymbolContext(eSymbolContextEverything
));
211 if (sc
.GetBlock().GetContainingInlinedBlock().IsValid()) {
212 // Skip inlined functions
215 SBFunction
function(sc
.GetFunction());
216 if (function
.IsValid()) {
217 addr_t lo_pc
= function
.GetStartAddress().GetFileAddress();
218 if (lo_pc
== LLDB_INVALID_ADDRESS
) {
219 // Skip functions that don't have concrete instances in the
223 addr_t hi_pc
= function
.GetEndAddress().GetFileAddress();
224 const char *func_demangled_name
= function
.GetName();
225 const char *func_mangled_name
= function
.GetMangledName();
228 const bool is_objc_method
= ((func_demangled_name
[0] == '-') ||
229 (func_demangled_name
[0] == '+')) &&
230 (func_demangled_name
[1] == '[');
232 // Dump all objective C methods, or external symbols
233 dump
= is_objc_method
;
235 dump
= sc
.GetSymbol().IsExternal();
240 printf("\n name: %s\n", func_demangled_name
);
241 if (func_mangled_name
)
242 printf("mangled: %s\n", func_mangled_name
);
243 printf(" range: [0x%16.16llx - 0x%16.16llx)\n type: ",
246 printf("[0x%16.16llx - 0x%16.16llx) ", lo_pc
, hi_pc
);
248 SBType function_type
= function
.GetType();
249 SBType return_type
= function_type
.GetFunctionReturnType();
252 return_type
= return_type
.GetCanonicalType();
254 if (func_mangled_name
&& func_mangled_name
[0] == '_' &&
255 func_mangled_name
[1] == 'Z') {
256 printf("%s %s\n", return_type
.GetName(),
257 func_demangled_name
);
259 SBTypeList function_args
=
260 function_type
.GetFunctionArgumentTypes();
261 const size_t num_function_args
= function_args
.GetSize();
263 if (is_objc_method
) {
264 const char *class_name_start
= func_demangled_name
+ 2;
266 if (num_function_args
== 0) {
267 printf("%c(%s)[%s\n", func_demangled_name
[0],
268 return_type
.GetName(), class_name_start
);
270 const char *class_name_end
=
271 strchr(class_name_start
, ' ');
272 const int class_name_len
=
273 class_name_end
- class_name_start
;
274 printf("%c(%s)[%*.*s", func_demangled_name
[0],
275 return_type
.GetName(), class_name_len
,
276 class_name_len
, class_name_start
);
278 const char *selector_pos
= class_name_end
+ 1;
279 for (uint32_t function_arg_idx
= 0;
280 function_arg_idx
< num_function_args
;
281 ++function_arg_idx
) {
282 const char *selector_end
=
283 strchr(selector_pos
, ':') + 1;
284 const int selector_len
= selector_end
- selector_pos
;
285 SBType function_arg_type
=
286 function_args
.GetTypeAtIndex(function_arg_idx
);
290 function_arg_type
.GetCanonicalType();
292 printf(" %*.*s", selector_len
, selector_len
,
294 if (function_arg_type
.IsValid()) {
295 printf("(%s)", function_arg_type
.GetName());
299 selector_pos
= selector_end
;
304 printf("%s ", return_type
.GetName());
305 if (strchr(func_demangled_name
, '('))
308 printf("%s(", func_demangled_name
);
310 for (uint32_t function_arg_idx
= 0;
311 function_arg_idx
< num_function_args
;
312 ++function_arg_idx
) {
313 SBType function_arg_type
=
314 function_args
.GetTypeAtIndex(function_arg_idx
);
318 function_arg_type
.GetCanonicalType();
320 if (function_arg_type
.IsValid()) {
321 printf("%s%s", function_arg_idx
> 0 ? ", " : "",
322 function_arg_type
.GetName());
324 printf("%s???", function_arg_idx
> 0 ? ", " : "");
337 fprintf(stderr
, "error: %s\n", error
.GetCString());