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