bds@lzaz.ATT.COM (B.SZABLAK) (12/22/88)
/*
* mdb.c - MINIX program debugger
*
* Written by Bruce D. Szablak
*
* This free software is provided for non-commerical use. No warrantee
* of fitness for any use is implied. You get what you pay for. Anyone
* may make modifications and distribute them, but please keep this header
* in the distribution.
*/
#define T_OK 0
#define T_GETINS 1
#define T_GETDATA 2
#define T_GETUSER 3
#define T_SETINS 4
#define T_SETDATA 5
#define T_SETUSER 6
#define T_RESUME 7
#define T_EXIT 8
#define T_STEP 9
#include "stdio.h"
#include "signal.h"
#include "ctype.h"
#include "setjmp.h"
#include "user.h"
struct proc *prc;
#define BP_REG 14
#define MAXLINE 120
#define REG(r) ((long)&((struct proc *)0)->p_reg[r])
#define PC ((long)&((struct proc *)0)->p_pcpsw.pc)
#define MAXB 10
#define MAXP 3
#define MAXARG 20
#define SIZ (1 + sizeof(struct proc)/sizeof(long))
#define MAXLINE 120
long ptrace(), strtol(), reg_addr(), lbuf[SIZ], saddr, eaddr, dasm();
int curpid, cursig;
char *strcpy(), *prog, sbuf[MAXLINE], cbuf[MAXLINE], *cmd, *addr_to_name(),
*getexp(), *cmdstart;
jmp_buf mainlp;
extern errno;
struct b_pnt
{
struct b_pnt *nxt, *prv;
long addr;
long oldval;
char cmd[1];
} *b_head, *curpnt;
cleanup()
{
curpid = 0;
curpnt = 0;
while (b_head) freepnt(b_head);
}
dowait()
{
int stat, ls, hs;
while (wait(&stat) != curpid) {};
ls = stat & 0xFF;
hs = (stat >> 8) & 0xFF;
if (ls == 0)
{
if (hs != 127)
printf("child exited with status %d\n", hs);
cleanup();
return 0;
}
if (hs == 0)
{
printf("child terminated by signal %d\n", ls & 0x7F);
if (ls & 0x80) printf("(core dumped)\n");
cleanup();
return 0;
}
return cursig = hs;
}
update()
{
int i;
for (i = 0; i < (SIZ-1); i++)
{
lbuf[i] = ptrace(T_GETUSER, curpid, (long)(i*sizeof(long)),0L);
}
saddr = (long)prc->p_map[T].mem_vir << CLICK_SHIFT;
eaddr = (long)(prc->p_map[D].mem_vir + prc->p_map[D].mem_len)
<< CLICK_SHIFT;
}
findbpnt(verbose)
{
for (curpnt = b_head; curpnt; curpnt = curpnt->nxt)
{
if (curpnt->addr == prc->p_pcpsw.pc)
{
ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval);
if (curpnt->cmd[0] != '\n')
cmd = strcpy(cbuf, curpnt->cmd);
else if (verbose)
printf("Breakpoint hit.\n");
return;
}
}
if (verbose) printf("Unknown breakpoint hit.\n");
}
disp_regs()
{
int i;
if (curpid <= 0)
{
printf("No active process.\n");
return 1;
}
printf("\npc=%lx psw=%x\n\n",(long)prc->p_pcpsw.pc, prc->p_pcpsw.psw);
printf(
" 0 1 2 3 4 5 6 7\nD");
for (i = 0; i < 8; i++) printf(" %08lx", prc->p_reg[i]);
printf("\nA");
for (; i < NR_REGS; i++) printf(" %08lx", prc->p_reg[i]);
printf(" %08lx\n\n", (long)prc->p_sp);
return 0;
}
char *
skip(s)
register char *s;
{
while (isspace(*s)) ++s;
return *s ? s : s-1;
}
endcmd()
{
while (*cmd != '\n' && *cmd != ';') ++cmd;
}
#define BREAK(l) (0xA0000000 | ((l) & 0xFFFF))
exebpnt(restart)
{
ptrace(T_STEP, curpid, 0L, (long)restart);
if (dowait() == 0) return 1;
ptrace(T_SETINS, curpid, curpnt->addr, BREAK(curpnt->oldval));
curpnt = 0;
return 0;
}
tstart(req, verbose, val, cnt)
{
if (curpid == 0)
{
if (verbose) printf("No active process.\n");
return;
}
if (req == T_EXIT)
{
ptrace(T_EXIT, curpid, 0L, (long)val);
dowait();
return;
}
if (cnt==0) cnt = 1;
do
{
if (curpnt)
{
if (exebpnt(val)) return;
if (req == T_RESUME) cnt++;
val = 0;
}
else
{
ptrace(req, curpid, 0L, (long)val);
if (dowait() == 0) return;
val = 0;
switch (cursig)
{
case SIGEMT: /* breakpoint */
update();
findbpnt(cnt <= 1);
break;
case SIGTRAP: /* trace trap? */
if (req == T_STEP) break;
default: /* signal */
val = cursig;
break;
}
}
}
while (--cnt > 0);
update();
dasm((long)prc->p_pcpsw.pc, 1, 1);
}
catch(sig)
{
signal(sig, catch);
if (sig == SIGINT || sig == SIGQUIT) return;
tstart(T_EXIT, 0, sig, 0);
exit(0);
}
run(name, argstr, tflg)
char *name, *argstr;
{
int procid;
if( (procid = fork()) == 0 )
{
char *argv[MAXARG], *inf = 0, *outf = 0;
int argc;
if (tflg && ptrace(T_OK, 0, 0L, 0L) < 0)
{
perror("ptrace");
exit(127);
}
argv[0] = name;
for (argc = 1; ; )
{
argstr = skip(argstr);
if (*argstr == '\n' || *argstr == ';')
{
argv[argc] = 0;
if (inf) freopen(inf, "r", stdin);
if (outf) freopen(outf, "w", stdout);
execv(name, argv);
perror("execv");
exit( 127 );
}
if (*argstr == '<') inf = argstr+1;
else if (*argstr == '>') outf = argstr+1;
else if (argc == MAXARG)
{
printf("Too many arguments.\n");
exit(127);
}
else argv[argc++] = argstr;
while (!isspace(*argstr)) argstr++;
if (*argstr == '\n') argstr[1] = '\n', argstr[2] = 0;
*argstr++ = 0;
}
}
if (procid < 0)
{
printf("Fork failed.\n");
}
return procid;
}
#define ADDQ(l) (((l >> 16) & 0xF1FF) == 0x508F)
#define ADDQ_CNT(l) ((((l >> 25) - 1) & 7) + 1)
#define LEA(l) ((l >> 16) == 0x4FEF)
#define LEA_DISP(l) ((long)(int)l)
#define ADDA(l) ((int)(l >> 16) == 0xDFFC)
backtrace(all)
{
char sep;
long pc, bp, off, val, obp;
if (curpid <= 0)
{
printf("No process.\n");
return;
}
pc = prc->p_pcpsw.pc;
bp = prc->p_reg[BP_REG];
if (bp == 0)
{
printf("No active frame.\n");
return;
}
errno = 0;
do
{
symbolic(pc, '(');
pc = ptrace(T_GETDATA, curpid, bp+4, 0L);
off = ptrace(T_GETDATA, curpid, pc, 0L);
obp = bp;
bp += 2*sizeof(val);
if (ADDQ(off))
off = ADDQ_CNT(off) + bp;
else if (LEA(off))
off = LEA_DISP(off) + bp;
else if (ADDA(off))
off = ptrace(T_GETDATA, curpid, pc+2, 0L) + bp;
else
goto skiplp;
for (;;)
{
if (errno) return;
val = ptrace(T_GETDATA, curpid, bp, 0L) >> 16;
printf("0x%04x", (int)val);
bp += sizeof(int);
if (bp >= off) break;
putc(',', stdout);
}
skiplp:
fputs(")\n", stdout);
bp = ptrace(T_GETDATA, curpid, obp, 0L);
}
while (all && bp);
}
freepnt(pnt)
struct b_pnt *pnt;
{
if (pnt->prv) pnt->prv->nxt = pnt->nxt;
else b_head = pnt->nxt;
if (pnt->nxt) pnt->nxt->prv = pnt->prv;
if (curpid > 0) ptrace(T_SETINS, curpid, pnt->addr, pnt->oldval);
free(pnt);
if (pnt == curpnt) curpnt = 0;
}
breakpt(addr, cmd)
long addr;
char *cmd;
{
char *s;
struct b_pnt *new, *malloc();
int lng;
if (curpid <= 0)
{
printf("No active process.\n");
return;
}
for (new = b_head; new; new=new->nxt)
if (new->addr == addr)
{
printf("Breakpoint already exists here.\n");
return;
}
new = malloc(sizeof(struct b_pnt) + strlen(cmd));
if (new == 0)
{
printf("No room.\n");
return;
}
new->nxt = b_head;
new->prv = 0;
if (b_head) b_head->prv = new;
b_head = new;
new->addr = addr;
strcpy(new->cmd, cmd);
new->oldval = ptrace(T_GETINS, curpid, addr, 0L);
ptrace(T_SETINS, curpid, addr, BREAK(new->oldval));
if (ptrace(T_GETINS, curpid, addr, 0L) != BREAK(new->oldval))
{
perror("Can't set breakpoint");
freepnt(new);
}
}
modify(addr, cnt, verbose)
long addr;
{
long curval, off;
if (curpid == 0)
{
printf("No active process.\n");
return;
}
curval = ptrace(T_GETDATA, curpid, addr, 0L);
do
{
if (cursig == SIGTRAP) cursig = 0;
if (verbose)
{
off = ptrace(T_GETUSER, curpid, PC, 0L);
dasm(off, 1, 0);
}
if (curpnt && exebpnt(cursig)) return;
else
{
ptrace(T_STEP, curpid, addr, 0L);
switch (dowait())
{
case 0: return;
case SIGEMT: update(); findbpnt(0); break;
}
}
if (curval != ptrace(T_GETDATA, curpid, addr, 0L))
{
printf("Modification detected\n");
break;
}
}
while (--cnt);
update();
dasm(prc->p_pcpsw.pc, 1, 1);
return;
}
display(addr, req)
long addr;
{
int count, size, out, shift;
long val, msk;
char fmt;
if (curpid == 0)
{
printf("No active process\n");
return;
}
count = strtol(cmd, &cmd, 0);
if (count == 0) count = 1;
if (*cmd == 'i' || *cmd == 'I')
{
if (req == T_GETUSER)
{
printf("Can't disassemble a register's contents.\n");
longjmp(mainlp);
}
dasm(addr, count, *cmd == 'i');
return;
}
switch (*cmd++)
{
case 'b': size = sizeof(char); break;
case 'h': size = sizeof(short); break;
case 'l': size = sizeof(long); break;
default : size = sizeof(int); --cmd; break;
}
switch (fmt = *cmd)
{
case 'c': count *= size; size = sizeof(char); break;
case 's': addr = ptrace(req, curpid, addr, 0L); req = T_GETDATA;
case 'a': size = sizeof(char);
break;
}
out = 0;
msk = size == sizeof(long) ? 0xFFFFFFFF : (1L << (8*size)) - 1;
shift = 32 - 8*size;
do
{
val = (ptrace(req, curpid, addr, 0L) >> shift) & msk;
if (out == 0) printf("\n0x%08lx: ", addr);
switch (fmt)
{
case 'c':
printf(isprint(val) ? " %c " : "\\%03o ", (char)val);
if (++out == 8) out = 0;
break;
case 'u':
printf("%12lu ", val); if (++out == 4) out = 0; break;
case 'x':
printf("%*lx ", 2*size, val);
if (++out == (size == 4 ? 4 : 8)) out = 0;
break;
case 'o':
printf("%*lo ", 3*size, val);
if (++out == (size == 4 ? 4 : 8)) out = 0;
break;
case 's':
case 'a':
if (val) fputc((char)val, stdout);
else goto exitlp;
if (++out == 64) out = 0;
break;
default:
case 'd':
printf("%12ld ", val); if (++out == 4) out = 0; break;
}
addr += size;
}
while (--count > 0 || fmt == 's' || fmt == 'a');
exitlp:
fputc('\n', stdout);
}
fill(addr, req)
long addr;
{
int count, size, shift, seg;
long val, msk, nval;
char fmt;
if (curpid == 0)
{
printf("No active process\n");
return;
}
count = strtol(cmd, &cmd, 0);
switch (*cmd++)
{
case 'b': size = sizeof(char); break;
case 'h': size = sizeof(short); break;
case 'l': size = sizeof(long); break;
default : size = sizeof(int); --cmd; break;
}
shift = 32 - 8*size;
msk = (0x80000000 >> 8*size);
cmd = getexp(cmd, &nval, &seg);
nval <<= shift;
do
{
val = ptrace(req, curpid, addr, 0L) | (nval & msk);
val &= (nval | ~msk);
ptrace(req+3, curpid, addr, val);
addr += size;
}
while (--count>0);
}
command(savestr)
char *savestr;
{
char c, *p;
int i, seg;
long exp;
struct b_pnt *bp;
seg = S; /* don't restrict segment expressions are in */
cmdstart = cmd = skip(cmd);
cmd = getexp(cmd, &exp, &seg);
if (exp == 0)
{
seg = T;
exp = prc->p_pcpsw.pc;
}
switch (c = *cmd++)
{
case '!': /* escape to shell OR set variable to value */
if (cmd == cmdstart+1)
{
cmd = skip(cmd);
if (*cmd == '\n' || *cmd == ';')
{
i = run("/bin/sh", "\n", 0);
}
else
{
for (p=cmd+1; *p && !isspace(*p); p++) {};
*p++ = 0;
i = run(cmd, *p ? p : "\n", 0);
}
if (i > 0) while (wait(&seg) != i) {};
break;
}
if (seg == 'T')
{
printf("Can only modify data variables.\n");
break;
}
fill(exp, T_GETDATA);
break;
case 'T': /* top line of backtrace */
backtrace(0);
break;
case 't': /* back trace */
backtrace(1);
break;
case '/': /* print variable value */
display(exp, T_GETDATA);
break;
case 'x': /* print registers and instruction */
if (disp_regs()) break;
/*FALLTHROUGH*/
case 'X': /* print instruction */
i = strtol(cmd, &cmd, 0);
if (curpid > 0)
dasm(exp, i ? i : 1, 1);
else
printf("No active process.\n");
break;
case 'R': /* run program with no args */
case 'r': /* run program with args (possibly defaulted) */
tstart(T_EXIT, 0, 0, 0);
if (c == 'r')
{
cmd = skip(cmd);
if (*cmd == '\n' || *cmd == ';') cmd = sbuf;
else strcpy(sbuf, cmd);
}
else
{
cmd = "\n";
}
if (curpid = run(prog, cmd, 1))
{
if (dowait())
{
ptrace(T_SETUSER, curpid, REG(BP_REG), 0L);
update();
printf("Process stopped.\n");
}
}
break;
case 'c': /* continue program - ignore signal */
cursig = 0;
case 'C': /* continue program - handle signal */
i = 0;
if (seg == T && curpnt == 0 && cmd != cmdstart+1)
{
breakpt(exp, "\n");
curpnt = b_head;
ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval);
i = 1;
}
tstart(T_RESUME, 1, cursig, (int)strtol(cmd, &cmd, 0));
if (i) /* remove temporary bp */
{
freepnt(b_head);
}
if (cursig == SIGEMT) return;
if (curpid) printf("Process stopped by signal %d\n", cursig);
break;
case 'i': /* single step - ignore signal */
tstart(T_STEP, 1, 0, (int)strtol(cmd, &cmd, 0));
break;
case 'I': /* single step - handle signal */
tstart(T_STEP, 1, cursig, (int)strtol(cmd, &cmd, 0));
break;
case 'm': /* single step until location modified */
case 'M': /* single step until location modified - verbose */
modify(exp, (int)strtol(cmd, &cmd, 0), c == 'M');
break;
case 'k': /* kill current program */
tstart(T_EXIT, 1, 0, 0);
break;
case 'b': /* set a breakpoint at the given line */
if (seg == D)
{
printf("Address not in text space.\n");
return;
}
breakpt(exp, skip(cmd));
cmd = "\n";
return;
case 'B': /* print list of currently active breakpoints */
for (i = 1, bp = b_head; bp; bp=bp->nxt, i++)
{
p = addr_to_name(bp->addr - saddr, &exp);
printf("%2d: %s+0x%lx (0x%lx) - %s",
i, p, exp, bp->addr, bp->cmd);
}
break;
case 'd': /* delete breakpoint */
if (seg == T)
{
for (bp = b_head; bp && --exp; bp=bp->nxt) {};
if (bp) { freepnt(bp); break; }
}
printf("No such breakpoint.\n");
break;
case 'D': /* delete all breakpoints */
while(b_head) freepnt(b_head);
break;
case 'q': /* quit */
tstart(T_EXIT, 0, 0, 0L, 0);
exit(0);
case '\n':
case ';':
if (isdigit(*cmdstart)) symbolic(exp, '\n');
else printf("0x%lx\n", exp);
--cmd;
break;
case '$':
cmdstart = cmd;
cmd = skip(cmd+2);
if (*cmd == '!')
{
cmd++;
fill(reg_addr(cmdstart), T_GETUSER);
break;
}
if (*skip(cmd+2) == '/')
{
cmd++;
display(reg_addr(cmdstart), T_GETUSER);
break;
}
/*FALLTHROUGH*/
default:
printf("Unknown command.\n");
break;
}
while (*cmd != '\n' && *cmd != ';') ++cmd;
if (*cmd == ';') cmd = skip(cmd+1);
}
main(argc, argv)
char *argv[];
{
int i;
prc = lbuf;
for (i = 1; i < NSIG; i++) signal(i, catch);
strcpy(sbuf, "\n");
prog = argc > 1 ? argv[1] : "a.out";
if (argc > 2) getsyms(argv[2]);
setjmp(&mainlp);
while ((printf("* "), fflush(stdout),
fgets(cbuf, sizeof(cbuf), stdin)) != EOF)
{
if (strlen(cbuf) == sizeof(cbuf)-1)
{
printf("Command line too long.\n");
continue;
}
cmd = cbuf;
command();
while (*cmd != '\n') command();
}
tstart(T_EXIT, 0, 0, 0);
exit(0);
}bds@lzaz.ATT.COM (B.SZABLAK) (12/22/88)
/*
* dbexp.c - MINIX expresion parser
*
* Written by Bruce D. Szablak
*
* This free software is provided for non-commerical use. No warrantee
* of fitness for any use is implied. You get what you pay for. Anyone
* may make modifications and distribute them, but please keep this header
* in the distribution. NOTE: A PORTION OF THIS FILE IS DERIVED FROM THE
* SOURCE TO ANM.C. BEWARE THAT OTHER RESTRICTIONS MAY APPLY.
*/
#include <ctype.h>
#include <setjmp.h>
#include <stdio.h>
#include "user.h"
#include "out.h"
extern jmp_buf mainlp;
extern curpid;
int nsyms;
struct outname *nbufp = NULL;
long value(), strtol(), lookup(), ptrace();
#define idchar(c) (isalpha(c) || isdigit(c) || (c) == '_')
char *
addr_to_name(rel_addr, off_p)
long rel_addr, *off_p;
{
register int i, l = 0, r = nsyms;
do
{
i = (l + r) >> 1;
if (rel_addr < nbufp[i].on_valu) r = i;
else if (rel_addr > nbufp[i].on_valu) l = i + 1;
else break;
}
while (l < r);
if (l == nsyms || r == 0)
{
*off_p = rel_addr;
return "_start";
}
if (rel_addr < nbufp[i].on_valu) i--;
*off_p = rel_addr - nbufp[i].on_valu;
return nbufp[i].on_mptr;
}
symbolic(addr, sep)
long addr;
char sep;
{
long off;
extern long saddr, eaddr;
if (addr < saddr || addr > eaddr)
{
printf("0x%lx%c", addr, sep);
return;
}
fputs(addr_to_name(addr - saddr, &off), stdout);
if (off) printf("+0x%lx", off);
fputc(sep, stdout);
}
char *
getexp(buf, exp_p, seg_p)
char *buf;
int *seg_p;
long *exp_p;
{
extern char *skip();
long v = 0L;
buf = skip(buf);
if ((isalpha(*buf) && (isspace(buf[1]) || buf[1]==';'))
|| *buf=='\n' || *buf==';' || *buf=='/' || *buf == '!')
{
*exp_p = 0L;
return buf;
}
v = value(buf, &buf, seg_p);
buf = skip(buf);
if (*buf == '+')
{
v += value(skip(buf+1), &buf, seg_p);
}
else if (*buf == '-')
{
v -= value(skip(buf+1), &buf, seg_p);
}
*exp_p = v;
return skip(buf);
}
long
reg_addr(s)
char *s;
{
long val;
switch (*s++)
{
case 'a': case 'A': val = 32; break;
case 'd': case 'D': val = 0; break;
default: goto error;
}
if (*s >= '0' && *s <= '7')
{
return val + 4*(*s - '0');
}
error:
printf("Unknown register: %2.2s\n", s);
longjmp(mainlp);
}
long
value(s, s_p, seg_p)
char *s, **s_p;
int *seg_p;
{
long k;
if (*s == '\'') /* handle character constants here */
{
*s_p = s + 2;
return s[1];
}
if (*s == '-' || isdigit(*s))
{
return strtol(s, s_p, 0);
}
if (*s == '$')
{
k = reg_addr(s+1);
*s_p = s + 3;
return ptrace(3, curpid, k, 0L);
}
return lookup(s, s_p, seg_p);
}
long
lookup(s, s_p, seg_p)
char *s, **s_p;
int *seg_p;
{
extern long saddr;
char c;
int i, l;
for (l = 1; idchar(s[l]); ++l ) {}
c = s[l]; s[l] = 0;
if (strcmp("_start", s) == 0)
{
*seg_p = T;
*(*s_p = s + 6) = c;
return saddr;
}
for (i = 0; i < nsyms; i++)
if (strcmp(nbufp[i].on_mptr, s) == 0)
{
*seg_p = (nbufp[i].on_type & S_TYP) == S_MIN ? T : D;
*(*s_p = s + l) = c;
return nbufp[i].on_valu + saddr;
}
printf("%s: symbol not found\n", s);
longjmp(mainlp);
}
/******************END OF ORIGINAL CODE***********************/
/*
* The following code is actually a highly edited
* version of anm.c - The ACK version of nm
* That file's header follows:
*/
/* @(#)anm.c 1.6 */
/*
** print symbol tables for
** ACK object files
**
** anm [-gopruns] [name ...]
*/
#define ushort unsigned short
#define ushort unsigned short
long off;
char *malloc();
char *realloc();
long s_base[S_MAX]; /* for specially encoded bases */
getsyms(file)
char *file;
{
int compare();
FILE *fi;
struct outsect sbuf;
struct outhead hbuf;
struct outname nbuf;
char *cbufp;
long fi_to_co;
long n;
unsigned readcount;
int j;
fi = fopen(file,"r");
if (fi == NULL) {
fprintf(stderr, "db: cannot open %s\n", file);
return;
}
getofmt((char *)&hbuf, SF_HEAD, fi);
if (BADMAGIC(hbuf)) {
fprintf(stderr, "db: %s-- bad format\n", file);
fclose(fi);
return;
}
n = hbuf.oh_nname;
if (n == 0) {
fprintf(stderr, "db: %s-- no name list\n", file);
fclose(fi);
return;
}
if (hbuf.oh_nchar == 0) {
fprintf(stderr, "db: %s-- no names\n", file);
fclose(fi);
return;
}
if ((readcount = hbuf.oh_nchar) != hbuf.oh_nchar) {
fprintf(stderr, "db: string area too big in %s\n", file);
exit(2);
}
/* store special section bases */
if (hbuf.oh_flags & HF_8086) {
int i;
for (i=0; i<hbuf.oh_nsect; i++) {
getofmt((char *)&sbuf, SF_SECT, fi);
s_base[i+S_MIN] =
(sbuf.os_base>>12) & 03777760;
}
}
if ((cbufp = (char *)malloc(readcount)) == NULL) {
fprintf(stderr, "db: out of memory on %s\n", file);
exit(2);
}
fseek(fi, OFF_CHAR(hbuf), 0);
if (fread(cbufp, 1, readcount, fi) == 0) {
fprintf(stderr, "db: read error on %s\n", file);
exit(2);
}
fi_to_co = (long)cbufp - OFF_CHAR(hbuf);
fseek(fi, OFF_NAME(hbuf), 0);
nsyms = 0;
while (--n >= 0) {
getofmt((char *)&nbuf, SF_NAME, fi);
if (nbuf.on_foff == 0)
continue; /* skip entries without names */
if ((nbuf.on_type&S_EXT)==0)
continue;
nbuf.on_mptr = (char *)(nbuf.on_foff + fi_to_co);
/* adjust value for specially encoded bases */
if (hbuf.oh_flags & HF_8086) {
if (((nbuf.on_type&S_ETC) == 0) ||
((nbuf.on_type&S_ETC) == S_SCT)) {
j = nbuf.on_type&S_TYP;
if ((j>=S_MIN) && (j<=S_MAX))
nbuf.on_valu += s_base[j];
}
}
if (nbufp == NULL)
nbufp = (struct outname *)malloc(sizeof(struct outname));
else
nbufp = (struct outname *)realloc(nbufp, (nsyms+1)*sizeof(struct outname));
if (nbufp == NULL) {
fprintf(stderr, "db: out of memory on %s\n", file);
exit(2);
}
nbufp[nsyms++] = nbuf;
}
qsort(nbufp, nsyms, sizeof(struct outname), compare);
fclose(fi);
}
compare(p1, p2)
struct outname *p1, *p2;
{
if (p1->on_valu < p2->on_valu) return -1;
if (p1->on_valu > p2->on_valu) return 1;
return 0;
}
getofmt(p, s, f)
register char *p;
register char *s;
register FILE *f;
{
register i;
register long l;
for (;;) {
switch (*s++) {
/* case '0': p++; continue; */
case '1':
*p++ = getc(f);
continue;
case '2':
i = getc(f);
i |= (getc(f) << 8);
*((short *)p) = i; p += sizeof(short);
continue;
case '4':
l = (long)getc(f);
l |= ((long)getc(f) << 8);
l |= ((long)getc(f) << 16);
l |= ((long)getc(f) << 24);
*((long *)p) = l; p += sizeof(long);
continue;
default:
case '\0':
break;
}
break;
}
}bds@lzaz.ATT.COM (B.SZABLAK) (12/22/88)
/*
* mdbdis.c - MINIX program disassembler for the debugger
*
* Written by Bruce D. Szablak
*
* This free software is provided for non-commerical use. No warrantee
* of fitness for any use is implied. You get what you pay for. Anyone
* may make modifications and distribute them, but please keep this header
* in the distribution.
*/
#include <stdio.h>
#define BYTE 0
#define WORD 1
#define LONG 2
#define BFIELD(w,b,l) (((w) >> ((b)-(l)+1)) & (int)((1L<<(l))-1))
#define BTST(w,b) ((w) & (1 << (b)))
char opwfmt[] = "%s.%c\t";
#define OPI(s,w) printf(opwfmt, s, w)
char size[] = "bwl";
char *cc[] = {"ra", "f", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs",
"pl", "mi", "ge", "lt", "gt", "le" };
char *bitop[] = { "btst", "bchg", "bclr", "bset" };
char *imedop[] = { "ori", "andi", "subi", "addi", "?", "eori", "cmpi" };
char *misc1[] = { "negx", "clr", "neg", "not" };
char *misc2[] = { "reset", "nop", "stop", "rte", "??", "rts", "trapv", "rtr" };
char *shf[] = { "as", "ls", "rox", "ro" };
char *fmts[] = { "d%d", "a%d", "(a%d)", "(a%d)+", "-(a%d)" };
extern curpid;
extern char *addr_to_name();
extern long saddr, eaddr;
long gaddr, gbuf, ptrace();
int gempty, gisize, gjmp;
short
gword()
{
if (gempty)
{
gempty = 0;
gbuf = ptrace(1, curpid, gaddr, 0L);
gaddr += 2;
return gbuf >> 16;
}
gempty = 1;
gaddr += 2;
return gbuf;
}
long
glong()
{
gempty = 1;
gbuf = ptrace(1, curpid, gaddr, 0L);
gaddr += 4;
return gbuf;
}
reladdr(sep)
char sep;
{
int d = gword();
symbolic(gaddr + d - 2, sep);
}
movem(from, predec, rmsk)
{
int b, f = 0;
if (!from) putc(',', stdout);
for (b = 16; b--; rmsk >>= 1)
{
if (rmsk & 1)
{
if (f) putc('/', stdout);
else f = 1;
if (predec) printf("%c%d", b>7 ? 'a' : 'd', b % 8);
else printf("%c%d", b>7 ? 'd' : 'a', 7 - b % 8);
}
}
if (from) putc(',', stdout);
}
op1(mode,reg)
{
int d;
char *s;
long l;
if (mode < 5)
{
printf(fmts[mode], reg);
return;
}
if (mode == 5)
{
printf("%d(a%d)", gword(), reg);
return;
}
if (mode == 6)
{
d = gword();
printf("%d(a%d,%c%d.%c)",
BFIELD(d,7,8) | (BTST(d,7) ? 0xFF00 : 0), reg,
BTST(d,15) ? 'a' : 'd', BFIELD(d,14,3),
BTST(d,11) ? 'l' : 'w');
return;
}
switch (reg)
{
case 0: printf("%d", gword()); break;
case 1: symbolic(glong(), '\0'); break;
case 2: l = gaddr;
printf("%d(pc) {", d = gword());
symbolic(l+d, '}');
break;
case 3: d = gword();
printf("%d(pc,%c%d.%c)",
BFIELD(d,7,8) | (BTST(d,7) ? 0xFF00 : 0),
BTST(d,15) ? 'a' : 'd', BFIELD(d,14,3),
BTST(d,11) ? 'l' : 'w');
break;
case 4: putc('#', stdout);
if (gisize == LONG) symbolic(glong(), '\0');
else if (gisize == BYTE) printf("%d", (char)gword());
else printf("%d", gword());
break;
case 5: printf("sr"); break;
}
}
op2(f,m1,r1,m2,r2) /* f set means order passed, clear reverses order */
{
if (f) op1(m1,r1); else op1(m2,r2);
putc(',',stdout);
if (f) op1(m2,r2); else op1(m1,r1);
}
opmode(op, opm, reg, m, r)
char *op;
{
OPI(op, size[gisize=BFIELD(opm,1,2)]);
op2(BTST(opm,2),0,reg,m,r);
}
long
dasm(addr,cnt, symflg)
long addr;
{
int tflg = 0;
register unsigned int w, m1, m2, r1, r2, op;
char ds;
gaddr = addr; gempty = 1;
while (tflg || cnt--)
{
tflg = 0;
if (symflg) symbolic(gaddr, '\t');
else printf("0x%lx ", gaddr);
w = gword();
m1 = BFIELD(w,8,3); m2 = BFIELD(w,5,3);
r1 = BFIELD(w,11,3); r2 = BFIELD(w,2,3);
op = BFIELD(w,15,4);
switch (op)
{
case 0x0:
if (m2 == 1)
{
OPI("movep", BTST(w,6) ? 'l' : 'w');
op2(BTST(w,7),0,r1,5,r2);
break;
}
if (BTST(w,8))
{
OPI(bitop[BFIELD(w,7,2)], m2 ? 'b' : 'l');
op2(1,0,r1,m2,r2);
break;
}
if (r2 == 4)
{
OPI(bitop[BFIELD(w,7,2)], m2 ? 'b' : 'l');
gisize = WORD;
op2(1,7,4,m2,r2);
break;
}
OPI(imedop[r1],size[gisize = m1]);
op2(1,7,4,m2,r2);
break;
case 0x1:
gisize = BYTE; goto domove;
case 0x2:
gisize = LONG; goto domove;
case 0x3:
gisize = WORD;
domove:
OPI("move", size[gisize]);
op2(1,m2,r2,m1,r1);
break;
case 0x4:
if (BTST(w,8))
{
if (BTST(w,6))
{
printf("lea\t");
op1(m2,r2);
printf(",a%d", r1);
break;
}
printf("chk\t");
op1(m2,r2);
printf(",d%d", r1);
break;
}
if (r1 < 4)
{
if (m1 == 3)
{
printf("move\t");
gisize = WORD;
if (r1 == 0) printf("sr,");
op1(m2,r2);
if (r1 == 2) printf(",ccr");
if (r1 == 3) printf(",sr");
break;
}
OPI(misc1[r1], size[m1]);
op1(m2,r2);
break;
}
else if (r1 == 4)
{
switch(m1)
{
case 0: printf("nbcd\t"); break;
case 1: printf(m2 ? "pea\t" : "swap\t"); break;
case 2:
case 3: OPI(m2 ? "movem" : "ext",
BTST(w,6) ? 'l' : 'w');
if (m2) movem(1,m2==4, gword());
break;
}
op1(m2,r2);
break;
}
if (r1 == 5)
{
if (m1 == 3) printf("tas\t");
else OPI("tst", size[m1]);
op1(m2,r2);
break;
}
if (r1 == 6)
{
OPI("movem", BTST(w,6) ? 'l' : 'w');
op = gword();
op1(m2,r2);
movem(0,m2==4,op);
break;
}
if (BTST(w,7))
{
printf(BTST(w,6) ? "jmp\t" : "jsr\t");
op1(m2,r2);
break;
}
switch (m2)
{
case 0:
case 1: printf("trap\t#%d", BFIELD(w,3,4));
tflg = 1;
break;
case 2: printf("link\ta%d,#%d", r2, gword()); break;
case 3: printf("unlk\ta%d", r2); break;
case 4: printf("move.l a%d,usp", r2); break;
case 5: printf("move.l usp,a%d", r2); break;
case 6: printf(misc2[r2]); break;
}
break;
case 0x5:
if (BFIELD(w,7,2) == 3)
{
op = BFIELD(w,11,4);
if (m2 == 1)
{
printf("db%s\td%d,",cc[op], r2);
reladdr('\0');
}
else
{
printf("s%s\t",cc[op]);
op1(m2,r2);
}
}
else
{
printf("%sq\t#%d,",BTST(w,8)?"sub":"add",
((r1 - 1) & 7) + 1);
op1(m2,r2);
}
break;
case 0x6:
ds = BFIELD(w,7,8);
printf("b%s.%c\t", cc[BFIELD(w,11,4)], ds ? 's' : 'w');
if (m1) symbolic(gaddr+ds);
else reladdr('\0');
break;
case 0x7:
printf("moveq\t#%d,d%d",BFIELD(w,7,8),r1);
break;
case 0x8:
if (m1 == 3 || m1 == 7)
{
printf("div%c\t", BTST(w,8) ? 's' : 'u');
op2(0,0,r1,m2,r2);
}
else if (m1 == 4 && (m2 == 1 || m2 == 0))
{
printf(m2 ? "sbcd\t-(a%d),-(a%d)"
: "sbcd\td%d,d%d", r2, r1);
}
else
{
opmode("or",m1,r1,m2,r2);
}
break;
case 0x9:
case 0xD:
if ((m2 == 0 || m2 == 1) && m1 > 3 && m1 < 7)
{
OPI(op == 9 ? "subx" : "addx",
size[BFIELD(w,7,2)]);
m2 <<= 2;
op2(1,m2,r2,m2,r1);
}
else if (m1 == 3 || m1 == 7)
{
gisize = m1 == 3 ? WORD : LONG;
OPI(op==9 ? "sub" : "add", size[gisize]);
op2(1,m2,r2,1,r1);
}
else
{
opmode(op==9 ? "sub" : "add",m1,r1,m2,r2);
}
break;
case 0xB:
if (BTST(w,8))
{
if (m2 == 1)
{
OPI("cmpm", size[BFIELD(w,7,2)]);
printf("(a%d)+,(a%d)+",r2,r1);
}
else
{
opmode("eor",m1,r1,m2,r2);
}
}
else
{
opmode("cmp",m1,r1,m2,r2);
}
break;
case 0xC:
if (m1 == 3 || m1 == 7)
{
printf("mul%c\t", m1==7 ? 's' : 'u');
op2(0,0,r1,m2,r2);
}
else if (m1 == 4 && (m2 == 1 || m2 == 0))
{
printf(m2 ? "abcd\t-(a%d),-(a%d)"
: "abcd\td%d,d%d", r2, r1);
}
else if (m1 == 5)
{
op = BTST(w,3) ? 'a' : 'd';
printf("exg\t%c%d,%c%d",op,r1,op,r2);
}
else if (m1 == 6)
{
printf("exg\td%d,a%d",r1,r2);
}
else
{
opmode("and",m1,r1,m2,r2);
}
break;
case 0xE:
if (BFIELD(w,7,2) == 3)
{
printf("%s%c\t",shf[BFIELD(w,10,2)],
BTST(w,8) ? 'l' : 'r');
op1(m2,r2);
}
else
{
printf("%s%c\t",shf[BFIELD(w,4,2)],
BTST(w,8) ? 'l' : 'r');
if (BTST(w,5))
{
op2(1,0,r1,0,r2);
}
else
{
printf("#%d,",r1);
op1(0,r2);
}
}
break;
case 0xA:
case 0xF:
printf("%x", w);
break;
}
putc('\n',stdout);
}
return gaddr;
}Steinsbo%hsr.uninett%NORUNIX.BITNET@cunyvm.cuny.edu (Bjarne Steinsbo) (01/04/89)
>X-Originator: "B.SZABLAK" <bds@lzaz.att.com> >X-Bitnet-Sender: info-minix-request@UDEL.EDU >Organization: AT&T ISL Lincroft NJ USA /* * mdb.c - MINIX program debugger * * Written by Bruce D. Szablak * * This free software is provided for non-commerical use. No warrantee * of fitness for any use is implied. You get what you pay for. Anyone * may make modifications and distribute them, but please keep this header * in the distribution. */ #define T_OK 0 #define T_GETINS 1 #define T_GETDATA 2 #define T_GETUSER 3 #define T_SETINS 4 #define T_SETDATA 5 #define T_SETUSER 6 #define T_RESUME 7 #define T_EXIT 8 #define T_STEP 9 #include "stdio.h" #include "signal.h" #include "ctype.h" #include "setjmp.h" #include "user.h" struct proc *prc; #define BP_REG 14 #define MAXLINE 120 #define REG(r) ((long)&((struct proc *)0)->p_regr|) #define PC ((long)&((struct proc *)0)->p_pcpsw.pc) #define MAXB 10 #define MAXP 3 #define MAXARG 20 #define SIZ (1 + sizeof(struct proc)/sizeof(long)) #define MAXLINE 120 long ptrace(), strtol(), reg_addr(), lbufSIZ|, saddr, eaddr, dasm(); int curpid, cursig; char *strcpy(), *prog, sbufMAXLINE|, cbufMAXLINE|, *cmd, *addr_to_name(), *getexp(), *cmdstart; jmp_buf mainlp; extern errno; struct b_pnt { struct b_pnt *nxt, *prv; long addr; long oldval; char cmd1|; } *b_head, *curpnt; cleanup() { curpid = 0; curpnt = 0; while (b_head) freepnt(b_head); } dowait() { int stat, ls, hs; while (wait(&stat) != curpid) {}; ls = stat & 0xFF; hs = (stat >> 8) & 0xFF; if (ls == 0) { if (hs != 127) printf("child exited with status %d\n", hs); cleanup(); return 0; } if (hs == 0) { printf("child terminated by signal %d\n", ls & 0x7F); if (ls & 0x80) printf("(core dumped)\n"); cleanup(); return 0; } return cursig = hs; } update() { int i; for (i = 0; i < (SIZ-1); i++) { lbufi| = ptrace(T_GETUSER, curpid, (long)(i*sizeof(long)),0L); } saddr = (long)prc->p_mapT|.mem_vir << CLICK_SHIFT; eaddr = (long)(prc->p_mapD|.mem_vir + prc->p_mapD|.mem_len) << CLICK_SHIFT; } findbpnt(verbose) { for (curpnt = b_head; curpnt; curpnt = curpnt->nxt) { if (curpnt->addr == prc->p_pcpsw.pc) { ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); if (curpnt->cmd0| != '\n') cmd = strcpy(cbuf, curpnt->cmd); else if (verbose) printf("Breakpoint hit.\n"); return; } } if (verbose) printf("Unknown breakpoint hit.\n"); } disp_regs() { int i; if (curpid <= 0) { printf("No active process.\n"); return 1; } printf("\npc=%lx psw=%x\n\n",(long)prc->p_pcpsw.pc, prc->p_pcpsw.psw); printf( " 0 1 2 3 4 5 6 7\nD"); for (i = 0; i < 8; i++) printf(" %08lx", prc->p_regi|); printf("\nA"); for (; i < NR_REGS; i++) printf(" %08lx", prc->p_regi|); printf(" %08lx\n\n", (long)prc->p_sp); return 0; } char * skip(s) register char *s; { while (isspace(*s)) ++s; return *s ? s : s-1; } endcmd() { while (*cmd != '\n' && *cmd != ';') ++cmd; } #define BREAK(l) (0xA0000000 | ((l) & 0xFFFF)) exebpnt(restart) { ptrace(T_STEP, curpid, 0L, (long)restart); if (dowait() == 0) return 1; ptrace(T_SETINS, curpid, curpnt->addr, BREAK(curpnt->oldval)); curpnt = 0; return 0; } tstart(req, verbose, val, cnt) { if (curpid == 0) { if (verbose) printf("No active process.\n"); return; } if (req == T_EXIT) { ptrace(T_EXIT, curpid, 0L, (long)val); dowait(); return; } if (cnt==0) cnt = 1; do { if (curpnt) { if (exebpnt(val)) return; if (req == T_RESUME) cnt++; val = 0; } else { ptrace(req, curpid, 0L, (long)val); if (dowait() == 0) return; val = 0; switch (cursig) { case SIGEMT: /* breakpoint */ update(); findbpnt(cnt <= 1); break; case SIGTRAP: /* trace trap? */ if (req == T_STEP) break; default: /* signal */ val = cursig; break; } } } while (--cnt > 0); update(); dasm((long)prc->p_pcpsw.pc, 1, 1); } catch(sig) { signal(sig, catch); if (sig == SIGINT || sig == SIGQUIT) return; tstart(T_EXIT, 0, sig, 0); exit(0); } run(name, argstr, tflg) char *name, *argstr; { int procid; if( (procid = fork()) == 0 ) { char *argvMAXARG|, *inf = 0, *outf = 0; int argc; if (tflg && ptrace(T_OK, 0, 0L, 0L) < 0) { perror("ptrace"); exit(127); } argv0| = name; for (argc = 1; ; ) { argstr = skip(argstr); if (*argstr == '\n' || *argstr == ';') { argvargc| = 0; if (inf) freopen(inf, "r", stdin); if (outf) freopen(outf, "w", stdout); execv(name, argv); perror("execv"); exit( 127 ); } if (*argstr == '<') inf = argstr+1; else if (*argstr == '>') outf = argstr+1; else if (argc == MAXARG) { printf("Too many arguments.\n"); exit(127); } else argvargc++| = argstr; while (!isspace(*argstr)) argstr++; if (*argstr == '\n') argstr1| = '\n', argstr2| = 0; *argstr++ = 0; } } if (procid < 0) { printf("Fork failed.\n"); } return procid; } #define ADDQ(l) (((l >> 16) & 0xF1FF) == 0x508F) #define ADDQ_CNT(l) ((((l >> 25) - 1) & 7) + 1) #define LEA(l) ((l >> 16) == 0x4FEF) #define LEA_DISP(l) ((long)(int)l) #define ADDA(l) ((int)(l >> 16) == 0xDFFC) backtrace(all) { char sep; long pc, bp, off, val, obp; if (curpid <= 0) { printf("No process.\n"); return; } pc = prc->p_pcpsw.pc; bp = prc->p_regBP_REG|; if (bp == 0) { printf("No active frame.\n"); return; } errno = 0; do { symbolic(pc, '('); pc = ptrace(T_GETDATA, curpid, bp+4, 0L); off = ptrace(T_GETDATA, curpid, pc, 0L); obp = bp; bp += 2*sizeof(val); if (ADDQ(off)) off = ADDQ_CNT(off) + bp; else if (LEA(off)) off = LEA_DISP(off) + bp; else if (ADDA(off)) off = ptrace(T_GETDATA, curpid, pc+2, 0L) + bp; else goto skiplp; for (;;) { if (errno) return; val = ptrace(T_GETDATA, curpid, bp, 0L) >> 16; printf("0x%04x", (int)val); bp += sizeof(int); if (bp >= off) break; putc(',', stdout); } skiplp: fputs(")\n", stdout); bp = ptrace(T_GETDATA, curpid, obp, 0L); } while (all && bp); } freepnt(pnt) struct b_pnt *pnt; { if (pnt->prv) pnt->prv->nxt = pnt->nxt; else b_head = pnt->nxt; if (pnt->nxt) pnt->nxt->prv = pnt->prv; if (curpid > 0) ptrace(T_SETINS, curpid, pnt->addr, pnt->oldval); free(pnt); if (pnt == curpnt) curpnt = 0; } breakpt(addr, cmd) long addr; char *cmd; { char *s; struct b_pnt *new, *malloc(); int lng; if (curpid <= 0) { printf("No active process.\n"); return; } for (new = b_head; new; new=new->nxt) if (new->addr == addr) { printf("Breakpoint already exists here.\n"); return; } new = malloc(sizeof(struct b_pnt) + strlen(cmd)); if (new == 0) { printf("No room.\n"); return; } new->nxt = b_head; new->prv = 0; if (b_head) b_head->prv = new; b_head = new; new->addr = addr; strcpy(new->cmd, cmd); new->oldval = ptrace(T_GETINS, curpid, addr, 0L); ptrace(T_SETINS, curpid, addr, BREAK(new->oldval)); if (ptrace(T_GETINS, curpid, addr, 0L) != BREAK(new->oldval)) { perror("Can't set breakpoint"); freepnt(new); } } modify(addr, cnt, verbose) long addr; { long curval, off; if (curpid == 0) { printf("No active process.\n"); return; } curval = ptrace(T_GETDATA, curpid, addr, 0L); do { if (cursig == SIGTRAP) cursig = 0; if (verbose) { off = ptrace(T_GETUSER, curpid, PC, 0L); dasm(off, 1, 0); } if (curpnt && exebpnt(cursig)) return; else { ptrace(T_STEP, curpid, addr, 0L); switch (dowait()) { case 0: return; case SIGEMT: update(); findbpnt(0); break; } } if (curval != ptrace(T_GETDATA, curpid, addr, 0L)) { printf("Modification detected\n"); break; } } while (--cnt); update(); dasm(prc->p_pcpsw.pc, 1, 1); return; } display(addr, req) long addr; { int count, size, out, shift; long val, msk; char fmt; if (curpid == 0) { printf("No active process\n"); return; } count = strtol(cmd, &cmd, 0); if (count == 0) count = 1; if (*cmd == 'i' || *cmd == 'I') { if (req == T_GETUSER) { printf("Can't disassemble a register's contents.\n"); longjmp(mainlp); } dasm(addr, count, *cmd == 'i'); return; } switch (*cmd++) { case 'b': size = sizeof(char); break; case 'h': size = sizeof(short); break; case 'l': size = sizeof(long); break; default : size = sizeof(int); --cmd; break; } switch (fmt = *cmd) { case 'c': count *= size; size = sizeof(char); break; case 's': addr = ptrace(req, curpid, addr, 0L); req = T_GETDATA; case 'a': size = sizeof(char); break; } out = 0; msk = size == sizeof(long) ? 0xFFFFFFFF : (1L << (8*size)) - 1; shift = 32 - 8*size; do { val = (ptrace(req, curpid, addr, 0L) >> shift) & msk; if (out == 0) printf("\n0x%08lx: ", addr); switch (fmt) { case 'c': printf(isprint(val) ? " %c " : "\\%03o ", (char)val); if (++out == 8) out = 0; break; case 'u': printf("%12lu ", val); if (++out == 4) out = 0; break; case 'x': printf("%*lx ", 2*size, val); if (++out == (size == 4 ? 4 : 8)) out = 0; break; case 'o': printf("%*lo ", 3*size, val); if (++out == (size == 4 ? 4 : 8)) out = 0; break; case 's': case 'a': if (val) fputc((char)val, stdout); else goto exitlp; if (++out == 64) out = 0; break; default: case 'd': printf("%12ld ", val); if (++out == 4) out = 0; break; } addr += size; } while (--count > 0 || fmt == 's' || fmt == 'a'); exitlp: fputc('\n', stdout); } fill(addr, req) long addr; { int count, size, shift, seg; long val, msk, nval; char fmt; if (curpid == 0) { printf("No active process\n"); return; } count = strtol(cmd, &cmd, 0); switch (*cmd++) { case 'b': size = sizeof(char); break; case 'h': size = sizeof(short); break; case 'l': size = sizeof(long); break; default : size = sizeof(int); --cmd; break; } shift = 32 - 8*size; msk = (0x80000000 >> 8*size); cmd = getexp(cmd, &nval, &seg); nval <<= shift; do { val = ptrace(req, curpid, addr, 0L) | (nval & msk); val &= (nval | ~msk); ptrace(req+3, curpid, addr, val); addr += size; } while (--count>0); } command(savestr) char *savestr; { char c, *p; int i, seg; long exp; struct b_pnt *bp; seg = S; /* don't restrict segment expressions are in */ cmdstart = cmd = skip(cmd); cmd = getexp(cmd, &exp, &seg); if (exp == 0) { seg = T; exp = prc->p_pcpsw.pc; } switch (c = *cmd++) { case '!': /* escape to shell OR set variable to value */ if (cmd == cmdstart+1) { cmd = skip(cmd); if (*cmd == '\n' || *cmd == ';') { i = run("/bin/sh", "\n", 0); } else { for (p=cmd+1; *p && !isspace(*p); p++) {}; *p++ = 0; i = run(cmd, *p ? p : "\n", 0); } if (i > 0) while (wait(&seg) != i) {}; break; } if (seg == 'T') { printf("Can only modify data variables.\n"); break; } fill(exp, T_GETDATA); break; case 'T': /* top line of backtrace */ backtrace(0); break; case 't': /* back trace */ backtrace(1); break; case '/': /* print variable value */ display(exp, T_GETDATA); break; case 'x': /* print registers and instruction */ if (disp_regs()) break; /*FALLTHROUGH*/ case 'X': /* print instruction */ i = strtol(cmd, &cmd, 0); if (curpid > 0) dasm(exp, i ? i : 1, 1); else printf("No active process.\n"); break; case 'R': /* run program with no args */ case 'r': /* run program with args (possibly defaulted) */ tstart(T_EXIT, 0, 0, 0); if (c == 'r') { cmd = skip(cmd); if (*cmd == '\n' || *cmd == ';') cmd = sbuf; else strcpy(sbuf, cmd); } else { cmd = "\n"; } if (curpid = run(prog, cmd, 1)) { if (dowait()) { ptrace(T_SETUSER, curpid, REG(BP_REG), 0L); update(); printf("Process stopped.\n"); } } break; case 'c': /* continue program - ignore signal */ cursig = 0; case 'C': /* continue program - handle signal */ i = 0; if (seg == T && curpnt == 0 && cmd != cmdstart+1) { breakpt(exp, "\n"); curpnt = b_head; ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); i = 1; } tstart(T_RESUME, 1, cursig, (int)strtol(cmd, &cmd, 0)); if (i) /* remove temporary bp */ { freepnt(b_head); } if (cursig == SIGEMT) return; if (curpid) printf("Process stopped by signal %d\n", cursig); break; case 'i': /* single step - ignore signal */ tstart(T_STEP, 1, 0, (int)strtol(cmd, &cmd, 0)); break; case 'I': /* single step - handle signal */ tstart(T_STEP, 1, cursig, (int)strtol(cmd, &cmd, 0)); break; case 'm': /* single step until location modified */ case 'M': /* single step until location modified - verbose */ modify(exp, (int)strtol(cmd, &cmd, 0), c == 'M'); break; case 'k': /* kill current program */ tstart(T_EXIT, 1, 0, 0); break; case 'b': /* set a breakpoint at the given line */ if (seg == D) { printf("Address not in text space.\n"); return; } breakpt(exp, skip(cmd)); cmd = "\n"; return; case 'B': /* print list of currently active breakpoints */ for (i = 1, bp = b_head; bp; bp=bp->nxt, i++) { p = addr_to_name(bp->addr - saddr, &exp); printf("%2d: %s+0x%lx (0x%lx) - %s", i, p, exp, bp->addr, bp->cmd); } break; case 'd': /* delete breakpoint */ if (seg == T) { for (bp = b_head; bp && --exp; bp=bp->nxt) {}; if (bp) { freepnt(bp); break; } } printf("No such breakpoint.\n"); break; case 'D': /* delete all breakpoints */ while(b_head) freepnt(b_head); break; case 'q': /* quit */ tstart(T_EXIT, 0, 0, 0L, 0); exit(0); case '\n': case ';': if (isdigit(*cmdstart)) symbolic(exp, '\n'); else printf("0x%lx\n", exp); --cmd; break; case '$': cmdstart = cmd; cmd = skip(cmd+2); if (*cmd == '!') { cmd++; fill(reg_addr(cmdstart), T_GETUSER); break; } if (*skip(cmd+2) == '/') { cmd++; display(reg_addr(cmdstart), T_GETUSER); break; } /*FALLTHROUGH*/ default: printf("Unknown command.\n"); break; } while (*cmd != '\n' && *cmd != ';') ++cmd; if (*cmd == ';') cmd = skip(cmd+1); } main(argc, argv) char *argv|; { int i; prc = lbuf; for (i = 1; i < NSIG; i++) signal(i, catch); strcpy(sbuf, "\n"); prog = argc > 1 ? argv1| : "a.out"; if (argc > 2) getsyms(argv2|); setjmp(&mainlp); while ((printf("* "), fflush(stdout), fgets(cbuf, sizeof(cbuf), stdin)) != EOF) { if (strlen(cbuf) == sizeof(cbuf)-1) { printf("Command line too long.\n"); continue; } cmd = cbuf; command(); while (*cmd != '\n') command(); } tstart(T_EXIT, 0, 0, 0); exit(0); }