• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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