static int is_aout_shared_lib(const char *name) { struct exec ex; struct stat st; int fd; if (stat(name, &st) < 0) return 0; if ((st.st_mode & (S_IFREG|S_IFLNK)) == 0) return 0; fd = open(name, O_RDONLY); if (fd < 0) { return 0; } if (read(fd, &ex, sizeof ex) - sizeof ex != 0) { close(fd); return 0; } close(fd); if (N_GETMAGIC(ex) != ZMAGIC || (N_GETFLAG(ex) & EX_DYNAMIC) == 0) return 0; return 1; }
static void dump_segs(void) { printf(" Text segment starts at address %lx\n", origin + N_TXTOFF(*ex)); if (N_GETFLAG(*ex) & EX_DYNAMIC) { printf(" rel starts at %lx\n", sdt->sdt_rel); printf(" hash starts at %lx\n", sdt->sdt_hash); printf(" nzlist starts at %lx\n", sdt->sdt_nzlist); printf(" strings starts at %lx\n", sdt->sdt_strings); } printf(" Data segment starts at address %lx\n", origin + N_DATOFF(*ex)); if (N_GETFLAG(*ex) & EX_DYNAMIC) { printf(" _dynamic starts at %lx\n", origin + N_DATOFF(*ex)); printf(" so_debug starts at %lx\n", (unsigned long) dyn->d_debug); printf(" sdt starts at %lx\n", (unsigned long) dyn->d_un.d_sdt); printf(" got starts at %lx\n", sdt->sdt_got); printf(" plt starts at %lx\n", sdt->sdt_plt); printf(" rest of stuff starts at %lx\n", sdt->sdt_plt + sdt->sdt_plt_sz); } }
static int is_exos_aout(int fd) { struct exec hdr; u_int dynamic; if (lseek(fd, 0, SEEK_SET) == -1 || read(fd, &hdr, sizeof(hdr)) != sizeof(hdr) || lseek(fd, sizeof(hdr) + hdr.a_text, SEEK_SET) == -1 || read(fd, &dynamic, sizeof(dynamic)) != sizeof(dynamic)) return 0; if (N_GETMAGIC(hdr) != OMAGIC || N_GETMID(hdr) != MID_I386 || N_GETFLAG(hdr) != 0) return 0; return 1; }
static int is_executable(const char *fname, int fd, int *is_shlib, int *type) { union { #ifdef AOUT_SUPPORTED struct exec aout; #endif #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) Elf32_Ehdr elf32; #endif Elf_Ehdr elf; } hdr; int n; *is_shlib = 0; *type = TYPE_UNKNOWN; if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { warn("%s: can't read program header", fname); return (0); } #ifdef AOUT_SUPPORTED if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { /* a.out file */ if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC #if 1 /* Compatibility */ || hdr.aout.a_entry < __LDPGSZ #endif ) { warnx("%s: not a dynamic executable", fname); return (0); } *type = TYPE_AOUT; return (1); } #endif #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { /* Handle 32 bit ELF objects */ Elf32_Phdr phdr; int dynamic, i; dynamic = 0; *type = TYPE_ELF32; if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { warnx("%s: header too short", fname); return (0); } for (i = 0; i < hdr.elf32.e_phnum; i++) { if (read(fd, &phdr, hdr.elf32.e_phentsize) != sizeof(phdr)) { warnx("%s: can't read program header", fname); return (0); } if (phdr.p_type == PT_DYNAMIC) { dynamic = 1; break; } } if (!dynamic) { warnx("%s: not a dynamic ELF executable", fname); return (0); } if (hdr.elf32.e_type == ET_DYN) { if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { *is_shlib = 1; return (1); } warnx("%s: not a FreeBSD ELF shared object", fname); return (0); } return (1); } #endif if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { /* Handle default ELF objects on this architecture */ Elf_Phdr phdr; int dynamic, i; dynamic = 0; *type = TYPE_ELF; if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { warnx("%s: header too short", fname); return (0); } for (i = 0; i < hdr.elf.e_phnum; i++) { if (read(fd, &phdr, hdr.elf.e_phentsize) != sizeof(phdr)) { warnx("%s: can't read program header", fname); return (0); } if (phdr.p_type == PT_DYNAMIC) { dynamic = 1; break; } } if (!dynamic) { warnx("%s: not a dynamic ELF executable", fname); return (0); } if (hdr.elf.e_type == ET_DYN) { if (hdr.elf.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { *is_shlib = 1; return (1); } warnx("%s: not a FreeBSD ELF shared object", fname); return (0); } return (1); } warnx("%s: not a dynamic executable", fname); return (0); }
static #endif void dump_file(const char *fname) { int fd; struct stat sb; caddr_t objbase; if (stat(fname, &sb) == -1) { warnx("cannot stat \"%s\"", fname); ++error_count; return; } if ((sb.st_mode & S_IFMT) != S_IFREG) { warnx("\"%s\" is not a regular file", fname); ++error_count; return; } if ((fd = open(fname, O_RDONLY, 0)) == -1) { warnx("cannot open \"%s\"", fname); ++error_count; return; } objbase = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (objbase == (caddr_t) -1) { warnx("cannot mmap \"%s\"", fname); ++error_count; close(fd); return; } close(fd); file_base = (const char *) objbase; /* Makes address arithmetic easier */ if (IS_ELF(*(const Elf32_Ehdr*) align_struct(file_base))) { warnx("%s: this is an ELF program; use objdump to examine", fname); ++error_count; munmap(objbase, sb.st_size); return; } ex = (const struct exec *) align_struct(file_base); printf("%s: a_midmag = 0x%lx\n", fname, (long)ex->a_midmag); printf(" magic = 0x%lx = 0%lo, netmagic = 0x%lx = 0%lo\n", (long)N_GETMAGIC(*ex), (long)N_GETMAGIC(*ex), (long)N_GETMAGIC_NET(*ex), (long)N_GETMAGIC_NET(*ex)); if (N_BADMAG(*ex)) { warnx("%s: bad magic number", fname); ++error_count; munmap(objbase, sb.st_size); return; } printf(" a_text = 0x%lx\n", (long)ex->a_text); printf(" a_data = 0x%lx\n", (long)ex->a_data); printf(" a_bss = 0x%lx\n", (long)ex->a_bss); printf(" a_syms = 0x%lx\n", (long)ex->a_syms); printf(" a_entry = 0x%lx\n", (long)ex->a_entry); printf(" a_trsize = 0x%lx\n", (long)ex->a_trsize); printf(" a_drsize = 0x%lx\n", (long)ex->a_drsize); text_base = file_base + N_TXTOFF(*ex); data_base = file_base + N_DATOFF(*ex); rel_base = (const struct relocation_info *) align_struct(file_base + N_RELOFF(*ex)); sym_base = (const struct nlist *) align_struct(file_base + N_SYMOFF(*ex)); str_base = file_base + N_STROFF(*ex); rel_count = (ex->a_trsize + ex->a_drsize) / sizeof rel_base[0]; assert(rel_count * sizeof rel_base[0] == ex->a_trsize + ex->a_drsize); sym_count = ex->a_syms / sizeof sym_base[0]; assert(sym_count * sizeof sym_base[0] == ex->a_syms); if (sym_count != 0) { sym_used = (unsigned char *) calloc(sym_count, sizeof(unsigned char)); assert(sym_used != NULL); } printf(" Entry = 0x%lx\n", (long)ex->a_entry); printf(" Text offset = %x, address = %lx\n", N_TXTOFF(*ex), (long)N_TXTADDR(*ex)); printf(" Data offset = %lx, address = %lx\n", (long)N_DATOFF(*ex), (long)N_DATADDR(*ex)); /* * In an executable program file, everything is relocated relative to * the assumed run-time load address, i.e., N_TXTADDR(*ex), i.e., 0x1000. * * In a shared library file, everything is relocated relative to the * start of the file, i.e., N_TXTOFF(*ex), i.e., 0. * * The way to tell the difference is by looking at ex->a_entry. If it * is >= 0x1000, then we have an executable program. Otherwise, we * have a shared library. * * When a program is executed, the entire file is mapped into memory, * including the a.out header and so forth. But it is not mapped at * address 0; rather it is mapped at address 0x1000. The first page * of the user's address space is left unmapped in order to catch null * pointer dereferences. * * In this program, when we map in an executable program, we have to * simulate the empty page by decrementing our assumed base address by * a pagesize. */ text_addr = text_base; data_addr = data_base; origin = 0; if (ex->a_entry >= PAGE_SIZE) { /* Executable, not a shared library */ /* * The fields in the object have already been relocated on the * assumption that the object will be loaded at N_TXTADDR(*ex). * We have to compensate for that. */ text_addr -= PAGE_SIZE; data_addr -= PAGE_SIZE; origin = PAGE_SIZE; printf(" Program, origin = %lx\n", origin); } else if (N_GETFLAG(*ex) & EX_DYNAMIC) printf(" Shared library, origin = %lx\n", origin); else printf(" Object file, origin = %lx\n", origin); if (N_GETFLAG(*ex) & EX_DYNAMIC) { dyn = (const struct _dynamic *) align_struct(data_base); printf(" Dynamic version = %d\n", dyn->d_version); sdt = (const struct section_dispatch_table *) align_struct(text_addr + (unsigned long) dyn->d_un.d_sdt); rtrel_base = (const struct relocation_info *) align_struct(text_addr + sdt->sdt_rel); rtrel_count = (sdt->sdt_hash - sdt->sdt_rel) / sizeof rtrel_base[0]; assert(rtrel_count * sizeof rtrel_base[0] == (size_t)(sdt->sdt_hash - sdt->sdt_rel)); rtsym_base = (const struct nzlist *) align_struct(text_addr + sdt->sdt_nzlist); rtsym_count = (sdt->sdt_strings - sdt->sdt_nzlist) / sizeof rtsym_base[0]; assert(rtsym_count * sizeof rtsym_base[0] == (size_t)(sdt->sdt_strings - sdt->sdt_nzlist)); if (rtsym_count != 0) { rtsym_used = (unsigned char *) calloc(rtsym_count, sizeof(unsigned char)); assert(rtsym_used != NULL); } rtstr_base = text_addr + sdt->sdt_strings; } dump_segs(); dump_sods(); dump_rels("Relocations", rel_base, rel_count, sym_name, sym_used); dump_syms(); dump_rels("Run-time relocations", rtrel_base, rtrel_count, rtsym_name, rtsym_used); dump_rtsyms(); if (rtsym_used != NULL) { free(rtsym_used); rtsym_used = NULL; } if (sym_used != NULL) { free(sym_used); sym_used = NULL; } munmap(objbase, sb.st_size); }
void run_header(struct exec *exhdr, int extended_info) { char *id = NULL; assert(NULL != exhdr); /* print raw values */ printf( "\ta_midmag 0x%08x (mid %d, magic 0%o, flag 0x%x)\n" "\ta_text 0x%08x\n" "\ta_data 0x%08x\n" "\ta_bss 0x%08x\n" "\ta_syms 0x%08x\n" "\ta_entry 0x%08x\n" "\ta_trsize 0x%08x\n" "\ta_drsize 0x%08x\n", exhdr->a_midmag, N_GETMID(*exhdr), N_GETMAGIC(*exhdr), N_GETFLAG(*exhdr), exhdr->a_text, exhdr->a_data, exhdr->a_bss, exhdr->a_syms, exhdr->a_entry, exhdr->a_trsize, exhdr->a_drsize ); printf( "magic number %04o: %s\n", N_GETMAGIC(*exhdr), N_GETMAGIC(*exhdr) == OMAGIC ? "old impure format" : N_GETMAGIC(*exhdr) == NMAGIC ? "read-only text" : N_GETMAGIC(*exhdr) == ZMAGIC ? "demand load format" : N_GETMAGIC(*exhdr) == QMAGIC ? "deprecated format" : "totally funky" ); switch (N_GETMID(*exhdr)) { case MID_ZERO: id = "unknown - implementation dependent"; break; case MID_SUN010: id = "sun 68010/68020 binary"; break; case MID_SUN020: id = "sun 68020-only binary"; break; case MID_PC386: id = "386 PC binary. (so quoth BFD)"; break; case MID_HP200: id = "hp200 (68010) BSD binary"; break; case MID_I386: id = "i386 BSD binary"; break; case MID_M68K: id = "m68k BSD binary with 8K page sizes"; break; case MID_M68K4K: id = "m68k BSD binary with 4K page sizes"; break; case MID_NS32532: id = "ns32532"; break; case MID_SPARC: id = "sparc"; break; case MID_PMAX: id = "pmax"; break; case MID_VAX: id = "vax"; break; case MID_ALPHA: id = "Alpha BSD binary"; break; case MID_MIPS: id = "big-endian MIPS"; break; case MID_ARM6: id = "ARM6"; break; case MID_HP300: id = "hp300 (68020+68881) BSD binary"; break; case MID_HPUX: id = "hp200/300 HP-UX binary"; break; case MID_HPUX800: id = "hp800 HP-UX binary"; break; default: id = "don't know"; break; } printf("type %d, %s\n", N_GETMID(*exhdr), id); /* this left shift seems a bit bogus */ switch((N_GETFLAG(*exhdr) & EX_DPMASK)>>4) { case 0: id = "traditional executable or object file"; break; case 1: id = "object file contains PIC code"; break; case 2: id = "dynamic executable"; break; case 3: id = "position independent executable image"; break; default: id = NULL; } if (NULL != id) printf("flags: 0x%x, %s\n", N_GETFLAG(*exhdr), id); else printf("flags: 0x%x\n", N_GETFLAG(*exhdr)); if (extended_info) { unsigned long txt_addr; unsigned long dat_addr; unsigned long bss_addr; /* N_TXTADDR and N_DATADDR macros DON'T WORK */ if (N_GETMAGIC(*exhdr) == ZMAGIC) { txt_addr = __LDPGSZ; dat_addr = ((txt_addr + exhdr->a_text + __LDPGSZ - 1) & ~(__LDPGSZ - 1)); } else if (N_GETMAGIC(*exhdr) == OMAGIC) { txt_addr = 0; dat_addr = txt_addr + exhdr->a_text; } else { txt_addr = 0xdeadbeef; dat_addr = 0xcafebabe; } bss_addr = dat_addr + exhdr->a_data; printf(" text segment size = 0x%lx, text segment file offset = %ld\n", exhdr->a_text, N_TXTOFF(*exhdr)); printf(" data segment size = 0x%lx, data segment file offset = %ld\n", exhdr->a_data, N_DATOFF(*exhdr)); printf(" bss segment size = 0x%lx\n", exhdr->a_bss); printf(" text segment relocation size = 0x%lx, file offset = %ld, %d text relocations\n", exhdr->a_trsize, N_TRELOFF(*exhdr), exhdr->a_trsize/sizeof(struct relocation_info)); printf(" data segment relocation size = 0x%lx, file offset = %ld, %d data relocations\n", exhdr->a_drsize, N_DRELOFF(*exhdr), exhdr->a_drsize/sizeof(struct relocation_info)); printf(" symbol table size = 0x%lx, symbol table file offset = %ld (%d symbols)\n", exhdr->a_syms, N_SYMOFF(*exhdr), exhdr->a_syms/sizeof(struct nlist)); printf(" string table file offset = 0x%lx (%d)\n", N_STROFF(*exhdr), N_STROFF(*exhdr)); printf(" entry point = 0x%lx\n", exhdr->a_entry); printf(" text address = 0x%lx\n\tdata address = 0x%lx\n" "\tbss address = 0x%lx\n", txt_addr, dat_addr, bss_addr /* N_TXTADDR(*exhdr), N_DATADDR(*exhdr), N_BSSADDR(*exhdr) */ ); } }
int main (int argc, char *argv[]) { register struct nlist *s; register caddr_t strtab; register off_t stroff, symoff; register u_long symsize; register int cc; size_t strsize; struct nlist nbuf[1024]; struct exec exec; struct stat st; int fd; int pageOffset; if ((fd = open (argv[1], O_RDONLY)) < 0) { fprintf (stderr, "could not open %s\n", argv[1]); return -1; } if (lseek(fd, (off_t)0, SEEK_SET) == -1 || read(fd, &exec, sizeof(exec)) != sizeof(exec) || fstat(fd, &st) < 0) { fprintf (stderr, "Invalid binary file\n"); return -1; } if (N_BADMAG (exec) || N_GETMID (exec) != MID_I386) { fprintf (stderr, "invalid executable file N_BADMAG(exec) %d N_GETMID (exec) %d MID_I386 %d\n", N_BADMAG(exec), N_GETMID(exec), MID_I386); exit (1); } if (N_GETFLAG (exec) & EX_DYNAMIC) { fprintf (stderr, "are you giving me a dynamically linked executable??\n"); return -1; } symoff = N_SYMOFF(exec); symsize = exec.a_syms; stroff = symoff + symsize; #ifndef __linux__ /* Check for files too large to mmap. */ if (st.st_size - stroff > SIZE_T_MAX) { fprintf (stderr, "file too large\n"); return -1; } #endif /* * Map string table into our address space. This gives us * an easy way to randomly access all the strings, without * making the memory allocation permanent as with malloc/free * (i.e., munmap will return it to the system). */ strsize = st.st_size - stroff; pageOffset = stroff % 4096; stroff -= pageOffset; strsize += pageOffset; strtab = mmap(NULL, (size_t)strsize, PROT_READ, MAP_SHARED, fd, stroff); if (strtab == (char *)-1) { warn ("could not mmap string table"); return -1; } strtab += pageOffset; strsize -= pageOffset; if (lseek(fd, symoff, SEEK_SET) == -1) { fprintf (stderr, "could not lseek to symbol table\n"); return -1; } while (symsize > 0) { int i; cc = my_min(symsize, sizeof(nbuf)); if (read(fd, nbuf, cc) != cc) break; symsize -= cc; for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) { register int soff = s->n_un.n_strx; if (soff == 0 || (s->n_type & N_STAB) != 0) continue; for (i = 0; exclude[i]; i++) { if (!strcmp (&strtab[soff], exclude[i])) goto skip; } /* hack to avoid symbol with name equal to tmp filename used to build us */ if (strchr (&strtab[soff], '.') || strchr (&strtab[soff], '/')) goto skip; if (s->n_type & N_EXT) { printf ("\t.globl\t%s\n\t.set\t%s,0x%lx\n\t.weak\t%s\n\n", &strtab[soff], &strtab[soff], s->n_value, &strtab[soff]); } skip: ; } } munmap(strtab, strsize); return 0; }
static int exec_exos_aout(int fd, const char *path, char *const argv[], char *const envp[], struct Env *e, u_int flags) { u_int envid = e->env_id; struct exec hdr; u_int dynamic; int r; struct _exos_exec_args eea; if (lseek(fd, 0, SEEK_SET) == -1 || read(fd, &hdr, sizeof(hdr)) != sizeof(hdr) || lseek(fd, sizeof(hdr) + hdr.a_text, SEEK_SET) == -1 || read(fd, &dynamic, sizeof(dynamic)) != sizeof(dynamic)) return 0; if (N_GETMAGIC(hdr) != OMAGIC || N_GETMID(hdr) != MID_I386 || N_GETFLAG(hdr) != 0) return 0; if (!(flags & _EXEC_USE_FD)) { close(fd); fd = -1; } else if (lseek(fd, 0, SEEK_SET) == -1) return 0; if (dynamic < SHARED_LIBRARY_START) dynamic = 0; if (dynamic == 0 && (flags & _EXEC_SHLIB_ONLY)) { r = -EINVAL; goto err; } /* if static, then read in entire program... */ if (!dynamic) { u_int start_text_addr; if (flags & _EXEC_USE_FD) start_text_addr = __load_prog_fd(fd, 1, envid); else start_text_addr = __load_prog(path, argv[0], 1, envid); if (!start_text_addr) { r = -ENOEXEC; goto err; } /* set start address */ e->env_tf.tf_eip = start_text_addr; } /* if dynamic, then make sure shared library is available */ else if (dynamic) { struct stat sb; /* If flag so indicates, then require RO copy and use in mem version */ if (!(flags & _EXEC_SHLIB_ONLY)) { /* if the shared library is not already in memory, or if it's old */ /* then we need to (re)read it in */ if (stat(PATH_LIBEXOS, &sb)) { r = -errno; kprintf("error stat'ing sl: %d\n", errno); goto err; } /* if we don't have a RO copy or it's out of date... */ if (!isvamapped(SHARED_LIBRARY_START_RODATA) || memcmp(&sl_data->mod_time, &sb.st_mtimespec, sizeof(sb.st_mtimespec))) { int slfd; /* if it's out of date, then unmap it */ if (isvamapped(SHARED_LIBRARY_START_RODATA)) munmap((void*)SHARED_LIBRARY_START_RODATA, (sl_data->text_pages + sl_data->data_pages) * NBPG); slfd = open (PATH_LIBEXOS, O_RDONLY); if (slfd < 0) { r = -errno; kprintf("could not open shared library " PATH_LIBEXOS "\n"); goto err; } if ((r = __load_sl_image (slfd)) < 0) { kprintf("could not load library\n"); close(slfd); goto err; } *((struct timespec*)&sl_data->mod_time) = sb.st_mtimespec; assert(sys_self_mod_pte_range(0, PG_RO, PG_W, SHARED_LIBRARY_START_RODATA, 1) == 0); close (slfd); } } else { if (!isvamapped(SHARED_LIBRARY_START_RODATA)) { r = -EINVAL; goto err; } } /* share the text region read only/exec into child */ if (__vm_share_region(SHARED_LIBRARY_START_RODATA, sl_data->text_pages * NBPG, 0, 0, envid, SHARED_LIBRARY_START)) { kprintf ("__vm_share_region failed for text region\n"); r = -ENOEXEC; goto err; } /* share the read only data region into child cow */ if (__vm_share_region(SHARED_LIBRARY_START_RODATA + sl_data->text_pages * NBPG, sl_data->data_pages * NBPG, 0, 0, envid, SHARED_LIBRARY_START + sl_data->text_pages * NBPG)) { kprintf ("__vm_share_region failed for cow data region\n"); r = -ENOEXEC; goto err; } if (sys_mod_pte_range(0, PG_COW, PG_RO | PG_SHARED, SHARED_LIBRARY_START + sl_data->text_pages * NBPG, sl_data->data_pages, 0, envid) < 0) { kprintf ("sys_mod_pte_range failed for cow data region\n"); r = -ENOEXEC; goto err; } /* share the RO copy of the shared library */ if (__vm_share_region(SHARED_LIBRARY_START_RODATA, (sl_data->text_pages + sl_data->data_pages) * NBPG, 0, 0, envid, SHARED_LIBRARY_START_RODATA)) { kprintf ("__vm_share_region failed for read only text/data region\n"); r = -ENOEXEC; goto err; } /* demand alloc bss for sl or no? */ if (getenv("NO_BSS_DEMAND_ALLOC")) { /* zero the bss */ if (__zero_segment (envid, SHARED_LIBRARY_START + (sl_data->text_pages + sl_data->data_pages) * NBPG, sl_data->bss_pages * NBPG) < 0) { kprintf("could not create bss segment\n"); r = -ENOEXEC; goto err; } } /* otherwise the fault handler will deal with it */ /* set start address */ e->env_tf.tf_eip = SHARED_LIBRARY_START + sizeof(struct exec); } /* take care of args, etc */ if (flags & _EXEC_USE_FD) eea.eea_prog_fd = fd; else eea.eea_prog_fd = -1; if ((r = setup_new_stack(argv, envp, envid, &e->env_tf.tf_esp, &eea)) < 0) goto err; return 1; err: return r; }