xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_peread.c (revision 379728489ed47862c4927c75771e767b9476c9c4)
1 /*
2 Copyright (c) 2019, 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 
33 /*  This file reads the parts of a Windows PE
34     file appropriate to reading DWARF debugging data.
35 */
36 
37 #ifdef _WIN32
38 #define _CRT_SECURE_NO_WARNINGS
39 #endif /* _WIN32 */
40 
41 #include "config.h"
42 #include <stdio.h>
43 #ifdef HAVE_MALLOC_H
44 /* Useful include for some Windows compilers. */
45 #include <malloc.h>
46 #endif /* HAVE_MALLOC_H */
47 #ifdef HAVE_STDLIB_H
48 #include <stdlib.h>
49 #endif /* HAVE_STDLIB_H */
50 #include <string.h> /* memcpy */
51 #include <sys/types.h> /* open() */
52 #include <sys/stat.h> /* open() */
53 #include <fcntl.h> /* open() */
54 #include <time.h>
55 #ifdef HAVE_UNISTD_H
56 #include <unistd.h> /* lseek read close */
57 #elif defined(_WIN32) && defined(_MSC_VER)
58 #include <io.h>
59 #endif /* HAVE_UNISTD_H */
60 
61 /* Windows specific header files */
62 #if defined(_WIN32) && defined(HAVE_STDAFX_H)
63 #include "stdafx.h"
64 #endif /* HAVE_STDAFX_H */
65 
66 #include "libdwarf.h"
67 #include "libdwarfdefs.h"
68 #include "dwarf_base_types.h"
69 #include "dwarf_opaque.h"
70 #include "memcpy_swap.h"
71 #include "dwarf_error.h" /* for _dwarf_error() declaration */
72 #include "dwarf_reading.h"
73 #include "dwarf_object_read_common.h"
74 #include "dwarf_object_detector.h"
75 #include "dwarf_pe_descr.h"
76 #include "dwarf_peread.h"
77 
78 #ifdef HAVE_UNUSED_ATTRIBUTE
79 #define  UNUSEDARG __attribute__ ((unused))
80 #else
81 #define  UNUSEDARG
82 #endif
83 
84 #define DOS_HEADER_LEN 64
85 
86 #ifndef TYP
87 #define TYP(n,l) char n[l]
88 #endif /* TYP */
89 
90 
91 #ifndef SIZEOFT32
92 #define SIZEOFT32 4
93 #endif /* SIZEOFT32 */
94 
95 static int _dwarf_pe_object_access_init(
96     int  fd,
97     unsigned ftype,
98     unsigned endian,
99     unsigned offsetsize,
100     size_t filesize,
101     Dwarf_Unsigned access,
102     Dwarf_Obj_Access_Interface **binary_interface,
103     int *localerrnum);
104 
105 static unsigned long
106 magic_copy(char *d, unsigned len)
107 {
108     unsigned i = 0;
109     unsigned long v = 0;
110 
111     v = d[0];
112     for(i = 1 ; i < len; ++i) {
113         v <<= 8;
114         v |=  0xff&d[i];
115     }
116     return v;
117 }
118 
119 #ifdef WORDS_BIGENDIAN
120 #define ASNAR(func,t,s)                         \
121     do {                                        \
122         unsigned tbyte = sizeof(t) - sizeof(s); \
123         t = 0;                                  \
124         func(((char *)&t)+tbyte ,&s[0],sizeof(s));  \
125     } while (0)
126 #else /* LITTLE ENDIAN */
127 #define ASNAR(func,t,s)                         \
128     do {                                        \
129         t = 0;                                  \
130         func(&t,&s[0],sizeof(s));               \
131     } while (0)
132 #endif /* end LITTLE- BIG-ENDIAN */
133 
134 /*  name_array is 8 byte string */
135 static int
136 pe_section_name_get(dwarf_pe_object_access_internals_t *pep,
137     const char *name_array,
138     const char ** name_out,
139     int *errcode)
140 {
141 
142     if (name_array[0] == '/') {
143         long v = 0;
144         unsigned long u = 0;
145         const char *s = 0;
146         char temp_array[9];
147 
148         memcpy(temp_array,name_array+1,7);
149         temp_array[7] = 0;
150         v = atoi(temp_array);
151         if (v < 0) {
152             *errcode = DW_DLE_STRING_OFFSET_BAD;
153             return DW_DLV_ERROR;
154         }
155         u = v;
156         if (u > pep->pe_string_table_size) {
157             *errcode = DW_DLE_STRING_OFFSET_BAD;
158             return DW_DLV_ERROR;
159         }
160         s = pep->pe_string_table +u;
161         *name_out = s;
162         return DW_DLV_OK;
163     }
164     *name_out = name_array;
165     return DW_DLV_OK;
166 }
167 
168 
169 static Dwarf_Endianness
170 pe_get_byte_order (void *obj)
171 {
172     dwarf_pe_object_access_internals_t *pep =
173         (dwarf_pe_object_access_internals_t*)(obj);
174     return pep->pe_endian;
175 }
176 
177 
178 static Dwarf_Small
179 pe_get_length_size (void *obj)
180 {
181     dwarf_pe_object_access_internals_t *pep =
182         (dwarf_pe_object_access_internals_t*)(obj);
183     return pep->pe_offsetsize/8;
184 }
185 
186 static Dwarf_Small
187 pe_get_pointer_size (void *obj)
188 {
189     dwarf_pe_object_access_internals_t *pep =
190         (dwarf_pe_object_access_internals_t*)(obj);
191     return pep->pe_pointersize/8;
192 }
193 
194 
195 static Dwarf_Unsigned
196 pe_get_section_count (void *obj)
197 {
198     dwarf_pe_object_access_internals_t *pep =
199         (dwarf_pe_object_access_internals_t*)(obj);
200     return pep->pe_section_count;
201 }
202 
203 static int
204 pe_get_section_info (void *obj,
205     Dwarf_Half section_index,
206     Dwarf_Obj_Access_Section *return_section,
207     UNUSEDARG int *error)
208 {
209     dwarf_pe_object_access_internals_t *pep =
210         (dwarf_pe_object_access_internals_t*)(obj);
211 
212 
213     if (section_index < pep->pe_section_count) {
214         struct dwarf_pe_generic_image_section_header *sp = 0;
215         sp = pep->pe_sectionptr + section_index;
216         return_section->addr = pep->pe_OptionalHeader.ImageBase +
217             sp->VirtualAddress; ;
218         return_section->type = 0;
219         /*  SizeOfRawData can be rounded or truncated,
220             use VirtualSize for the real analog of Elf
221             section size. */
222         return_section->size = sp->VirtualSize;
223         return_section->name = sp->dwarfsectname;
224         return_section->link = 0;
225         return_section->info = 0;
226         return_section->entrysize = 0;
227         return DW_DLV_OK;
228     }
229     return DW_DLV_NO_ENTRY;
230 }
231 
232 
233 static int
234 load_optional_header32(dwarf_pe_object_access_internals_t *pep,
235     Dwarf_Unsigned offset, int*errcode)
236 {
237     int res = 0;
238     IMAGE_OPTIONAL_HEADER32_dw hdr;
239 
240     pep->pe_optional_header_size = sizeof(IMAGE_OPTIONAL_HEADER32_dw);
241 
242     if ((pep->pe_optional_header_size + offset) >
243         pep->pe_filesize) {
244         *errcode = DW_DLE_FILE_TOO_SMALL;
245         return DW_DLV_ERROR;
246     }
247 
248     res =  _dwarf_object_read_random(pep->pe_fd,
249         (char *)&hdr,
250         (off_t)offset, sizeof(IMAGE_OPTIONAL_HEADER32_dw),
251         (off_t)pep->pe_filesize,
252         errcode);
253     if (res != DW_DLV_OK) {
254         return res;
255     }
256 
257     /* This is a subset of fields. */
258     ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.Magic,
259         hdr.Magic);
260     pep->pe_OptionalHeader.MajorLinkerVersion= hdr.MajorLinkerVersion;
261     pep->pe_OptionalHeader.MinorLinkerVersion= hdr.MinorLinkerVersion;
262     ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.ImageBase,
263         hdr.ImageBase);
264     ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfCode,
265         hdr.SizeOfCode);
266     ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfImage,
267         hdr.SizeOfImage);
268     ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfHeaders,
269         hdr.SizeOfHeaders);
270     pep->pe_OptionalHeader.SizeOfDataDirEntry =
271         sizeof(IMAGE_DATA_DIRECTORY_dw);
272     return DW_DLV_OK;
273 }
274 static int
275 load_optional_header64(dwarf_pe_object_access_internals_t *pep,
276     Dwarf_Unsigned offset, int*errcode )
277 {
278     IMAGE_OPTIONAL_HEADER64_dw hdr;
279     int res = 0;
280 
281     pep->pe_optional_header_size = sizeof(IMAGE_OPTIONAL_HEADER64_dw);
282     if ((pep->pe_optional_header_size + offset) >
283         pep->pe_filesize) {
284         *errcode = DW_DLE_FILE_TOO_SMALL;
285         return DW_DLV_ERROR;
286     }
287     res =  _dwarf_object_read_random(pep->pe_fd,
288         (char *)&hdr,
289         (off_t)offset, sizeof(IMAGE_OPTIONAL_HEADER64_dw),
290         (off_t)pep->pe_filesize,
291         errcode);
292     if (res != DW_DLV_OK) {
293         return res;
294     }
295 
296     /* This is a subset of fields. */
297     ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.Magic,
298         hdr.Magic);
299     pep->pe_OptionalHeader.MajorLinkerVersion= hdr.MajorLinkerVersion;
300     pep->pe_OptionalHeader.MinorLinkerVersion= hdr.MinorLinkerVersion;
301     ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfCode,
302         hdr.SizeOfCode);
303     ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfImage,
304         hdr.SizeOfImage);
305     ASNAR(pep->pe_copy_word,pep->pe_OptionalHeader.SizeOfHeaders,
306         hdr.SizeOfHeaders);
307     pep->pe_OptionalHeader.SizeOfDataDirEntry =
308         sizeof(IMAGE_DATA_DIRECTORY_dw);
309     return DW_DLV_OK;
310 }
311 
312 static int
313 pe_load_section (void *obj, Dwarf_Half section_index,
314     Dwarf_Small **return_data, int *error)
315 {
316     dwarf_pe_object_access_internals_t *pep =
317         (dwarf_pe_object_access_internals_t*)(obj);
318 
319     if (0 < section_index &&
320         section_index < pep->pe_section_count) {
321         int res = 0;
322         struct dwarf_pe_generic_image_section_header *sp =
323             pep->pe_sectionptr + section_index;
324         Dwarf_Unsigned read_length = 0;
325 
326         if(sp->loaded_data) {
327             *return_data = sp->loaded_data;
328             return DW_DLV_OK;
329         }
330         if (!sp->VirtualSize) {
331             return DW_DLV_NO_ENTRY;
332         }
333         read_length = sp->SizeOfRawData;
334         if(sp->VirtualSize < read_length) {
335             /* Don't read padding that wasn't allocated in memory */
336             read_length = sp->VirtualSize;
337         }
338         if ((read_length + sp->PointerToRawData) >
339             pep->pe_filesize) {
340             *error = DW_DLE_FILE_TOO_SMALL;
341             return DW_DLV_ERROR;
342         }
343         sp->loaded_data = malloc((size_t)sp->SizeOfRawData);
344         if(!sp->loaded_data) {
345             *error = DW_DLE_ALLOC_FAIL;
346             return DW_DLV_ERROR;
347         }
348         res = _dwarf_object_read_random(pep->pe_fd,
349             (char *)sp->loaded_data,
350             (off_t)sp->PointerToRawData, (size_t)read_length,
351             (off_t)pep->pe_filesize,
352             error);
353         if (res != DW_DLV_OK) {
354             free(sp->loaded_data);
355             sp->loaded_data = 0;
356             return res;
357         }
358         if(sp->VirtualSize > read_length) {
359             /*  Zero space that was allocated but
360                 truncated from the file */
361             memset(sp->loaded_data + read_length, 0,
362                 (size_t)(sp->VirtualSize - read_length));
363         }
364         *return_data = sp->loaded_data;
365         return DW_DLV_OK;
366     }
367     return DW_DLV_NO_ENTRY;
368 }
369 
370 void
371 _dwarf_destruct_pe_access(
372     struct Dwarf_Obj_Access_Interface_s *aip)
373 {
374     dwarf_pe_object_access_internals_t *pep = 0;
375     Dwarf_Unsigned i = 0;
376 
377     if (!aip) {
378         return;
379     }
380     pep = (dwarf_pe_object_access_internals_t*)(aip->object);
381     if (pep->pe_destruct_close_fd) {
382         close(pep->pe_fd);
383         pep->pe_fd = -1;
384     }
385     free((char *)pep->pe_path);
386     pep->pe_path = 0;
387     if (pep->pe_sectionptr) {
388         struct dwarf_pe_generic_image_section_header  *sp = 0;
389 
390         sp = pep->pe_sectionptr;
391         for( i=0; i < pep->pe_section_count; ++i,++sp) {
392             if (sp->loaded_data) {
393                 free(sp->loaded_data);
394                 sp->loaded_data = 0;
395             }
396             free(sp->name);
397             sp->name = 0;
398             free(sp->dwarfsectname);
399             sp->dwarfsectname = 0;
400         }
401         free(pep->pe_sectionptr);
402         pep->pe_section_count = 0;
403     }
404     free(pep->pe_string_table);
405     pep->pe_string_table = 0;
406     free(pep);
407     free(aip);
408     return;
409 }
410 
411 
412 static int
413 dwarf_pe_load_dwarf_section_headers(
414     dwarf_pe_object_access_internals_t *pep,int *errcode)
415 {
416     Dwarf_Unsigned i = 0;
417     Dwarf_Unsigned input_count =
418         pep->pe_FileHeader.NumberOfSections;
419     Dwarf_Unsigned offset_in_input = pep->pe_section_table_offset;
420     Dwarf_Unsigned section_hdr_size = sizeof(IMAGE_SECTION_HEADER_dw);
421     struct dwarf_pe_generic_image_section_header *sec_outp = 0;
422     Dwarf_Unsigned cur_offset = offset_in_input;
423     Dwarf_Unsigned past_end_hdrs = offset_in_input +
424         section_hdr_size*input_count;
425 
426     /* internal sections include null initial section */
427     pep->pe_section_count = input_count+1;
428 
429     if (past_end_hdrs > pep->pe_filesize) {
430         *errcode = DW_DLE_FILE_TOO_SMALL;
431         return DW_DLV_ERROR;
432     }
433 
434     if (!offset_in_input) {
435         *errcode = DW_DLE_PE_OFFSET_BAD;
436         return DW_DLV_ERROR;
437     }
438     pep->pe_sectionptr =
439         (struct dwarf_pe_generic_image_section_header * )
440         calloc((size_t)pep->pe_section_count,
441         sizeof(struct dwarf_pe_generic_image_section_header));
442 
443 
444 
445     if (!pep->pe_sectionptr) {
446         *errcode = DW_DLE_ALLOC_FAIL;
447         return DW_DLV_ERROR;
448     }
449     sec_outp = pep->pe_sectionptr;
450     sec_outp->name = strdup("");
451     sec_outp->dwarfsectname = strdup("");
452     sec_outp++;
453     for ( ;  i < input_count;
454         ++i, cur_offset += section_hdr_size, sec_outp++) {
455 
456         int res = 0;
457         IMAGE_SECTION_HEADER_dw filesect;
458         char safe_name[IMAGE_SIZEOF_SHORT_NAME +1];
459         const char *expname = 0;
460 
461         res =  _dwarf_object_read_random(pep->pe_fd,
462             (char *)&filesect,(off_t)cur_offset,
463             sizeof(filesect),
464             (off_t)pep->pe_filesize,
465             errcode);
466         if (res != DW_DLV_OK) {
467             return res;
468         }
469         /*  The following is safe. filesect.Name is
470             IMAGE_SIZEOF_SHORT_NAME bytes long and may
471             not (not sure) have a NUL terminator. */
472         strncpy(safe_name,filesect.Name,IMAGE_SIZEOF_SHORT_NAME);
473         /*  Then add NUL terminator. */
474         safe_name[IMAGE_SIZEOF_SHORT_NAME] = 0;
475         sec_outp->name = strdup(safe_name);
476         res = pe_section_name_get(pep,
477             safe_name,&expname,errcode);
478         if (res != DW_DLV_OK) {
479             return res;
480         }
481         sec_outp->dwarfsectname = strdup(expname);
482 
483         if ( !sec_outp->name || !sec_outp->dwarfsectname) {
484             *errcode = DW_DLE_ALLOC_FAIL;
485             return DW_DLV_ERROR;
486         }
487         sec_outp->SecHeaderOffset = cur_offset;
488         ASNAR(pep->pe_copy_word,sec_outp->VirtualSize,
489             filesect.Misc.VirtualSize);
490         ASNAR(pep->pe_copy_word,sec_outp->VirtualAddress,
491             filesect.VirtualAddress);
492         ASNAR(pep->pe_copy_word,sec_outp->SizeOfRawData,
493             filesect.SizeOfRawData);
494         ASNAR(pep->pe_copy_word,sec_outp->PointerToRawData,
495             filesect.PointerToRawData);
496         if(sec_outp->SizeOfRawData > pep->pe_filesize ||
497             sec_outp->PointerToRawData > pep->pe_filesize ||
498             (sec_outp->SizeOfRawData+
499                 sec_outp->PointerToRawData > pep->pe_filesize)) {
500             *errcode = DW_DLE_FILE_TOO_SMALL;
501             return DW_DLV_ERROR;
502         }
503         ASNAR(pep->pe_copy_word,sec_outp->PointerToRelocations,
504             filesect.PointerToRelocations);
505         ASNAR(pep->pe_copy_word,sec_outp->PointerToLinenumbers,
506             filesect.PointerToLinenumbers);
507         ASNAR(pep->pe_copy_word,sec_outp->NumberOfRelocations,
508             filesect.NumberOfRelocations);
509         ASNAR(pep->pe_copy_word,sec_outp->NumberOfLinenumbers,
510             filesect.NumberOfLinenumbers);
511         ASNAR(pep->pe_copy_word,sec_outp->Characteristics,
512             filesect.Characteristics);
513         /* sec_outp->loaded data set when we load a section */
514     }
515     return DW_DLV_OK;
516 }
517 
518 
519 static int
520 dwarf_load_pe_sections(
521     dwarf_pe_object_access_internals_t *pep,int *errcode)
522 {
523     struct dos_header_dw dhinmem;
524     IMAGE_FILE_HEADER_dw ifh;
525     void (*word_swap) (void *, const void *, unsigned long);
526     unsigned locendian = 0;
527     int res = 0;
528     Dwarf_Unsigned dos_sig = 0;
529     Dwarf_Unsigned nt_address = 0;
530     char nt_sig_array[4];
531     unsigned long nt_signature = 0;
532 
533     if ( (sizeof(ifh) + sizeof(dhinmem))  >= pep->pe_filesize) {
534         /* corrupt object. */
535         *errcode = DW_DLE_PE_SIZE_SMALL;
536         return DW_DLV_ERROR;
537     }
538     res = _dwarf_object_read_random(pep->pe_fd,(char *)&dhinmem,
539         0, sizeof(dhinmem),(off_t)pep->pe_filesize, errcode);
540     if (res != DW_DLV_OK) {
541         return res;
542     }
543     dos_sig = magic_copy((char *)dhinmem.dh_mz,
544         sizeof(dhinmem.dh_mz));
545     if (dos_sig == IMAGE_DOS_SIGNATURE_dw) {
546         /*  IMAGE_DOS_SIGNATURE_dw assumes bytes reversed by little-endian
547             load, so we intrepet a match the other way. */
548         /* BIG ENDIAN. From looking at hex characters in object  */
549 #ifdef WORDS_BIGENDIAN
550         word_swap = _dwarf_memcpy_noswap_bytes;
551 #else  /* LITTLE ENDIAN */
552         word_swap = _dwarf_memcpy_swap_bytes;
553 #endif /* LITTLE- BIG-ENDIAN */
554         locendian = DW_OBJECT_MSB;
555     } else if (dos_sig == IMAGE_DOS_REVSIGNATURE_dw) {
556         /* raw load, so  intrepet a match the other way. */
557         /* LITTLE ENDIAN */
558 #ifdef WORDS_BIGENDIAN
559         word_swap = _dwarf_memcpy_swap_bytes;
560 #else   /* LITTLE ENDIAN */
561         word_swap = _dwarf_memcpy_noswap_bytes;
562 #endif  /* LITTLE- BIG-ENDIAN */
563         locendian = DW_OBJECT_LSB;
564     } else {
565         /* Not dos header not a PE file we recognize */
566         *errcode = DW_DLE_FILE_WRONG_TYPE;
567         return DW_DLV_ERROR;
568     }
569     if (locendian != pep->pe_endian) {
570         /*  Really this is a coding botch somewhere here,
571             not an object corruption. */
572         *errcode = DW_DLE_FILE_WRONG_TYPE;
573         return DW_DLV_ERROR;
574     }
575     pep->pe_copy_word = word_swap;
576     ASNAR(word_swap,nt_address,dhinmem.dh_image_offset);
577     if (pep->pe_filesize < (nt_address + sizeof(nt_sig_array))) {
578         /*  The nt_address is really a file offset. */
579         *errcode = DW_DLE_FILE_TOO_SMALL;
580         /* Not dos header not a PE file we recognize */
581         return DW_DLV_ERROR;
582     }
583 
584     res =  _dwarf_object_read_random(pep->pe_fd,
585         (char *)&nt_sig_array[0],
586         (off_t)nt_address, sizeof(nt_sig_array),
587         (off_t)pep->pe_filesize,errcode);
588     if (res != DW_DLV_OK) {
589         return res;
590     }
591     {   unsigned long lsig = 0;
592 
593         ASNAR(word_swap,lsig,nt_sig_array);
594         nt_signature = lsig;
595     }
596     if (nt_signature != IMAGE_NT_SIGNATURE_dw) {
597         *errcode = DW_DLE_FILE_WRONG_TYPE;
598         return DW_DLV_ERROR;
599     }
600 
601     pep->pe_nt_header_offset = nt_address  + SIZEOFT32;
602     if (pep->pe_filesize < (pep->pe_nt_header_offset +
603         sizeof(ifh))) {
604         *errcode = DW_DLE_FILE_TOO_SMALL;
605         /* Not image header not a PE file we recognize */
606         return DW_DLV_ERROR;
607     }
608     res = _dwarf_object_read_random(pep->pe_fd,(char *)&ifh,
609         (off_t)pep->pe_nt_header_offset, sizeof(ifh),
610         (off_t)pep->pe_filesize,errcode);
611     if (res != DW_DLV_OK) {
612         return res;
613     }
614     ASNAR(word_swap,pep->pe_FileHeader.Machine,ifh.Machine);
615     ASNAR(word_swap,pep->pe_FileHeader.NumberOfSections,
616         ifh.NumberOfSections);
617     ASNAR(word_swap,pep->pe_FileHeader.TimeDateStamp,
618         ifh.TimeDateStamp);
619     ASNAR(word_swap,pep->pe_FileHeader.PointerToSymbolTable,
620         ifh.PointerToSymbolTable);
621     ASNAR(word_swap,pep->pe_FileHeader.NumberOfSymbols,
622         ifh.NumberOfSymbols);
623     ASNAR(word_swap,pep->pe_FileHeader.SizeOfOptionalHeader,
624         ifh.SizeOfOptionalHeader);
625     ASNAR(word_swap,pep->pe_FileHeader.Characteristics,
626         ifh.Characteristics);
627 
628     pep->pe_optional_header_offset = pep->pe_nt_header_offset+
629         sizeof(ifh);
630     if (pep->pe_offsetsize == 32) {
631         res = load_optional_header32(pep,
632             pep->pe_optional_header_offset,errcode);
633         pep->pe_optional_header_size = sizeof(IMAGE_OPTIONAL_HEADER32_dw);
634     } else if (pep->pe_offsetsize == 64) {
635         res = load_optional_header64(pep,
636             pep->pe_optional_header_offset,errcode);
637         pep->pe_optional_header_size = sizeof(IMAGE_OPTIONAL_HEADER64_dw);
638     } else {
639         *errcode = DW_DLE_OFFSET_SIZE;
640         return DW_DLV_ERROR;
641     }
642     if (res != DW_DLV_OK) {
643         return res;
644     }
645 
646     pep->pe_section_table_offset = pep->pe_optional_header_offset
647         + pep->pe_optional_header_size;
648     pep->pe_symbol_table_offset =
649         pep->pe_FileHeader.PointerToSymbolTable;
650     if (pep->pe_symbol_table_offset >= pep->pe_filesize) {
651         *errcode = DW_DLE_OFFSET_SIZE;
652         return DW_DLV_ERROR;
653     }
654     if (pep->pe_symbol_table_offset) {
655         pep->pe_string_table_offset  =
656             pep->pe_symbol_table_offset +
657             (pep->pe_FileHeader.NumberOfSymbols *
658             IMAGE_SIZEOF_SYMBOL);
659     }
660 
661     if (pep->pe_string_table_offset >= pep->pe_filesize) {
662         *errcode = DW_DLE_OFFSET_SIZE;
663         pep->pe_string_table_size = 0;
664         return DW_DLV_ERROR;
665     }
666     if (pep->pe_string_table_offset) {
667         /*  https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#coff-string-table  */
668         /* The first 4 bytes of the string table contain
669             the size of the string table. */
670         char size_field[4];
671 
672         if ((pep->pe_string_table_offset+sizeof(size_field)) >
673             pep->pe_filesize) {
674             *errcode = DW_DLE_FILE_TOO_SMALL;
675             return DW_DLV_ERROR;
676         }
677         memset(size_field,0,sizeof(size_field));
678         res =  _dwarf_object_read_random(pep->pe_fd,
679             (char *)size_field, (off_t)pep->pe_string_table_offset,
680             sizeof(size_field),
681             (off_t)pep->pe_filesize,errcode);
682         if (res != DW_DLV_OK) {
683             return res;
684         }
685         ASNAR(pep->pe_copy_word,pep->pe_string_table_size,
686             size_field);
687         if( pep->pe_string_table_size >= pep->pe_filesize ) {
688             *errcode = DW_DLE_PE_OFFSET_BAD;
689             return DW_DLV_ERROR;
690         }
691         if ((pep->pe_string_table_offset+pep->pe_string_table_size) >
692             pep->pe_filesize) {
693             *errcode = DW_DLE_FILE_TOO_SMALL;
694             return DW_DLV_ERROR;
695         }
696         pep->pe_string_table =
697             (char *)malloc((size_t)pep->pe_string_table_size);
698         if (!pep->pe_string_table) {
699             *errcode = DW_DLE_ALLOC_FAIL;
700             return DW_DLV_ERROR;
701         }
702         res = _dwarf_object_read_random(pep->pe_fd,
703             (char *)pep->pe_string_table, (off_t)pep->pe_string_table_offset,
704             (size_t)pep->pe_string_table_size,
705             (off_t)pep->pe_filesize,errcode);
706         if (res != DW_DLV_OK) {
707             return res;
708         }
709     }
710     res = dwarf_pe_load_dwarf_section_headers(pep,errcode);
711     return res;
712 }
713 
714 int
715 _dwarf_pe_setup(int fd,
716     char *true_path,
717     unsigned ftype,
718     unsigned endian,
719     unsigned offsetsize,
720     size_t filesize,
721     Dwarf_Unsigned access,
722     unsigned groupnumber,
723     Dwarf_Handler errhand,
724     Dwarf_Ptr errarg,
725     Dwarf_Debug *dbg,Dwarf_Error *error)
726 {
727     Dwarf_Obj_Access_Interface *binary_interface = 0;
728     dwarf_pe_object_access_internals_t *pep = 0;
729     int res = DW_DLV_OK;
730     int localerrnum = 0;
731 
732     res = _dwarf_pe_object_access_init(
733         fd,
734         ftype,endian,offsetsize,filesize,access,
735         &binary_interface,
736         &localerrnum);
737     if (res != DW_DLV_OK) {
738         if (res == DW_DLV_NO_ENTRY) {
739             return res;
740         }
741         _dwarf_error(NULL, error, localerrnum);
742         return DW_DLV_ERROR;
743     }
744     /*  allocates and initializes Dwarf_Debug,
745         generic code */
746     res = dwarf_object_init_b(binary_interface, errhand, errarg,
747         groupnumber, dbg, error);
748     if (res != DW_DLV_OK){
749         _dwarf_destruct_pe_access(binary_interface);
750         return res;
751     }
752     pep = binary_interface->object;
753     pep->pe_path = strdup(true_path);
754     return res;
755 }
756 
757 static Dwarf_Obj_Access_Methods pe_methods = {
758     pe_get_section_info,
759     pe_get_byte_order,
760     pe_get_length_size,
761     pe_get_pointer_size,
762     pe_get_section_count,
763     pe_load_section,
764     0 /* ignore pe relocations. */
765 };
766 
767 /* On any error this frees internals. */
768 static int
769 _dwarf_pe_object_access_internals_init(
770     dwarf_pe_object_access_internals_t * internals,
771     int  fd,
772     unsigned ftype,
773     unsigned endian,
774     unsigned offsetsize,
775     size_t filesize,
776     UNUSEDARG Dwarf_Unsigned access,
777     int *errcode)
778 {
779     dwarf_pe_object_access_internals_t * intfc = internals;
780     struct Dwarf_Obj_Access_Interface_s *localdoas = 0;
781     int res = 0;
782 
783     /*  Must malloc as _dwarf_destruct_pe_access()
784         forces that due to other uses. */
785     localdoas = (struct Dwarf_Obj_Access_Interface_s *)
786         malloc(sizeof(struct Dwarf_Obj_Access_Interface_s));
787     if (!localdoas) {
788         free(internals);
789         *errcode = DW_DLE_ALLOC_FAIL;
790         return DW_DLV_ERROR;
791     }
792     memset(localdoas,0,sizeof(struct Dwarf_Obj_Access_Interface_s));
793     intfc->pe_ident[0]    = 'P';
794     intfc->pe_ident[1]    = '1';
795     intfc->pe_fd          = fd;
796     intfc->pe_is_64bit    = ((offsetsize==64)?TRUE:FALSE);
797     intfc->pe_offsetsize  = offsetsize;
798     intfc->pe_pointersize = offsetsize;
799     intfc->pe_filesize    = filesize;
800     intfc->pe_ftype       = ftype;
801     /* pe_path set by caller */
802 
803 #ifdef WORDS_BIGENDIAN
804     if (endian == DW_ENDIAN_LITTLE ) {
805         intfc->pe_copy_word = _dwarf_memcpy_swap_bytes;
806         intfc->pe_endian = DW_OBJECT_LSB;
807     } else {
808         intfc->pe_copy_word = _dwarf_memcpy_noswap_bytes;
809         intfc->pe_endian = DW_OBJECT_MSB;
810     }
811 #else  /* LITTLE ENDIAN */
812     if (endian == DW_ENDIAN_LITTLE ) {
813         intfc->pe_copy_word = _dwarf_memcpy_noswap_bytes;
814         intfc->pe_endian = DW_OBJECT_LSB;
815     } else {
816         intfc->pe_copy_word = _dwarf_memcpy_swap_bytes;
817         intfc->pe_endian = DW_OBJECT_MSB;
818     }
819 #endif /* LITTLE- BIG-ENDIAN */
820     res = dwarf_load_pe_sections(intfc,errcode);
821     if (res != DW_DLV_OK) {
822         localdoas->object = intfc;
823         localdoas->methods = 0;
824         _dwarf_destruct_pe_access(localdoas);
825         localdoas = 0;
826         return res;
827     }
828     free(localdoas);
829     localdoas = 0;
830     return DW_DLV_OK;
831 }
832 
833 
834 static int
835 _dwarf_pe_object_access_init(
836     int  fd,
837     unsigned ftype,
838     unsigned endian,
839     unsigned offsetsize,
840     size_t filesize,
841     Dwarf_Unsigned access,
842     Dwarf_Obj_Access_Interface **binary_interface,
843     int *localerrnum)
844 {
845 
846     int res = 0;
847     dwarf_pe_object_access_internals_t *internals = 0;
848     Dwarf_Obj_Access_Interface *intfc = 0;
849 
850     internals = malloc(sizeof(dwarf_pe_object_access_internals_t));
851     if (!internals) {
852         *localerrnum = DW_DLE_ALLOC_FAIL;
853         /* Impossible case, we hope. Give up. */
854         return DW_DLV_ERROR;
855     }
856     memset(internals,0,sizeof(*internals));
857     res = _dwarf_pe_object_access_internals_init(internals,
858         fd,
859         ftype, endian, offsetsize, filesize,
860         access,
861         localerrnum);
862     if (res != DW_DLV_OK){
863         /* *err is already set. and the call freed internals */
864         return DW_DLV_ERROR;
865     }
866 
867     intfc = malloc(sizeof(Dwarf_Obj_Access_Interface));
868     if (!intfc) {
869         /* Impossible case, we hope. Give up. */
870         free(internals);
871         *localerrnum = DW_DLE_ALLOC_FAIL;
872         return DW_DLV_ERROR;
873     }
874     /* Initialize the interface struct */
875     intfc->object = internals;
876     intfc->methods = &pe_methods;
877     *binary_interface = intfc;
878     return DW_DLV_OK;
879 }
880