tools/jprof/bfd.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/jprof/bfd.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,231 @@
     1.4 +// vim:ts=8:sw=2:et:
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "leaky.h"
    1.10 +
    1.11 +#ifdef USE_BFD
    1.12 +#include <stdio.h>
    1.13 +#include <string.h>
    1.14 +#include <fcntl.h>
    1.15 +#include <unistd.h>
    1.16 +#include <libgen.h>
    1.17 +#include <bfd.h>
    1.18 +#include <cxxabi.h>
    1.19 +
    1.20 +static bfd *try_debug_file(const char *filename, unsigned long crc32)
    1.21 +{
    1.22 +  int fd = open(filename, O_RDONLY);
    1.23 +  if (fd < 0)
    1.24 +    return nullptr;
    1.25 +
    1.26 +  unsigned char buf[4*1024];
    1.27 +  unsigned long crc = 0;
    1.28 +
    1.29 +  while (1) {
    1.30 +    ssize_t count = read(fd, buf, sizeof(buf));
    1.31 +    if (count <= 0)
    1.32 +      break;
    1.33 +
    1.34 +    crc = bfd_calc_gnu_debuglink_crc32(crc, buf, count);
    1.35 +  }
    1.36 +
    1.37 +  close(fd);
    1.38 +
    1.39 +  if (crc != crc32)
    1.40 +    return nullptr;
    1.41 +
    1.42 +  bfd *object = bfd_openr(filename, nullptr);
    1.43 +  if (!bfd_check_format(object, bfd_object)) {
    1.44 +    bfd_close(object);
    1.45 +    return nullptr;
    1.46 +  }
    1.47 +
    1.48 +  return object;
    1.49 +}
    1.50 +
    1.51 +static bfd *find_debug_file(bfd *lib, const char *aFileName)
    1.52 +{
    1.53 +  // check for a separate debug file with symbols
    1.54 +  asection *sect = bfd_get_section_by_name(lib, ".gnu_debuglink");
    1.55 +
    1.56 +  if (!sect)
    1.57 +    return nullptr;
    1.58 +
    1.59 +  bfd_size_type debuglinkSize = bfd_section_size (objfile->obfd, sect);
    1.60 +
    1.61 +  char *debuglink = new char[debuglinkSize];
    1.62 +  bfd_get_section_contents(lib, sect, debuglink, 0, debuglinkSize);
    1.63 +
    1.64 +  // crc checksum is aligned to 4 bytes, and after the NUL.
    1.65 +  int crc_offset = (int(strlen(debuglink)) & ~3) + 4;
    1.66 +  unsigned long crc32 = bfd_get_32(lib, debuglink + crc_offset);
    1.67 +
    1.68 +  // directory component
    1.69 +  char *dirbuf = strdup(aFileName);
    1.70 +  const char *dir = dirname(dirbuf);
    1.71 +
    1.72 +  static const char debug_subdir[] = ".debug";
    1.73 +  // This is gdb's default global debugging info directory, but gdb can
    1.74 +  // be instructed to use a different directory.
    1.75 +  static const char global_debug_dir[] = "/usr/lib/debug";
    1.76 +
    1.77 +  char *filename =
    1.78 +    new char[strlen(global_debug_dir) + strlen(dir) + crc_offset + 3];
    1.79 +
    1.80 +  // /path/debuglink
    1.81 +  sprintf(filename, "%s/%s", dir, debuglink);
    1.82 +  bfd *debugFile = try_debug_file(filename, crc32);
    1.83 +  if (!debugFile) {
    1.84 +
    1.85 +    // /path/.debug/debuglink
    1.86 +    sprintf(filename, "%s/%s/%s", dir, debug_subdir, debuglink);
    1.87 +    debugFile = try_debug_file(filename, crc32);
    1.88 +    if (!debugFile) {
    1.89 +
    1.90 +      // /usr/lib/debug/path/debuglink
    1.91 +      sprintf(filename, "%s/%s/%s", global_debug_dir, dir, debuglink);
    1.92 +      debugFile = try_debug_file(filename, crc32);
    1.93 +    }
    1.94 +  }
    1.95 +
    1.96 +  delete[] filename;
    1.97 +  free(dirbuf);
    1.98 +  delete[] debuglink;
    1.99 +
   1.100 +  return debugFile;
   1.101 +}
   1.102 +
   1.103 +
   1.104 +// Use an indirect array to avoid copying tons of objects
   1.105 +Symbol ** leaky::ExtendSymbols(int num)
   1.106 +{
   1.107 +  long n = numExternalSymbols + num;
   1.108 +
   1.109 +  externalSymbols = (Symbol**)
   1.110 +                    realloc(externalSymbols,
   1.111 +                            (size_t) (sizeof(externalSymbols[0]) * n));
   1.112 +  Symbol *new_array = new Symbol[n];
   1.113 +  for (int i = 0; i < num; i++) {
   1.114 +    externalSymbols[i + numExternalSymbols] = &new_array[i];
   1.115 +  }
   1.116 +  lastSymbol = externalSymbols + n;
   1.117 +  Symbol **sp = externalSymbols + numExternalSymbols;
   1.118 +  numExternalSymbols = n;
   1.119 +  return sp;
   1.120 +}
   1.121 +
   1.122 +#define NEXT_SYMBOL do { sp++; \
   1.123 +                         if (sp >= lastSymbol) { \
   1.124 +                           sp = ExtendSymbols(16384); \
   1.125 +                         } \
   1.126 +                       } while (0)
   1.127 +
   1.128 +void leaky::ReadSymbols(const char *aFileName, u_long aBaseAddress)
   1.129 +{
   1.130 +  int initialSymbols = usefulSymbols;
   1.131 +  if (nullptr == externalSymbols) {
   1.132 +    externalSymbols = (Symbol**) calloc(sizeof(Symbol*),10000);
   1.133 +    Symbol *new_array = new Symbol[10000];
   1.134 +    for (int i = 0; i < 10000; i++) {
   1.135 +      externalSymbols[i] = &new_array[i];
   1.136 +    }
   1.137 +    numExternalSymbols = 10000;
   1.138 +  }
   1.139 +  Symbol** sp = externalSymbols + usefulSymbols;
   1.140 +  lastSymbol = externalSymbols + numExternalSymbols;
   1.141 +
   1.142 +  // Create a dummy symbol for the library so, if it doesn't have any
   1.143 +  // symbols, we show it by library.
   1.144 +  (*sp)->Init(aFileName, aBaseAddress);
   1.145 +  NEXT_SYMBOL;
   1.146 +
   1.147 +  bfd_boolean kDynamic = (bfd_boolean) false;
   1.148 +
   1.149 +  static int firstTime = 1;
   1.150 +  if (firstTime) {
   1.151 +    firstTime = 0;
   1.152 +    bfd_init ();
   1.153 +  }
   1.154 +
   1.155 +  bfd* lib = bfd_openr(aFileName, nullptr);
   1.156 +  if (nullptr == lib) {
   1.157 +    return;
   1.158 +  }
   1.159 +  if (!bfd_check_format(lib, bfd_object)) {
   1.160 +    bfd_close(lib);
   1.161 +    return;
   1.162 +  }
   1.163 +
   1.164 +  bfd *symbolFile = find_debug_file(lib, aFileName);
   1.165 +
   1.166 +  // read mini symbols
   1.167 +  PTR minisyms;
   1.168 +  unsigned int size;
   1.169 +  long symcount = 0;
   1.170 +
   1.171 +  if (symbolFile) {
   1.172 +    symcount = bfd_read_minisymbols(symbolFile, kDynamic, &minisyms, &size);
   1.173 +    if (symcount == 0) {
   1.174 +      bfd_close(symbolFile);
   1.175 +    } else {
   1.176 +      bfd_close(lib);
   1.177 +    }
   1.178 +  }
   1.179 +  if (symcount == 0) {
   1.180 +    symcount = bfd_read_minisymbols(lib, kDynamic, &minisyms, &size);
   1.181 +    if (symcount == 0) {
   1.182 +      // symtab is empty; try dynamic symbols
   1.183 +      kDynamic = (bfd_boolean) true;
   1.184 +      symcount = bfd_read_minisymbols(lib, kDynamic, &minisyms, &size);
   1.185 +    }
   1.186 +    symbolFile = lib;
   1.187 +  }
   1.188 +
   1.189 +  asymbol* store;
   1.190 +  store = bfd_make_empty_symbol(symbolFile);
   1.191 +
   1.192 +  // Scan symbols
   1.193 +  size_t demangle_buffer_size = 128;
   1.194 +  char *demangle_buffer = (char*) malloc(demangle_buffer_size);
   1.195 +  bfd_byte* from = (bfd_byte *) minisyms;
   1.196 +  bfd_byte* fromend = from + symcount * size;
   1.197 +  for (; from < fromend; from += size) {
   1.198 +    asymbol *sym;
   1.199 +    sym = bfd_minisymbol_to_symbol(symbolFile, kDynamic, (const PTR) from, store);
   1.200 +
   1.201 +    symbol_info syminfo;
   1.202 +    bfd_get_symbol_info (symbolFile, sym, &syminfo);
   1.203 +
   1.204 +//    if ((syminfo.type == 'T') || (syminfo.type == 't')) {
   1.205 +      const char* nm = bfd_asymbol_name(sym);
   1.206 +      if (nm && nm[0]) {
   1.207 +        char* dnm = nullptr;
   1.208 +        if (strncmp("__thunk", nm, 7)) {
   1.209 +          dnm =
   1.210 +            abi::__cxa_demangle(nm, demangle_buffer, &demangle_buffer_size, 0);
   1.211 +          if (dnm) {
   1.212 +            demangle_buffer = dnm;
   1.213 +          }
   1.214 +        }
   1.215 +        (*sp)->Init(dnm ? dnm : nm, syminfo.value + aBaseAddress);
   1.216 +        NEXT_SYMBOL;
   1.217 +      }
   1.218 +//    }
   1.219 +  }
   1.220 +
   1.221 +  free(demangle_buffer);
   1.222 +  demangle_buffer = nullptr;
   1.223 +
   1.224 +  bfd_close(symbolFile);
   1.225 +
   1.226 +  int interesting = sp - externalSymbols;
   1.227 +  if (!quiet) {
   1.228 +    printf("%s provided %d symbols\n", aFileName,
   1.229 +           interesting - initialSymbols);
   1.230 +  }
   1.231 +  usefulSymbols = interesting;
   1.232 +}
   1.233 +
   1.234 +#endif /* USE_BFD */

mercurial