220 lines · cpp
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-exception6//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#else16#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#endif27 28#include <string>29 30using namespace lldb;31 32// This quick sample code shows how to create a debugger instance and33// create an "i386" executable target. Then we can lookup the executable34// 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 the37// symbol.38//39// To build the program, type (while in this directory):40//41// $ make42//43// then (for example):44//45// $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/svn/ToT/build/Debug ./a.out46// executable_path file_address47class LLDBSentry {48public:49 LLDBSentry() {50 // Initialize LLDB51 SBDebugger::Initialize();52 }53 ~LLDBSentry() {54 // Terminate LLDB55 SBDebugger::Terminate();56 }57};58 59static 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"67void 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}85int 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 target92 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#else118 optreset = 1;119 optind = 1;120#endif121 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 in161 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 lookup170 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 it185 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 offset189 // address that can be used to do a symbol lookup by address190 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 module194 // and only ask for what we need. You can logical or together195 // bits from the SymbolContextItem enumeration found in196 // lldb-enumeration.h to request only what you want. Here we197 // are asking for everything.198 //199 // NOTE: the less you ask for, the less LLDB will parse as200 // 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