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
magic_copy(char * d,unsigned len)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
pe_section_name_get(dwarf_pe_object_access_internals_t * pep,const char * name_array,const char ** name_out,int * errcode)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
pe_get_byte_order(void * obj)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
pe_get_length_size(void * obj)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
pe_get_pointer_size(void * obj)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
pe_get_section_count(void * obj)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
pe_get_section_info(void * obj,Dwarf_Half section_index,Dwarf_Obj_Access_Section * return_section,UNUSEDARG int * error)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
load_optional_header32(dwarf_pe_object_access_internals_t * pep,Dwarf_Unsigned offset,int * errcode)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
load_optional_header64(dwarf_pe_object_access_internals_t * pep,Dwarf_Unsigned offset,int * errcode)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
pe_load_section(void * obj,Dwarf_Half section_index,Dwarf_Small ** return_data,int * error)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
_dwarf_destruct_pe_access(struct Dwarf_Obj_Access_Interface_s * aip)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
dwarf_pe_load_dwarf_section_headers(dwarf_pe_object_access_internals_t * pep,int * errcode)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
dwarf_load_pe_sections(dwarf_pe_object_access_internals_t * pep,int * errcode)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
_dwarf_pe_setup(int fd,char * true_path,unsigned ftype,unsigned endian,unsigned offsetsize,size_t filesize,Dwarf_Unsigned access,unsigned groupnumber,Dwarf_Handler errhand,Dwarf_Ptr errarg,Dwarf_Debug * dbg,Dwarf_Error * error)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
_dwarf_pe_object_access_internals_init(dwarf_pe_object_access_internals_t * internals,int fd,unsigned ftype,unsigned endian,unsigned offsetsize,size_t filesize,UNUSEDARG Dwarf_Unsigned access,int * errcode)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
_dwarf_pe_object_access_init(int fd,unsigned ftype,unsigned endian,unsigned offsetsize,size_t filesize,Dwarf_Unsigned access,Dwarf_Obj_Access_Interface ** binary_interface,int * localerrnum)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