/src/libdwarf/src/lib/libdwarf/dwarf_object_detector.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright (c) 2018-2020, David Anderson All rights reserved. |
3 | | |
4 | | Redistribution and use in source and binary forms, with |
5 | | or without modification, are permitted provided that the |
6 | | following conditions are met: |
7 | | |
8 | | Redistributions of source code must retain the above |
9 | | copyright notice, this list of conditions and the following |
10 | | disclaimer. |
11 | | |
12 | | Redistributions in binary form must reproduce the above |
13 | | copyright notice, this list of conditions and the following |
14 | | disclaimer in the documentation and/or other materials |
15 | | provided with the distribution. |
16 | | |
17 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
18 | | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
19 | | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 | | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
22 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
24 | | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
25 | | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
28 | | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
29 | | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | | */ |
31 | | |
32 | | #include <config.h> |
33 | | |
34 | | #include <stdlib.h> /* free() */ |
35 | | #include <stdio.h> /* SEEK_END SEEK_SET */ |
36 | | #include <string.h> /* memset() strlen() */ |
37 | | |
38 | | #ifdef _WIN32 |
39 | | #ifdef HAVE_STDAFX_H |
40 | | #include "stdafx.h" |
41 | | #endif /* HAVE_STDAFX_H */ |
42 | | #include <io.h> /* lseek() off_t ssize_t */ |
43 | | #elif defined HAVE_UNISTD_H |
44 | | #include <unistd.h> /* lseek() off_t */ |
45 | | #endif /* _WIN32 */ |
46 | | |
47 | | #ifdef HAVE_FCNTL_H |
48 | | #include <fcntl.h> /* open() O_RDONLY */ |
49 | | #endif /* HAVE_FCNTL_H */ |
50 | | |
51 | | #include "dwarf.h" |
52 | | #include "libdwarf.h" |
53 | | #include "libdwarf_private.h" |
54 | | #include "dwarf_base_types.h" |
55 | | #include "dwarf_opaque.h" |
56 | | #include "dwarf_memcpy_swap.h" |
57 | | #include "dwarf_object_read_common.h" |
58 | | #include "dwarf_object_detector.h" |
59 | | #include "dwarf_string.h" |
60 | | |
61 | | #ifndef O_BINARY |
62 | 27.8k | #define O_BINARY 0 |
63 | | #endif /* O_BINARY */ |
64 | | |
65 | | #ifndef O_RDONLY |
66 | | #define O_RDONLY 0 |
67 | | #endif |
68 | | |
69 | | /* TYP, SIZEOFT32 and ASNAR |
70 | | mean we can use correctly-sized arrays of char for the |
71 | | struct members instead of determining a proper integer |
72 | | that size. |
73 | | |
74 | | We are dealing with carefully constructed structs |
75 | | that do not have any alignment-forced (hidden) |
76 | | unused bytes so reading lengths from the real structs |
77 | | works for each variable. */ |
78 | | |
79 | | #define TYP(n,l) char (n)[(l)] |
80 | 8.82k | #define SIZEOFT32 4 |
81 | | |
82 | 19.0k | #define DW_DLV_NO_ENTRY -1 |
83 | 127k | #define DW_DLV_OK 0 |
84 | 47.0k | #define DW_DLV_ERROR 1 |
85 | | |
86 | | #ifndef EI_NIDENT |
87 | | #define EI_NIDENT 16 |
88 | 18.2k | #define EI_CLASS 4 |
89 | 18.2k | #define EI_DATA 5 |
90 | 18.2k | #define EI_VERSION 6 |
91 | 13.2k | #define ELFCLASS32 1 |
92 | 4.96k | #define ELFCLASS64 2 |
93 | 17.5k | #define ELFDATA2LSB 1 |
94 | 677 | #define ELFDATA2MSB 2 |
95 | | #endif /* EI_NIDENT */ |
96 | | |
97 | 17.6k | #define DSYM_SUFFIX ".dSYM/Contents/Resources/DWARF/" |
98 | | #define PATHSIZE 2000 |
99 | | |
100 | | #ifndef MH_MAGIC |
101 | | /* mach-o 32bit */ |
102 | 9.11k | #define MH_MAGIC 0xfeedface |
103 | 7.47k | #define MH_CIGAM 0xcefaedfe |
104 | | #endif /* MH_MAGIC */ |
105 | | #ifndef MH_MAGIC_64 |
106 | | /* mach-o 64bit */ |
107 | 5.45k | #define MH_MAGIC_64 0xfeedfacf |
108 | 5.01k | #define MH_CIGAM_64 0xcffaedfe |
109 | | #endif /* MH_MAGIC_64 */ |
110 | | |
111 | | /* A flag not public to users. */ |
112 | | static int _dwarf_global_debuglink_crc_suppress; |
113 | | |
114 | | int |
115 | | dwarf_suppress_debuglink_crc(int dw_suppress) |
116 | 0 | { |
117 | 0 | int old = _dwarf_global_debuglink_crc_suppress; |
118 | 0 | _dwarf_global_debuglink_crc_suppress = dw_suppress; |
119 | 0 | return old; |
120 | 0 | } |
121 | | |
122 | | int _dwarf_get_suppress_debuglink_crc(void) |
123 | 0 | { |
124 | 0 | return _dwarf_global_debuglink_crc_suppress; |
125 | 0 | } |
126 | | |
127 | | static unsigned long |
128 | | magic_copy(unsigned char *d, unsigned len) |
129 | 12.1k | { |
130 | 12.1k | unsigned i = 0; |
131 | 12.1k | unsigned long v = 0; |
132 | | |
133 | 12.1k | v = d[0]; |
134 | 42.5k | for (i = 1 ; i < len; ++i) { |
135 | 30.3k | v <<= 8; |
136 | 30.3k | v |= d[i]; |
137 | 30.3k | } |
138 | 12.1k | return v; |
139 | 12.1k | } |
140 | | |
141 | | #define EI_NIDENT 16 |
142 | | /* An incomplete elf header, good for 32 and 64bit elf */ |
143 | | struct elf_header { |
144 | | unsigned char e_ident[EI_NIDENT]; |
145 | | TYP(e_type,2); |
146 | | TYP(e_machine,2); |
147 | | TYP(e_version,4); |
148 | | }; |
149 | | |
150 | | /* Windows. Certain PE objects. |
151 | | The following references may be of interest. |
152 | | https://msdn.microsoft.com/library/windows/\ |
153 | | desktop/ms680547(v=vs.85).aspx |
154 | | #PE format overview and various machine magic numbers |
155 | | |
156 | | https://msdn.microsoft.com/en-us/library/\ |
157 | | ms809762.aspx |
158 | | # describes some details of PE headers, basically an overview |
159 | | |
160 | | https://msdn.microsoft.com/en-us/library/\ |
161 | | windows/desktop/aa383751(v=vs.85).aspx |
162 | | #defines sizes of various types |
163 | | |
164 | | https://msdn.microsoft.com/fr-fr/library/\ |
165 | | windows/desktop/ms680313(v=vs.85).aspx |
166 | | #defines IMAGE_FILE_HEADER and Machine fields (32/64) |
167 | | |
168 | | https://msdn.microsoft.com/fr-fr/library/\ |
169 | | windows/desktop/ms680305(v=vs.85).aspx |
170 | | #defines IMAGE_DATA_DIRECTORY |
171 | | |
172 | | https://msdn.microsoft.com/en-us/library/\ |
173 | | windows/desktop/ms680339(v=vs.85).aspx |
174 | | #Defines IMAGE_OPTIONAL_HEADER and some magic numbers |
175 | | |
176 | | https://msdn.microsoft.com/fr-fr/library/\ |
177 | | windows/desktop/ms680336(v=vs.85).aspx |
178 | | # defines _IMAGE_NT_HEADERS 32 64 |
179 | | |
180 | | https://msdn.microsoft.com/en-us/library/\ |
181 | | windows/desktop/ms680341(v=vs.85).aspx |
182 | | # defines _IMAGE_SECTION_HEADER |
183 | | |
184 | | */ |
185 | | |
186 | | /* ===== START pe structures */ |
187 | | |
188 | | struct dos_header { |
189 | | TYP(dh_mz,2); |
190 | | TYP(dh_dos_data,58); |
191 | | TYP(dh_image_offset,4); |
192 | | }; |
193 | | |
194 | 3.04k | #define IMAGE_DOS_SIGNATURE_dw 0x5A4D |
195 | 2.36k | #define IMAGE_DOS_REVSIGNATURE_dw 0x4D5A |
196 | 2.55k | #define IMAGE_NT_SIGNATURE_dw 0x00004550 |
197 | 1.75k | #define IMAGE_FILE_MACHINE_I386_dw 0x14c |
198 | 154 | #define IMAGE_FILE_MACHINE_IA64_dw 0x200 |
199 | 173 | #define IMAGE_FILE_MACHINE_AMD64_dw 0x8664 |
200 | | |
201 | | struct pe_image_file_header { |
202 | | TYP(im_machine,2); |
203 | | TYP(im_sectioncount,2); |
204 | | TYP(im_ignoring,(3*4)); |
205 | | TYP(im_opt_header_size,2); |
206 | | TYP(im_ignoringb,2); |
207 | | }; |
208 | | |
209 | | /* ===== END pe structures */ |
210 | | |
211 | | /* For following MacOS file naming convention */ |
212 | | static const char * |
213 | | getseparator (const char *f) |
214 | 8.81k | { |
215 | 8.81k | const char *p = 0; |
216 | 8.81k | const char *q = 0; |
217 | 8.81k | char c = 0;; |
218 | | |
219 | 8.81k | p = NULL; |
220 | 8.81k | q = f; |
221 | 158k | do { |
222 | 158k | c = *q++; |
223 | 158k | if (c == '\\' || c == '/' || c == ':') { |
224 | 17.6k | p = q; |
225 | 17.6k | } |
226 | 158k | } while (c); |
227 | 8.81k | return p; |
228 | 8.81k | } |
229 | | |
230 | | static const char * |
231 | | getbasename (const char *f) |
232 | 8.81k | { |
233 | 8.81k | const char *pseparator = getseparator (f); |
234 | 8.81k | if (!pseparator) { |
235 | 0 | return f; |
236 | 0 | } |
237 | 8.81k | return pseparator; |
238 | 8.81k | } |
239 | | |
240 | | /* Not a standard function. */ |
241 | | static int |
242 | | dw_stpcpy(char *dest,const char *src,char **destend, char *endpoint) |
243 | 29.9k | { |
244 | 29.9k | const char *cp = src; |
245 | 29.9k | char *dp = dest; |
246 | | |
247 | 618k | for ( ; *cp; ++cp,++dp) { |
248 | 588k | if (dp >= endpoint) { |
249 | 0 | return DW_DLV_ERROR; |
250 | 0 | } |
251 | 588k | *dp = *cp; |
252 | 588k | } |
253 | 29.9k | if (dp >= endpoint) { |
254 | 0 | return DW_DLV_ERROR; |
255 | 0 | } |
256 | 29.9k | *dp = 0; |
257 | 29.9k | *destend = dp; |
258 | 29.9k | return DW_DLV_OK; |
259 | 29.9k | } |
260 | | |
261 | | /* This started like Elf, so check initial fields. */ |
262 | | static int |
263 | | fill_in_elf_fields(struct elf_header *h, |
264 | | unsigned *endian, |
265 | | /* Size of the object file offsets, not DWARF offset |
266 | | size. */ |
267 | | unsigned *objoffsetsize, |
268 | | int *errcode) |
269 | 18.2k | { |
270 | 18.2k | unsigned locendian = 0; |
271 | 18.2k | unsigned locoffsetsize = 0; |
272 | | |
273 | 18.2k | switch(h->e_ident[EI_CLASS]) { |
274 | 13.2k | case ELFCLASS32: |
275 | 13.2k | locoffsetsize = 32; |
276 | 13.2k | break; |
277 | 4.96k | case ELFCLASS64: |
278 | 4.96k | locoffsetsize = 64; |
279 | 4.96k | break; |
280 | 4 | default: |
281 | 4 | *errcode = DW_DLE_ELF_CLASS_BAD; |
282 | 4 | return DW_DLV_ERROR; |
283 | 18.2k | } |
284 | 18.2k | switch(h->e_ident[EI_DATA]) { |
285 | 17.5k | case ELFDATA2LSB: |
286 | 17.5k | locendian = DW_END_little; |
287 | 17.5k | break; |
288 | 677 | case ELFDATA2MSB: |
289 | 677 | locendian = DW_END_big; |
290 | 677 | break; |
291 | 4 | default: |
292 | 4 | *errcode = DW_DLE_ELF_ENDIAN_BAD; |
293 | 4 | return DW_DLV_ERROR; |
294 | 18.2k | } |
295 | 18.2k | if (h->e_ident[EI_VERSION] != 1 /* EV_CURRENT */) { |
296 | 35 | *errcode = DW_DLE_ELF_VERSION_BAD; |
297 | 35 | return DW_DLV_ERROR; |
298 | 35 | } |
299 | 18.2k | *endian = locendian; |
300 | 18.2k | *objoffsetsize = locoffsetsize; |
301 | 18.2k | return DW_DLV_OK; |
302 | 18.2k | } |
303 | | static char archive_magic[8] = { |
304 | | '!','<','a','r','c','h','>',0x0a |
305 | | }; |
306 | | static int |
307 | 3.91k | is_archive_magic(struct elf_header *h) { |
308 | 3.91k | int i = 0; |
309 | 3.91k | int len = sizeof(archive_magic); |
310 | 3.91k | const char *cp = (const char *)h; |
311 | 4.02k | for ( ; i < len; ++i) { |
312 | 4.02k | if (cp[i] != archive_magic[i]) { |
313 | 3.91k | return FALSE; |
314 | 3.91k | } |
315 | 4.02k | } |
316 | 3 | return TRUE; |
317 | 3.91k | } |
318 | | |
319 | | /* A bit unusual in that it always sets *is_pe_flag |
320 | | Return of DW_DLV_OK it is a PE file we recognize. */ |
321 | | static int |
322 | | is_pe_object(int fd, |
323 | | unsigned long filesize, |
324 | | unsigned *endian, |
325 | | unsigned *offsetsize, |
326 | | int *errcode) |
327 | 3.91k | { |
328 | 3.91k | unsigned dos_sig = 0; |
329 | 3.91k | unsigned locendian = 0; |
330 | 3.91k | void (*word_swap) (void *, const void *, unsigned long); |
331 | 3.91k | unsigned long nt_address = 0; |
332 | 3.91k | struct dos_header dhinmem; |
333 | 3.91k | char nt_sig_array[4]; |
334 | 3.91k | unsigned long nt_sig = 0; |
335 | 3.91k | struct pe_image_file_header ifh; |
336 | 3.91k | int res = 0; |
337 | | |
338 | 3.91k | if (filesize < (sizeof (struct dos_header) + |
339 | 3.91k | SIZEOFT32 + sizeof(struct pe_image_file_header))) { |
340 | 872 | *errcode = DW_DLE_FILE_TOO_SMALL; |
341 | 872 | return DW_DLV_ERROR; |
342 | 872 | } |
343 | 3.04k | res = _dwarf_object_read_random(fd,(char *)&dhinmem, |
344 | 3.04k | 0,sizeof(dhinmem),filesize,errcode); |
345 | 3.04k | if (res != DW_DLV_OK) { |
346 | 0 | return res; |
347 | 0 | } |
348 | | /* No swap here, want it as in the file */ |
349 | 3.04k | dos_sig = magic_copy((unsigned char *)dhinmem.dh_mz, |
350 | 3.04k | sizeof(dhinmem.dh_mz)); |
351 | 3.04k | if (dos_sig == IMAGE_DOS_SIGNATURE_dw) { |
352 | | /* IMAGE_DOS_SIGNATURE_dw assumes bytes |
353 | | reversed by little-endian |
354 | | load, so we intrepet a match the other way. */ |
355 | | /* BIG ENDIAN. From looking at hex characters in object */ |
356 | | #ifdef WORDS_BIGENDIAN |
357 | | word_swap = _dwarf_memcpy_noswap_bytes; |
358 | | #else /* LITTLE ENDIAN */ |
359 | 677 | word_swap = _dwarf_memcpy_swap_bytes; |
360 | 677 | #endif /* LITTLE- BIG-ENDIAN */ |
361 | 677 | locendian = DW_END_big; |
362 | 2.36k | } else if (dos_sig == IMAGE_DOS_REVSIGNATURE_dw) { |
363 | | /* raw load, so intrepet a match the other way. */ |
364 | | /* LITTLE ENDIAN */ |
365 | | #ifdef WORDS_BIGENDIAN |
366 | | word_swap = _dwarf_memcpy_swap_bytes; |
367 | | #else /* LITTLE ENDIAN */ |
368 | 2.18k | word_swap = _dwarf_memcpy_noswap_bytes; |
369 | 2.18k | #endif /* LITTLE- BIG-ENDIAN */ |
370 | 2.18k | locendian = DW_END_little; |
371 | 2.18k | } else { |
372 | | /* Not dos header not a PE file we recognize */ |
373 | 184 | *errcode = DW_DLE_FILE_WRONG_TYPE; |
374 | 184 | return DW_DLV_ERROR; |
375 | 184 | } |
376 | 2.85k | ASNAR(word_swap,nt_address, dhinmem.dh_image_offset); |
377 | 2.85k | if (filesize < nt_address) { |
378 | | /* Not dos header not a PE file we recognize */ |
379 | 263 | *errcode = DW_DLE_FILE_TOO_SMALL; |
380 | 263 | return DW_DLV_ERROR; |
381 | 263 | } |
382 | 2.59k | if (filesize < (nt_address + SIZEOFT32 + |
383 | 2.59k | sizeof(struct pe_image_file_header))) { |
384 | 41 | *errcode = DW_DLE_FILE_TOO_SMALL; |
385 | | /* Not dos header not a PE file we recognize */ |
386 | 41 | return DW_DLV_ERROR; |
387 | 41 | } |
388 | 2.55k | res = _dwarf_object_read_random(fd,(char *)&nt_sig_array[0], |
389 | 2.55k | nt_address, sizeof(nt_sig_array),filesize,errcode); |
390 | 2.55k | if (res != DW_DLV_OK) { |
391 | 0 | return res; |
392 | 0 | } |
393 | 2.55k | { unsigned long lsig = 0; |
394 | | |
395 | 2.55k | ASNAR(word_swap,lsig,nt_sig_array); |
396 | 2.55k | nt_sig = lsig; |
397 | 2.55k | } |
398 | 2.55k | if (nt_sig != IMAGE_NT_SIGNATURE_dw) { |
399 | 242 | *errcode = DW_DLE_FILE_WRONG_TYPE; |
400 | 242 | return DW_DLV_ERROR; |
401 | 242 | } |
402 | 2.31k | res = _dwarf_object_read_random(fd,(char *)&ifh, |
403 | 2.31k | nt_address + SIZEOFT32, |
404 | 2.31k | sizeof(struct pe_image_file_header), |
405 | 2.31k | filesize, |
406 | 2.31k | errcode); |
407 | 2.31k | if (res != DW_DLV_OK) { |
408 | 0 | return res; |
409 | 0 | } |
410 | 2.31k | { |
411 | 2.31k | unsigned long machine = 0; |
412 | | |
413 | 2.31k | ASNAR(word_swap,machine,ifh.im_machine); |
414 | 2.31k | switch(machine) { |
415 | 1.75k | case IMAGE_FILE_MACHINE_I386_dw: |
416 | 1.75k | *offsetsize = 32; |
417 | 1.75k | *endian = locendian; |
418 | 1.75k | return DW_DLV_OK; |
419 | 154 | case IMAGE_FILE_MACHINE_IA64_dw: |
420 | 173 | case IMAGE_FILE_MACHINE_AMD64_dw: |
421 | 173 | *offsetsize = 64; |
422 | 173 | *endian = locendian; |
423 | 173 | return DW_DLV_OK; |
424 | 387 | default: break; |
425 | 2.31k | } |
426 | 2.31k | } |
427 | 387 | *errcode = DW_DLE_IMAGE_FILE_UNKNOWN_TYPE; |
428 | 387 | return DW_DLV_ERROR; |
429 | 2.31k | } |
430 | | |
431 | | static int |
432 | | is_mach_o_magic(struct elf_header *h, |
433 | | unsigned *endian, |
434 | | unsigned *offsetsize) |
435 | 9.11k | { |
436 | 9.11k | unsigned long magicval = 0; |
437 | 9.11k | unsigned locendian = 0; |
438 | 9.11k | unsigned locoffsetsize = 0; |
439 | | |
440 | | /* No swapping here. Need to match size of |
441 | | Mach-o magic field. */ |
442 | 9.11k | magicval = magic_copy(h->e_ident,4); |
443 | 9.11k | if (magicval == MH_MAGIC) { |
444 | 1.64k | locendian = DW_END_big; |
445 | 1.64k | locoffsetsize = 32; |
446 | 7.47k | } else if (magicval == MH_CIGAM) { |
447 | 2.01k | locendian = DW_END_little; |
448 | 2.01k | locoffsetsize = 32; |
449 | 5.45k | }else if (magicval == MH_MAGIC_64) { |
450 | 442 | locendian = DW_END_big; |
451 | 442 | locoffsetsize = 64; |
452 | 5.01k | } else if (magicval == MH_CIGAM_64) { |
453 | 1.09k | locendian = DW_END_little; |
454 | 1.09k | locoffsetsize = 64; |
455 | 3.91k | } else { |
456 | 3.91k | return FALSE; |
457 | 3.91k | } |
458 | 5.19k | *endian = locendian; |
459 | 5.19k | *offsetsize = locoffsetsize; |
460 | 5.19k | return TRUE; |
461 | 9.11k | } |
462 | | |
463 | | int |
464 | | dwarf_object_detector_fd(int fd, |
465 | | unsigned *ftype, |
466 | | unsigned *endian, |
467 | | unsigned *offsetsize, |
468 | | Dwarf_Unsigned *filesize, |
469 | | int *errcode) |
470 | 27.4k | { |
471 | 27.4k | struct elf_header h; |
472 | 27.4k | size_t readlen = sizeof(h); |
473 | 27.4k | int res = 0; |
474 | 27.4k | off_t fsize = 0; |
475 | 27.4k | off_t lsval = 0; |
476 | 27.4k | ssize_t readval = 0; |
477 | | |
478 | 27.4k | fsize = lseek(fd,0L,SEEK_END); |
479 | 27.4k | if (fsize < 0) { |
480 | 12 | *errcode = DW_DLE_SEEK_ERROR; |
481 | 12 | return DW_DLV_ERROR; |
482 | 12 | } |
483 | 27.4k | if (fsize <= (off_t)readlen) { |
484 | | /* Not a real object file */ |
485 | 47 | *errcode = DW_DLE_FILE_TOO_SMALL; |
486 | 47 | return DW_DLV_ERROR; |
487 | 47 | } |
488 | 27.3k | lsval = lseek(fd,0L,SEEK_SET); |
489 | 27.3k | if (lsval < 0) { |
490 | 0 | *errcode = DW_DLE_SEEK_ERROR; |
491 | 0 | return DW_DLV_ERROR; |
492 | 0 | } |
493 | 27.3k | readval = read(fd,&h,readlen); |
494 | 27.3k | if (readval != (ssize_t)readlen) { |
495 | 0 | *errcode = DW_DLE_READ_ERROR; |
496 | 0 | return DW_DLV_ERROR; |
497 | 0 | } |
498 | 27.3k | if (h.e_ident[0] == 0x7f && |
499 | 27.3k | h.e_ident[1] == 'E' && |
500 | 27.3k | h.e_ident[2] == 'L' && |
501 | 27.3k | h.e_ident[3] == 'F') { |
502 | | /* is ELF */ |
503 | | |
504 | 18.2k | res = fill_in_elf_fields(&h,endian,offsetsize,errcode); |
505 | 18.2k | if (res != DW_DLV_OK) { |
506 | 43 | return res; |
507 | 43 | } |
508 | 18.2k | *ftype = DW_FTYPE_ELF; |
509 | 18.2k | *filesize = (size_t)fsize; |
510 | 18.2k | return DW_DLV_OK; |
511 | 18.2k | } |
512 | 9.11k | if (is_mach_o_magic(&h,endian,offsetsize)) { |
513 | 5.19k | *ftype = DW_FTYPE_MACH_O; |
514 | 5.19k | *filesize = (size_t)fsize; |
515 | 5.19k | return DW_DLV_OK; |
516 | 5.19k | } |
517 | 3.91k | if (is_archive_magic(&h)) { |
518 | 3 | *ftype = DW_FTYPE_ARCHIVE; |
519 | 3 | *filesize = (size_t)fsize; |
520 | 3 | return DW_DLV_OK; |
521 | 3 | } |
522 | 3.91k | res = is_pe_object(fd,fsize,endian,offsetsize,errcode); |
523 | 3.91k | if (res == DW_DLV_OK ) { |
524 | 1.92k | *ftype = DW_FTYPE_PE; |
525 | 1.92k | *filesize = (size_t)fsize; |
526 | 1.92k | return DW_DLV_OK; |
527 | 1.92k | } |
528 | | /* Unknown object format. */ |
529 | 1.98k | return DW_DLV_NO_ENTRY; |
530 | 3.91k | } |
531 | | |
532 | | int |
533 | | dwarf_object_detector_path_dSYM( |
534 | | const char *path, |
535 | | char *outpath, unsigned long outpath_len, |
536 | | char ** gl_pathnames, |
537 | | unsigned gl_pathcount, |
538 | | unsigned *ftype, |
539 | | unsigned *endian, |
540 | | unsigned *offsetsize, |
541 | | Dwarf_Unsigned *filesize, |
542 | | unsigned char *pathsource, |
543 | | int *errcode) |
544 | 8.81k | { |
545 | 8.81k | char *cp = 0; |
546 | 8.81k | size_t plen = strlen(path); |
547 | 8.81k | size_t dsprefixlen = sizeof(DSYM_SUFFIX); |
548 | 8.81k | int fd = -1; |
549 | 8.81k | int res = 0; |
550 | 8.81k | int have_outpath = outpath && outpath_len; |
551 | | |
552 | 8.81k | (void)gl_pathnames; |
553 | 8.81k | (void)gl_pathcount; |
554 | 8.81k | if (have_outpath) { |
555 | | /* Looking for MacOS dSYM */ |
556 | 8.81k | if ((2*plen + dsprefixlen +2) >= (size_t)outpath_len) { |
557 | 0 | *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; |
558 | 0 | return DW_DLV_ERROR; |
559 | 0 | } |
560 | 8.81k | res = dw_stpcpy(outpath,path,&cp,outpath+outpath_len); |
561 | 8.81k | if (res == DW_DLV_ERROR) { |
562 | 0 | *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; |
563 | 0 | return DW_DLV_ERROR; |
564 | 0 | } |
565 | 8.81k | res = dw_stpcpy(cp,DSYM_SUFFIX,&cp,outpath+outpath_len); |
566 | 8.81k | if (res == DW_DLV_ERROR) { |
567 | 0 | *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; |
568 | 0 | return DW_DLV_ERROR; |
569 | 0 | } |
570 | 8.81k | res= dw_stpcpy(cp,getbasename(path),&cp,outpath+outpath_len); |
571 | 8.81k | if (res == DW_DLV_ERROR) { |
572 | 0 | *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; |
573 | 0 | return DW_DLV_ERROR; |
574 | 0 | } |
575 | 8.81k | fd = open(outpath,O_RDONLY|O_BINARY); |
576 | 8.81k | if (fd < 0) { |
577 | 8.81k | outpath[0] = 0; |
578 | 8.81k | return DW_DLV_NO_ENTRY; |
579 | 8.81k | } |
580 | 0 | *pathsource = DW_PATHSOURCE_dsym; |
581 | 0 | res = dwarf_object_detector_fd(fd, |
582 | 0 | ftype,endian,offsetsize,filesize,errcode); |
583 | 0 | if (res != DW_DLV_OK) { |
584 | 0 | close(fd); |
585 | 0 | return res; |
586 | 0 | } |
587 | 0 | close(fd); |
588 | 0 | return DW_DLV_OK; |
589 | 0 | } |
590 | 0 | return DW_DLV_NO_ENTRY; |
591 | 8.81k | } |
592 | | |
593 | | static int |
594 | | blockmatch(unsigned char *l, |
595 | | unsigned char* r, |
596 | | unsigned length) |
597 | 0 | { |
598 | 0 | unsigned int i = 0; |
599 | 0 | for ( ; i < length; ++i) { |
600 | 0 | if (l[i] != r[i]) { |
601 | 0 | return FALSE; |
602 | 0 | } |
603 | 0 | } |
604 | 0 | return TRUE; |
605 | 0 | } |
606 | | |
607 | | /* The debug version we expect not to have debuglink, |
608 | | checking here if buildid matches. |
609 | | Returns TRUE or FALSE */ |
610 | | static Dwarf_Bool |
611 | | match_buildid( |
612 | | unsigned char * crc_base, |
613 | | unsigned buildid_length_base, |
614 | | unsigned char *buildid_base, |
615 | | /* *_base is executable info while |
616 | | *_debug is the debug object. */ |
617 | | unsigned char *crc_debug, |
618 | | unsigned buildid_length_debug, |
619 | | unsigned char *buildid_debug) |
620 | 0 | { |
621 | 0 | if (!_dwarf_get_suppress_debuglink_crc() && \ |
622 | 0 | crc_debug && crc_base) { |
623 | | /* crc available for both */ |
624 | 0 | if (!blockmatch(crc_debug,crc_base,4)) { |
625 | 0 | return FALSE; |
626 | 0 | } |
627 | 0 | return TRUE; |
628 | 0 | } |
629 | 0 | if (!blockmatch(buildid_base,buildid_debug, |
630 | 0 | buildid_length_base)) { |
631 | 0 | return FALSE; |
632 | 0 | } |
633 | 0 | if (buildid_length_base != buildid_length_debug) { |
634 | 0 | return FALSE; |
635 | 0 | } |
636 | 0 | return TRUE; |
637 | 0 | } |
638 | | |
639 | | static int |
640 | | _dwarf_debuglink_finder_newpath( |
641 | | char * path_in, |
642 | | unsigned char *crc_in, |
643 | | unsigned buildid_len_in, |
644 | | unsigned char *buildid_in, |
645 | | dwarfstring *m, |
646 | | int * fd_out) |
647 | 6 | { |
648 | 6 | unsigned char lcrc[4]; |
649 | 6 | char *debuglinkpath = 0; /* must be freed */ |
650 | 6 | unsigned char *crc = 0; |
651 | 6 | char *debuglinkfullpath = 0; |
652 | 6 | unsigned debuglinkfullpath_strlen = 0; |
653 | 6 | unsigned buildid_type = 0; |
654 | 6 | char * buildidownername = 0; |
655 | 6 | unsigned char *buildid = 0; |
656 | 6 | unsigned buildid_length = 0; |
657 | 6 | char ** paths = 0; /* must be freed */ |
658 | 6 | unsigned paths_count = 0; |
659 | 6 | Dwarf_Debug dbg = 0; |
660 | 6 | Dwarf_Error error = 0; |
661 | 6 | char *path = path_in; |
662 | 6 | Dwarf_Bool didmatch = FALSE; |
663 | 6 | int res = 0; |
664 | | |
665 | 6 | res = dwarf_init_path(path, |
666 | 6 | 0,0, |
667 | 6 | DW_GROUPNUMBER_ANY, |
668 | 6 | 0,0, &dbg,&error); |
669 | 6 | if (res == DW_DLV_ERROR) { |
670 | | /* ASSERT: dbg is NULL as init failed */ |
671 | 6 | dwarf_dealloc_error(dbg,error); |
672 | 6 | error = 0; |
673 | 6 | return DW_DLV_NO_ENTRY; |
674 | 6 | } |
675 | 0 | if (res == DW_DLV_NO_ENTRY) { |
676 | | /* should never happen */ |
677 | 0 | return DW_DLV_NO_ENTRY; |
678 | 0 | } |
679 | 0 | res = dwarf_gnu_debuglink(dbg, |
680 | 0 | &debuglinkpath, |
681 | 0 | &crc, &debuglinkfullpath, &debuglinkfullpath_strlen, |
682 | 0 | &buildid_type, &buildidownername, |
683 | 0 | &buildid, &buildid_length, |
684 | 0 | &paths, &paths_count, &error); |
685 | 0 | if (res == DW_DLV_ERROR) { |
686 | 0 | dwarf_dealloc_error(dbg,error); |
687 | 0 | dwarf_finish(dbg); |
688 | 0 | error = 0; |
689 | 0 | dbg = 0; |
690 | 0 | return DW_DLV_NO_ENTRY; |
691 | 0 | } |
692 | 0 | if (res == DW_DLV_NO_ENTRY) { |
693 | | /* There is no debuglink section */ |
694 | 0 | dwarf_finish(dbg); |
695 | 0 | dbg = 0; |
696 | 0 | return DW_DLV_NO_ENTRY; |
697 | 0 | } |
698 | 0 | free(paths); |
699 | 0 | paths = 0; |
700 | |
|
701 | 0 | memset(&lcrc[0],0,sizeof(lcrc)); |
702 | 0 | if (!_dwarf_get_suppress_debuglink_crc() &&crc_in && !crc) { |
703 | 0 | int res1 = 0; |
704 | |
|
705 | 0 | res1 = dwarf_crc32(dbg,lcrc,&error); |
706 | 0 | if (res1 == DW_DLV_ERROR) { |
707 | 0 | paths = 0; |
708 | 0 | free(debuglinkfullpath); |
709 | 0 | dwarf_dealloc_error(dbg,error); |
710 | 0 | dwarf_finish(dbg); |
711 | 0 | error = 0; |
712 | 0 | dbg = 0; |
713 | | /* Cannot match the crc_in, give up. */ |
714 | 0 | return DW_DLV_NO_ENTRY; |
715 | 0 | } |
716 | 0 | if (res1 == DW_DLV_OK) { |
717 | 0 | crc = &lcrc[0]; |
718 | 0 | } |
719 | 0 | } |
720 | 0 | free(debuglinkfullpath); |
721 | 0 | didmatch = match_buildid( |
722 | | /* This is about the executable */ |
723 | 0 | crc_in,buildid_len_in,buildid_in, |
724 | | /* pass in local so we can calculate the missing crc */ |
725 | | /* following is the target, ie, debug */ |
726 | 0 | crc,buildid_length,buildid); |
727 | 0 | if (error) { |
728 | | /* This should never happen. It would mean |
729 | | error was set without DW_DLV_ERROR */ |
730 | 0 | dwarf_dealloc_error(dbg,error); |
731 | 0 | error = 0; |
732 | 0 | } |
733 | 0 | if (didmatch) { |
734 | 0 | dwarfstring_append(m,path); |
735 | 0 | *fd_out = dbg->de_fd; |
736 | 0 | dbg->de_owns_fd = FALSE; |
737 | 0 | dwarf_finish(dbg); |
738 | 0 | dbg = 0; |
739 | 0 | return DW_DLV_OK; |
740 | 0 | } |
741 | 0 | dwarf_finish(dbg); |
742 | 0 | return DW_DLV_NO_ENTRY; |
743 | 0 | } |
744 | | |
745 | | static int |
746 | | _dwarf_debuglink_finder_internal( |
747 | | char **gl_pathnames, |
748 | | unsigned int gl_pathcount, |
749 | | char * path_in, |
750 | | dwarfstring *m, |
751 | | int * fd_out, |
752 | | int * errcode) |
753 | 8.81k | { |
754 | 8.81k | int res = 0; |
755 | | /* This local dbg is opened and then dwarf_finish() |
756 | | here. No dbg in the arguments! */ |
757 | 8.81k | Dwarf_Debug dbg = 0; |
758 | 8.81k | char * path = 0; |
759 | 8.81k | Dwarf_Error error = 0; |
760 | 8.81k | unsigned int p = 0; |
761 | 8.81k | char *debuglinkpath = 0; |
762 | 8.81k | unsigned char *crc = 0; |
763 | 8.81k | char *debuglinkfullpath = 0; /* must be freed*/ |
764 | 8.81k | unsigned debuglinkfullpath_strlen = 0; |
765 | 8.81k | unsigned buildid_type = 0; |
766 | 8.81k | char * buildidownername = 0; |
767 | 8.81k | unsigned char *buildid = 0; |
768 | 8.81k | unsigned buildid_length = 0; |
769 | 8.81k | char ** paths = 0; /* must be freed */ |
770 | 8.81k | unsigned paths_count = 0; |
771 | 8.81k | unsigned i = 0; |
772 | | |
773 | 8.81k | path = path_in; |
774 | | /* This path will work. |
775 | | Already know the file is there. */ |
776 | 8.81k | res = dwarf_init_path(path, |
777 | 8.81k | 0,0, |
778 | 8.81k | DW_GROUPNUMBER_ANY, |
779 | 8.81k | 0,0, &dbg, &error); |
780 | 8.81k | if (res == DW_DLV_ERROR) { |
781 | 5.30k | *errcode = dwarf_errno(error); |
782 | 5.30k | dwarf_dealloc_error(dbg,error); |
783 | 5.30k | error = 0; |
784 | 5.30k | return res; |
785 | 5.30k | } |
786 | 3.50k | if (res == DW_DLV_NO_ENTRY) { |
787 | 2.61k | return res; |
788 | 2.61k | } |
789 | 892 | for (p = 0; p < gl_pathcount; ++p) { |
790 | 0 | const char *lpath = 0; |
791 | |
|
792 | 0 | lpath = (const char *)gl_pathnames[p]; |
793 | 0 | res = dwarf_add_debuglink_global_path(dbg, |
794 | 0 | lpath, &error); |
795 | 0 | if (res != DW_DLV_OK){ |
796 | 0 | if (res == DW_DLV_ERROR) { |
797 | 0 | *errcode = dwarf_errno(error); |
798 | 0 | dwarf_dealloc_error(dbg,error); |
799 | 0 | error = 0; |
800 | 0 | } |
801 | 0 | dwarf_finish(dbg); |
802 | 0 | return res; |
803 | 0 | } |
804 | 0 | } |
805 | 892 | res = dwarf_gnu_debuglink(dbg, |
806 | 892 | &debuglinkpath, |
807 | 892 | &crc, &debuglinkfullpath, &debuglinkfullpath_strlen, |
808 | 892 | &buildid_type, &buildidownername, |
809 | 892 | &buildid, &buildid_length, |
810 | 892 | &paths, &paths_count, &error); |
811 | 892 | if (res == DW_DLV_ERROR) { |
812 | 542 | *errcode = dwarf_errno(error); |
813 | 542 | dwarf_dealloc_error(dbg,error); |
814 | 542 | dwarf_finish(dbg); |
815 | 542 | return DW_DLV_NO_ENTRY; |
816 | 542 | } |
817 | 350 | if (res == DW_DLV_NO_ENTRY) { |
818 | | /* There is no debuglink buildid section? */ |
819 | 0 | dwarf_finish(dbg); |
820 | 0 | return DW_DLV_NO_ENTRY; |
821 | 0 | } |
822 | 884 | for (i =0; i < paths_count; ++i) { |
823 | 534 | char *pa = paths[i]; |
824 | 534 | int pfd = 0; |
825 | | |
826 | | /* First, open the file to determine if it exists. |
827 | | If not, loop again */ |
828 | | |
829 | 534 | pfd = open(pa,O_RDONLY|O_BINARY); |
830 | 534 | if (pfd < 0) { |
831 | | /* This is the usual path. */ |
832 | 528 | continue; |
833 | 528 | } |
834 | 6 | close(pfd); |
835 | | /* ASSERT: never returns DW_DLV_ERROR */ |
836 | 6 | res = _dwarf_debuglink_finder_newpath( |
837 | 6 | pa,crc,buildid_length, buildid, |
838 | 6 | m,fd_out); |
839 | 6 | if (res == DW_DLV_OK) { |
840 | 0 | free(debuglinkfullpath); |
841 | 0 | free(paths); |
842 | 0 | paths = 0; |
843 | 0 | dwarf_finish(dbg); |
844 | 0 | return DW_DLV_OK; |
845 | 0 | } |
846 | 6 | *errcode = 0; |
847 | 6 | continue; |
848 | 6 | } |
849 | 350 | free(debuglinkfullpath); |
850 | 350 | free(paths); |
851 | 350 | paths = 0; |
852 | 350 | dwarf_finish(dbg); |
853 | 350 | return DW_DLV_NO_ENTRY; |
854 | 350 | } |
855 | | |
856 | | int |
857 | | dwarf_object_detector_path_b( |
858 | | const char * path, |
859 | | char * outpath, |
860 | | unsigned long outpath_len, |
861 | | char ** gl_pathnames, |
862 | | unsigned gl_pathcount, |
863 | | unsigned * ftype, |
864 | | unsigned * endian, |
865 | | unsigned * offsetsize, |
866 | | Dwarf_Unsigned * filesize, |
867 | | unsigned char * pathsource, |
868 | | int *errcode) |
869 | 23.7k | { |
870 | 23.7k | int fd = -1; |
871 | 23.7k | int res = 0; |
872 | 23.7k | int have_outpath = outpath && outpath_len; |
873 | 23.7k | unsigned char lpathsource = DW_PATHSOURCE_basic; |
874 | | |
875 | 23.7k | if (pathsource) { |
876 | 23.7k | lpathsource = *pathsource; |
877 | 23.7k | } |
878 | 23.7k | if (lpathsource == DW_PATHSOURCE_basic && have_outpath) { |
879 | | /* On return from the following call we could well |
880 | | close the fd above and open a new one. */ |
881 | 8.81k | int debuglink_fd = -1; |
882 | 8.81k | size_t dllenszt = 0; |
883 | 8.81k | char *cp = 0; |
884 | 8.81k | dwarfstring m; |
885 | | |
886 | 8.81k | dwarfstring_constructor(&m); |
887 | 8.81k | res = _dwarf_debuglink_finder_internal( |
888 | 8.81k | gl_pathnames,gl_pathcount, |
889 | 8.81k | (char *)path, &m,&debuglink_fd, errcode); |
890 | 8.81k | if (res == DW_DLV_ERROR) { |
891 | 5.30k | dwarfstring_destructor(&m); |
892 | 5.30k | if (debuglink_fd != -1) { |
893 | 0 | close(debuglink_fd); |
894 | 0 | } |
895 | 5.30k | return res; |
896 | 5.30k | } |
897 | 3.50k | if (res == DW_DLV_NO_ENTRY) { |
898 | | /* We did not find an alternative path */ |
899 | 3.50k | res = dw_stpcpy(outpath,path,&cp,outpath+outpath_len); |
900 | 3.50k | if (res != DW_DLV_OK) { |
901 | 0 | *errcode = DW_DLE_PATH_SIZE_TOO_SMALL; |
902 | 0 | return DW_DLV_ERROR; |
903 | 0 | } |
904 | 3.50k | lpathsource = DW_PATHSOURCE_basic; |
905 | 3.50k | } else { |
906 | 0 | if (debuglink_fd != -1) { |
907 | 0 | close(debuglink_fd); |
908 | 0 | debuglink_fd = -1; |
909 | 0 | } |
910 | 0 | dllenszt = dwarfstring_strlen(&m)+1; |
911 | 0 | if (dllenszt >= (size_t)outpath_len) { |
912 | 0 | *errcode = DW_DLE_DEBUGLINK_PATH_SHORT; |
913 | 0 | return DW_DLV_ERROR; |
914 | 0 | } |
915 | 0 | res = dw_stpcpy(outpath,dwarfstring_string(&m), |
916 | 0 | &cp,outpath+outpath_len); |
917 | 0 | if (res != DW_DLV_OK) { |
918 | 0 | *errcode = DW_DLE_DEBUGLINK_PATH_SHORT; |
919 | 0 | return DW_DLV_ERROR; |
920 | 0 | } |
921 | 0 | lpathsource = DW_PATHSOURCE_debuglink; |
922 | 0 | } |
923 | 3.50k | dwarfstring_destructor(&m); |
924 | 3.50k | fd = open(outpath,O_RDONLY|O_BINARY); |
925 | | /* fall through to get fsize etc */ |
926 | 14.9k | } else { |
927 | 14.9k | lpathsource = DW_PATHSOURCE_basic; |
928 | 14.9k | fd = open(path,O_RDONLY|O_BINARY); |
929 | 14.9k | } |
930 | 18.4k | if (fd < 0) { |
931 | 0 | if (pathsource) { |
932 | 0 | *pathsource = DW_PATHSOURCE_unspecified; |
933 | 0 | } |
934 | 0 | return DW_DLV_NO_ENTRY; |
935 | 0 | } |
936 | 18.4k | res = dwarf_object_detector_fd(fd, |
937 | 18.4k | ftype,endian,offsetsize,filesize,errcode); |
938 | 18.4k | if (res != DW_DLV_OK) { |
939 | 1.69k | lpathsource = DW_PATHSOURCE_unspecified; |
940 | 1.69k | } |
941 | 18.4k | if (pathsource) { |
942 | 18.4k | *pathsource = lpathsource; |
943 | 18.4k | } |
944 | 18.4k | close(fd); |
945 | 18.4k | return res; |
946 | 18.4k | } |