Bug 1869043 remove declaration of missing CreateOrDestroyAudioTracks r=padenot
[gecko.git] / tools / jprof / bfd.cpp
blob6be8fde760476e74a72fc665fc673fd7e15aecd9
1 // vim:ts=8:sw=2:et:
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "leaky.h"
8 #ifdef USE_BFD
9 # include <stdio.h>
10 # include <string.h>
11 # include <fcntl.h>
12 # include <unistd.h>
13 # include <libgen.h>
14 # include <bfd.h>
15 # include <cxxabi.h>
17 static bfd* try_debug_file(const char* filename, unsigned long crc32) {
18 int fd = open(filename, O_RDONLY);
19 if (fd < 0) return nullptr;
21 unsigned char buf[4 * 1024];
22 unsigned long crc = 0;
24 while (1) {
25 ssize_t count = read(fd, buf, sizeof(buf));
26 if (count <= 0) break;
28 crc = bfd_calc_gnu_debuglink_crc32(crc, buf, count);
31 close(fd);
33 if (crc != crc32) return nullptr;
35 bfd* object = bfd_openr(filename, nullptr);
36 if (!bfd_check_format(object, bfd_object)) {
37 bfd_close(object);
38 return nullptr;
41 return object;
44 static bfd* find_debug_file(bfd* lib, const char* aFileName) {
45 // check for a separate debug file with symbols
46 asection* sect = bfd_get_section_by_name(lib, ".gnu_debuglink");
48 if (!sect) return nullptr;
50 bfd_size_type debuglinkSize = bfd_section_size(objfile->obfd, sect);
52 char* debuglink = new char[debuglinkSize];
53 bfd_get_section_contents(lib, sect, debuglink, 0, debuglinkSize);
55 // crc checksum is aligned to 4 bytes, and after the NUL.
56 int crc_offset = (int(strlen(debuglink)) & ~3) + 4;
57 unsigned long crc32 = bfd_get_32(lib, debuglink + crc_offset);
59 // directory component
60 char* dirbuf = strdup(aFileName);
61 const char* dir = dirname(dirbuf);
63 static const char debug_subdir[] = ".debug";
64 // This is gdb's default global debugging info directory, but gdb can
65 // be instructed to use a different directory.
66 static const char global_debug_dir[] = "/usr/lib/debug";
68 char* filename =
69 new char[strlen(global_debug_dir) + strlen(dir) + crc_offset + 3];
71 // /path/debuglink
72 sprintf(filename, "%s/%s", dir, debuglink);
73 bfd* debugFile = try_debug_file(filename, crc32);
74 if (!debugFile) {
75 // /path/.debug/debuglink
76 sprintf(filename, "%s/%s/%s", dir, debug_subdir, debuglink);
77 debugFile = try_debug_file(filename, crc32);
78 if (!debugFile) {
79 // /usr/lib/debug/path/debuglink
80 sprintf(filename, "%s/%s/%s", global_debug_dir, dir, debuglink);
81 debugFile = try_debug_file(filename, crc32);
85 delete[] filename;
86 free(dirbuf);
87 delete[] debuglink;
89 return debugFile;
92 // Use an indirect array to avoid copying tons of objects
93 Symbol** leaky::ExtendSymbols(int num) {
94 long n = numExternalSymbols + num;
96 externalSymbols = (Symbol**)realloc(externalSymbols,
97 (size_t)(sizeof(externalSymbols[0]) * n));
98 Symbol* new_array = new Symbol[n];
99 for (int i = 0; i < num; i++) {
100 externalSymbols[i + numExternalSymbols] = &new_array[i];
102 lastSymbol = externalSymbols + n;
103 Symbol** sp = externalSymbols + numExternalSymbols;
104 numExternalSymbols = n;
105 return sp;
108 # define NEXT_SYMBOL \
109 do { \
110 sp++; \
111 if (sp >= lastSymbol) { \
112 sp = ExtendSymbols(16384); \
114 } while (0)
116 void leaky::ReadSymbols(const char* aFileName, u_long aBaseAddress) {
117 int initialSymbols = usefulSymbols;
118 if (nullptr == externalSymbols) {
119 externalSymbols = (Symbol**)calloc(sizeof(Symbol*), 10000);
120 Symbol* new_array = new Symbol[10000];
121 for (int i = 0; i < 10000; i++) {
122 externalSymbols[i] = &new_array[i];
124 numExternalSymbols = 10000;
126 Symbol** sp = externalSymbols + usefulSymbols;
127 lastSymbol = externalSymbols + numExternalSymbols;
129 // Create a dummy symbol for the library so, if it doesn't have any
130 // symbols, we show it by library.
131 (*sp)->Init(aFileName, aBaseAddress);
132 NEXT_SYMBOL;
134 bfd_boolean kDynamic = (bfd_boolean) false;
136 static int firstTime = 1;
137 if (firstTime) {
138 firstTime = 0;
139 bfd_init();
142 bfd* lib = bfd_openr(aFileName, nullptr);
143 if (nullptr == lib) {
144 return;
146 if (!bfd_check_format(lib, bfd_object)) {
147 bfd_close(lib);
148 return;
151 bfd* symbolFile = find_debug_file(lib, aFileName);
153 // read mini symbols
154 PTR minisyms;
155 unsigned int size;
156 long symcount = 0;
158 if (symbolFile) {
159 symcount = bfd_read_minisymbols(symbolFile, kDynamic, &minisyms, &size);
160 if (symcount == 0) {
161 bfd_close(symbolFile);
162 } else {
163 bfd_close(lib);
166 if (symcount == 0) {
167 symcount = bfd_read_minisymbols(lib, kDynamic, &minisyms, &size);
168 if (symcount == 0) {
169 // symtab is empty; try dynamic symbols
170 kDynamic = (bfd_boolean) true;
171 symcount = bfd_read_minisymbols(lib, kDynamic, &minisyms, &size);
173 symbolFile = lib;
176 asymbol* store;
177 store = bfd_make_empty_symbol(symbolFile);
179 // Scan symbols
180 size_t demangle_buffer_size = 128;
181 char* demangle_buffer = (char*)malloc(demangle_buffer_size);
182 bfd_byte* from = (bfd_byte*)minisyms;
183 bfd_byte* fromend = from + symcount * size;
184 for (; from < fromend; from += size) {
185 asymbol* sym;
186 sym =
187 bfd_minisymbol_to_symbol(symbolFile, kDynamic, (const PTR)from, store);
189 symbol_info syminfo;
190 bfd_get_symbol_info(symbolFile, sym, &syminfo);
192 // if ((syminfo.type == 'T') || (syminfo.type == 't')) {
193 const char* nm = bfd_asymbol_name(sym);
194 if (nm && nm[0]) {
195 char* dnm = nullptr;
196 if (strncmp("__thunk", nm, 7)) {
197 dnm =
198 abi::__cxa_demangle(nm, demangle_buffer, &demangle_buffer_size, 0);
199 if (dnm) {
200 demangle_buffer = dnm;
203 (*sp)->Init(dnm ? dnm : nm, syminfo.value + aBaseAddress);
204 NEXT_SYMBOL;
206 // }
209 free(demangle_buffer);
210 demangle_buffer = nullptr;
212 bfd_close(symbolFile);
214 int interesting = sp - externalSymbols;
215 if (!quiet) {
216 printf("%s provided %d symbols\n", aFileName, interesting - initialSymbols);
218 usefulSymbols = interesting;
221 #endif /* USE_BFD */