Exemple #1
0
/*
 * rexec
 *	Read the exec structure; ignore any files that don't look
 *	exactly right. Return MID.
 * 	return -1 for files that don't look right.
 *	XXX it's hard to be sure when to ignore files, and when to error
 *	out.
 */
static int
rexec(int rfd, int wfd)
{
	RLIB *rp;
	long nsyms;
	int nr, symlen;
	char *strtab = 0;
	char *sym;
	struct exec ebuf;
	struct nlist nl;
	off_t r_off, w_off;
	long strsize;
	int result = -1;

	/* Get current offsets for original and tmp files. */
	r_off = lseek(rfd, (off_t)0, SEEK_CUR);
	w_off = lseek(wfd, (off_t)0, SEEK_CUR);

	/* Read in exec structure. */
	nr = read(rfd, (char *)&ebuf, sizeof(struct exec));
	if (nr != sizeof(struct exec))
		goto bad;

	/* Check magic number and symbol count. */
	if (BAD_OBJECT(ebuf) || ebuf.a_syms == 0)
		goto bad;
	fix_header_order(&ebuf);

	/* Seek to string table. */
	if (lseek(rfd, N_STROFF(ebuf) + r_off, SEEK_SET) == (off_t)-1) {
		if (errno == EINVAL)
			goto bad;
		else
			error(archive);
	}

	/* Read in size of the string table. */
	nr = read(rfd, (char *)&strsize, sizeof(strsize));
	if (nr != sizeof(strsize))
		goto bad;

	strsize = fix_32_order(strsize, N_GETMID(ebuf));

	/* Read in the string table. */
	strsize -= sizeof(strsize);
	strtab = (char *)emalloc(strsize);
	nr = read(rfd, strtab, strsize);
	if (nr != strsize) 
		goto bad;

	/* Seek to symbol table. */
	if (fseek(fp, N_SYMOFF(ebuf) + r_off, SEEK_SET) == (off_t)-1)
		goto bad;

	result = N_GETMID(ebuf);
	/* For each symbol read the nlist entry and save it as necessary. */
	nsyms = ebuf.a_syms / sizeof(struct nlist);
	while (nsyms--) {
		if (!fread((char *)&nl, sizeof(struct nlist), 1, fp)) {
			if (feof(fp))
				badfmt();
			error(archive);
		}
		fix_nlist_order(&nl, N_GETMID(ebuf));

		/* Ignore if no name or local. */
		if (!nl.n_un.n_strx || !(nl.n_type & N_EXT))
			continue;

		/*
		 * If the symbol is an undefined external and the n_value
		 * field is non-zero, keep it.
		 */
		if ((nl.n_type & N_TYPE) == N_UNDF && !nl.n_value)
			continue;

		/* First four bytes are the table size. */
		sym = strtab + nl.n_un.n_strx - sizeof(long);
		symlen = strlen(sym) + 1;

		rp = (RLIB *)emalloc(sizeof(RLIB));
		rp->sym = (char *)emalloc(symlen);
		bcopy(sym, rp->sym, symlen);
		rp->symlen = symlen;
		rp->pos = w_off;

		/* Build in forward order for "ar -m" command. */
		*pnext = rp;
		pnext = &rp->next;

		++symcnt;
		tsymlen += symlen;
	}

bad: 	if (nr < 0)
		error(archive);
	free(strtab);
	(void)lseek(rfd, (off_t)r_off, SEEK_SET);
	return result;
}
Exemple #2
0
/*
 * read_exec
 *	Read the exec structure; ignore any files that don't look
 *	exactly right. Return MID.
 *	return -1 for files that don't look right.
 *	XXX it's hard to be sure when to ignore files, and when to error
 *	out.
 */
int
read_exec(FILE *rfp, FILE *wfp, long *symcnt, long *tsymlen)
{
	union {
		struct exec exec;
		Elf32_Ehdr elf32;
		Elf64_Ehdr elf64;
	} eh;
	struct nlist nl;
	off_t r_off, w_off;
	char *strtab = NULL;
	long strsize, nsyms;
	int i;

	/* Get current offsets for original and tmp files. */
	r_off = ftello(rfp);
	w_off = ftello(wfp);

	/* Read in exec structure. */
	if (fread(&eh, sizeof(eh), 1, rfp) != 1)
		err(1, "fread: %s", archive);

	if (!elf32_chk_header(&eh.elf32)) {
		Elf32_Sym sbuf;
		char *shstr;
		Elf32_Shdr *shdr;
		size_t stabsize;

		elf32_fix_header(&eh.elf32);
		if (eh.elf32.e_ehsize < sizeof eh.elf32) {
			warnx("%s: ELF header is too short", archive);
			goto bad;
		}

		if (!(shdr = elf32_load_shdrs(archive, rfp, r_off, &eh.elf32)))
			goto bad;
		elf32_fix_shdrs(&eh.elf32, shdr);

		if (!(shstr = elf32_shstrload(archive, rfp, r_off, &eh.elf32,
		    shdr))) {
			free(shdr);
			goto bad;
		}

		if (!(strtab = elf32_strload(archive, rfp, r_off, &eh.elf32,
		    shdr, shstr, ELF_STRTAB, &stabsize))) {
			free(shstr);
			free(shdr);
			goto bad;
		}

		/* find the symtab section */
		for (i = 0; i < eh.elf32.e_shnum; i++)
			if (!strcmp(shstr + shdr[i].sh_name, ELF_SYMTAB)) {
				nsyms = shdr[i].sh_size / sizeof(Elf32_Sym);
				break;
			}

		if (i == eh.elf32.e_shnum) {
			free(shstr);
			free(shdr);
			goto bad;
		}

		if (fseeko(rfp, r_off + shdr[i].sh_offset, SEEK_SET))
			err(1, "fseeko: %s", archive);

		for (i = 0; i < nsyms; i++) {
			if (fread(&sbuf, sizeof(sbuf), 1, rfp) != 1)
				err(1, "fread: %s", archive);

			elf32_fix_sym(&eh.elf32, &sbuf);
			if (!sbuf.st_name || sbuf.st_name > stabsize)
				continue;

			if (elf32_2nlist(&sbuf, &eh.elf32, shdr, shstr, &nl))
				continue;

			addsym(&nl, strtab, r_off - r_fuzz -
			    sizeof(struct ar_hdr), symcnt, tsymlen, archive);
		}

		free(strtab);
		free(shstr);
		free(shdr);
		(void)fseeko(rfp, r_off, SEEK_SET);
		return MID_ELFFL | eh.elf32.e_machine;

	} else if (!elf64_chk_header(&eh.elf64)) {
		Elf64_Sym sbuf;
		char *shstr;
		Elf64_Shdr *shdr;
		size_t stabsize;

		elf64_fix_header(&eh.elf64);
		if (eh.elf64.e_ehsize < sizeof eh.elf64) {
			warnx("%s: ELF header is too short", archive);
			goto bad;
		}

		if (!(shdr = elf64_load_shdrs(archive, rfp, r_off, &eh.elf64)))
			goto bad;
		elf64_fix_shdrs(&eh.elf64, shdr);

		if (!(shstr = elf64_shstrload(archive, rfp, r_off, &eh.elf64,
		    shdr))) {
			free(shdr);
			goto bad;
		}

		if (!(strtab = elf64_strload(archive, rfp, r_off, &eh.elf64,
		    shdr, shstr, ELF_STRTAB, &stabsize))) {
			free(shstr);
			free(shdr);
			goto bad;
		}

		/* find the symtab section */
		for (i = 0; i < eh.elf64.e_shnum; i++)
			if (!strcmp(shstr + shdr[i].sh_name, ELF_SYMTAB)) {
				nsyms = shdr[i].sh_size / sizeof(Elf64_Sym);
				break;
			}

		if (i == eh.elf64.e_shnum) {
			free(shstr);
			free(shdr);
			goto bad;
		}

		if (fseeko(rfp, r_off + shdr[i].sh_offset, SEEK_SET))
			err(1, "fseeko: %s", archive);

		for (i = 0; i < nsyms; i++) {
			if (fread(&sbuf, sizeof(sbuf), 1, rfp) != 1)
				err(1, "fread: %s", archive);

			elf64_fix_sym(&eh.elf64, &sbuf);
			if (!sbuf.st_name || sbuf.st_name > stabsize)
				continue;

			if (elf64_2nlist(&sbuf, &eh.elf64, shdr, shstr, &nl))
				continue;

			addsym(&nl, strtab, r_off - r_fuzz -
			    sizeof(struct ar_hdr), symcnt, tsymlen, archive);
		}

		free(strtab);
		free(shstr);
		free(shdr);
		(void)fseeko(rfp, r_off, SEEK_SET);
		return MID_ELFFL | eh.elf64.e_machine;

	} else if (BAD_OBJECT(eh.exec) || eh.exec.a_syms == 0)
		goto bad;

	fix_header_order(&eh.exec);

	/* Seek to string table. */
	if (fseeko(rfp, N_STROFF(eh.exec) + r_off, SEEK_SET) == -1) {
		if (errno == EINVAL)
			goto bad;
		else
			err(1, "lseek: %s", archive);
	}

	/* Read in size of the string table. */
	if (fread((char *)&strsize, sizeof(strsize), 1, rfp) != 1)
		err(1, "fread: %s", archive);

	strsize = fix_32_order(strsize, N_GETMID(eh.exec));

	/* Read in the string table. */
	strsize -= sizeof(strsize);
	strtab = malloc(strsize);
	if (!strtab)
		err(1, "malloc: %s", archive);
	if (fread(strtab, strsize, 1, rfp) != 1)
		err(1, "fread: %s", archive);

	/* Seek to symbol table. */
	if (fseek(rfp, N_SYMOFF(eh.exec) + r_off, SEEK_SET) == (off_t)-1)
		err(1, "fseeko: %s", archive);

	/* For each symbol read the nlist entry and save it as necessary. */
	nsyms = eh.exec.a_syms / sizeof(struct nlist);
	while (nsyms--) {
		if (!fread((char *)&nl, sizeof(struct nlist), 1, rfp)) {
			if (feof(rfp))
				badfmt();
			err(1, "fread: %s", archive);
		}
		fix_nlist_order(&nl, N_GETMID(eh.exec));

		addsym(&nl, strtab - sizeof(long), r_off - r_fuzz -
		    sizeof(struct ar_hdr), symcnt, tsymlen, archive);
	}

bad:
	free(strtab);
	(void)fseeko(rfp, r_off, SEEK_SET);
	return N_GETMID(eh.exec);
}
Exemple #3
0
/*
 * show_file()
 *	show symbols from the object file pointed to by fp.  The current
 *	file pointer for fp is expected to be at the beginning of an object
 *	file header.
 */
int
show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head)
{
	u_long text, data, bss, total;
	struct nlist *np, *names, **snames;
	char *stab;
	int i, aout, nnames;
	size_t stabsize;
	off_t staboff;

	aout = 0;
	if (!elf32_chk_header(&head->elf32)) {
		struct elf_symtab es;

		es.name = name;
		es.ehdr = &head->elf32;
		if (head->elf32.e_ehsize < sizeof head->elf32) {
			warnx("%s: ELF header is too short", name);
			return 1;
		}

		if (!(es.shdr = elf32_load_shdrs(name, fp, foff, es.ehdr)))
			return (1);
		elf32_fix_shdrs(es.ehdr, es.shdr);
		es.shstr = NULL;

		if (issize)
			i = elf32_size(es.ehdr, es.shdr, &text, &data, &bss);
		else {
			nrawnames = 0;
			names = NULL;
			i = elf32_symload(&es, fp, foff, elf_symadd, &names);
			stab = es.stab;
			stabsize = es.stabsz;
		}
		free(es.shstr);
		free(es.shdr);
		if (i)
			return (i);

	} else if (!elf64_chk_header(&head->elf64)) {
		struct elf_symtab es;

		es.name = name;
		es.ehdr = &head->elf64;
		if (head->elf64.e_ehsize < sizeof head->elf64) {
			warnx("%s: ELF header is too short", name);
			return 1;
		}
		if (!(es.shdr = elf64_load_shdrs(name, fp, foff, es.ehdr)))
			return (1);
		elf64_fix_shdrs(es.ehdr, es.shdr);
		es.shstr = NULL;

		if (issize)
			i = elf64_size(es.ehdr, es.shdr, &text, &data, &bss);
		else {
			nrawnames = 0;
			names = NULL;
			i = elf64_symload(&es, fp, foff, elf_symadd, &names);
			stab = es.stab;
			stabsize = es.stabsz;
		}
		free(es.shstr);
		free(es.shdr);
		if (i)
			return (i);

	} else if (BAD_OBJECT(head->aout)) {
		if (warn_fmt)
			warnx("%s: bad format", name);
		return (1);
	} else do {
		u_int32_t w;

		aout++;

		fix_header_order(&head->aout);

		if (issize) {
			text = head->aout.a_text;
			data = head->aout.a_data;
			bss = head->aout.a_bss;
			break;
		}

		/* stop if the object file contains no symbol table */
		if (!head->aout.a_syms) {
			warnx("%s: no name list", name);
			return(1);
		}

		if (fseeko(fp, foff + N_SYMOFF(head->aout), SEEK_SET)) {
			warn("%s", name);
			return(1);
		}

#ifdef __LP64__
		nrawnames = head->aout.a_syms / sizeof(struct nlist32);
#else
		nrawnames = head->aout.a_syms / sizeof(*names);
#endif
		/* get memory for the symbol table */
		if ((names = calloc(nrawnames, sizeof(struct nlist))) == NULL) {
			warn("%s: malloc names", name);
			return (1);
		}

#ifdef __LP64__
		for (np = names, i = nrawnames; i--; np++) {
			struct nlist32 nl32;

			if (fread(&nl32, sizeof(nl32), 1, fp) != 1) {
				warnx("%s: cannot read symbol table", name);
				free(names);
				return (1);
			}
			np->n_type = nl32.type;
			np->n_other = nl32.other;
			if (byte_sex(N_GETMID(head->aout)) != BYTE_ORDER) {
				np->n_un.n_strx = swap32(nl32.strx);
				np->n_desc = swap16(nl32.desc);
				np->n_value = swap32(nl32.value);
			} else {
				np->n_un.n_strx = nl32.strx;
				np->n_desc = nl32.desc;
				np->n_value = nl32.value;
			}
		}
#else
		if (fread(names, head->aout.a_syms, 1, fp) != 1) {
			warnx("%s: cannot read symbol table", name);
			free(names);
			return (1);
		}
		fix_nlists_order(names, nrawnames, N_GETMID(head->aout));
#endif

		staboff = ftello(fp);
		/*
		 * Following the symbol table comes the string table.
		 * The first 4-byte-integer gives the total size of the
		 * string table _including_ the size specification itself.
		 */
		if (fread(&w, sizeof(w), (size_t)1, fp) != 1) {
			warnx("%s: cannot read stab size", name);
			free(names);
			return(1);
		}

		stabsize = fix_32_order(w, N_GETMID(head->aout));
		if ((stab = malloc(stabsize)) == NULL) {
			warn("%s: malloc", name);
			return 1;
		}

		if (pread(fileno(fp), stab, stabsize, staboff) != stabsize) {
			free(stab);
			warn("%s: pread", name);
			return 1;
		}

		stabsize -= 4;		/* we already have the size */
		for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
			/*
			 * make n_un.n_name a character pointer by adding
			 * the string table's base to n_un.n_strx
			 *
			 * don't mess with zero offsets
			 */
			if (np->n_un.n_strx)
				np->n_un.n_name = stab + np->n_un.n_strx;
			else
				np->n_un.n_name = "";
		}
	} while (0);

	if (issize) {
		static int first = 1;

		if (first) {
			first = 0;
			printf("text\tdata\tbss\tdec\thex\n");
		}

		total = text + data + bss;
		printf("%lu\t%lu\t%lu\t%lu\t%lx",
		    text, data, bss, total, total);
		if (count > 1)
			(void)printf("\t%s", name);

		total_text += text;
		total_data += data;
		total_bss += bss;
		total_total += total;

		printf("\n");
		return (0);
	}
	/* else we are nm */

	/*
	 * it seems that string table is sequential
	 * relative to the symbol table order
	 */
	if ((snames = calloc(nrawnames, sizeof *snames)) == NULL) {
		warn("%s: malloc snames", name);
		free(names);
		return (1);
	}

	/*
	 * fix up the symbol table and filter out unwanted entries
	 *
	 * common symbols are characterized by a n_type of N_UNDF and a
	 * non-zero n_value -- change n_type to N_COMM for all such
	 * symbols to make life easier later.
	 *
	 * filter out all entries which we don't want to print anyway
	 */
	for (np = names, i = nnames = 0; i < nrawnames; np++, i++) {
		if (aout && SYMBOL_TYPE(np->n_type) == N_UNDF && np->n_value)
			np->n_type = N_COMM | (np->n_type & N_EXT);
		if (!print_all_symbols && IS_DEBUGGER_SYMBOL(np->n_type))
			continue;
		if (print_only_external_symbols && !IS_EXTERNAL(np->n_type))
			continue;
		if (print_only_undefined_symbols &&
		    SYMBOL_TYPE(np->n_type) != N_UNDF)
			continue;

		snames[nnames++] = np;
	}

	/* sort the symbol table if applicable */
	if (sfunc)
		qsort(snames, (size_t)nnames, sizeof(*snames), sfunc);

	if (count > 1)
		(void)printf("\n%s:\n", name);

	/* print out symbols */
	for (i = 0; i < nnames; i++) {
		if (show_extensions && snames[i] != names &&
		    SYMBOL_TYPE((snames[i] -1)->n_type) == N_INDR)
			continue;
		print_symbol(name, snames[i], aout);
	}

	free(snames);
	free(names);
	free(stab);
	return(0);
}