- 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
 | 
						|
 */
 | 
						|
 |