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 */