You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
724 lines
19 KiB
724 lines
19 KiB
3 years ago
|
/*
|
||
|
* File: int.c
|
||
|
*
|
||
|
* Synopsis: PC interrupt caller, memory R/W, I/O port R/W
|
||
|
*
|
||
|
* System: MSDOS - Turbo C or Borland C (other compilers need some work)
|
||
|
*
|
||
|
* A utility for PC systems programmers to:
|
||
|
* - perform and visualise the results of interrupt calls
|
||
|
* - use buffers (inc files) to set register pairs
|
||
|
* - view the interrupt vector table
|
||
|
* - read & write I/O ports
|
||
|
*
|
||
|
* NB: This utility must be used with EXTREME CARE. Using bad interrupt and/or
|
||
|
* I/O calls can destroy data on your memory/disk(s) and might crash your
|
||
|
* machine.
|
||
|
*
|
||
|
* Compatible with int.c ditributed with Ralf Brown's interrupt lists
|
||
|
* Comments/suggestions welcome on the email address below.
|
||
|
*
|
||
|
*
|
||
|
* Copyright (c) 1992-1994 Angelo Haritsis <ah@doc.ic.ac.uk>
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms are permitted provided
|
||
|
* that the above copyright notice and this paragraph are duplicated in all
|
||
|
* such forms and that any documentation, advertising materials, and other
|
||
|
* materials related to such distribution and use acknowledge that the
|
||
|
* software was developed by Angelo Haritsis.
|
||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
*
|
||
|
* TODO:
|
||
|
* > -fbuf filename (write mem with vals from a file)
|
||
|
*/
|
||
|
|
||
|
#ifndef lint
|
||
|
static char rcsid[] = "$Header: E:/SRC/MISC\RCS\int.c 1.2 1994/04/11 20:11:36 ah Exp ah $";
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <io.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <assert.h>
|
||
|
#include <ctype.h>
|
||
|
#include <dos.h>
|
||
|
|
||
|
#define PROG "int"
|
||
|
#define VERSION "1.0"
|
||
|
#define NOTREACHED 0
|
||
|
|
||
|
|
||
|
#define PARSE_JUSTARGS 0x01
|
||
|
#define PARSE_NOACTION 0x02
|
||
|
|
||
|
/*
|
||
|
* Types
|
||
|
*/
|
||
|
typedef int (*fun_ptr) (char **, int *);
|
||
|
|
||
|
typedef struct s_opt {
|
||
|
char *opts; /* option name */
|
||
|
int size; /* bytes for the ptr element (1, 2, 4);
|
||
|
* 0 means execute the function following
|
||
|
* parsing (argv, &opt_now)
|
||
|
*/
|
||
|
void *ptr; /* pointer to the data element to be loaded or a function if size = 0 */
|
||
|
} OPTION;
|
||
|
|
||
|
typedef struct s_dbuff {
|
||
|
unsigned *ptr_to_seg; /* the area where the segment is held */
|
||
|
unsigned *ptr_to_off; /* the area where the offset is held */
|
||
|
void far *addr; /* the address (when explicitly given) */
|
||
|
char logo[20];
|
||
|
#define DBUFF_HEX 0x01
|
||
|
#define DBUFF_ASC 0x02
|
||
|
#define DBUFF_BIN 0x04
|
||
|
int mode; /* display mode */
|
||
|
long bytes; /* # of bytes to show */
|
||
|
} DBUFFER;
|
||
|
|
||
|
typedef struct s_doserr {
|
||
|
int errno;
|
||
|
int class;
|
||
|
int action;
|
||
|
int locus;
|
||
|
} DOS_ERROR;
|
||
|
|
||
|
/*
|
||
|
* Globals
|
||
|
*/
|
||
|
char switchchar[] = "-+/";
|
||
|
|
||
|
char usage[] =
|
||
|
"usage: " PROG " [-h] [-q] [int=# | int# | -int #] [[-]reg[=]val] ...\n"
|
||
|
" [-buf sreg:reg=\"str\"]\n"
|
||
|
" [-d[a|b|hx] sreg:reg[:#bytes]] [-d[a|hx] faraddr[:#bytes]]\n"
|
||
|
" [-divt int#-int#]]\n"
|
||
|
" [-in[w] port#] [-out[w] port#,val]\n"
|
||
|
" str: printf fmt (%#s allowed to setup buffers)\n";
|
||
|
|
||
|
char help[] =
|
||
|
" eg.\n"
|
||
|
" o Interrupts (+ buffer setup)\n"
|
||
|
" " PROG " 0x10 -ax 0x12 same as: int int=0x10 ax=0x12 (set VGA graphics mode)\n"
|
||
|
" " PROG " 0x10 ah=0x10 al=1 bh=9 (set VGA border color; use to adjust display)\n"
|
||
|
" " PROG " 0x21 -ah 9 -buf ds:dx=\"hello world\\n$\" -q (INT 21,9 'hello world')\n"
|
||
|
" " PROG " an_int -buf es:bx=\"%512s\" (creates a scratch buffer of 512 bytes)\n"
|
||
|
" " PROG " 0x33 ax=9 bx=0 cx=0 -fbuf es:bx=cursor.dat (mouse cursor from file)\n"
|
||
|
" o Memory (-d: display: called after interrupt)\n"
|
||
|
" " PROG " -q -dhx 0x400049:18 (BIOS video area data)\n"
|
||
|
" " PROG " -q es=0x40 -bx 0x49 -dhx es:bx:18 (same as above)\n"
|
||
|
" " PROG " -q -db 0xF8000000:512 >file (binary dump of AMIBIOS serial data)\n"
|
||
|
" o IVT\n"
|
||
|
" " PROG " -q -divt (display vectors from interrupt vector table = IVT)\n"
|
||
|
" " PROG " -q -divt 0x10-0x1F (display IVT slots 0x10 to 0x1F)\n"
|
||
|
" o I/O Ports\n"
|
||
|
" " PROG " -out 0x70,0 -in 0x71 (read seconds from CMOS)\n"
|
||
|
" " PROG " -out 0x70,0 -out 0x71,0 (zero-out seconds in CMOS)\n";
|
||
|
|
||
|
char *int_error[] = {
|
||
|
NULL,
|
||
|
"Parse",
|
||
|
};
|
||
|
|
||
|
char str_flags[] = "0N..ODITSZ0A0P1C"; /* 80x86 flag register */
|
||
|
|
||
|
union REGS reg;
|
||
|
struct SREGS sreg;
|
||
|
unsigned int reg_bp, reg_sp, flags;
|
||
|
int int_call; /* the interrupt to be called */
|
||
|
int dos_errno;
|
||
|
int quiet_mode = 0; /* quiet means just execute int - no reg display * /* does not apply on display
|
||
|
* opts */
|
||
|
int buff_now = 0;
|
||
|
char *buff[10]; /* array of read buffer pointers */
|
||
|
|
||
|
int dbuff_now = 0;
|
||
|
DBUFFER dbuff[10]; /* the buffers to show at end of intr */
|
||
|
|
||
|
|
||
|
/* --- Prototypes --- */
|
||
|
OPTION *parse_an_opt(char *argv[], int *opt_now, int mode);
|
||
|
void doit(void);
|
||
|
void reg_display(void);
|
||
|
int set_int_val(char **argv, int *opt_now);
|
||
|
int ivt_display(char **argv, int *opt_now);
|
||
|
int ioport_out(char **argv, int *opt_now);
|
||
|
int ioport_in(char **argv, int *opt_now);
|
||
|
int read_escape(char **p);
|
||
|
int set_buff(char **argv, int *opt_now);
|
||
|
int set_fbuff(char **argv, int *opt_now);
|
||
|
int set_dbuff(char **argv, int *opt_now);
|
||
|
int dbuff_parse(void **ptr, char *tok);
|
||
|
int set_dbuff(char **argv, int *opt_now);
|
||
|
int show_help(char **argv, int *opt_now);
|
||
|
int set_quiet(char **argv, int *opt_now);
|
||
|
void error_exit(int err, char *s);
|
||
|
|
||
|
/* --- */
|
||
|
|
||
|
/*
|
||
|
* Structure with all the `action' to be done for an option
|
||
|
* NB: Care with matching prefixes (longer must come first)
|
||
|
*/
|
||
|
OPTION Opt[] = {
|
||
|
|
||
|
/* NB: put the longer strings first ! */
|
||
|
|
||
|
{"$DEFAULT", 0, (void *) set_int_val},
|
||
|
{"DIVT", 0, (void *) ivt_display}, /* display int vector table */
|
||
|
{"INT", 2, (void *) &int_call},
|
||
|
|
||
|
{"OUTW", 0, (void *) ioport_out}, /* I/O port write, read */
|
||
|
{"OUT", 0, (void *) ioport_out},
|
||
|
{"INW", 0, (void *) ioport_in},
|
||
|
{"IN", 0, (void *) ioport_in},
|
||
|
|
||
|
{"DBUF", 0, (void *) set_dbuff},
|
||
|
{"FBUF", 0, (void *) set_fbuff},
|
||
|
{"BUF", 0, (void *) set_buff},
|
||
|
{"DHX", 0, (void *) set_dbuff}, /* display mem contents (hex) */
|
||
|
|
||
|
{"FL", 2, (void *) &(reg.x.flags)}, /* set flags (won't affect anything) */
|
||
|
|
||
|
{"AX", 2, (void *) &(reg.x.ax)}, /* set general registers */
|
||
|
{"BX", 2, (void *) &(reg.x.bx)},
|
||
|
{"CX", 2, (void *) &(reg.x.cx)},
|
||
|
{"DX", 2, (void *) &(reg.x.dx)},
|
||
|
{"AH", 1, (void *) &(reg.h.ah)},
|
||
|
{"BH", 1, (void *) &(reg.h.bh)},
|
||
|
{"CH", 1, (void *) &(reg.h.ch)},
|
||
|
{"DH", 1, (void *) &(reg.h.dh)},
|
||
|
{"AL", 1, (void *) &(reg.h.al)},
|
||
|
{"BL", 1, (void *) &(reg.h.bl)},
|
||
|
{"CL", 1, (void *) &(reg.h.cl)},
|
||
|
{"DL", 1, (void *) &(reg.h.dl)},
|
||
|
|
||
|
{"SI", 2, (void *) &(reg.x.si)}, /* set index, stack registers */
|
||
|
{"DI", 2, (void *) &(reg.x.di)},
|
||
|
{"BP", 0, 0},
|
||
|
{"SP", 0, 0},
|
||
|
|
||
|
{"CS", 2, (void *) &(sreg.cs)}, /* set segment registers */
|
||
|
{"DS", 2, (void *) &(sreg.ds)},
|
||
|
{"ES", 2, (void *) &(sreg.es)},
|
||
|
{"SS", 2, (void *) &(sreg.ss)},
|
||
|
|
||
|
{"DA", 0, (void *) set_dbuff}, /* display mem contents (ascii) */
|
||
|
{"D", 0, (void *) set_dbuff}, /* display mem contents (ascii+hex) */
|
||
|
{"Q", 0, (void *) set_quiet}, /* quiet (no disply of reg contents) */
|
||
|
{"H", 0, (void *) show_help}, /* help */
|
||
|
};
|
||
|
|
||
|
|
||
|
int cdecl
|
||
|
main(int argc, char *argv[])
|
||
|
{
|
||
|
int opt_now;
|
||
|
|
||
|
if (argc == 1)
|
||
|
error_exit(0, NULL);
|
||
|
|
||
|
/* parse the arguments and do proper action */
|
||
|
for (opt_now = 1; opt_now < argc; opt_now++)
|
||
|
if (parse_an_opt(argv, &opt_now, 0) == NULL)
|
||
|
error_exit(1, NULL);
|
||
|
doit();
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Parses an argument and calls proper function or assigns numbers
|
||
|
* accordingly. Reentrant.
|
||
|
*/
|
||
|
OPTION *
|
||
|
parse_an_opt(char *argv[], int *opt_now, int mode)
|
||
|
{
|
||
|
int i, arg_len, get_next_arg;
|
||
|
char *opts, *optarg, *p;
|
||
|
long val;
|
||
|
|
||
|
opts = argv[*opt_now];
|
||
|
if (strchr(switchchar, opts[0])) /* option starts with a switch char, skip it */
|
||
|
opts++, argv[*opt_now]++;
|
||
|
for (i = 0; i < (sizeof(Opt) / sizeof(OPTION)); i++) {
|
||
|
arg_len = strlen(Opt[i].opts);
|
||
|
get_next_arg = opts[arg_len] == 0;
|
||
|
if (strncmpi(opts, Opt[i].opts, arg_len) == 0) {
|
||
|
if (mode & PARSE_NOACTION) /* do not perform action */
|
||
|
return (&Opt[i]); /* just return ptr to Opt slot */
|
||
|
switch (Opt[i].size) {
|
||
|
|
||
|
case 0: /* call the function */
|
||
|
if (!(mode & PARSE_JUSTARGS) && Opt[i].ptr != (void *) 0)
|
||
|
if ((*((fun_ptr) Opt[i].ptr)) (argv, opt_now) == 0)
|
||
|
return (NULL); /* error */
|
||
|
return (&Opt[i]);
|
||
|
|
||
|
case 1: /* ptr is a byte, short, int */
|
||
|
case 2:
|
||
|
case 4:
|
||
|
if (get_next_arg)
|
||
|
optarg = argv[++(*opt_now)]; /* get next option */
|
||
|
else
|
||
|
optarg = opts + arg_len + 1; /* skip a separator (eg =) */
|
||
|
val = strtol(optarg, &p, 0);
|
||
|
if (p == optarg)
|
||
|
return (NULL);
|
||
|
switch (Opt[i].size) {
|
||
|
case 1:
|
||
|
*((char *) Opt[i].ptr) = (char) val;
|
||
|
break;
|
||
|
case 2:
|
||
|
*((short *) Opt[i].ptr) = (short) val;
|
||
|
break;
|
||
|
case 4:
|
||
|
*((long *) Opt[i].ptr) = (long) val;
|
||
|
break;
|
||
|
}
|
||
|
return (&Opt[i]);
|
||
|
|
||
|
default:
|
||
|
assert(NOTREACHED);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (mode & PARSE_JUSTARGS)
|
||
|
return (&Opt[0]); /* default */
|
||
|
else {
|
||
|
i = (*((fun_ptr) Opt[0].ptr)) (argv, opt_now); /* default */
|
||
|
return (i == 0 ? NULL : &Opt[0]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Call the interrupt if asked and display the result buffers
|
||
|
*/
|
||
|
void
|
||
|
doit(void)
|
||
|
{
|
||
|
int i;
|
||
|
long j;
|
||
|
unsigned char far *ptr;
|
||
|
unsigned char b;
|
||
|
|
||
|
dos_errno = 0;
|
||
|
if (int_call != -1) {
|
||
|
reg_bp = _BP;
|
||
|
reg_sp = _SP;
|
||
|
flags = _FLAGS;
|
||
|
reg_display();
|
||
|
}
|
||
|
if (int_call > 0 && int_call < 256) {
|
||
|
quiet_mode || printf("\nINT: 0x%02X\n", int_call);
|
||
|
int86x(int_call, ®, ®, &sreg); /**/
|
||
|
if (reg.x.cflag != 0) /* error occured */
|
||
|
dos_errno = _doserrno;
|
||
|
reg_bp = _BP;
|
||
|
reg_sp = _SP;
|
||
|
quiet_mode || printf("\n");
|
||
|
flags = reg.x.flags;
|
||
|
reg_display();
|
||
|
if (!quiet_mode && (int_call == 0x21 || int_call == 0x24)) /* dos call */
|
||
|
printf("DOSERR: %04X (%u)\n", dos_errno, dos_errno);
|
||
|
}
|
||
|
/* display dbuffers */
|
||
|
|
||
|
for (i = 0; i < dbuff_now; i++) {
|
||
|
ptr = (unsigned char far *) MK_FP(*(dbuff[i].ptr_to_seg), *(dbuff[i].ptr_to_off));
|
||
|
|
||
|
if (dbuff[i].mode & DBUFF_BIN) /* binary */
|
||
|
setmode(1, O_BINARY);
|
||
|
else
|
||
|
printf("\n*<%s> {\n", dbuff[i].logo);
|
||
|
for (j = 0; j < dbuff[i].bytes; j++, ptr++) {
|
||
|
b = *ptr & 0x00FF; /* byte to display */
|
||
|
if (dbuff[i].mode & DBUFF_BIN) { /* binary */
|
||
|
putchar(b);
|
||
|
continue; /* nothing else */
|
||
|
}
|
||
|
if (dbuff[i].mode & DBUFF_HEX)
|
||
|
printf("%02X", b);
|
||
|
if (dbuff[i].mode == DBUFF_ASC)
|
||
|
putchar(iscntrl(b) ? '.' : b);
|
||
|
else if (dbuff[i].mode & DBUFF_ASC)
|
||
|
printf("(%c)", iscntrl(b) ? '.' : b);
|
||
|
if (dbuff[i].mode != DBUFF_ASC)
|
||
|
printf(" ");
|
||
|
}
|
||
|
fflush(stdout);
|
||
|
if (dbuff[i].mode & DBUFF_BIN) /* binary */
|
||
|
setmode(1, O_TEXT);
|
||
|
else
|
||
|
printf("}\n");
|
||
|
}
|
||
|
/* free the read buffers allocated */
|
||
|
for (i = 0; i < buff_now; i++)
|
||
|
free(buff[i]);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
reg_display(void)
|
||
|
{
|
||
|
char s[32];
|
||
|
int i, bit_on;
|
||
|
|
||
|
if (quiet_mode)
|
||
|
return;
|
||
|
printf(
|
||
|
"AX=%04X BX=%04X CX=%04X DX=%04X\n"
|
||
|
"SI=%04X DI=%04X BP=%04X SP=%04X\n"
|
||
|
"CS=%04X DS=%04X ES=%04X SS=%04X",
|
||
|
reg.x.ax, reg.x.bx, reg.x.cx, reg.x.dx,
|
||
|
reg.x.si, reg.x.di, reg_bp, reg_sp,
|
||
|
sreg.cs, sreg.ds, sreg.es, sreg.ss);
|
||
|
strncpy(s, str_flags, 32); /* use a scratch copy */
|
||
|
/* and now the flags */
|
||
|
flags = reg.x.flags;
|
||
|
for (i = 0; i < 16; i++) {
|
||
|
bit_on = (flags & ((unsigned) 0x8000 >> i)) != 0;
|
||
|
if (s[i] == '.')
|
||
|
s[i] = bit_on ? '1' : '0';
|
||
|
else
|
||
|
s[i] = bit_on ? s[i] : tolower(s[i]);
|
||
|
}
|
||
|
printf(" CPU Flags: %16s\n", s);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 'default' argument function - see if it is an interrupt
|
||
|
*/
|
||
|
int
|
||
|
set_int_val(char **argv, int *opt_now)
|
||
|
{
|
||
|
long val;
|
||
|
char *p;
|
||
|
|
||
|
val = strtol(argv[*opt_now], &p, 0);
|
||
|
if (val <= 0 || val > 255 || p - argv[*opt_now] != strlen(argv[*opt_now]))
|
||
|
return (0); /* problems */
|
||
|
int_call = (int) val;
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Display a slot of the Interrupt Vector Table
|
||
|
*/
|
||
|
int
|
||
|
ivt_display(char **argv, int *opt_now)
|
||
|
{
|
||
|
char sfrom[20], sto[20];
|
||
|
int from, to, i;
|
||
|
void far *p;
|
||
|
|
||
|
if ((i = sscanf(argv[*opt_now + 1], "%[0-9xX]-%s", sfrom, sto)) == 2) { /* is a range given ? */
|
||
|
(*opt_now)++; /* consume next arg */
|
||
|
from = (int) strtol(sfrom, (char **) &sfrom, 0);
|
||
|
to = (int) strtol(sto, (char **) &sto, 0);
|
||
|
} else {
|
||
|
from = 0;
|
||
|
to = 255;
|
||
|
}
|
||
|
/* do it now */
|
||
|
printf("Interrupt Vector Table (0x%02X to 0x%02X)\n", from, to);
|
||
|
for (i = from; i <= to; i++) {
|
||
|
disable(); /* just in case ... */
|
||
|
p = (void far *) *((long far *) (4L * i));
|
||
|
enable();
|
||
|
printf(" * 0x%02X (%3u): %Fp\n", i, i, p);
|
||
|
}
|
||
|
printf("\n");
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ioport_out(char **argv, int *opt_now)
|
||
|
{
|
||
|
char *optarg, sport[10], sval[10];
|
||
|
int word_op, port, val;
|
||
|
|
||
|
optarg = argv[*opt_now];
|
||
|
word_op = (toupper(optarg[3]) == 'W') ? 1 : 0;
|
||
|
if (isdigit(optarg[3 + word_op])) /* arg follows with no delimiter */
|
||
|
optarg += 3 + word_op;
|
||
|
else
|
||
|
optarg = argv[++(*opt_now)];
|
||
|
if (sscanf(optarg, "%[^ ,;]%*[ ,;]%s", sport, sval) != 2)
|
||
|
return (0);
|
||
|
port = (int) strtol(sport, (char **) &sport, 0);
|
||
|
val = (int) strtol(sval, (char **) &sval, 0);
|
||
|
if (word_op)
|
||
|
outport(port, (unsigned) val);
|
||
|
else
|
||
|
outportb(port, val);
|
||
|
int_call = -1;
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ioport_in(char **argv, int *opt_now)
|
||
|
{
|
||
|
char *optarg, sport[10];
|
||
|
int word_op, port, val;
|
||
|
|
||
|
optarg = argv[*opt_now];
|
||
|
word_op = (toupper(optarg[2]) == 'W') ? 1 : 0;
|
||
|
if (isdigit(optarg[2 + word_op])) /* arg follows with no delimiter */
|
||
|
optarg += 2 + word_op;
|
||
|
else
|
||
|
optarg = argv[++(*opt_now)];
|
||
|
if (sscanf(optarg, "%s", sport) != 1)
|
||
|
return (0);
|
||
|
port = (int) strtol(sport, (char **) &sport, 0);
|
||
|
if (word_op) {
|
||
|
val = inport(port);
|
||
|
quiet_mode || printf("INW 0x%04X (%5u): 0x%04X (%5u)\n", port, port, val, val);
|
||
|
} else {
|
||
|
val = inportb(port);
|
||
|
quiet_mode || printf("IN 0x%04X (%5u): 0x%02X (%3u)\n", port, port, val, val);
|
||
|
}
|
||
|
quiet_mode || printf("\n");
|
||
|
int_call = -1;
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
#define ESCAPES 10
|
||
|
static int esc_to_code[ESCAPES][2] = {
|
||
|
{'n', '\n'},
|
||
|
{'t', '\t'},
|
||
|
{'v', '\v'},
|
||
|
{'b', 'b'},
|
||
|
{'r', '\r'},
|
||
|
{'f', '\f'},
|
||
|
{'a', '\a'},
|
||
|
{'\\', '\\'},
|
||
|
{'\?', '?'},
|
||
|
{'\'', '\''},
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* returns with *p pointing to char after the one(s) consumed
|
||
|
*/
|
||
|
int
|
||
|
read_escape(char **p)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if (isdigit(**p)) /* octal */
|
||
|
return ((int) strtol(*p, p, 8));
|
||
|
else if (**p == 'x') /* hex */
|
||
|
return ((int) strtol(*p + 1, p, 16));
|
||
|
for (i = 0; i < ESCAPES; i++)
|
||
|
if (**p == esc_to_code[i][0]) {
|
||
|
(*p)++; /* consume it */
|
||
|
return (esc_to_code[i][1]);
|
||
|
}
|
||
|
/* otherwise, return the character un-translated */
|
||
|
(*p)++; /* consume it */
|
||
|
return (**p);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* load seg register values to point ot the created buffer
|
||
|
*/
|
||
|
void
|
||
|
load_regpair(char *s_seg, char *s_off, void far *buff)
|
||
|
{
|
||
|
int len;
|
||
|
char stmp[50], *argv_fake[3];
|
||
|
|
||
|
/* load the regs */
|
||
|
argv_fake[0] = stmp;
|
||
|
argv_fake[1] = "";
|
||
|
len = 0;
|
||
|
sprintf(stmp, "-%s 0x%X", s_seg, FP_SEG(buff));
|
||
|
parse_an_opt(argv_fake, (int *) &len, PARSE_JUSTARGS); /* make it think it's an option */
|
||
|
sprintf(stmp, "-%s 0x%X", s_off, FP_OFF(buff));
|
||
|
parse_an_opt(argv_fake, (int *) &len, PARSE_JUSTARGS); /* and again for offs register */
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* set registers accordingly
|
||
|
*/
|
||
|
int
|
||
|
set_buff(char **argv, int *opt_now)
|
||
|
{
|
||
|
char *optarg, *p, *dp;
|
||
|
char s_seg[10], s_off[10];
|
||
|
char stmp[50];
|
||
|
static char dummy[] = ""; /* for case of %s in fmt str */
|
||
|
unsigned int len;
|
||
|
|
||
|
optarg = argv[++(*opt_now)]; /* s_off pair */
|
||
|
sscanf(optarg, "%[^:]:%s", &s_seg, &s_off);
|
||
|
if (s_off[2] == '=')
|
||
|
s_off[2] = 0;
|
||
|
optarg = argv[++(*opt_now)]; /* printf like string */
|
||
|
/* how big a buffer ? */
|
||
|
len = strlen(optarg);
|
||
|
/* add the %# lengths (extra buffer space) */
|
||
|
for (p = strchr(optarg, '%'); p != NULL; p = strchr(p + 1, '%'))
|
||
|
len += atoi(p + 1);
|
||
|
|
||
|
if ((buff[buff_now] = (char *) malloc(len)) == NULL)
|
||
|
return (0);
|
||
|
/* create escape chars again (since cmd processing makes \ into \\) */
|
||
|
p = optarg, dp = stmp;
|
||
|
while (*p)
|
||
|
if (*p == '\\') {
|
||
|
p++; /* consume \ */
|
||
|
*dp++ = read_escape(&p);
|
||
|
} else
|
||
|
*dp++ = *p++;
|
||
|
|
||
|
/* load the buffer; 5 % fields are enough (XXX ..f func problem if \0 appears before end of fmt) */
|
||
|
sprintf(buff[buff_now], stmp, dummy, dummy, dummy, dummy, dummy);
|
||
|
|
||
|
load_regpair(s_seg, s_off, (void far *) buff[buff_now]);
|
||
|
buff_now++;
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* set register pair to point to buffer with data from a file
|
||
|
*/
|
||
|
int
|
||
|
set_fbuff(char **argv, int *opt_now)
|
||
|
{
|
||
|
char *optarg, *fname;
|
||
|
char s_seg[10], s_off[80];
|
||
|
long len;
|
||
|
FILE *f;
|
||
|
|
||
|
optarg = argv[++(*opt_now)]; /* s_off pair */
|
||
|
sscanf(optarg, "%[^:]:%s", &s_seg, &s_off);
|
||
|
if (s_off[2] == '=') {
|
||
|
s_off[2] = 0;
|
||
|
fname = &s_off[3];
|
||
|
} else
|
||
|
return (0);
|
||
|
|
||
|
if ((f = fopen(fname, "rb")) == NULL)
|
||
|
return (0);
|
||
|
len = filelength(fileno(f));
|
||
|
if (len > 65500L || (buff[buff_now] = (char *) malloc((unsigned int)len)) == NULL)
|
||
|
return (0);
|
||
|
if (fread(buff[buff_now], (int) len, 1, f) != 1)
|
||
|
return (0);
|
||
|
load_regpair(s_seg, s_off, (void far *) buff[buff_now]);
|
||
|
buff_now++;
|
||
|
fclose(f);
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
dbuff_parse(void **ptr, char *tok)
|
||
|
{
|
||
|
char stmp[50], *argv_fake[3];
|
||
|
OPTION *p_opt;
|
||
|
int len = 0;
|
||
|
|
||
|
argv_fake[0] = stmp;
|
||
|
argv_fake[1] = "";
|
||
|
sprintf(stmp, "-%s 0", tok);
|
||
|
p_opt = parse_an_opt(argv_fake, &len, PARSE_JUSTARGS | PARSE_NOACTION);
|
||
|
if (p_opt == NULL || p_opt == &Opt[0])
|
||
|
return (0);
|
||
|
*ptr = (unsigned *) p_opt->ptr;
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* add to the list of the buffers to be displayed at end
|
||
|
*/
|
||
|
int
|
||
|
set_dbuff(char **argv, int *opt_now)
|
||
|
{
|
||
|
char mode_char;
|
||
|
char *optarg, *p;
|
||
|
char tok[3][15]; /* max 3 tokens of 15 chars each */
|
||
|
int i;
|
||
|
long addr;
|
||
|
unsigned long num = 1L; /* number of bytes to display */
|
||
|
DBUFFER *dpb;
|
||
|
|
||
|
dpb = &dbuff[dbuff_now];
|
||
|
dpb->mode = DBUFF_HEX | DBUFF_ASC;
|
||
|
mode_char = toupper(argv[*opt_now][1]);
|
||
|
dpb->mode &= (mode_char == 'A') ? ~DBUFF_HEX : ~0;
|
||
|
dpb->mode &= (mode_char == 'H') ? ~DBUFF_ASC : ~0;
|
||
|
if (mode_char == 'B') { /* binary mode */
|
||
|
dpb->mode &= ~(DBUFF_HEX | DBUFF_ASC);
|
||
|
dpb->mode |= DBUFF_BIN;
|
||
|
}
|
||
|
optarg = argv[++(*opt_now)]; /* reg pair */
|
||
|
strncpy(dpb->logo, optarg, 20);
|
||
|
/* collect tokens */
|
||
|
for (i = 0, p = strtok(optarg, ":="); p; p = strtok(NULL, ":="))
|
||
|
strcpy(tok[i++], p);
|
||
|
if (i > 3)
|
||
|
return (0);
|
||
|
/* process them */
|
||
|
addr = strtoul(tok[0], &p, 0);
|
||
|
if ((p - tok[0]) > 0) { /* first is addr */
|
||
|
if (i > 1) { /* there's a 2nd token */
|
||
|
num = strtoul(tok[1], &p, 0);
|
||
|
if ((p - tok[1]) == 0 || num == 0)
|
||
|
return (0); /* wrong argument */
|
||
|
}
|
||
|
dpb->addr = (void far *) addr;
|
||
|
dpb->ptr_to_off = (unsigned *) &(dpb->addr);
|
||
|
dpb->ptr_to_seg = ((unsigned *) &(dpb->addr)) + 1;
|
||
|
} else { /* should be Reg:Reg[:#] format */
|
||
|
if (dbuff_parse((void **) &(dpb->ptr_to_seg), tok[0]) == 0)
|
||
|
return (0);
|
||
|
if (dbuff_parse((void **) &(dpb->ptr_to_off), tok[1]) == 0)
|
||
|
return (0);
|
||
|
if (i > 2) { /* num argument */
|
||
|
num = strtoul(tok[2], &p, 0);
|
||
|
if ((p - tok[2]) == 0 || num == 0)
|
||
|
return (0); /* wrong argument */
|
||
|
}
|
||
|
}
|
||
|
dpb->bytes = num;
|
||
|
dbuff_now++; /* have inserted an element */
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
set_quiet(char **argv, int *opt_now)
|
||
|
{
|
||
|
argv = argv, opt_now = opt_now; /* eliminate warning */
|
||
|
return (quiet_mode = 1);
|
||
|
}
|
||
|
|
||
|
#define fmsg stdout /* DOS stderr cannot be redir'ed >:-{ */
|
||
|
|
||
|
int
|
||
|
show_help(char **argv, int *opt_now)
|
||
|
{
|
||
|
argv = argv, opt_now = opt_now; /* eliminate warning */
|
||
|
fprintf(fmsg,
|
||
|
PROG ": Execute and investigate interrupts/system data (ver " VERSION ")\n"
|
||
|
"Copyright (c) 1992-1994 A. Haritsis <ah@doc.ic.ac.uk>. Distribute freely.\n");
|
||
|
error_exit(0, help);
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
error_exit(int err, char *s)
|
||
|
{
|
||
|
if (err > 0)
|
||
|
fprintf(fmsg, PROG ": %s error\n", int_error[err]);
|
||
|
fprintf(fmsg, "%s", usage);
|
||
|
if (s != NULL)
|
||
|
fprintf(fmsg, "%s", s);
|
||
|
exit(err);
|
||
|
}
|