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); }
int main(int argc, char **argv) { char input[100], *s; PersistentBuf sb; CircBuf circ; struct iovec iov[2]; { sb.buf = buf; sb.alloced = 10; sb.len = 0; if (*(++argv)) { sb.alloced = atoi(*argv); if (*(++argv)) { sb.len = strlen(*argv); perperl_memcpy(buf, *argv, sb.len); } } perperl_circ_init(&circ, sb.alloced ? &sb : NULL); } while (1) { printf("buf_len=%d data_len=%d free_len=%d\n", perperl_circ_buf_len(&circ), perperl_circ_data_len(&circ), perperl_circ_free_len(&circ) ); printf("free:"); dump_segs(iov, perperl_circ_free_segs(&circ, iov)); printf("data:"); dump_segs(iov, perperl_circ_data_segs(&circ, iov)); printf("\n? "); gets(input); s = strtok(input, " "); switch(s ? s[0] : ' ') { case 'q': exit(0); break; case 'a': if ((s = strtok(NULL, " "))) { int l = strlen(s); if (l > perperl_circ_free_len(&circ)) { printf("too big\n"); } else { int i, l2 = l, nsegs = perperl_circ_free_segs(&circ, iov); for (i = 0; i < nsegs && l2; ++i) { perperl_memcpy(iov[i].iov_base, s, iov[i].iov_len); s += iov[i].iov_len; l2 -= iov[i].iov_len; } perperl_circ_adj_len(&circ, l); printf("added %d bytes\n", l); } } break; case 'r': if ((s = strtok(NULL, " "))) { int l = atoi(s); if (l > perperl_circ_data_len(&circ)) { printf("too big\n"); } else { perperl_circ_adj_len(&circ, -l); printf("removed %d bytes\n", l); } } break; case 'e': if ((s = strtok(NULL, " "))) { int l = atoi(s); if (l > sizeof(buf)) { printf("too big\n"); } else { perperl_circ_realloc(&circ, buf, l); printf("new size %d bytes\n", l); } } case 'i': if ((s = strtok(NULL, " "))) { sb.buf = buf; sb.alloced = atoi(s); sb.len = 0; if ((s = strtok(NULL, " "))) { sb.len = strlen(s); memcpy(buf, s, sb.len); } perperl_circ_init(&circ, sb.alloced ? &sb : NULL); } } } }