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