UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
addr2line.cpp
Go to the documentation of this file.
1 
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 
26 typedef 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;
34  bfd *abfd;
35  asection *section;
37 
38 static 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 
43 typedef 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 
52 static int slurp_symtab (bfd *);
53 static void find_address_in_section (bfd *, asection *, void *);
54 static void find_offset_in_section (bfd *, asection *, sym_info *);
55 static 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 
58 static const char *program_name = "addr2line";
59 
60 void 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 
70 void 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 
77 void 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 
89 off_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 
109 void list_matching_formats (char **p)
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 
139 static 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 
161 static 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 
186 static 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 
206 static 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 
265 int 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 
308 int libtrace_close (void)
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 
318 int 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
331 static 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 
346 int 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 
381  libtrace_close();
382  return EXIT_SUCCESS;
383  }
384 
385  return EXIT_FAILURE;
386 }
387 #endif /*MAIN_FUNC*/
static int slurp_symtab(bfd *)
Definition: addr2line.cpp:139
int libtrace_close(void)
Definition: addr2line.cpp:308
static libtrace_data m_libtrace_data
Definition: addr2line.cpp:38
int libtrace_resolve(void *addr, char *buf_func, size_t buf_func_len, char *buf_file, size_t buf_file_len,...)
Definition: addr2line.cpp:318
const char * filename
Definition: addr2line.cpp:46
const char * functionname
Definition: addr2line.cpp:47
bfd_boolean found
Definition: addr2line.cpp:49
#define FILE
Definition: test_webapi.cpp:30
unsigned int line
Definition: addr2line.cpp:48
void bfd_nonfatal(const char *string)
Definition: addr2line.cpp:60
int main(int argc, char **argv)
The entry point for linux server and client. Initializes the program and calls Qcommon_Frame in an in...
Definition: linux_main.cpp:47
bfd_boolean with_functions
Definition: addr2line.cpp:29
void report(const char *format, va_list args)
Definition: addr2line.cpp:70
bfd_boolean do_demangle
Definition: addr2line.cpp:30
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)
Definition: addr2line.cpp:206
int libtrace_init(const char *file_name, const char *section_name, const char *target)
Definition: addr2line.cpp:265
struct _libtrace_data libtrace_data
bfd_boolean base_names
Definition: addr2line.cpp:31
GLsizei size
Definition: r_gl.h:152
off_t get_file_size(const char *file_name)
Definition: addr2line.cpp:89
asection * section
Definition: addr2line.cpp:35
asymbol ** syms
Definition: addr2line.cpp:32
struct _sym_info sym_info
void list_matching_formats(char **p)
Definition: addr2line.cpp:109
static const char * program_name
Definition: addr2line.cpp:58
voidpf stream
Definition: ioapi.h:42
QGL_EXTERN GLint i
Definition: r_gl.h:113
void set_default_bfd_target(void)
Definition: addr2line.cpp:124
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
bfd_vma pc
Definition: addr2line.cpp:45
GLsizei const GLvoid GLenum usage
Definition: r_gl.h:152
static void find_address_in_section(bfd *, asection *, void *)
Definition: addr2line.cpp:161
GLsizei const GLvoid * data
Definition: r_gl.h:152
static void find_offset_in_section(bfd *, asection *, sym_info *)
Definition: addr2line.cpp:186
bfd_boolean unwind_inlines
Definition: addr2line.cpp:28
void non_fatal(const char *format,...)
Definition: addr2line.cpp:77
#define ADDR_BUF_LEN
void format(__printf__, 1, 2)))