static Pe * read_unmmapped_file(int fildes, size_t maxsize, Pe_Cmd cmd, Pe *parent) { union { struct { struct mz_hdr mz; struct pe_hdr pe; }; unsigned char raw[1]; } mem; ssize_t nread = pread_retry (fildes, &mem.mz, sizeof(mem.mz), 0); if (nread == -1) return NULL; /* this handles MZ-only binaries wrong, but who cares, really? */ off_t peaddr = le32_to_cpu(mem.mz.peaddr); ssize_t prev_nread = nread; nread += pread_retry (fildes, &mem.pe, sizeof(mem.pe), peaddr); if (nread == prev_nread) return NULL; mem.mz.peaddr = cpu_to_le32(offsetof(typeof(mem), pe)); Pe_Kind kind = determine_kind(&mem, nread); switch (kind) { case PE_K_PE_OBJ: return file_read_pe_obj(fildes, NULL, mem.raw, maxsize, cmd, parent); case PE_K_PE_EXE: return file_read_pe_exe(fildes, NULL, mem.raw, maxsize, cmd, parent); default: break; } return allocate_pe(fildes, NULL, maxsize, cmd, parent, PE_K_NONE, 0); }
static unsigned char get_pid_class (pid_t pid) { char *fname; if (asprintf (&fname, PROCEXEFMT, pid) < 0) return ELFCLASSNONE; int fd = open (fname, O_RDONLY); free (fname); if (fd < 0) return ELFCLASSNONE; unsigned char buf[EI_CLASS + 1]; ssize_t nread = pread_retry (fd, &buf, sizeof buf, 0); close (fd); if (nread != sizeof buf || buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1 || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3 || (buf[EI_CLASS] != ELFCLASS64 && buf[EI_CLASS] != ELFCLASS32)) return ELFCLASSNONE; return buf[EI_CLASS]; }
static int grovel_auxv (pid_t pid, Dwfl *dwfl, GElf_Addr *sysinfo_ehdr) { char *fname; if (asprintf (&fname, PROCAUXVFMT, pid) < 0) return ENOMEM; int fd = open (fname, O_RDONLY); free (fname); if (fd < 0) return errno == ENOENT ? 0 : errno; GElf_Addr sysinfo_ehdr64 = 0; GElf_Addr sysinfo_ehdr32 = 0; GElf_Addr segment_align64 = dwfl->segment_align; GElf_Addr segment_align32 = dwfl->segment_align; off_t offset = 0; ssize_t nread; union { Elf64_auxv_t a64[64]; Elf32_auxv_t a32[128]; } d; do { eu_static_assert (sizeof d.a64 == sizeof d.a32); nread = pread_retry (fd, d.a64, sizeof d.a64, offset); if (nread < 0) { int ret = errno; close (fd); return ret; } for (size_t a32i = 0; a32i < nread / sizeof d.a32[0]; a32i++) { const Elf32_auxv_t *a32 = d.a32 + a32i; switch (a32->a_type) { case AT_SYSINFO_EHDR: sysinfo_ehdr32 = a32->a_un.a_val; break; case AT_PAGESZ: segment_align32 = a32->a_un.a_val; break; } } for (size_t a64i = 0; a64i < nread / sizeof d.a64[0]; a64i++) { const Elf64_auxv_t *a64 = d.a64 + a64i; switch (a64->a_type) { case AT_SYSINFO_EHDR: sysinfo_ehdr64 = a64->a_un.a_val; break; case AT_PAGESZ: segment_align64 = a64->a_un.a_val; break; } } offset += nread; } while (nread == sizeof d.a64); close (fd); bool valid64 = sysinfo_ehdr64 != 0 || segment_align64 != dwfl->segment_align; bool valid32 = sysinfo_ehdr32 != 0 || segment_align32 != dwfl->segment_align; unsigned char pid_class = ELFCLASSNONE; if (valid64 && valid32) pid_class = get_pid_class (pid); if (pid_class == ELFCLASS64 || (valid64 && ! valid32)) { *sysinfo_ehdr = sysinfo_ehdr64; dwfl->segment_align = segment_align64; return 0; } if (pid_class == ELFCLASS32 || (! valid64 && valid32)) { *sysinfo_ehdr = sysinfo_ehdr32; dwfl->segment_align = segment_align32; return 0; } return ENOEXEC; }