![cinap_lenrek](/assets/img/avatar_default.png)
from the unicode-db patch readme: command() receives a char* that is assigned to lp, which is a Rune*, and lp is incremented later in readchar(), so each read consumed 4 bytes. The only time command() is called is in runpcs() with bkpt->comm, which is a char* built in subpcs through a char*, so the string stored in bkpt->comm was not a Rune string. A way to test the bug is: db program main:b argv/X :r
311 lines
4.3 KiB
C
311 lines
4.3 KiB
C
/*
|
|
*
|
|
* debugger
|
|
*
|
|
*/
|
|
|
|
#include "defs.h"
|
|
#include "fns.h"
|
|
|
|
char BADEQ[] = "unexpected `='";
|
|
|
|
BOOL executing;
|
|
extern Rune *lp;
|
|
|
|
char eqformat[ARB] = "z";
|
|
char stformat[ARB] = "zMi";
|
|
|
|
ADDR ditto;
|
|
|
|
ADDR dot;
|
|
int dotinc;
|
|
WORD adrval, cntval, loopcnt;
|
|
int adrflg, cntflg;
|
|
|
|
/* command decoding */
|
|
int
|
|
command(Rune *buf, int defcom)
|
|
{
|
|
char *reg;
|
|
char savc;
|
|
Rune *savlp=lp;
|
|
char savlc = lastc;
|
|
char savpc = peekc;
|
|
static char lastcom = '=', savecom = '=';
|
|
|
|
if (defcom == 0)
|
|
defcom = lastcom;
|
|
if (buf) {
|
|
if (*buf==EOR)
|
|
return(FALSE);
|
|
clrinp();
|
|
lp=buf;
|
|
}
|
|
do {
|
|
adrflg=expr(0); /* first address */
|
|
if (adrflg){
|
|
dot=expv;
|
|
ditto=expv;
|
|
}
|
|
adrval=dot;
|
|
|
|
if (rdc()==',' && expr(0)) { /* count */
|
|
cntflg=TRUE;
|
|
cntval=expv;
|
|
} else {
|
|
cntflg=FALSE;
|
|
cntval=1;
|
|
reread();
|
|
}
|
|
|
|
if (!eol(rdc()))
|
|
lastcom=lastc; /* command */
|
|
else {
|
|
if (adrflg==0)
|
|
dot=inkdot(dotinc);
|
|
reread();
|
|
lastcom=defcom;
|
|
}
|
|
switch(lastcom) {
|
|
case '/':
|
|
case '=':
|
|
case '?':
|
|
savecom = lastcom;
|
|
acommand(lastcom);
|
|
break;
|
|
|
|
case '>':
|
|
lastcom = savecom;
|
|
savc=rdc();
|
|
if (reg=regname(savc))
|
|
rput(cormap, reg, dot);
|
|
else
|
|
error("bad variable");
|
|
break;
|
|
|
|
case '!':
|
|
lastcom=savecom;
|
|
shell();
|
|
break;
|
|
|
|
case '$':
|
|
lastcom=savecom;
|
|
printtrace(nextchar());
|
|
break;
|
|
|
|
case ':':
|
|
if (!executing) {
|
|
executing=TRUE;
|
|
subpcs(nextchar());
|
|
executing=FALSE;
|
|
lastcom=savecom;
|
|
}
|
|
break;
|
|
|
|
case 0:
|
|
prints(DBNAME);
|
|
break;
|
|
|
|
default:
|
|
error("bad command");
|
|
}
|
|
flushbuf();
|
|
} while (rdc()==';');
|
|
if (buf == 0)
|
|
reread();
|
|
else {
|
|
clrinp();
|
|
lp=savlp;
|
|
lastc = savlc;
|
|
peekc = savpc;
|
|
}
|
|
|
|
if(adrflg)
|
|
return dot;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* [/?][wml]
|
|
*/
|
|
|
|
void
|
|
acommand(int pc)
|
|
{
|
|
int eqcom;
|
|
Map *map;
|
|
char *fmt;
|
|
char buf[512];
|
|
|
|
if (pc == '=') {
|
|
eqcom = 1;
|
|
fmt = eqformat;
|
|
map = dotmap;
|
|
} else {
|
|
eqcom = 0;
|
|
fmt = stformat;
|
|
if (pc == '/')
|
|
map = cormap;
|
|
else
|
|
map = symmap;
|
|
}
|
|
if (!map) {
|
|
snprint(buf, sizeof(buf), "no map for %c", pc);
|
|
error(buf);
|
|
}
|
|
|
|
switch (rdc())
|
|
{
|
|
case 'm':
|
|
if (eqcom)
|
|
error(BADEQ);
|
|
cmdmap(map);
|
|
break;
|
|
|
|
case 'L':
|
|
case 'l':
|
|
if (eqcom)
|
|
error(BADEQ);
|
|
cmdsrc(lastc, map);
|
|
break;
|
|
|
|
case 'W':
|
|
case 'w':
|
|
if (eqcom)
|
|
error(BADEQ);
|
|
cmdwrite(lastc, map);
|
|
break;
|
|
|
|
default:
|
|
reread();
|
|
getformat(fmt);
|
|
scanform(cntval, !eqcom, fmt, map, eqcom);
|
|
}
|
|
}
|
|
|
|
void
|
|
cmdsrc(int c, Map *map)
|
|
{
|
|
ulong w;
|
|
long locval, locmsk;
|
|
ADDR savdot;
|
|
ushort sh;
|
|
char buf[512];
|
|
int ret;
|
|
|
|
if (c == 'L')
|
|
dotinc = 4;
|
|
else
|
|
dotinc = 2;
|
|
savdot=dot;
|
|
expr(1);
|
|
locval=expv;
|
|
if (expr(0))
|
|
locmsk=expv;
|
|
else
|
|
locmsk = ~0;
|
|
if (c == 'L')
|
|
while ((ret = get4(map, dot, &w)) > 0 && (w&locmsk) != locval)
|
|
dot = inkdot(dotinc);
|
|
else
|
|
while ((ret = get2(map, dot, &sh)) > 0 && (sh&locmsk) != locval)
|
|
dot = inkdot(dotinc);
|
|
if (ret < 0) {
|
|
dot=savdot;
|
|
error("%r");
|
|
}
|
|
symoff(buf, 512, dot, CANY);
|
|
dprint(buf);
|
|
}
|
|
|
|
static char badwrite[] = "can't write process memory or text image";
|
|
|
|
void
|
|
cmdwrite(int wcom, Map *map)
|
|
{
|
|
ADDR savdot;
|
|
char *format;
|
|
int pass;
|
|
|
|
if (wcom == 'w')
|
|
format = "x";
|
|
else
|
|
format = "X";
|
|
expr(1);
|
|
pass = 0;
|
|
do {
|
|
pass++;
|
|
savdot=dot;
|
|
exform(1, 1, format, map, 0, pass);
|
|
dot=savdot;
|
|
if (wcom == 'W') {
|
|
if (put4(map, dot, expv) <= 0)
|
|
error(badwrite);
|
|
} else {
|
|
if (put2(map, dot, expv) <= 0)
|
|
error(badwrite);
|
|
}
|
|
savdot=dot;
|
|
dprint("=%8t");
|
|
exform(1, 0, format, map, 0, pass);
|
|
newline();
|
|
} while (expr(0));
|
|
dot=savdot;
|
|
}
|
|
|
|
/*
|
|
* collect a register name; return register offset
|
|
* this is not what i'd call a good division of labour
|
|
*/
|
|
|
|
char *
|
|
regname(int regnam)
|
|
{
|
|
static char buf[64];
|
|
char *p;
|
|
int c;
|
|
|
|
p = buf;
|
|
*p++ = regnam;
|
|
while (isalnum(c = readchar())) {
|
|
if (p >= buf+sizeof(buf)-1)
|
|
error("register name too long");
|
|
*p++ = c;
|
|
}
|
|
*p = 0;
|
|
reread();
|
|
return (buf);
|
|
}
|
|
|
|
/*
|
|
* shell escape
|
|
*/
|
|
|
|
void
|
|
shell(void)
|
|
{
|
|
int rc, unixpid;
|
|
char *argp = (char*)lp;
|
|
|
|
while (lastc!=EOR)
|
|
rdc();
|
|
if ((unixpid=fork())==0) {
|
|
*lp=0;
|
|
execl("/bin/rc", "rc", "-c", argp, nil);
|
|
exits("execl"); /* botch */
|
|
} else if (unixpid == -1) {
|
|
error("cannot fork");
|
|
} else {
|
|
mkfault = 0;
|
|
while ((rc = waitpid()) != unixpid){
|
|
if(rc == -1 && mkfault){
|
|
mkfault = 0;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
prints("!");
|
|
reread();
|
|
}
|
|
}
|