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