* Parse a PE file into an ELF structure. */
| 1343 | * Parse a PE file into an ELF structure. |
| 1344 | */ |
| 1345 | ELF *e9tool::parsePE(const char *filename) |
| 1346 | { |
| 1347 | int fd = open(filename, O_RDONLY, 0); |
| 1348 | if (fd < 0) |
| 1349 | error("failed to open file \"%s\" for reading: %s", filename, |
| 1350 | strerror(errno)); |
| 1351 | |
| 1352 | struct stat stat; |
| 1353 | if (fstat(fd, &stat) != 0) |
| 1354 | error("failed to get statistics for file \"%s\": %s", filename, |
| 1355 | strerror(errno)); |
| 1356 | |
| 1357 | size_t size = (size_t)stat.st_size; |
| 1358 | void *ptr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); |
| 1359 | if (ptr == MAP_FAILED) |
| 1360 | error("failed to map file \"%s\" into memory: %s", filename, |
| 1361 | strerror(errno)); |
| 1362 | close(fd); |
| 1363 | const uint8_t *data = (const uint8_t *)ptr; |
| 1364 | |
| 1365 | if (size < 0x3c + sizeof(uint32_t)) |
| 1366 | error("failed to parse PE file \"%s\"; file size (%zu) is too small " |
| 1367 | "for MS-DOS header", filename, size); |
| 1368 | if (data[0] != 'M' || data[1] != 'Z') |
| 1369 | error("failed to parse PE file \"%s\"; invalid MS-DOS stub header " |
| 1370 | "magic number, expected \"MZ\"", filename); |
| 1371 | uint32_t pe_offset = *(const uint32_t *)(data + 0x3c); |
| 1372 | const size_t pe_hdr_size = sizeof(uint32_t) + sizeof(IMAGE_FILE_HEADER) + |
| 1373 | sizeof(IMAGE_OPTIONAL_HEADER64); |
| 1374 | if (pe_offset < 0x3c + sizeof(uint32_t) || pe_offset + pe_hdr_size > size) |
| 1375 | error("failed to parse PE file \"%s\"; file size (%zu) is too small" |
| 1376 | "for PE header(s)", filename, size); |
| 1377 | if (data[pe_offset] != 'P' || |
| 1378 | data[pe_offset+1] != 'E' || |
| 1379 | data[pe_offset+2] != 0x0 || |
| 1380 | data[pe_offset+3] != 0x0) |
| 1381 | error("failed to parse PE file \"%s\"; invalid PE signature, " |
| 1382 | "expected \"PE\\0\\0\"", filename); |
| 1383 | const IMAGE_FILE_HEADER *file_hdr = |
| 1384 | (PIMAGE_FILE_HEADER)(data + pe_offset + sizeof(uint32_t)); |
| 1385 | if (file_hdr->Machine != IMAGE_FILE_MACHINE_AMD64) |
| 1386 | error("failed to parse PE file \"%s\"; invalid machine (0x%x), " |
| 1387 | "expected x86_64 (0x%x)", filename, file_hdr->Machine, |
| 1388 | IMAGE_FILE_MACHINE_AMD64); |
| 1389 | if (file_hdr->SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER64)) |
| 1390 | error("failed to parse PE file \"%s\"; invalid optional header " |
| 1391 | "size (%zu), expected (>=%zu)", filename, |
| 1392 | file_hdr->SizeOfOptionalHeader, |
| 1393 | sizeof(IMAGE_OPTIONAL_HEADER64)); |
| 1394 | const IMAGE_OPTIONAL_HEADER64 *opt_hdr = |
| 1395 | (PIMAGE_OPTIONAL_HEADER64)(file_hdr + 1); |
| 1396 | static const uint16_t PE64_MAGIC = 0x020b; |
| 1397 | if (opt_hdr->Magic != PE64_MAGIC) |
| 1398 | error("failed to parse PE file \"%s\"; invalid magic number (0x%x), " |
| 1399 | "expected PE64 (0x%x)", filename, opt_hdr->Magic, PE64_MAGIC); |
| 1400 | BinaryType type = BINARY_TYPE_PE_EXE; |
| 1401 | if ((file_hdr->Characteristics & IMAGE_FILE_DLL) != 0) |
| 1402 | type = BINARY_TYPE_PE_DLL; |