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/. */
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;
25 ssize_t count
= read(fd
, buf
, sizeof(buf
));
26 if (count
<= 0) break;
28 crc
= bfd_calc_gnu_debuglink_crc32(crc
, buf
, count
);
33 if (crc
!= crc32
) return nullptr;
35 bfd
* object
= bfd_openr(filename
, nullptr);
36 if (!bfd_check_format(object
, bfd_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";
69 new char[strlen(global_debug_dir
) + strlen(dir
) + crc_offset
+ 3];
72 sprintf(filename
, "%s/%s", dir
, debuglink
);
73 bfd
* debugFile
= try_debug_file(filename
, crc32
);
75 // /path/.debug/debuglink
76 sprintf(filename
, "%s/%s/%s", dir
, debug_subdir
, debuglink
);
77 debugFile
= try_debug_file(filename
, crc32
);
79 // /usr/lib/debug/path/debuglink
80 sprintf(filename
, "%s/%s/%s", global_debug_dir
, dir
, debuglink
);
81 debugFile
= try_debug_file(filename
, crc32
);
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
;
108 # define NEXT_SYMBOL \
111 if (sp >= lastSymbol) { \
112 sp = ExtendSymbols(16384); \
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
);
134 bfd_boolean kDynamic
= (bfd_boolean
) false;
136 static int firstTime
= 1;
142 bfd
* lib
= bfd_openr(aFileName
, nullptr);
143 if (nullptr == lib
) {
146 if (!bfd_check_format(lib
, bfd_object
)) {
151 bfd
* symbolFile
= find_debug_file(lib
, aFileName
);
159 symcount
= bfd_read_minisymbols(symbolFile
, kDynamic
, &minisyms
, &size
);
161 bfd_close(symbolFile
);
167 symcount
= bfd_read_minisymbols(lib
, kDynamic
, &minisyms
, &size
);
169 // symtab is empty; try dynamic symbols
170 kDynamic
= (bfd_boolean
) true;
171 symcount
= bfd_read_minisymbols(lib
, kDynamic
, &minisyms
, &size
);
177 store
= bfd_make_empty_symbol(symbolFile
);
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
) {
187 bfd_minisymbol_to_symbol(symbolFile
, kDynamic
, (const PTR
)from
, store
);
190 bfd_get_symbol_info(symbolFile
, sym
, &syminfo
);
192 // if ((syminfo.type == 'T') || (syminfo.type == 't')) {
193 const char* nm
= bfd_asymbol_name(sym
);
196 if (strncmp("__thunk", nm
, 7)) {
198 abi::__cxa_demangle(nm
, demangle_buffer
, &demangle_buffer_size
, 0);
200 demangle_buffer
= dnm
;
203 (*sp
)->Init(dnm
? dnm
: nm
, syminfo
.value
+ aBaseAddress
);
209 free(demangle_buffer
);
210 demangle_buffer
= nullptr;
212 bfd_close(symbolFile
);
214 int interesting
= sp
- externalSymbols
;
216 printf("%s provided %d symbols\n", aFileName
, interesting
- initialSymbols
);
218 usefulSymbols
= interesting
;