Category : Tutorials + Patches
Archive   : INTER43D.ZIP
Filename : INT.C

 
Output of file : INT.C contained in archive : INTER43D.ZIP
/*
* 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
*
* 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
#include
#include
#include
#include
#include
#include
#include

#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 . 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);
}


  3 Responses to “Category : Tutorials + Patches
Archive   : INTER43D.ZIP
Filename : INT.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/