Coverage Report

Created: 2023-01-09 06:09

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