Example #1
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);
}
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);
	    }
	}
    }
}