00001
00002
00003
00004
00005
00006
00007 #include "systrace.h"
00008
00009 #ifdef TRACE_SOURCE_FILES
00010
00011 #include <sys/stat.h>
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <errno.h>
00015 #include <string.h>
00016 #include <limits.h>
00017 #include <assert.h>
00018 #include "iotools.h"
00019
00020
00021 #include <bfd.h>
00022 #define DMGL_PARAMS (1 << 0)
00023 #define DMGL_ANSI (1 << 1)
00024
00025
00026
00027
00028 typedef struct _libtrace_data {
00029 bfd_boolean unwind_inlines;
00030 bfd_boolean with_functions;
00031 bfd_boolean do_demangle;
00032 bfd_boolean base_names;
00033 asymbol **syms;
00034
00035 bfd *abfd;
00036 asection *section;
00037 } libtrace_data;
00038
00039
00040
00041 static libtrace_data m_libtrace_data = {
00042 FALSE,
00043 FALSE,
00044 FALSE,
00045 TRUE,
00046 NULL,
00047 NULL,
00048 NULL,
00049 };
00050
00051
00052
00053
00054
00055
00056
00057 typedef struct _sym_info {
00058 bfd_vma pc;
00059 const char *filename;
00060 const char *functionname;
00061 unsigned int line;
00062 bfd_boolean found;
00063 } sym_info;
00064
00065
00066
00067 static int slurp_symtab (bfd *);
00068 static void find_address_in_section (bfd *, asection *, void *);
00069 static void find_offset_in_section (bfd *, asection *, sym_info *);
00070 static int translate_addresses (bfd *abfd, asection *section,
00071 void *addr,
00072 char *buf_func, size_t buf_func_len,
00073 char *buf_file, size_t buf_file_len,
00074 unsigned int &line);
00075
00076
00077 static const char *program_name = NULL;
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 void set_program_name(const char *name)
00091 {
00092 program_name = name;
00093 }
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 const char *get_program_name()
00106 {
00107 return program_name;
00108 }
00109
00110
00111
00112 void *get_bfd_pointer()
00113 {
00114 return (void *)m_libtrace_data.abfd;
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 void bfd_nonfatal(const char *string)
00127 {
00128 const char *errmsg = bfd_errmsg (bfd_get_error ());
00129
00130 if (string)
00131 print_err("%s: %s", __FILE__, __LINE__, __func__, string, errmsg);
00132 else
00133 print_err("%s", __FILE__, __LINE__, __func__, errmsg);
00134 }
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 off_t get_file_size(const char * file_name)
00151 {
00152 struct stat statbuf;
00153
00154 if (stat(file_name, &statbuf) < 0)
00155 {
00156 if (errno == ENOENT)
00157 print_err("'%s': no such file", __FILE__, __LINE__, __func__, file_name);
00158 else
00159 print_warning("could not locate '%s'. reason: %s",
00160 __FILE__, __LINE__, __func__, file_name, strerror (errno));
00161 }
00162 else
00163 {
00164 if (! S_ISREG (statbuf.st_mode))
00165 print_warning("'%s' is not an ordinary file", __FILE__, __LINE__, __func__, file_name);
00166 else
00167 return statbuf.st_size;
00168 }
00169
00170 return 0;
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 void list_matching_formats(char **p)
00186 {
00187 if (!p || !*p)
00188 return;
00189
00190 char **x = p;
00191 char *buf;
00192 char *aux;
00193 long l = 0;
00194
00195 while (*p)
00196 {
00197 l += strlen(*p)+1;
00198 p++;
00199 }
00200 p = x;
00201 buf = new char[l];
00202 aux = buf;
00203 while (*p)
00204 {
00205 sprintf(aux, " %s", *p);
00206 aux += strlen(*p)+1;
00207 p++;
00208 }
00209 print_err("matching formats:%s", __FILE__, __LINE__, __func__, buf);
00210 delete [] buf;
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 static int slurp_symtab(bfd *abfd)
00250 {
00251 long symcount;
00252 unsigned int size;
00253
00254 if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
00255 return -1;
00256
00257 symcount = bfd_read_minisymbols(abfd, FALSE, (void **)(&m_libtrace_data.syms), &size);
00258 if (symcount == 0)
00259 symcount = bfd_read_minisymbols(abfd, TRUE ,
00260 (void **)(&m_libtrace_data.syms), &size);
00261
00262 if (symcount < 0)
00263 {
00264 bfd_nonfatal(bfd_get_filename(abfd));
00265 return -1;
00266 }
00267
00268 return 0;
00269 }
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 static void find_address_in_section(bfd *abfd, asection *section, void *data)
00283 {
00284 bfd_vma vma;
00285 bfd_size_type size;
00286 sym_info *psi = (sym_info*)data;
00287
00288 if (psi->found)
00289 return;
00290
00291 if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
00292 return;
00293
00294 vma = bfd_get_section_vma(abfd, section);
00295 if (psi->pc < vma)
00296 return;
00297
00298 size = bfd_get_section_size(section);
00299 if (psi->pc >= vma + size)
00300 return;
00301
00302 psi->found = bfd_find_nearest_line(abfd, section,
00303 m_libtrace_data.syms, psi->pc - vma,
00304 &psi->filename, &psi->functionname,
00305 &psi->line);
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 static void find_offset_in_section(bfd *abfd, asection *section, sym_info *psi)
00322 {
00323 bfd_size_type size;
00324
00325 if (psi->found)
00326 return;
00327
00328 if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
00329 return;
00330
00331 size = bfd_get_section_size(section);
00332 if (psi->pc >= size)
00333 return;
00334
00335 psi->found = bfd_find_nearest_line(abfd, section,
00336 m_libtrace_data.syms, psi->pc,
00337 &psi->filename, &psi->functionname,
00338 &psi->line);
00339 }
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 static int translate_addresses(bfd *abfd, asection *section,
00361 void *xaddr,
00362 char *buf_func, size_t buf_func_len,
00363 char *buf_file, size_t buf_file_len,
00364 unsigned int &line)
00365 {
00366 #define ADDR_BUF_LEN ((CHAR_BIT/4)*(sizeof(void*))+1)
00367 char addr[ADDR_BUF_LEN+1] = {0};
00368 sym_info si = {0};
00369
00370 sprintf(addr, "%p", xaddr);
00371 si.pc = bfd_scan_vma (addr, NULL, 16);
00372
00373 si.found = FALSE;
00374 if (section)
00375 find_offset_in_section(abfd, section, &si);
00376 else
00377 bfd_map_over_sections(abfd, find_address_in_section, &si);
00378
00379 if (! si.found)
00380 {
00381 if (buf_func != NULL)
00382 snprintf(buf_func, buf_func_len, "%s ??:0",
00383 m_libtrace_data.with_functions ? "??" : "");
00384 }
00385 else
00386 {
00387 line = si.line;
00388 do
00389 {
00390 if (m_libtrace_data.with_functions)
00391 {
00392 const char *name;
00393 char *alloc = NULL;
00394
00395 name = si.functionname;
00396 if (name == NULL || *name == '\0')
00397 name = "??";
00398 else
00399 if (m_libtrace_data.do_demangle)
00400 {
00401 alloc = bfd_demangle(abfd, name, DMGL_ANSI | DMGL_PARAMS);
00402 if (alloc != NULL)
00403 name = alloc;
00404 }
00405
00406 if (buf_func != NULL)
00407 snprintf(buf_func, buf_func_len, "%s", name);
00408
00409 if (alloc != NULL)
00410 free (alloc);
00411 }
00412
00413 if (m_libtrace_data.base_names && si.filename != NULL)
00414 {
00415 const char *h = strrchr(si.filename, '/');
00416 if (h != NULL)
00417 si.filename = h + 1;
00418 }
00419
00420 if (buf_file != NULL)
00421 snprintf(buf_file, buf_file_len, "%s",
00422 si.filename ? si.filename : "??");
00423 if (!m_libtrace_data.unwind_inlines)
00424 si.found = FALSE;
00425 else
00426 si.found = bfd_find_inliner_info(abfd, &si.filename, &si.functionname, &si.line);
00427 } while (si.found);
00428 }
00429
00430 return si.found;
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 int libtrace_init(const char *file_name, const char *section_name, const char *target)
00449 {
00450 char **matching = NULL;
00451
00452 bfd_init();
00453
00454
00455 if (get_file_size(file_name) < 1)
00456 return -1;
00457
00458 m_libtrace_data.abfd = bfd_openr(file_name, target);
00459 if (m_libtrace_data.abfd == NULL)
00460 {
00461 bfd_nonfatal(file_name);
00462 return -1;
00463 }
00464
00465 if (bfd_check_format(m_libtrace_data.abfd, bfd_archive))
00466 {
00467 print_err ("%s: cannot get addresses from archive",
00468 __FILE__, __LINE__, __func__, file_name);
00469 return -1;
00470 }
00471
00472 if (!bfd_check_format_matches(m_libtrace_data.abfd, bfd_object, &matching))
00473 {
00474 bfd_nonfatal(bfd_get_filename(m_libtrace_data.abfd));
00475 if (bfd_get_error() == bfd_error_file_ambiguously_recognized)
00476 {
00477 list_matching_formats(matching);
00478 free (matching);
00479 }
00480 return -1;
00481 }
00482
00483 if (section_name != NULL)
00484 {
00485 m_libtrace_data.section = bfd_get_section_by_name(m_libtrace_data.abfd,
00486 section_name);
00487 if (m_libtrace_data.section == NULL)
00488 print_err("%s: cannot find section %s",
00489 __FILE__, __LINE__, __func__, file_name, section_name);
00490 } else
00491 m_libtrace_data.section = NULL;
00492
00493 if (0 != slurp_symtab(m_libtrace_data.abfd))
00494 return -1;
00495
00496 return 0;
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 void libtrace_close(void)
00510 {
00511 if (m_libtrace_data.syms != NULL)
00512 {
00513 free (m_libtrace_data.syms);
00514 m_libtrace_data.syms = NULL;
00515 }
00516
00517 bfd_close(m_libtrace_data.abfd);
00518 }
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537 int libtrace_resolve(void *addr,
00538 char *buf_func, size_t buf_func_len,
00539 char *buf_file, size_t buf_file_len,
00540 unsigned int &line)
00541 {
00542 int ret = FALSE;
00543 ret = translate_addresses(m_libtrace_data.abfd,
00544 m_libtrace_data.section, addr,
00545 buf_func, buf_func_len,
00546 buf_file, buf_file_len, line);
00547 assert(0 == ret);
00548
00549 return 0;
00550 }
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 #endif
00575