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/SBProcess.h" 23 #include "LLDB/SBStream.h" 24 #include "LLDB/SBSymbol.h" 25 #include "LLDB/SBTarget.h" 26 #include "LLDB/SBThread.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 "i386" executable target. Then we can lookup the executable 36 // module and resolve a file address into a section offset address, 37 // and find all symbol context objects (if any) for that address: 38 // compile unit, function, deepest block, line table entry and the 39 // symbol. 40 // 41 // To build the program, type (while in this directory): 42 // 43 // $ make 44 // 45 // then (for example): 46 // 47 // $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/svn/ToT/build/Debug ./a.out 48 // executable_path file_address 49 //---------------------------------------------------------------------- 50 class LLDBSentry { 51 public: 52 LLDBSentry() { 53 // Initialize LLDB 54 SBDebugger::Initialize(); 55 } 56 ~LLDBSentry() { 57 // Terminate LLDB 58 SBDebugger::Terminate(); 59 } 60 }; 61 62 static struct option g_long_options[] = { 63 {"help", no_argument, NULL, 'h'}, 64 {"verbose", no_argument, NULL, 'v'}, 65 {"arch", required_argument, NULL, 'a'}, 66 {"platform", required_argument, NULL, 'p'}, 67 {NULL, 0, NULL, 0}}; 68 69 #define PROGRAM_NAME "lldb-lookup" 70 void usage() { 71 puts("NAME\n" 72 " " PROGRAM_NAME " -- symbolicate addresses using lldb.\n" 73 "\n" 74 "SYNOPSIS\n" 75 " " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] " 76 "[--verbose] [--help] --] <PATH> <ADDRESS> " 77 "[<ADDRESS>....]\n" 78 "\n" 79 "DESCRIPTION\n" 80 " Loads the executable pointed to by <PATH> and looks up and " 81 "<ADDRESS>\n" 82 " arguments\n" 83 "\n" 84 "EXAMPLE\n" 85 " " PROGRAM_NAME " --arch=x86_64 -- /usr/lib/dyld 0x100000000\n"); 86 exit(0); 87 } 88 int main(int argc, char const *argv[]) { 89 // Use a sentry object to properly initialize/terminate LLDB. 90 LLDBSentry sentry; 91 92 SBDebugger debugger(SBDebugger::Create()); 93 94 // Create a debugger instance so we can create a target 95 if (!debugger.IsValid()) 96 fprintf(stderr, "error: failed to create a debugger object\n"); 97 98 bool show_usage = false; 99 bool verbose = false; 100 const char *arch = NULL; 101 const char *platform = NULL; 102 std::string short_options("h?"); 103 for (const struct option *opt = g_long_options; opt->name; ++opt) { 104 if (isprint(opt->val)) { 105 short_options.append(1, (char)opt->val); 106 switch (opt->has_arg) { 107 case no_argument: 108 break; 109 case required_argument: 110 short_options.append(1, ':'); 111 break; 112 case optional_argument: 113 short_options.append(2, ':'); 114 break; 115 } 116 } 117 } 118 #ifdef __GLIBC__ 119 optind = 0; 120 #else 121 optreset = 1; 122 optind = 1; 123 #endif 124 char ch; 125 while ((ch = getopt_long_only(argc, (char *const *)argv, 126 short_options.c_str(), g_long_options, 0)) != 127 -1) { 128 switch (ch) { 129 case 0: 130 break; 131 132 case 'a': 133 if (arch != NULL) { 134 fprintf(stderr, 135 "error: the --arch option can only be specified once\n"); 136 exit(1); 137 } 138 arch = optarg; 139 break; 140 141 case 'p': 142 platform = optarg; 143 break; 144 145 case 'v': 146 verbose = true; 147 break; 148 149 case 'h': 150 case '?': 151 default: 152 show_usage = true; 153 break; 154 } 155 } 156 argc -= optind; 157 argv += optind; 158 159 if (show_usage || argc < 2) 160 usage(); 161 162 int arg_idx = 0; 163 // The first argument is the file path we want to look something up in 164 const char *exe_file_path = argv[arg_idx]; 165 const char *addr_cstr; 166 const bool add_dependent_libs = false; 167 SBError error; 168 SBStream strm; 169 strm.RedirectToFileHandle(stdout, false); 170 171 while ((addr_cstr = argv[++arg_idx]) != NULL) { 172 // The second argument in the address that we want to lookup 173 lldb::addr_t file_addr = strtoull(addr_cstr, NULL, 0); 174 175 // Create a target using the executable. 176 SBTarget target = debugger.CreateTarget(exe_file_path, arch, platform, 177 add_dependent_libs, error); 178 if (!error.Success()) { 179 fprintf(stderr, "error: %s\n", error.GetCString()); 180 exit(1); 181 } 182 183 printf("%sLooking up 0x%llx in '%s':\n", (arg_idx > 1) ? "\n" : "", 184 file_addr, exe_file_path); 185 186 if (target.IsValid()) { 187 // Find the executable module so we can do a lookup inside it 188 SBFileSpec exe_file_spec(exe_file_path, true); 189 SBModule module(target.FindModule(exe_file_spec)); 190 191 // Take a file virtual address and resolve it to a section offset 192 // address that can be used to do a symbol lookup by address 193 SBAddress addr = module.ResolveFileAddress(file_addr); 194 bool success = addr.IsValid() && addr.GetSection().IsValid(); 195 if (success) { 196 // We can resolve a section offset address in the module 197 // and only ask for what we need. You can logical or together 198 // bits from the SymbolContextItem enumeration found in 199 // lldb-enumeration.h to request only what you want. Here we 200 // are asking for everything. 201 // 202 // NOTE: the less you ask for, the less LLDB will parse as 203 // LLDB does partial parsing on just about everything. 204 SBSymbolContext sc(module.ResolveSymbolContextForAddress( 205 addr, eSymbolContextEverything)); 206 207 strm.Printf(" Address: %s + 0x%llx\n Summary: ", 208 addr.GetSection().GetName(), addr.GetOffset()); 209 addr.GetDescription(strm); 210 strm.Printf("\n"); 211 if (verbose) 212 sc.GetDescription(strm); 213 } else { 214 printf( 215 "error: 0x%llx does not resolve to a valid file address in '%s'\n", 216 file_addr, exe_file_path); 217 } 218 } 219 } 220 221 return 0; 222 } 223