UFO: Alien Invasion
Loading...
Searching...
No Matches
addr2line.cpp
Go to the documentation of this file.
1
5
6#include <unistd.h>
7
8#include <sys/stat.h>
9
10#include <getopt.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <stdarg.h>
14#include <string.h>
15#include <errno.h>
16#include <limits.h>
17#include <assert.h>
18
19#pragma GCC visibility push(hidden)
20#include "bfd.h"
21#include "bucomm.h"
22#include "demangle.h"
23#include "libiberty.h"
24#pragma GCC visibility pop
25
26typedef struct _libtrace_data
27{
28 bfd_boolean unwind_inlines;
29 bfd_boolean with_functions;
30 bfd_boolean do_demangle;
31 bfd_boolean base_names;
32 asymbol **syms;
33
34 bfd *abfd;
35 asection *section;
37
38static libtrace_data m_libtrace_data = { .unwind_inlines = TRUE, .with_functions = TRUE, .do_demangle = TRUE,
39 .base_names = TRUE, .syms = nullptr, .abfd = nullptr, .section = nullptr, };
40
43typedef struct _sym_info
44{
45 bfd_vma pc;
46 const char *filename;
47 const char *functionname;
48 unsigned int line;
49 bfd_boolean found;
50} sym_info;
51
52static int slurp_symtab (bfd *);
53static void find_address_in_section (bfd *, asection *, void *);
54static void find_offset_in_section (bfd *, asection *, sym_info *);
55static int translate_addresses (bfd *abfd, asection *section, void *addr, char *buf_func, size_t buf_func_len,
56 char *buf_file, size_t buf_file_len);
57
58static const char *program_name = "addr2line";
59
60void bfd_nonfatal (const char *string)
61{
62 const char *errmsg = bfd_errmsg(bfd_get_error());
63
64 if (string)
65 fprintf(stderr, "%s: %s: %s\n", program_name, string, errmsg);
66 else
67 fprintf(stderr, "%s: %s\n", program_name, errmsg);
68}
69
70void report (const char * format, va_list args)
71{
72 fprintf(stderr, "%s: ", program_name);
73 vfprintf(stderr, format, args);
74 putc('\n', stderr);
75}
76
77void non_fatal (const char *format, ...)
78{
79 va_list args;
80
81 va_start(args, format);
82 report(format, args);
83 va_end(args);
84}
85
89off_t get_file_size (const char * file_name)
90{
91 struct stat statbuf;
92
93 if (stat(file_name, &statbuf) < 0) {
94 if (errno == ENOENT)
95 non_fatal("'%s': No such file", file_name);
96 else
97 non_fatal("Warning: could not locate '%s'. reason: %s", file_name, strerror(errno));
98 } else if (!S_ISREG (statbuf.st_mode))
99 non_fatal("Warning: '%s' is not an ordinary file", file_name);
100 else
101 return statbuf.st_size;
102
103 return 0;
104}
105
110{
111 if (!p || !*p)
112 return;
113
114 fprintf(stderr, "%s: Matching formats: ", program_name);
115 while (*p)
116 fprintf(stderr, " %s", *p++);
117 fputc('\n', stderr);
118}
119
125{
126 /* The macro TARGET is defined by Makefile.
127 E.g.: -DTARGET='"i686-pc-linux-gnu"'. */
128 const char *target = TARGET;
129
130 if (!bfd_set_default_target(target)) {
131 non_fatal("can't set BFD default target to `%s': %s", target, bfd_errmsg(bfd_get_error()));
132 return;
133 }
134
135 return;
136}
137
139static int slurp_symtab (bfd *abfd)
140{
141 long symcount;
142 unsigned int size;
143
144 if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
145 return -1;
146
147 symcount = bfd_read_minisymbols(abfd, FALSE, (void *) &m_libtrace_data.syms, &size);
148 if (symcount == 0)
149 symcount = bfd_read_minisymbols(abfd, TRUE /* dynamic */, (void *) &m_libtrace_data.syms, &size);
150
151 if (symcount < 0) {
152 bfd_nonfatal(bfd_get_filename(abfd));
153 return -1;
154 }
155
156 return 0;
157}
158
161static void find_address_in_section (bfd *abfd, asection *section, void *data)
162{
163 bfd_vma vma;
164 bfd_size_type size;
165 sym_info *psi = (sym_info*) data;
166
167 if (psi->found)
168 return;
169
170 if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
171 return;
172
173 vma = bfd_get_section_vma(abfd, section);
174 if (psi->pc < vma)
175 return;
176
177 size = bfd_get_section_size(section);
178 if (psi->pc >= vma + size)
179 return;
180
181 psi->found = bfd_find_nearest_line(abfd, section, m_libtrace_data.syms, psi->pc - vma, &psi->filename,
182 &psi->functionname, &psi->line);
183}
184
186static void find_offset_in_section (bfd *abfd, asection *section, sym_info *psi)
187{
188 bfd_size_type size;
189
190 if (psi->found)
191 return;
192
193 if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
194 return;
195
196 size = bfd_get_section_size(section);
197 if (psi->pc >= size)
198 return;
199
200 psi->found = bfd_find_nearest_line(abfd, section, m_libtrace_data.syms, psi->pc, &psi->filename,
201 &psi->functionname, &psi->line);
202}
203
206static int translate_addresses (bfd *abfd, asection *section, void *xaddr, char *buf_func, size_t buf_func_len,
207 char *buf_file, size_t buf_file_len)
208{
209#define ADDR_BUF_LEN ((CHAR_BIT/4)*(sizeof(void*))+1)
210 char addr[ADDR_BUF_LEN + 1] = { 0 };
211 sym_info si = { 0 };
212
213 sprintf(addr, "%p", xaddr);
214 si.pc = bfd_scan_vma(addr, nullptr, 16);
215
216 si.found = FALSE;
217 if (section)
218 find_offset_in_section(abfd, section, &si);
219 else
220 bfd_map_over_sections(abfd, find_address_in_section, &si);
221
222 if (!si.found) {
223 if (buf_func != nullptr)
224 snprintf(buf_func, buf_func_len, "%s ??:0", m_libtrace_data.with_functions ? "??" : "");
225 } else {
226 do {
227 if (m_libtrace_data.with_functions) {
228 const char *name;
229 char *alloc = nullptr;
230
231 name = si.functionname;
232 if (name == nullptr || *name == '\0')
233 name = "??";
234 else if (m_libtrace_data.do_demangle) {
235 alloc = bfd_demangle(abfd, name, DMGL_ANSI | DMGL_PARAMS);
236 if (alloc != nullptr)
237 name = alloc;
238 }
239
240 if (buf_func != nullptr)
241 snprintf(buf_func, buf_func_len, "%s", name);
242
243 free(alloc);
244 }
245
246 if (m_libtrace_data.base_names && si.filename != nullptr) {
247 char *h = strrchr(si.filename, '/');
248 if (h != nullptr)
249 si.filename = h + 1;
250 }
251
252 if (buf_file != nullptr)
253 snprintf(buf_file, buf_file_len, "%s:%u", si.filename ? si.filename : "??", si.line);
254 if (!m_libtrace_data.unwind_inlines)
255 si.found = FALSE;
256 else
257 si.found = bfd_find_inliner_info(abfd, &si.filename, &si.functionname, &si.line);
258 } while (si.found);
259 }
260
261 return si.found;
262}
263/* --------------------------------------------------------------- */
264
265int libtrace_init (const char *file_name, const char *section_name, const char *target)
266{
267 char **matching = nullptr;
268
269 bfd_init();
271
272 if (get_file_size(file_name) < 1)
273 return -1;
274
275 m_libtrace_data.abfd = bfd_openr(file_name, target);
276 if (m_libtrace_data.abfd == nullptr) {
277 bfd_nonfatal(file_name);
278 return -1;
279 }
280
281 if (bfd_check_format(m_libtrace_data.abfd, bfd_archive)) {
282 non_fatal("%s: cannot get addresses from archive", file_name);
283 return -1;
284 }
285
286 if (!bfd_check_format_matches(m_libtrace_data.abfd, bfd_object, &matching)) {
287 bfd_nonfatal(bfd_get_filename(m_libtrace_data.abfd));
288 if (bfd_get_error() == bfd_error_file_ambiguously_recognized) {
289 list_matching_formats(matching);
290 free(matching);
291 }
292 return -1;
293 }
294
295 if (section_name != nullptr) {
296 m_libtrace_data.section = bfd_get_section_by_name(m_libtrace_data.abfd, section_name);
297 if (m_libtrace_data.section == nullptr)
298 non_fatal("%s: cannot find section %s", file_name, section_name);
299 } else
300 m_libtrace_data.section = nullptr;
301
302 if (0 != slurp_symtab(m_libtrace_data.abfd))
303 return -1;
304
305 return 0;
306}
307
309{
310 free(m_libtrace_data.syms);
311 m_libtrace_data.syms = nullptr;
312
313 bfd_close(m_libtrace_data.abfd);
314
315 return 0;
316}
317
318int libtrace_resolve (void *addr, char *buf_func, size_t buf_func_len, char *buf_file, size_t buf_file_len, ...)
319{
320 int ret = FALSE;
321 ret = translate_addresses(m_libtrace_data.abfd, m_libtrace_data.section, addr, buf_func, buf_func_len, buf_file,
322 buf_file_len);
323 assert(0 == ret);
324
325 return 0;
326}
327
328/* --------------------------------------------------------------- */
329
330#ifdef MAIN_FUNC
331static void usage (FILE *stream, int status)
332{
333 fprintf(stream, "Usage: %s image addr <addr...>\n", program_name);
334 fprintf(stream, "Ex: %s cpptraced 0x8048f0e 0x8048fd4 \n", program_name);
335 /*
336 list_supported_targets(program_name, stream). e.g.:
337 elf32-i386 a.out-i386-linux efi-app-ia32
338 elf32-little elf32-big elf64-x86-64
339 elf64-little elf64-big srec symbolsrec
340 tekhex binary ihex
341 trad-core
342 */
343 exit(status);
344}
345
346int main (int argc, char **argv)
347{
348 const char *file_name = nullptr;
349 const char *section_name = nullptr;
350 char *target = nullptr;
351
352#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
353 setlocale (LC_MESSAGES, "");
354#endif
355#if defined (HAVE_SETLOCALE)
356 setlocale (LC_CTYPE, "");
357#endif
358 /* bindtextdomain(PACKAGE, LOCALEDIR);*/
359 /* textdomain(PACKAGE);*/
360 /* expandargv(&argc, &argv); /*libiberty*/
361
362 if (argc < 3) {
363 usage(stderr, 1);
364 }
365
366 file_name = argv[1];
367
368#define FUNC_MAX (PATH_MAX)
369 if (0 == libtrace_init(file_name, section_name, target)) {
370 int i;
371 void *sym = nullptr;
372 char func[FUNC_MAX + 1] = { 0 };
373 char file[PATH_MAX + 1] = { 0 };
374
375 for (i = argc - 2; i < argc; i++) {
376 sscanf(argv[i], "%p", &sym);
377 libtrace_resolve(sym, func, FUNC_MAX, file, PATH_MAX);
378 printf("%s [%s]\n", func, file);
379 }
380
382 return EXIT_SUCCESS;
383 }
384
385 return EXIT_FAILURE;
386}
387#endif /*MAIN_FUNC*/
int libtrace_resolve(void *addr, char *buf_func, size_t buf_func_len, char *buf_file, size_t buf_file_len,...)
void bfd_nonfatal(const char *string)
Definition addr2line.cpp:60
void list_matching_formats(char **p)
static void find_offset_in_section(bfd *, asection *, sym_info *)
static void find_address_in_section(bfd *, asection *, void *)
off_t get_file_size(const char *file_name)
Definition addr2line.cpp:89
static libtrace_data m_libtrace_data
Definition addr2line.cpp:38
int libtrace_init(const char *file_name, const char *section_name, const char *target)
static int slurp_symtab(bfd *)
#define ADDR_BUF_LEN
void set_default_bfd_target(void)
void non_fatal(const char *format,...)
Definition addr2line.cpp:77
static const char * program_name
Definition addr2line.cpp:58
void report(const char *format, va_list args)
Definition addr2line.cpp:70
static int translate_addresses(bfd *abfd, asection *section, void *addr, char *buf_func, size_t buf_func_len, char *buf_file, size_t buf_file_len)
int libtrace_close(void)
voidpf void uLong size
Definition ioapi.h:42
voidpf stream
Definition ioapi.h:42
int main(int argc, char **argv)
The entry point for linux server and client. Initializes the program and calls Qcommon_Frame in an in...
void format(__printf__, 1, 2)))
QGL_EXTERN GLsizei const GLvoid * data
Definition r_gl.h:89
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLsizei const GLvoid GLenum usage
Definition r_gl.h:89
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
bfd_boolean do_demangle
Definition addr2line.cpp:30
bfd_boolean unwind_inlines
Definition addr2line.cpp:28
asection * section
Definition addr2line.cpp:35
asymbol ** syms
Definition addr2line.cpp:32
bfd_boolean base_names
Definition addr2line.cpp:31
bfd_boolean with_functions
Definition addr2line.cpp:29
bfd_boolean found
Definition addr2line.cpp:49
const char * filename
Definition addr2line.cpp:46
bfd_vma pc
Definition addr2line.cpp:45
const char * functionname
Definition addr2line.cpp:47
unsigned int line
Definition addr2line.cpp:48
#define FILE