 98ddbffe6e
			
		
	
	
		98ddbffe6e
		
	
	
	
	
		
			
			- it can disassemble object files (dis386o) and executables
    (dis386a)
  - only useful for as long as we still have ack
		
	
			
		
			
				
	
	
		
			938 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			938 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * misc.c: interface to Bruce Evan's dis86 package.
 | |
|  *
 | |
|  * $Id: misc.c,v 1.1 1997/10/20 12:00:00 cwr Exp cwr $
 | |
|  *
 | |
|  * Heavily modified by C W Rose.
 | |
|  */
 | |
| 
 | |
| /* Version settings */
 | |
| #define MINIX
 | |
| #undef OS2
 | |
| #undef TEST
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #ifdef MINIX
 | |
| #include <minix/config.h>
 | |
| #include <minix/const.h>
 | |
| #include <a.out.h>
 | |
| #endif
 | |
| #ifdef OS2
 | |
| typedef unsigned char u8_t;
 | |
| typedef unsigned int u16_t;
 | |
| typedef unsigned long u32_t;
 | |
| #include </local/minix/minix/config.h>
 | |
| #include </local/minix/minix/const.h>
 | |
| #include </local/minix/a.out.h>
 | |
| #endif
 | |
| #include <assert.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include "const.h"
 | |
| #include "type.h"
 | |
| #undef S_ABS				/* clash with a.out.h */
 | |
| #include "out.h"			/* ACK compiler output header */
 | |
| #include "var.h"			/* db header */
 | |
| #include "dis386.h"			/* dis386 package header */
 | |
| 
 | |
| /* Standard defines */
 | |
| #define FAILED -1
 | |
| #define MAYBE 0
 | |
| #define OK 1
 | |
| 
 | |
| /* Local defines */
 | |
| 
 | |
| #ifndef lint
 | |
| static char *Version = "@(#) misc.c $Revision: 1.1 $ $Date: 1997/10/20 12:00:00 $";
 | |
| #endif
 | |
| 
 | |
| /* Global variables */
 | |
| PRIVATE bool_t forceupper;
 | |
| PRIVATE bool_t someupper = TRUE;
 | |
| PRIVATE count_t stringcount = 0;
 | |
| PRIVATE char *string_ptr = (char *)0;	/* stringptr ambiguous at 8th char */
 | |
| PRIVATE char *stringstart = (char *)0;
 | |
| 
 | |
| /* Externals */
 | |
| 
 | |
| /* Forward declarations */
 | |
| #if 0
 | |
| PUBLIC void closestring(void);				/* */
 | |
| PUBLIC u8_pt get8(void);				/* */
 | |
| PUBLIC u16_t get16(void);				/* */
 | |
| PUBLIC u32_t get32(void);				/* */
 | |
| PUBLIC void openstring(char *string, int len);		/* */
 | |
| PUBLIC void outbyte(char_pt byte);			/* */
 | |
| PUBLIC void outcolon(void);				/* */
 | |
| PUBLIC void outcomma(void);				/* */
 | |
| PUBLIC void outh4(u4_pt num);				/* */
 | |
| PUBLIC void outh8(u8_pt num);				/* */
 | |
| PUBLIC void outh16(u16_t num);				/* */
 | |
| PUBLIC void outh32(u32_t num);				/* */
 | |
| PUBLIC bool_pt outnl(void);				/* */
 | |
| PUBLIC count_t outsegaddr(struct address_s *ap, offset_t addr);	/* */
 | |
| PUBLIC count_t outsegreg(offset_t num);			/* */
 | |
| PUBLIC void outspace(void);				/* */
 | |
| PUBLIC void outstr(char *s);				/* */
 | |
| PUBLIC void outtab(void);				/* */
 | |
| PUBLIC void outustr(char *s);				/* */
 | |
| PUBLIC count_t stringpos(void);				/* */
 | |
| PUBLIC count_t stringtab(void);				/* */
 | |
| PUBLIC void outrel(struct nlist *sp, offset_t off);	/* */
 | |
| PUBLIC void outsym(struct nlist *sp, offset_t off);	/* */
 | |
| PUBLIC struct nlist *findrval(offset_t value, int where);/* */
 | |
| PUBLIC struct nlist *findsval(offset_t value, int where);/* */
 | |
| PUBLIC int dasm(offset_t addr, offset_t count);		/* */
 | |
| #endif
 | |
| 
 | |
| PRIVATE u8_pt peek8(struct address_s *ap);			/* */
 | |
| PRIVATE u16_t peek16(struct address_s *ap);			/* */
 | |
| PRIVATE u32_t peek32(struct address_s *ap);			/* */
 | |
| PRIVATE struct nlist *find_arval(offset_t value, int where);	/* */
 | |
| PRIVATE struct nlist *find_orval(offset_t value, int where);	/* */
 | |
| PRIVATE struct nlist *find_asval(offset_t value, int where);	/* */
 | |
| PRIVATE struct nlist *find_osval(offset_t value, int where);	/* */
 | |
| PRIVATE int dis_one(void);					/* */
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Close string device.
 | |
|  */
 | |
| PUBLIC void closestring()
 | |
| {
 | |
|   stringcount = 0;
 | |
|   stringstart = string_ptr = (char *)0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Get 8 bits from current instruction pointer and advance pointer.
 | |
|  */
 | |
| PUBLIC u8_pt get8()
 | |
| {
 | |
|   u8_pt temp;
 | |
| 
 | |
|   temp = peek8(&uptr);
 | |
|   ++uptr.off;
 | |
|   return temp;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Get 16 bits from current instruction pointer and advance pointer.
 | |
|  */
 | |
| PUBLIC u16_pt get16()
 | |
| {
 | |
|   u16_pt temp;
 | |
| 
 | |
|   temp = peek16(&uptr);
 | |
|   uptr.off += 2;
 | |
|   return temp;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Get 32 bits from current instruction pointer and advance pointer.
 | |
|  */
 | |
| PUBLIC u32_t get32()
 | |
| {
 | |
|   u32_t temp;
 | |
| 
 | |
|   temp = peek32(&uptr);
 | |
|   uptr.off += 4;
 | |
|   return temp;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Open string device.
 | |
|  */
 | |
| PUBLIC void openstring(string, len)
 | |
| char *string; int len;
 | |
| {
 | |
|   while (--len >= 0)
 | |
| 	string[len] = '\0';
 | |
|   stringcount = 0;
 | |
|   stringstart = string_ptr = string;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print char to currently open output devices.
 | |
|  */
 | |
| PUBLIC void outbyte(char_pt byte)
 | |
| {
 | |
|   /* convert to upper case if required */
 | |
|   if (forceupper && byte >= 'a' && byte <= 'z')
 | |
| 	byte += 'A' - 'a';
 | |
| 
 | |
|   /* increment the output line character count, allowing for tab stops */
 | |
|   if (string_ptr != NULL) {
 | |
| 	if ((*string_ptr++ = byte) == '\t')
 | |
| 		stringcount = 8 * (stringcount / 8 + 1);
 | |
| 	else
 | |
| 		++stringcount;
 | |
|   }
 | |
|   else
 | |
| 	(void) fputc(byte, stdout);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print colon.
 | |
|  */
 | |
| PUBLIC void outcolon()
 | |
| {
 | |
|   outbyte(':');
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print comma.
 | |
|  */
 | |
| PUBLIC void outcomma()
 | |
| {
 | |
|   outbyte(',');
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print 4 bits hex.
 | |
|  */
 | |
| PUBLIC void outh4(u4_pt num)
 | |
| {
 | |
|   static char hexdigits[] = "0123456789abcdef";
 | |
| 
 | |
|   forceupper = someupper;
 | |
|   outbyte(hexdigits[num % 16]);
 | |
|   forceupper = FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print 8 bits hex.
 | |
|  */
 | |
| PUBLIC void outh8(u8_pt num)
 | |
| {
 | |
|   outh4(num / 16);
 | |
|   outh4(num);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print 16 bits hex.
 | |
|  */
 | |
| PUBLIC void outh16(u16_pt num)
 | |
| {
 | |
|   outh8(num / 256);
 | |
|   outh8(num);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print 32 bits hex.
 | |
|  */
 | |
| PUBLIC void outh32(u32_t num)
 | |
| {
 | |
|   outh16((u16_t) (num >> 16));
 | |
|   outh16((u16_t) num);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print newline.
 | |
|  */
 | |
| PUBLIC bool_pt outnl()
 | |
| {
 | |
|   /* bool_pt avoids change in type.h */
 | |
|   outstr("\n");
 | |
|   return OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print segmented address.
 | |
|  */
 | |
| PUBLIC count_t outsegaddr(struct address_s *ap, offset_t addr)
 | |
| {
 | |
|   count_t bytes_printed;
 | |
| 
 | |
|   bytes_printed = 2;
 | |
| 
 | |
|   if (ap->base == regs.csbase)
 | |
| 	outustr("cs");
 | |
|   else if (ap->base == regs.dsbase)
 | |
| 	outustr("ds");
 | |
|   else if (ap->base == regs.esbase)
 | |
| 	outustr("es");
 | |
|   else if (processor >= 386 && ap->base == regs.fsbase)
 | |
| 	outustr("fs");
 | |
|   else if (processor >= 386 && ap->base == regs.gsbase)
 | |
| 	outustr("gs");
 | |
|   else if (ap->base == regs.ssbase)
 | |
| 	outustr("ss");
 | |
|   else
 | |
| 	bytes_printed = outsegreg(ap->base);
 | |
| 
 | |
|   if (bytes_printed > 4)
 | |
| 	outbyte('+');
 | |
|   else
 | |
| 	outcolon();
 | |
|   bytes_printed++;
 | |
| 
 | |
|   if (ap->off >= 0x10000) {
 | |
| 	outh32(ap->off + addr);
 | |
| 	return bytes_printed + 8;
 | |
|   }
 | |
|   else {
 | |
| 	outh16((u16_pt) ap->off + addr);
 | |
| 	return bytes_printed + 4;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print segment register.
 | |
|  */
 | |
| PUBLIC count_t outsegreg(offset_t num)
 | |
| {
 | |
|   if ((num % HCLICK_SIZE) != 0 || num >= 0x100000) {
 | |
| 	outh32(num);
 | |
| 	return 8;
 | |
|   }
 | |
|   outh16((u16_pt) (num / HCLICK_SIZE));
 | |
|   return 4;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print space.
 | |
|  */
 | |
| PUBLIC void outspace()
 | |
| {
 | |
|   outbyte(' ');
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print string.
 | |
|  */
 | |
| PUBLIC void outstr(char *s)
 | |
| {
 | |
|   while (*s)
 | |
| 	outbyte(*s++);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Print tab.
 | |
|  */
 | |
| PUBLIC void outtab()
 | |
| {
 | |
|   outbyte('\t');
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Print string, perhaps converting case to upper.
 | |
|  */
 | |
| PUBLIC void outustr(char *s)
 | |
| {
 | |
|   forceupper = someupper;
 | |
|   while (*s)
 | |
| 	outbyte(*s++);
 | |
|   forceupper = FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * p e e k 8
 | |
|  *
 | |
|  * Get a byte from the process.
 | |
|  *
 | |
|  * Returns:	byte	Success
 | |
|  *
 | |
|  * Note: aborts on read error.
 | |
|  */
 | |
| PRIVATE u8_pt peek8(struct address_s *ap)
 | |
| {
 | |
|   unsigned int uj;
 | |
| 
 | |
|   /* with luck buffering should make this fairly quick */
 | |
|   if (fseek(disfp, (long)(ap->off), SEEK_CUR) != 0) {
 | |
| 	fprintf(stderr, "Cannot seek forward in object file\n");
 | |
| 	exit(1);
 | |
|   }
 | |
|   uj = fgetc(disfp) & 0377;
 | |
|   if (fseek(disfp, -(long)(ap->off + 1), SEEK_CUR) != 0) {
 | |
| 	fprintf(stderr, "Cannot seek backward in object file\n");
 | |
| 	exit(1);
 | |
|   }
 | |
| 
 | |
|   return uj;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * p e e k 1 6
 | |
|  *
 | |
|  * Get a 16-bit short from the process.
 | |
|  *
 | |
|  * Returns:	2 bytes	Success
 | |
|  *
 | |
|  * Note: aborts on read error.
 | |
|  */
 | |
| PRIVATE u16_t peek16(struct address_s *ap)
 | |
| {
 | |
|   unsigned int uj;
 | |
| 
 | |
|   /* with luck buffering should make this fairly quick */
 | |
|   if (fseek(disfp, (long)(ap->off), SEEK_CUR) != 0) {
 | |
| 	fprintf(stderr, "Cannot seek forward in object file\n");
 | |
| 	exit(1);
 | |
|   }
 | |
|   /* Intel has right to left byte ordering */
 | |
| #if 1
 | |
|   uj = fgetc(disfp) & 0377;
 | |
|   uj |= (fgetc(disfp) & 0377) << 8;
 | |
| #else
 | |
|   uj = fgetc(disfp) & 0377;
 | |
|   uj <<= 8;
 | |
|   uj |= fgetc(disfp) & 0377;
 | |
| #endif
 | |
|   if (fseek(disfp, -(long)(ap->off + 2), SEEK_CUR) != 0) {
 | |
| 	fprintf(stderr, "Cannot seek backward in object file\n");
 | |
| 	exit(1);
 | |
|   }
 | |
| 
 | |
|   return uj;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * p e e k 3 2
 | |
|  *
 | |
|  * Get a 32-bit int from the process.
 | |
|  *
 | |
|  * Returns:	4 bytes	Success
 | |
|  *
 | |
|  * Note: aborts on read error.
 | |
|  */
 | |
| PRIVATE u32_t peek32(struct address_s *ap)
 | |
| {
 | |
|   unsigned int uj;
 | |
| 
 | |
|   /* with luck buffering should make this fairly quick */
 | |
|   if (fseek(disfp, (long)(ap->off), SEEK_CUR) != 0) {
 | |
| 	fprintf(stderr, "Cannot seek forward in object file\n");
 | |
| 	exit(1);
 | |
|   }
 | |
| #if 1
 | |
|   /* Intel has right to left byte ordering */
 | |
|   uj = fgetc(disfp) & 0377;
 | |
|   uj |= (fgetc(disfp) & 0377) << 8;
 | |
|   uj |= (fgetc(disfp) & 0377) << 16;
 | |
|   uj |= (fgetc(disfp) & 0377) << 24;
 | |
| #else
 | |
|   uj = fgetc(disfp) & 0377;
 | |
|   uj <<= 8;
 | |
|   uj |= fgetc(disfp) & 0377;
 | |
|   uj <<= 8;
 | |
|   uj |= fgetc(disfp) & 0377;
 | |
|   uj <<= 8;
 | |
|   uj |= fgetc(disfp) & 0377;
 | |
| #endif
 | |
|   if (fseek(disfp, -(long)(ap->off + 4), SEEK_CUR) != 0) {
 | |
| 	fprintf(stderr, "Cannot seek backward in object file\n");
 | |
| 	exit(1);
 | |
|   }
 | |
| 
 | |
|   return uj;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Return current offset of string device.
 | |
|  */
 | |
| PUBLIC count_t stringpos()
 | |
| {
 | |
|   return string_ptr - stringstart;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Return current "tab" spot of string device.
 | |
|  */
 | |
| PUBLIC count_t stringtab()
 | |
| {
 | |
|   return stringcount;
 | |
| }
 | |
| 
 | |
| /******************** sym.c ***********************/
 | |
| 
 | |
| /*
 | |
|  * f i n d r v a l
 | |
|  *
 | |
|  * Check if an address refers to a relocation structure,
 | |
|  * and if so return the table entry.
 | |
|  *
 | |
|  * Returns:	Pointer to struct nlist		Success
 | |
|  * 		Null pointer			Failure
 | |
|  *
 | |
|  * Note that the nlist interface must be maintained for use by unasm().
 | |
|  */
 | |
| PUBLIC struct nlist *findrval(offset_t value, int where)
 | |
| {
 | |
|   if (aoutfp != (FILE *)NULL)
 | |
| 	return (find_arval(value, where));
 | |
|   else if (objfp != (FILE *)NULL)
 | |
| 	return (find_orval(value, where));
 | |
|   else
 | |
| 	return (struct nlist *)NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * f i n d _ a r v a l
 | |
|  *
 | |
|  * Check if an address refers to an a.out file relocation structure,
 | |
|  * and if so return the table entry.
 | |
|  *
 | |
|  * Returns:	Pointer to struct nlist		Success
 | |
|  * 		Null pointer			Failure
 | |
|  *
 | |
|  * Note that the nlist interface must be maintained for use by unasm().
 | |
|  * ### Do any available ACK compilers have this feature?
 | |
|  */
 | |
| PRIVATE struct nlist *find_arval(offset_t value, int where)
 | |
| {
 | |
|   return (struct nlist *)NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * f i n d _ o r v a l
 | |
|  *
 | |
|  * Check if an address refers to an object file relocation structure,
 | |
|  * and if so return the table entry.
 | |
|  *
 | |
|  * Returns:	Pointer to struct nlist		Success
 | |
|  * 		Null pointer			Failure
 | |
|  *
 | |
|  * Note that the nlist interface must be maintained for use by unasm().
 | |
|  * The table entry is stored in a static buffer which is overwritten
 | |
|  * on successive calls.
 | |
|  */
 | |
| PRIVATE struct nlist *find_orval(offset_t value, int where)
 | |
| {
 | |
|   char data[20];
 | |
|   int j, k, status;
 | |
|   long int lj;
 | |
|   static struct nlist sym;
 | |
| 
 | |
|   /* we need to have an object file */
 | |
|   if (objfp == (FILE *)NULL) return (struct nlist *)NULL;
 | |
| 
 | |
|   /* Sections in an object file usually have the order text, rom, data, bss.
 | |
|    * The order is actually set out in the section data header.  Assume that
 | |
|    * the first user section is text, and all else is data.
 | |
|    */
 | |
|   if (where != CSEG && where != DSEG)
 | |
| 	return(struct nlist *)NULL;
 | |
| 
 | |
|   /* check for a relocation entry */
 | |
|   status = FAILED;
 | |
|   for (j = 0 ; j < o_hdrbuf.oh_nrelo ; j++) {
 | |
| 	if (value == o_reltab[j].or_addr) {
 | |
| 		/* abandon non-matching section entries */
 | |
| 		if (where == CSEG && (o_reltab[j].or_sect & S_TYP) != S_MIN)
 | |
| 			continue;
 | |
| 		if (where == DSEG && ((o_reltab[j].or_sect & S_TYP) <= S_MIN ||
 | |
| 				(o_reltab[j].or_sect & S_TYP) > (S_MIN + 3)))
 | |
| 			continue;
 | |
| 		/* the address is an offset from the symbol or section base */
 | |
| 		if (o_reltab[j].or_nami < o_hdrbuf.oh_nname) {
 | |
| 			lj = o_symtab[o_reltab[j].or_nami].on_foff -
 | |
| 					(long)OFF_CHAR(o_hdrbuf);
 | |
| 			/* check that addressing isn't messed up */
 | |
| 			assert(lj >= 0 && lj < o_hdrbuf.oh_nchar);
 | |
| 			/* name size is defined by SZ_NAME */
 | |
| 			sprintf(data, "%-13s", o_strtab + lj);
 | |
| 			/* convert from rel table to executable symbol table format */
 | |
| 			for (k = 0 ; k < sizeof(sym.n_name) ; k++) {
 | |
| 				sym.n_name[k] = data[k];/* 8 characters */
 | |
| 			}
 | |
| 			sym.n_value = o_symtab[o_reltab[j].or_nami].on_valu;
 | |
| 							/* long */
 | |
| #if 1
 | |
| 			sym.n_sclass = (where == CSEG) ? N_TEXT : N_DATA;
 | |
| #else
 | |
| 			sym.n_sclass = (o_symtab[o_reltab[j].or_nami].on_type &
 | |
| 					S_TYP) - S_MIN;	/* unsigned char */
 | |
| #endif
 | |
| 			sym.n_numaux = 0;		/* unsigned char */
 | |
| 			sym.n_type = 0;			/* unsigned short */
 | |
| 			status = OK;
 | |
| 			break;
 | |
| 		}
 | |
| 		/* the address is an absolute number relative to the pc */
 | |
| 		else if (o_reltab[j].or_nami == o_hdrbuf.oh_nname) {
 | |
| 			strcpy(data, "Absolute");
 | |
| 			/* convert from relocation data to executable symbol table format */
 | |
| 			for (k = 0 ; k < sizeof(sym.n_name) ; k++) {
 | |
| 				sym.n_name[k] = data[k];
 | |
| 			}
 | |
| 			sym.n_value = 0;
 | |
| 			sym.n_sclass = (where == CSEG) ? N_TEXT : N_DATA;
 | |
| 			sym.n_numaux = 0;
 | |
| 			sym.n_type = 0;
 | |
| 			status = OK;
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
|   }
 | |
|   return (status == OK ? &sym : (struct nlist *)NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * f i n d s v a l
 | |
|  *
 | |
|  * Check if an address refers to a symbol,
 | |
|  * and if so return the table entry.
 | |
|  *
 | |
|  * Returns:	Pointer to struct nlist		Success
 | |
|  * 		Null pointer			Failure
 | |
|  *
 | |
|  * Note that the nlist interface must be maintained for use by unasm().
 | |
|  */
 | |
| PUBLIC struct nlist *findsval(offset_t value, int where)
 | |
| {
 | |
|   if (aoutfp != (FILE *)NULL)
 | |
| 	return (find_asval(value, where));
 | |
|   else if (objfp != (FILE *)NULL)
 | |
| 	return (find_osval(value, where));
 | |
|   else
 | |
| 	return (struct nlist *)NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * f i n d _ a s v a l
 | |
|  *
 | |
|  * Check if an address refers to an a.out file symbol,
 | |
|  * and if so return the table entry.
 | |
|  *
 | |
|  * Returns:	Pointer to struct nlist		Success
 | |
|  * 		Null pointer			Failure
 | |
|  *
 | |
|  * Note that the nlist interface must be maintained for use by unasm().
 | |
|  * The table entry is stored in a static buffer which is overwritten
 | |
|  * on successive calls.
 | |
|  */
 | |
| PRIVATE struct nlist *find_asval(offset_t value, int where)
 | |
| {
 | |
|   int j, status;
 | |
|   static struct nlist sym;
 | |
| 
 | |
|   /* Sections in an a.out file have the order text, data, bss
 | |
|    * but this function is called only with CSEG and DSEG.
 | |
|    */
 | |
|   if (where != CSEG && where != DSEG)
 | |
| 	return(struct nlist *)NULL;
 | |
| 
 | |
|   /* do a linear search for a symbol, as the symbol tables are unsorted */
 | |
|   status = FAILED;
 | |
|   for (j = 0 ; j < (a_hdrbuf.a_syms / sizeof(struct nlist)) ; j++) {
 | |
| 	if (value == a_symtab[j].n_value &&
 | |
| 			((where == CSEG && (a_symtab[j].n_sclass & N_SECT) == N_TEXT) ||
 | |
| 			(where == DSEG && ((a_symtab[j].n_sclass & N_SECT) == N_DATA ||
 | |
| 			(a_symtab[j].n_sclass & N_SECT) == N_BSS)))) {
 | |
| 		(void) memcpy(&sym, &a_symtab[j], sizeof(struct nlist));
 | |
| 		status = OK;
 | |
| 		break;
 | |
| 	}
 | |
|   }
 | |
|   return (status == OK) ? &sym : (struct nlist *)NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * f i n d _ o s v a l
 | |
|  *
 | |
|  * Check if an address refers to an object file symbol,
 | |
|  * and if so return the table entry.
 | |
|  *
 | |
|  * Returns:	Pointer to struct nlist		Success
 | |
|  * 		Null pointer			Failure
 | |
|  *
 | |
|  * Note that the nlist interface must be maintained for use by unasm().
 | |
|  * The table entry is stored in a static buffer which is overwritten
 | |
|  * on successive calls.
 | |
|  */
 | |
| PRIVATE struct nlist *find_osval(offset_t value, int where)
 | |
| {
 | |
|   int j, k, sec, status;
 | |
|   long int lj;
 | |
|   struct locname *np;
 | |
|   static struct nlist sym;
 | |
| 
 | |
|   /* Sections in an object file usually have the order text, rom, data, bss.
 | |
|    * The order is actually set out in the section data header.  Assume that
 | |
|    * the first user section is text, and all else is data.
 | |
|    */
 | |
|   if (where != CSEG && where != DSEG)
 | |
| 	return(struct nlist *)NULL;
 | |
| 
 | |
|   /* do a linear search for a local symbol, as the tables are unsorted */
 | |
|   status = FAILED;
 | |
|   if (where == DSEG) {
 | |
| 	/* nb. hardcoded assumption of section order */
 | |
| 	for (sec = 1 ; status == FAILED && sec < 4 ; sec++) {
 | |
| 		for (np = locsym[sec] ; status == FAILED && np !=
 | |
| 					(struct locname *)NULL ; np = np->l_next) {
 | |
| 			if (np->l_value == value) {
 | |
| 				for (k = 0 ; k < sizeof(sym.n_name) ; k++) {
 | |
| 					sym.n_name[k] = np->l_name[k];/* 8 characters */
 | |
| 				}
 | |
| 				sym.n_value = value;		/* long */
 | |
| 				sym.n_sclass = N_DATA;		/* unsigned char */
 | |
| 				sym.n_numaux = 0;		/* unsigned char */
 | |
| 				sym.n_type = 0;			/* unsigned short */
 | |
| 				status = OK;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   /* do a linear search for a symbol, as the symbol tables are unsorted */
 | |
|   for (j = 0 ; status == FAILED && j < o_hdrbuf.oh_nname ; j++) {
 | |
| 	if (value == o_symtab[j].on_valu) {
 | |
| 		/* abandon non-matching section entries */
 | |
| 		if (where == CSEG && (o_symtab[j].on_type & S_TYP) != S_MIN)
 | |
| 			continue;
 | |
| 		if (where == DSEG && ((o_symtab[j].on_type & S_TYP) <= S_MIN ||
 | |
| 				(o_symtab[j].on_type & S_TYP) > (S_MIN + 3)))
 | |
| 			continue;
 | |
| #if 0
 | |
| 			((where == CSEG && sect == (o_symtab[j].on_type & S_TYP)) ||
 | |
| 			(where == DSEG && sect <= (o_symtab[j].on_type & S_TYP)))) {
 | |
| #endif
 | |
| 		/* find the name in the object file symbol table */
 | |
| 		lj = o_symtab[j].on_foff - (long)OFF_CHAR(o_hdrbuf);
 | |
| 		/* check that the offset addressing isn't messed up */
 | |
| 		assert(lj >= 0 && lj < o_hdrbuf.oh_nchar);
 | |
| 		/* convert from object to executable symbol table format */
 | |
| 		for (k = 0 ; k < sizeof(sym.n_name) ; k++) {
 | |
| 			sym.n_name[k] = *(o_strtab + lj + k);
 | |
| 							/* 8 characters */
 | |
| 		}
 | |
| 		sym.n_value = o_symtab[j].on_valu;	/* long */
 | |
| 		sym.n_sclass = (where == CSEG) ? N_TEXT : N_DATA;
 | |
| 							/* unsigned char */
 | |
| 		sym.n_numaux = 0;			/* unsigned char */
 | |
| 		sym.n_type = 0;				/* unsigned short */
 | |
| 		status = OK;
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   return (status == OK ? &sym : (struct nlist *)NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * o u t r e l
 | |
|  *
 | |
|  * Output a symbol name from an nlist structure.
 | |
|  *
 | |
|  * Returns:	Nothing		Always
 | |
|  *
 | |
|  * Note that the nlist interface must be maintained for use by unasm().
 | |
|  * The label may be a segment name, in which case the address is relative
 | |
|  * to that segment and must be dereferenced further.
 | |
|  */
 | |
| PUBLIC void outrel(struct nlist *sp, offset_t off)
 | |
| {
 | |
|   char data[20];
 | |
|   int j, k;
 | |
|   struct nlist *spnew;
 | |
| 
 | |
|   /* get a local copy of the label */
 | |
|   for (j = 0 ; j < 20 ; j++) {
 | |
| 	data[j] = sp->n_name[j];
 | |
| 	if (data[j] == ' ' || data[j] == '\0')
 | |
| 		break;
 | |
|   }
 | |
|   data[j] = '\0';
 | |
|   data[8] = '\0';
 | |
| 
 | |
|   /* see if we have a section name */
 | |
|   for (k = 0 ; k < 4 ; k++) {
 | |
| 	if (strcmp(data, o_secnam[k]) == 0) {
 | |
| 		/* look up the name in the appropriate section */
 | |
| 		if ((spnew = findsval(off, (k ? DSEG : CSEG))) != (struct nlist *)NULL) {
 | |
| 			/* get a local copy of the label */
 | |
| 			for (j = 0 ; j < 20 ; j++) {
 | |
| 				data[j] = spnew->n_name[j];
 | |
| 				if (data[j] == '\0') break;
 | |
| 			}
 | |
| 			data[8] = '\0';
 | |
| 		}
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   /* output the result */
 | |
|   for (j = 0 ; data[j] != 0 ; j++)
 | |
| 	outbyte(data[j]);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * o u t s y m
 | |
|  *
 | |
|  * Output a symbol name from an nlist structure.
 | |
|  *
 | |
|  * Returns:	Nothing		Always
 | |
|  *
 | |
|  * Note that the nlist interface must be maintained for use by unasm().
 | |
|  */
 | |
| PUBLIC void outsym(struct nlist *sp, offset_t off)
 | |
| {
 | |
|   char *s;
 | |
|   char *send;
 | |
| 
 | |
|   /* output the symbol name */
 | |
|   for (s = sp->n_name, send = s + sizeof sp->n_name; *s != 0 && s < send; ++s)
 | |
| 	outbyte(*s);
 | |
| 
 | |
|   /* if the required address is offset from the name, output that too */
 | |
|   if ((off -= sp->n_value) != 0) {
 | |
| 	outbyte('+');
 | |
| 	if (off >= 0x10000)
 | |
| 		outh32(off);
 | |
| 	else if (off >= 0x100)
 | |
| 		outh16((u16_pt) off);
 | |
| 	else
 | |
| 		outh8((u8_pt) off);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * d a s m
 | |
|  *
 | |
|  * Disassemble a stream of instructions.
 | |
|  *
 | |
|  * Returns:	OK	Success
 | |
|  *		FAILED	Otherwise
 | |
|  */
 | |
| PUBLIC int dasm(offset_t addr, offset_t count)
 | |
| {
 | |
| #if (_WORD_SIZE == 4)
 | |
|   bits32 = TRUE;		/* set mode */
 | |
| #else
 | |
|   bits32 = FALSE;
 | |
| #endif
 | |
|   processor = bits32 ? 386 : 0;
 | |
|   uptr.off = 0;
 | |
|   uptr.base = 0;
 | |
| 
 | |
|   while (uptr.off < count) {
 | |
| 	addrbase = addr;
 | |
| 	/* assume that the object file text segment is first */
 | |
| 	if (objfp != (FILE *)NULL && uptr.off >= o_sectab[0].os_flen)
 | |
| 		return FAILED;
 | |
| 	if (aoutfp != (FILE *)NULL && uptr.off >= (A_DATAPOS(a_hdrbuf) - 1))
 | |
| 		return FAILED;
 | |
| 	if (dis_one() == FAILED)
 | |
| 		return FAILED;
 | |
|   }
 | |
|   return OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * d i s _ o n e
 | |
|  *
 | |
|  * Disassemble a single instruction.
 | |
|  *
 | |
|  * Returns:	OK		Always
 | |
|  *
 | |
|  * File read failures are handled at a low level by simply
 | |
|  * baling out of the program; the startup checks on file
 | |
|  * readability should make this a rare occurrence.  Hence
 | |
|  * there are no error returns from this routine.
 | |
|  * The output is written into a static line buffer, which
 | |
|  * is overwritten on successive calls.
 | |
|  */
 | |
| PRIVATE int dis_one()
 | |
| {
 | |
|   int idone, column, maxcol;
 | |
|   static char line[81];
 | |
|   struct address_s newuptr;
 | |
|   struct address_s olduptr;
 | |
|   struct nlist *sp;
 | |
| 
 | |
|   do {
 | |
| 	/* output a label */
 | |
| 	if ((sp = findsval(uptr.off + addrbase, CSEG)) != NULL
 | |
| 			&& sp->n_value == uptr.off + addrbase) {
 | |
| 		outsym(sp, uptr.off + addrbase);
 | |
| 		outbyte(':');
 | |
| 		(void) outnl();
 | |
| 	}
 | |
| 
 | |
| 	/* park the current address */
 | |
| 	olduptr = uptr;
 | |
| 
 | |
| 	/* initialise the string input */
 | |
| 	openstring(line, sizeof(line));
 | |
| 
 | |
| 	/* output an instruction */
 | |
| 	idone = puti();
 | |
| 
 | |
| 	/* terminate the line buffer */
 | |
| 	line[stringpos()] = 0;
 | |
| 
 | |
| 	/* deinitialise the string input */
 | |
| 	closestring();
 | |
| 
 | |
| 	/* park the new address, set by puti() */
 | |
| 	newuptr = uptr;
 | |
| 
 | |
| 	/* get back the current address */
 | |
| 	uptr = olduptr;
 | |
| 
 | |
| 	/* output the segment data */
 | |
| 	column = outsegaddr(&uptr, addrbase);
 | |
| 	outspace();
 | |
| 	outspace();
 | |
| 	column += 2;
 | |
| 
 | |
| 	/* output the raw bytes of the current instruction */
 | |
| 	while (uptr.off != newuptr.off) {
 | |
| 	    outh8(get8());
 | |
| 	    column += 2;
 | |
| 	}
 | |
| 
 | |
| 	/* format the disassembled output */
 | |
| 	maxcol = bits32 ? 24 : 16;
 | |
| 	while (column < maxcol) {
 | |
| 	    outtab();
 | |
| 	    column += 8;
 | |
| 	}
 | |
| 	outtab();
 | |
| 
 | |
| 	/* display the collected buffer */
 | |
| 	outstr(line);
 | |
| 	(void) outnl();
 | |
|   } while (!idone);			/* eat all prefixes */
 | |
| 
 | |
|   return OK;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * EOF
 | |
|  */
 | |
| 
 |