changeset 167:c25367bb7656

objgrep: written, compiles
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Fri, 04 Jul 2014 00:54:33 +0000
parents 861f5ca49581
children ed1a06bf525d
files .hgignore objgrep/Makefile objgrep/coffconst.h objgrep/filestruct.h objgrep/globals.c objgrep/globals.h objgrep/grep.c objgrep/intstruct.h objgrep/lowlevel.c objgrep/main.c objgrep/mkpattern.c objgrep/tables.c
diffstat 12 files changed, 728 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Jun 30 18:00:09 2014 +0000
+++ b/.hgignore	Fri Jul 04 00:54:33 2014 +0000
@@ -36,6 +36,8 @@
 ^mysteryffs/extract$
 ^mysteryffs/scan1$
 
+^objgrep/objgrep$
+
 ^pirollback/analyze$
 ^pirollback/catino$
 ^pirollback/dumpjournal$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/Makefile	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,18 @@
+CC=	gcc
+CFLAGS=	-O2
+PROG=	objgrep
+OBJS=	globals.o grep.o lowlevel.o main.o mkpattern.o tables.o
+HDRS=	coffconst.h filestruct.h globals.h intstruct.h
+
+all:	${PROG}
+
+${PROG}: ${OBJS}
+	${CC} -o $@ ${OBJS}
+
+${OBJS}: ${HDRS}
+
+install:
+	install -c -o bin -g bin -m 755 ${PROG} /usr/local/bin
+
+clean:
+	rm -f *.o ${PROG} *errs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/coffconst.h	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,62 @@
+/********************** STORAGE CLASSES **********************/
+
+#define C_NULL		0
+#define C_AUTO		1	/* automatic variable		*/
+#define C_EXT		2	/* external symbol		*/
+#define C_STAT		3	/* static			*/
+#define C_REG		4	/* register variable		*/
+#define C_EXTREF	5	/* external reference 		*/
+#define C_LABEL		6	/* label			*/
+#define C_ULABEL	7	/* undefined label		*/
+#define C_MOS		8	/* member of structure		*/
+#define C_ARG		9	/* function argument		*/
+#define C_STRTAG	10	/* structure tag		*/
+#define C_MOU		11	/* member of union		*/
+#define C_UNTAG		12	/* union tag			*/
+#define C_TPDEF		13	/* type definition		*/
+#define C_USTATIC	14	/* undefined static		*/
+#define C_ENTAG		15	/* enumeration tag		*/
+#define C_MOE		16	/* member of enumeration	*/
+#define C_REGPARM	17	/* register parameter		*/
+#define C_FIELD		18	/* bit field			*/
+#define C_UEXT		19	/* Tentative external definition */
+#define C_STATLAB	20	/* Static load time label */
+#define C_EXTLAB	21	/* External load time label */
+#define C_SYSTEM	23	/* System Wide variable */
+#define	C_VARARG	27	/* from TI's spraao8.pdf */
+#define C_BLOCK		100	/* ".bb" or ".eb"		*/
+#define C_FCN		101	/* ".bf" or ".ef"		*/
+#define C_EOS		102	/* end of structure		*/
+#define C_FILE		103	/* file name			*/
+#define C_LINE		104	/* line # reformatted as symbol table entry */
+
+/* Type of a symbol, in low 4 bits of the word.  */
+
+#define T_VOID		0	/* seen in void ptrs in our objects */
+#define T_CHAR		2	/* character		*/
+#define T_SHORT		3	/* short integer	*/
+#define T_INT		4	/* integer		*/
+#define T_LONG		5	/* long integer		*/
+#define T_FLOAT		6	/* floating point	*/
+#define T_DOUBLE	7	/* double word		*/
+#define T_STRUCT	8	/* structure 		*/
+#define T_UNION		9	/* union 		*/
+#define T_ENUM		10	/* enumeration 		*/
+#define T_MOE		11	/* member of enumeration*/
+#define T_UCHAR		12	/* unsigned character	*/
+#define T_USHORT	13	/* unsigned short	*/
+#define T_UINT		14	/* unsigned integer	*/
+#define T_ULONG		15	/* unsigned long	*/
+
+/* Derived types, in n_type.  */
+
+#define DT_NON		0	/* no derived type */
+#define DT_PTR		1	/* pointer */
+#define DT_FCN		2	/* function */
+#define DT_ARY		3	/* array */
+
+/* Reloc types */
+
+#define	RTYPE_LONG	0x11
+#define	RTYPE_THUMB_BL	0x16
+#define	RTYPE_ARM_B	0x17
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/filestruct.h	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,46 @@
+/*
+ * Here we are going to define the structures found in the COFF artifact
+ * file to be analyzed.
+ */
+
+struct external_filehdr {
+    u_char f_magic[2];	/* magic number			*/
+    u_char f_nscns[2];	/* number of sections		*/
+    u_char f_timdat[4];	/* time & date stamp		*/
+    u_char f_symptr[4];	/* file pointer to symtab	*/
+    u_char f_nsyms[4];	/* number of symtab entries	*/
+    u_char f_opthdr[2];	/* sizeof(optional hdr)		*/
+    u_char f_flags[2];	/* flags			*/
+    u_char f_target_id[2];    /* magic no. (TI COFF-specific) */
+};
+
+struct external_scnhdr {
+	u_char		s_name[8];	/* section name			*/
+	u_char		s_paddr[4];	/* physical address, aliased s_nlib */
+	u_char		s_vaddr[4];	/* virtual address		*/
+	u_char		s_size[4];	/* section size (in WORDS)      */
+	u_char		s_scnptr[4];	/* file ptr to raw data for section */
+	u_char		s_relptr[4];	/* file ptr to relocation	*/
+	u_char		s_lnnoptr[4];	/* file ptr to line numbers	*/
+	u_char		s_nreloc[4];	/* number of relocation entries	*/
+	u_char		s_nlnno[4];	/* number of line number entries*/
+	u_char		s_flags[4];	/* flags			*/
+	u_char		s_reserved[2];  /* reserved                     */ 
+	u_char		s_page[2];      /* section page number (LOAD)   */
+};
+
+struct external_syment {
+	u_char	e_name[8];
+	u_char	e_value[4];
+	u_char	e_scnum[2];
+	u_char	e_type[2];
+	u_char	e_sclass;
+	u_char	e_numaux;
+};
+
+struct external_reloc {
+  u_char r_vaddr[4];
+  u_char r_symndx[4];
+  u_char r_reserved[2]; /* extended pmad byte for COFF2 */
+  u_char r_type[2];
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/globals.c	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,23 @@
+/*
+ * Definitions of global vars for the objgrep program, based on tiobjd.
+ */
+
+#include <sys/types.h>
+
+char *objfilename, *binfilename;
+u_char *objfilemap, *binfilemap;
+size_t objfile_tot_size, binfile_tot_size;
+
+struct external_filehdr *filehdr_struct;
+struct external_scnhdr *sections_raw;
+unsigned nsections;
+struct external_syment *symtab_raw;
+unsigned nsymtab;
+unsigned strtab_offset;
+
+struct internal_scnhdr *sections, *grep_section;
+struct internal_syment **symtab;
+u_char *pattern_match, *pattern_mask;
+unsigned pattern_len;
+struct internal_reloc *relocs;
+unsigned match_offset;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/globals.h	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,21 @@
+/*
+ * extern declarations of global vars for the objgrep program, based on tiobjd.
+ */
+
+extern char *objfilename, *binfilename;
+extern u_char *objfilemap, *binfilemap;
+extern size_t objfile_tot_size, binfile_tot_size;
+
+extern struct external_filehdr *filehdr_struct;
+extern struct external_scnhdr *sections_raw;
+extern unsigned nsections;
+extern struct external_syment *symtab_raw;
+extern unsigned nsymtab;
+extern unsigned strtab_offset;
+
+extern struct internal_scnhdr *sections, *grep_section;
+extern struct internal_syment **symtab;
+extern u_char *pattern_match, *pattern_mask;
+extern unsigned pattern_len;
+extern struct internal_reloc *relocs;
+extern unsigned match_offset;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/grep.c	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,35 @@
+/*
+ * objgrep: the actual grep operation
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "globals.h"
+
+do_grep()
+{
+	uint32_t *match, *mask, *haystack;
+	unsigned matchlen_words, haystack_len_words, haystack_limit;
+	unsigned i, j;
+
+	match = (uint32_t *)pattern_match;
+	mask = (uint32_t *)pattern_mask;
+	haystack = (uint32_t *)binfilemap;
+	matchlen_words = pattern_len >> 2;
+	haystack_len_words = binfile_tot_size >> 2;
+	haystack_limit = haystack_len_words - matchlen_words;
+	for (i = 0; i <= haystack_limit; i++) {
+		for (j = 0; j < matchlen_words; j++)
+			if ((haystack[i+j] & mask[j]) != match[j])
+				goto haystack_next;
+		/* got a match! */
+		match_offset = i << 2;
+		return(1);
+haystack_next:	continue;
+	}
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/intstruct.h	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,35 @@
+/*
+ * The structures defined in this header file
+ * are internal to our utility.
+ */
+
+struct internal_scnhdr {
+	char		*name;
+	unsigned	size;
+	unsigned	data_offset;
+	unsigned	reloc_offset;
+	unsigned	line_offset;
+	unsigned	nreloc;
+	unsigned	nlineent;
+	unsigned	flags;
+	unsigned	nsymbols;
+};
+
+struct internal_syment {
+	unsigned	number;
+	char		*name;
+	unsigned	value;
+	int		scnum;
+	int		type;
+	int		class;
+	u_char		*aux;
+	struct internal_scnhdr *section;
+};
+
+struct internal_reloc {
+	unsigned	location;
+	struct internal_scnhdr *secbase;
+	struct internal_syment *extsym;
+	int		type;
+	unsigned	addend;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/lowlevel.c	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,89 @@
+/*
+ * This C module implements the low-level steps of file mapping and access.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "globals.h"
+
+mmap_objfile()
+{
+	int fd;
+	struct stat st;
+
+	fd = open(objfilename, O_RDONLY);
+	if (fd < 0) {
+		perror(objfilename);
+		exit(2);
+	}
+	fstat(fd, &st);
+	if (!S_ISREG(st.st_mode)) {
+		fprintf(stderr, "error: %s is not a regular file\n",
+			objfilename);
+		exit(2);
+	}
+	objfile_tot_size = st.st_size;
+	objfilemap = mmap(NULL, objfile_tot_size, PROT_READ, MAP_PRIVATE,
+			  fd, 0L);
+	if (objfilemap == MAP_FAILED) {
+		perror("mmap");
+		exit(2);
+	}
+	close(fd);
+}
+
+mmap_binfile()
+{
+	int fd;
+	struct stat st;
+
+	fd = open(binfilename, O_RDONLY);
+	if (fd < 0) {
+		perror(binfilename);
+		exit(2);
+	}
+	fstat(fd, &st);
+	if (!S_ISREG(st.st_mode)) {
+		fprintf(stderr, "error: %s is not a regular file\n",
+			binfilename);
+		exit(2);
+	}
+	binfile_tot_size = st.st_size;
+	binfilemap = mmap(NULL, binfile_tot_size, PROT_READ, MAP_PRIVATE,
+			  fd, 0L);
+	if (binfilemap == MAP_FAILED) {
+		perror("mmap");
+		exit(2);
+	}
+	close(fd);
+}
+
+unsigned
+get_u16(ptr)
+	u_char *ptr;
+{
+	return ptr[0] | ptr[1] << 8;
+}
+
+get_s16(ptr)
+	u_char *ptr;
+{
+	int i;
+
+	i = ptr[0] | ptr[1] << 8;
+	if (i >= 32768)
+		i -= 65536;
+	return(i);
+}
+
+unsigned
+get_u32(ptr)
+	u_char *ptr;
+{
+	return ptr[0] | ptr[1] << 8 | ptr[2] << 16 | ptr[3] << 24;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/main.c	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,48 @@
+/*
+ * objgrep main() function
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "globals.h"
+#include "intstruct.h"
+
+main(argc, argv)
+	char **argv;
+{
+	unsigned n;
+
+	if (argc != 4) {
+		fprintf(stderr, "usage: %s <objfile> <section> <binfile>\n",
+			argv[0]);
+		exit(2);
+	}
+	objfilename = argv[1];
+	mmap_objfile();
+	initial_parse_hdr();
+	get_int_section_table();
+	for (n = 0; n < nsections; n++)
+		if (!strcmp(sections[n].name, argv[2])) {
+			grep_section = sections + n;
+			break;
+		}
+	if (!grep_section) {
+		fprintf(stderr, "no section named \"%s\" found in %s\n",
+			argv[2], objfilename);
+		exit(2);
+	}
+	get_int_symbol_table();
+	prepare_pattern();
+	binfilename = argv[3];
+	mmap_binfile();
+	if (!do_grep()) {
+		printf("no match\n");
+		exit(1);
+	}
+	printf("%s:%s found in %s at 0x%x\n", objfilename, grep_section->name,
+		binfilename, match_offset);
+	exit(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/mkpattern.c	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,178 @@
+/*
+ * objgrep: preparation of matching pattern
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "filestruct.h"
+#include "intstruct.h"
+#include "coffconst.h"
+#include "globals.h"
+
+extern unsigned get_u16(), get_u32();
+
+static unsigned
+arm_branch_reloc(origbits, location)
+	u_char *origbits;
+	unsigned location;
+{
+	unsigned word, dest;
+
+	word = get_u32(origbits + location);
+	if ((word & 0x0E000000) != 0x0A000000) {
+		fprintf(stderr,
+			"error: invalid ARM_B reloc: opcode not B or BL\n");
+		exit(2);
+	}
+	dest = (word & 0x00FFFFFF) << 2;
+	if (dest & 0x02000000)
+		dest |= 0xFC000000;
+	dest += location + 8;
+	return(dest);
+}
+
+static unsigned
+thumb_bl_reloc(origbits, location)
+	u_char *origbits;
+	unsigned location;
+{
+	unsigned ins1, ins2;
+	unsigned dest;
+
+	ins1 = get_u16(origbits + location);
+	ins2 = get_u16(origbits + location + 2);
+	if ((ins1 & 0xF800) != 0xF000 || (ins2 & 0xF800) != 0xF800) {
+		fprintf(stderr,
+			"error: invalid Thumb_BL reloc: opcode not BL\n");
+		exit(2);
+	}
+	dest = ((ins1 & 0x7FF) << 12) | ((ins2 & 0x7FF) << 1);
+	if (dest & 0x00400000)
+		dest |= 0xFF800000;
+	dest += location + 4;
+	return(dest);
+}
+
+prepare_pattern()
+{
+	u_char *origbits;
+	unsigned pad, n;
+	struct internal_reloc *irel;
+	struct external_reloc *xrel;
+	unsigned lastloc, symidx;
+	struct internal_syment *sym;
+
+	origbits = objfilemap + grep_section->data_offset;
+	pattern_len = (grep_section->size + 3) & ~3;
+	pattern_match = malloc(pattern_len);
+	if (!pattern_match) {
+		perror("malloc");
+		exit(2);
+	}
+	bcopy(origbits, pattern_match, grep_section->size);
+	pattern_mask = malloc(pattern_len);
+	if (!pattern_mask) {
+		perror("malloc");
+		exit(2);
+	}
+	memset(pattern_mask, 0xFF, grep_section->size);
+	pad = pattern_len - grep_section->size;
+	if (pad) {
+		bzero(pattern_match + grep_section->size, pad);
+		bzero(pattern_mask + grep_section->size, pad);
+	}
+	if (!grep_section->nreloc)
+		return(0);
+	xrel = (struct external_reloc *)
+				(objfilemap + grep_section->reloc_offset);
+	irel = malloc(sizeof(struct internal_reloc) * grep_section->nreloc);
+	if (!irel) {
+		perror("malloc");
+		exit(2);
+	}
+	relocs = irel;
+	for (n = 0; n < grep_section->nreloc; n++, xrel++, irel++) {
+		irel->location = get_u32(xrel->r_vaddr);
+		if (n && irel->location < lastloc) {
+			fprintf(stderr, "error: non-increasing reloc order\n");
+			exit(2);
+		}
+		lastloc = irel->location + 4;
+		if (lastloc > grep_section->size) {
+			fprintf(stderr,
+			"error: reloc spills past the end of the section\n");
+			exit(2);
+		}
+		symidx = get_u32(xrel->r_symndx);
+		if (symidx == 0xFFFFFFFF)
+			sym = 0;
+		else if (symidx >= nsymtab || !symtab[symidx]) {
+			fprintf(stderr,
+				"error: reloc references invalid symbol #%u\n",
+				symidx);
+			exit(2);
+		} else
+			sym = symtab[symidx];
+		if (sym && sym->value) {
+			fprintf(stderr,
+		"error: symbol #%u referenced by reloc has nonzero value\n");
+			exit(2);
+		}
+		if (!sym) {
+			irel->secbase = grep_section;
+			irel->extsym = 0;
+		} else if (sym->class == C_EXT && !sym->scnum == 0) {
+			irel->extsym = sym;
+			irel->secbase = 0;
+		} else if (sym->class == C_STAT && sym->section &&
+			   !strcmp(sym->name, sym->section->name)) {
+			irel->secbase = sym->section;
+			irel->extsym = 0;
+		} else {
+			fprintf(stderr, "error: unable to grok reloc\n");
+			exit(2);
+		}
+		irel->type = get_u16(xrel->r_type);
+		switch (irel->type) {
+		case RTYPE_LONG:
+			if (irel->location & 3) {
+align_error:			fprintf(stderr, "error: misaligned reloc\n");
+				exit(2);
+			}
+			irel->addend = get_u32(origbits + irel->location);
+			*(uint32_t *)(pattern_match + irel->location) = 0;
+			*(uint32_t *)(pattern_mask + irel->location) = 0;
+			break;
+		case RTYPE_ARM_B:
+			if (irel->location & 3)
+				goto align_error;
+			irel->addend = arm_branch_reloc(origbits,
+							irel->location);
+			bzero(pattern_match + irel->location, 3);
+			bzero(pattern_mask + irel->location, 3);
+			break;
+		case RTYPE_THUMB_BL:
+			if (irel->location & 1)
+				goto align_error;
+			irel->addend = thumb_bl_reloc(origbits, irel->location);
+			pattern_match[irel->location+0] = 0;
+			pattern_match[irel->location+1] &= 0xF8;
+			pattern_match[irel->location+2] = 0;
+			pattern_match[irel->location+3] &= 0xF8;
+			pattern_mask[irel->location+0] = 0;
+			pattern_mask[irel->location+1] = 0xF8;
+			pattern_mask[irel->location+2] = 0;
+			pattern_mask[irel->location+3] = 0xF8;
+			break;
+		default:
+			fprintf(stderr, "error: reloc type 0x%x unsupported\n",
+				irel->type);
+			exit(2);
+		}
+	}
+	return(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/objgrep/tables.c	Fri Jul 04 00:54:33 2014 +0000
@@ -0,0 +1,171 @@
+/*
+ * This C module contains functions for the initial parsing
+ * of the section and symbol tables.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "filestruct.h"
+#include "intstruct.h"
+#include "globals.h"
+
+extern unsigned get_u16(), get_u32();
+
+initial_parse_hdr()
+{
+	unsigned symtab_offset;
+
+	filehdr_struct = (struct external_filehdr *) objfilemap;
+	if (get_u16(filehdr_struct->f_magic) != 0xC2) {
+		fprintf(stderr, "error: %s is not a TI COFF2 object\n",
+			objfilename);
+		exit(2);
+	}
+	if (get_u16(filehdr_struct->f_target_id) != 0x97) {
+		fprintf(stderr, "error: TI COFF object %s is not for TMS470\n",
+			objfilename);
+		exit(2);
+	}
+	if (get_u16(filehdr_struct->f_opthdr)) {
+		fprintf(stderr,
+			"error: %s has the \"optional\" header present\n",
+			objfilename);
+		exit(2);
+	}
+	sections_raw = (struct external_scnhdr *)
+				(objfilemap + sizeof(struct external_filehdr));
+	nsections = get_u16(filehdr_struct->f_nscns);
+	symtab_offset = get_u32(filehdr_struct->f_symptr);
+	symtab_raw = (struct external_syment *)(objfilemap + symtab_offset);
+	nsymtab = get_u32(filehdr_struct->f_nsyms);
+	strtab_offset = symtab_offset +
+				sizeof(struct external_syment) * nsymtab;
+}
+
+static char *
+get_secorsym_name(ptr)
+	u_char *ptr;
+{
+	char *alloc;
+
+	if (ptr[0]) {
+		if (ptr[7]) {
+			alloc = malloc(9);
+			if (!alloc) {
+				perror("malloc");
+				exit(2);
+			}
+			bcopy(ptr, alloc, 8);
+			alloc[8] = '\0';
+			return(alloc);
+		} else
+			return((char *) ptr);
+	}
+	if (ptr[1] || ptr[2] || ptr[3]) {
+		fprintf(stderr, "error: malformed name in %s at offset 0x%x\n",
+			objfilename, ptr - objfilemap);
+		exit(2);
+	}
+	return(objfilemap + strtab_offset + get_u32(ptr+4));
+}
+
+get_int_section_table()
+{
+	unsigned n;
+
+	sections = malloc(sizeof(struct internal_scnhdr) * nsections);
+	if (!sections) {
+		perror("malloc");
+		exit(2);
+	}
+	for (n = 0; n < nsections; n++) {
+		sections[n].name = get_secorsym_name(sections_raw[n].s_name);
+		if (get_u32(sections_raw[n].s_paddr))
+			fprintf(stderr,
+				"warning: section #%u (%s) has nonzero paddr\n",
+				n, sections[n].name);
+		if (get_u32(sections_raw[n].s_vaddr))
+			fprintf(stderr,
+				"warning: section #%u (%s) has nonzero vaddr\n",
+				n, sections[n].name);
+		sections[n].size = get_u32(sections_raw[n].s_size);
+		sections[n].data_offset = get_u32(sections_raw[n].s_scnptr);
+		sections[n].reloc_offset = get_u32(sections_raw[n].s_relptr);
+		sections[n].line_offset = get_u32(sections_raw[n].s_lnnoptr);
+		sections[n].nreloc = get_u32(sections_raw[n].s_nreloc);
+		sections[n].nlineent = get_u32(sections_raw[n].s_nlnno);
+		sections[n].flags = get_u32(sections_raw[n].s_flags);
+		if (get_u16(sections_raw[n].s_reserved))
+			fprintf(stderr,
+	"warning: section #%u (%s): some nonzero value in s_reserved bytes\n",
+				n, sections[n].name);
+		if (get_u16(sections_raw[n].s_page))
+			fprintf(stderr,
+	"warning: section #%u (%s): some nonzero value in s_page bytes\n",
+				n, sections[n].name);
+		sections[n].nsymbols = 0;
+	}
+}
+
+get_int_symbol_table()
+{
+	unsigned n;
+	struct internal_syment *in;
+
+	symtab = malloc(sizeof(struct internal_syment *) * nsymtab);
+	if (!symtab) {
+		perror("malloc");
+		exit(2);
+	}
+	for (n = 0; n < nsymtab; ) {
+		in = malloc(sizeof(struct internal_syment));
+		if (!in) {
+			perror("malloc");
+			exit(2);
+		}
+		symtab[n] = in;
+		in->number = n;
+		in->name = get_secorsym_name(symtab_raw[n].e_name);
+		in->value = get_u32(symtab_raw[n].e_value);
+		in->scnum = get_s16(symtab_raw[n].e_scnum);
+		if (in->scnum > 0) {
+			if (in->scnum > nsections) {
+				fprintf(stderr,
+					"symtab entry #%u: scnum too big\n", n);
+				exit(2);
+			}
+			in->section = sections + in->scnum - 1;
+			in->section->nsymbols++;
+		} else if (in->scnum < -2) {
+			fprintf(stderr,
+				"symtab entry #%u: scnum < -2\n", n);
+			exit(2);
+		} else
+			in->section = 0;
+		in->type = get_u16(symtab_raw[n].e_type);
+		in->class = symtab_raw[n].e_sclass;
+		switch (symtab_raw[n++].e_numaux) {
+		case 0:
+			in->aux = 0;
+			continue;
+		case 1:
+			if (n >= nsymtab) {
+				fprintf(stderr,
+				"error: last symbol's aux spills over\n");
+				exit(2);
+			}
+			symtab[n] = 0;
+			in->aux = (u_char *)(symtab_raw + n);
+			n++;
+			continue;
+		default:
+			n--;
+			fprintf(stderr, "symtab entry #%u: invalid numaux\n",
+				n);
+			exit(2);
+		}
+	}
+}