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
31using 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//----------------------------------------------------------------------
49class LLDBSentry
50{
51public:
52    LLDBSentry() {
53        // Initialize LLDB
54        SBDebugger::Initialize();
55    }
56    ~LLDBSentry() {
57        // Terminate LLDB
58        SBDebugger::Terminate();
59    }
60};
61
62static 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"
72void
73usage ()
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}
91int
92main (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