debugger
This commit is contained in:
parent
a84cbb2a17
commit
84114f0665
15 changed files with 3179 additions and 0 deletions
311
src/cmd/db/command.c
Normal file
311
src/cmd/db/command.c
Normal file
|
|
@ -0,0 +1,311 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* debugger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
char BADEQ[] = "unexpected `='";
|
||||||
|
|
||||||
|
BOOL executing;
|
||||||
|
extern char *lp;
|
||||||
|
|
||||||
|
char eqformat[ARB] = "z";
|
||||||
|
char stformat[ARB] = "zMi";
|
||||||
|
|
||||||
|
ADDR ditto;
|
||||||
|
|
||||||
|
ADDR dot;
|
||||||
|
WORD dotinc;
|
||||||
|
WORD adrval, cntval, loopcnt;
|
||||||
|
int adrflg, cntflg;
|
||||||
|
|
||||||
|
/* command decoding */
|
||||||
|
|
||||||
|
int
|
||||||
|
command(char *buf, int defcom)
|
||||||
|
{
|
||||||
|
char *reg;
|
||||||
|
char savc;
|
||||||
|
char *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(correg, reg, dot);
|
||||||
|
else
|
||||||
|
error("bad variable");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '!':
|
||||||
|
lastcom=savecom;
|
||||||
|
shell();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '$':
|
||||||
|
lastcom=savecom;
|
||||||
|
printdollar(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) {
|
||||||
|
sprint(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)
|
||||||
|
{
|
||||||
|
u32int 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 = lp;
|
||||||
|
|
||||||
|
while (lastc!=EOR)
|
||||||
|
rdc();
|
||||||
|
if ((unixpid=fork())==0) {
|
||||||
|
*lp=0;
|
||||||
|
execl("/bin/rc", "rc", "-c", argp, 0);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
111
src/cmd/db/defs.h
Normal file
111
src/cmd/db/defs.h
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* db - common definitions
|
||||||
|
* something of a grab-bag
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <mach.h>
|
||||||
|
|
||||||
|
typedef long WORD;
|
||||||
|
typedef ulong ADDR;
|
||||||
|
|
||||||
|
#define HUGEINT 0x7fffffff /* enormous WORD */
|
||||||
|
|
||||||
|
#define MAXOFF 0x1000000
|
||||||
|
#define INCDIR "/usr/lib/adb"
|
||||||
|
#define DBNAME "db\n"
|
||||||
|
#define CMD_VERBS "?/=>!$: \t"
|
||||||
|
|
||||||
|
typedef int BOOL;
|
||||||
|
|
||||||
|
#define MAXPOS 80
|
||||||
|
#define MAXLIN 128
|
||||||
|
#define ARB 512
|
||||||
|
#define MAXCOM 64
|
||||||
|
#define MAXARG 32
|
||||||
|
#define LINSIZ 4096
|
||||||
|
#define MAXSYM 255
|
||||||
|
|
||||||
|
#define EOR '\n'
|
||||||
|
#define SPC ' '
|
||||||
|
#define TB '\t'
|
||||||
|
|
||||||
|
#define STDIN 0
|
||||||
|
#define STDOUT 1
|
||||||
|
|
||||||
|
#define TRUE (-1)
|
||||||
|
#define FALSE 0
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* run modes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SINGLE 1
|
||||||
|
#define CONTIN 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* breakpoints
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BKPTCLR 0 /* not a real breakpoint */
|
||||||
|
#define BKPTSET 1 /* real, ready to trap */
|
||||||
|
#define BKPTSKIP 2 /* real, skip over it next time */
|
||||||
|
#define BKPTTMP 3 /* temporary; clear when it happens */
|
||||||
|
|
||||||
|
struct bkpt {
|
||||||
|
ADDR loc;
|
||||||
|
uchar save[4];
|
||||||
|
int count;
|
||||||
|
int initcnt;
|
||||||
|
int flag;
|
||||||
|
char comm[MAXCOM];
|
||||||
|
struct bkpt *nxtbkpt;
|
||||||
|
};
|
||||||
|
typedef struct bkpt BKPT;
|
||||||
|
|
||||||
|
#define BADREG (-1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* common globals
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern WORD adrval;
|
||||||
|
extern vlong expv;
|
||||||
|
extern int adrflg;
|
||||||
|
extern WORD cntval;
|
||||||
|
extern int cntflg;
|
||||||
|
extern WORD loopcnt;
|
||||||
|
extern ADDR maxoff;
|
||||||
|
extern ADDR localval;
|
||||||
|
extern ADDR maxfile;
|
||||||
|
extern ADDR maxstor;
|
||||||
|
|
||||||
|
extern ADDR dot;
|
||||||
|
extern WORD dotinc;
|
||||||
|
|
||||||
|
extern int xargc;
|
||||||
|
|
||||||
|
extern BOOL wtflag;
|
||||||
|
extern char *corfil, *symfil;
|
||||||
|
extern BOOL mkfault;
|
||||||
|
extern BOOL regdirty;
|
||||||
|
|
||||||
|
extern int pid;
|
||||||
|
extern int pcsactive;
|
||||||
|
#define NNOTE 10
|
||||||
|
extern int nnote;
|
||||||
|
extern char note[NNOTE][ERRMAX];
|
||||||
|
|
||||||
|
extern int ending;
|
||||||
|
extern Fhdr *corhdr, *symhdr;
|
||||||
|
extern Map *cormap, *symmap, *dotmap;
|
||||||
|
extern Regs *correg;
|
||||||
|
|
||||||
|
extern BKPT *bkpthead;
|
||||||
|
extern int kflag;
|
||||||
|
extern int lastc, peekc;
|
||||||
397
src/cmd/db/expr.c
Normal file
397
src/cmd/db/expr.c
Normal file
|
|
@ -0,0 +1,397 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* debugger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
static long dbround(long, long);
|
||||||
|
|
||||||
|
extern ADDR ditto;
|
||||||
|
vlong expv;
|
||||||
|
|
||||||
|
static WORD
|
||||||
|
ascval(void)
|
||||||
|
{
|
||||||
|
Rune r;
|
||||||
|
|
||||||
|
if (readchar() == 0)
|
||||||
|
return (0);
|
||||||
|
r = lastc;
|
||||||
|
while(quotchar()) /*discard chars to ending quote */
|
||||||
|
;
|
||||||
|
return((WORD) r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read a floating point number
|
||||||
|
* the result must fit in a WORD
|
||||||
|
*/
|
||||||
|
|
||||||
|
static WORD
|
||||||
|
fpin(char *buf)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
WORD w;
|
||||||
|
float f;
|
||||||
|
} x;
|
||||||
|
|
||||||
|
x.f = atof(buf);
|
||||||
|
return (x.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
WORD
|
||||||
|
defval(WORD w)
|
||||||
|
{
|
||||||
|
if (expr(0))
|
||||||
|
return (expv);
|
||||||
|
else
|
||||||
|
return (w);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
expr(int a)
|
||||||
|
{ /* term | term dyadic expr | */
|
||||||
|
int rc;
|
||||||
|
WORD lhs;
|
||||||
|
|
||||||
|
rdc();
|
||||||
|
reread();
|
||||||
|
rc=term(a);
|
||||||
|
while (rc) {
|
||||||
|
lhs = expv;
|
||||||
|
switch ((int)readchar()) {
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
term(a|1);
|
||||||
|
expv += lhs;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
term(a|1);
|
||||||
|
expv = lhs - expv;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
term(a|1);
|
||||||
|
expv = dbround(lhs,expv);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
term(a|1);
|
||||||
|
expv *= lhs;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '%':
|
||||||
|
term(a|1);
|
||||||
|
if(expv != 0)
|
||||||
|
expv = lhs/expv;
|
||||||
|
else{
|
||||||
|
if(lhs)
|
||||||
|
expv = 1;
|
||||||
|
else
|
||||||
|
expv = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '&':
|
||||||
|
term(a|1);
|
||||||
|
expv &= lhs;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '|':
|
||||||
|
term(a|1);
|
||||||
|
expv |= lhs;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ')':
|
||||||
|
if ((a&2)==0)
|
||||||
|
error("unexpected `)'");
|
||||||
|
|
||||||
|
default:
|
||||||
|
reread();
|
||||||
|
return(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
term(int a)
|
||||||
|
{ /* item | monadic item | (expr) | */
|
||||||
|
u32int u;
|
||||||
|
|
||||||
|
switch ((int)readchar()) {
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
term(a|1);
|
||||||
|
if (get4(cormap, (ADDR)expv, &u) < 0)
|
||||||
|
error("%r");
|
||||||
|
expv = u;
|
||||||
|
return(1);
|
||||||
|
|
||||||
|
case '@':
|
||||||
|
term(a|1);
|
||||||
|
if (get4(symmap, (ADDR)expv, &u) < 0)
|
||||||
|
error("%r");
|
||||||
|
expv = u;
|
||||||
|
return(1);
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
term(a|1);
|
||||||
|
expv = -expv;
|
||||||
|
return(1);
|
||||||
|
|
||||||
|
case '~':
|
||||||
|
term(a|1);
|
||||||
|
expv = ~expv;
|
||||||
|
return(1);
|
||||||
|
|
||||||
|
case '(':
|
||||||
|
expr(2);
|
||||||
|
if (readchar()!=')')
|
||||||
|
error("syntax error: `)' expected");
|
||||||
|
return(1);
|
||||||
|
|
||||||
|
default:
|
||||||
|
reread();
|
||||||
|
return(item(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
item(int a)
|
||||||
|
{ /* name [ . local ] | number | . | ^ | <register | 'x | | */
|
||||||
|
char *base;
|
||||||
|
char savc;
|
||||||
|
ulong u;
|
||||||
|
Symbol s;
|
||||||
|
char gsym[MAXSYM], lsym[MAXSYM];
|
||||||
|
|
||||||
|
readchar();
|
||||||
|
if (isfileref()) {
|
||||||
|
readfname(gsym);
|
||||||
|
rdc(); /* skip white space */
|
||||||
|
if (lastc == ':') { /* it better be */
|
||||||
|
rdc(); /* skip white space */
|
||||||
|
if (!getnum(readchar))
|
||||||
|
error("bad number");
|
||||||
|
if (expv == 0)
|
||||||
|
expv = 1; /* file begins at line 1 */
|
||||||
|
if(file2pc(gsym, expv, &u) < 0)
|
||||||
|
error("%r");
|
||||||
|
expv = u;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
error("bad file location");
|
||||||
|
} else if (symchar(0)) {
|
||||||
|
readsym(gsym);
|
||||||
|
if (lastc=='.') {
|
||||||
|
readchar(); /* ugh */
|
||||||
|
if (lastc == '.') {
|
||||||
|
lsym[0] = '.';
|
||||||
|
readchar();
|
||||||
|
readsym(lsym+1);
|
||||||
|
} else if (symchar(0)) {
|
||||||
|
readsym(lsym);
|
||||||
|
} else
|
||||||
|
lsym[0] = 0;
|
||||||
|
if (localaddr(cormap, correg, gsym, lsym, &u) < 0)
|
||||||
|
error("%r");
|
||||||
|
expv = u;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (lookupsym(0, gsym, &s) < 0)
|
||||||
|
error("symbol not found");
|
||||||
|
if (s.loc.type != LADDR)
|
||||||
|
error("symbol not kept in memory");
|
||||||
|
expv = s.loc.addr;
|
||||||
|
}
|
||||||
|
reread();
|
||||||
|
} else if (getnum(readchar)) {
|
||||||
|
;
|
||||||
|
} else if (lastc=='.') {
|
||||||
|
readchar();
|
||||||
|
if (!symchar(0) && lastc != '.') {
|
||||||
|
expv = dot;
|
||||||
|
} else {
|
||||||
|
if (findsym(locaddr(dbrget(cormap, mach->pc)), CTEXT, &s) < 0)
|
||||||
|
error("no current function");
|
||||||
|
if (lastc == '.') {
|
||||||
|
lsym[0] = '.';
|
||||||
|
readchar();
|
||||||
|
readsym(lsym+1);
|
||||||
|
} else
|
||||||
|
readsym(lsym);
|
||||||
|
if (localaddr(cormap, correg, s.name, lsym, &u) < 0)
|
||||||
|
error("%r");
|
||||||
|
expv = u;
|
||||||
|
}
|
||||||
|
reread();
|
||||||
|
} else if (lastc=='"') {
|
||||||
|
expv=ditto;
|
||||||
|
} else if (lastc=='+') {
|
||||||
|
expv=inkdot(dotinc);
|
||||||
|
} else if (lastc=='^') {
|
||||||
|
expv=inkdot(-dotinc);
|
||||||
|
} else if (lastc=='<') {
|
||||||
|
savc=rdc();
|
||||||
|
base = regname(savc);
|
||||||
|
expv = dbrget(cormap, base);
|
||||||
|
}
|
||||||
|
else if (lastc=='\'')
|
||||||
|
expv = ascval();
|
||||||
|
else if (a)
|
||||||
|
error("address expected");
|
||||||
|
else {
|
||||||
|
reread();
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAXBASE 16
|
||||||
|
|
||||||
|
/* service routines for expression reading */
|
||||||
|
int
|
||||||
|
getnum(int (*rdf)(void))
|
||||||
|
{
|
||||||
|
char *cp;
|
||||||
|
int base, d;
|
||||||
|
BOOL fpnum;
|
||||||
|
char num[MAXLIN];
|
||||||
|
|
||||||
|
base = 0;
|
||||||
|
fpnum = FALSE;
|
||||||
|
if (lastc == '#') {
|
||||||
|
base = 16;
|
||||||
|
(*rdf)();
|
||||||
|
}
|
||||||
|
if (convdig(lastc) >= MAXBASE)
|
||||||
|
return (0);
|
||||||
|
if (lastc == '0')
|
||||||
|
switch ((*rdf)()) {
|
||||||
|
case 'x':
|
||||||
|
case 'X':
|
||||||
|
base = 16;
|
||||||
|
(*rdf)();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
base = 10;
|
||||||
|
(*rdf)();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
case 'O':
|
||||||
|
base = 8;
|
||||||
|
(*rdf)();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (base == 0)
|
||||||
|
base = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (base == 0)
|
||||||
|
base = 10;
|
||||||
|
expv = 0;
|
||||||
|
for (cp = num, *cp = lastc; ;(*rdf)()) {
|
||||||
|
if ((d = convdig(lastc)) < base) {
|
||||||
|
expv *= base;
|
||||||
|
expv += d;
|
||||||
|
*cp++ = lastc;
|
||||||
|
}
|
||||||
|
else if (lastc == '.') {
|
||||||
|
fpnum = TRUE;
|
||||||
|
*cp++ = lastc;
|
||||||
|
} else {
|
||||||
|
reread();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fpnum)
|
||||||
|
expv = fpin(num);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
readsym(char *isymbol)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
Rune r;
|
||||||
|
|
||||||
|
p = isymbol;
|
||||||
|
do {
|
||||||
|
if (p < &isymbol[MAXSYM-UTFmax-1]){
|
||||||
|
r = lastc;
|
||||||
|
p += runetochar(p, &r);
|
||||||
|
}
|
||||||
|
readchar();
|
||||||
|
} while (symchar(1));
|
||||||
|
*p = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
readfname(char *filename)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
Rune c;
|
||||||
|
|
||||||
|
/* snarf chars until un-escaped char in terminal char set */
|
||||||
|
p = filename;
|
||||||
|
do {
|
||||||
|
if ((c = lastc) != '\\' && p < &filename[MAXSYM-UTFmax-1])
|
||||||
|
p += runetochar(p, &c);
|
||||||
|
readchar();
|
||||||
|
} while (c == '\\' || strchr(CMD_VERBS, lastc) == 0);
|
||||||
|
*p = 0;
|
||||||
|
reread();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
convdig(int c)
|
||||||
|
{
|
||||||
|
if (isdigit(c))
|
||||||
|
return(c-'0');
|
||||||
|
else if (!isxdigit(c))
|
||||||
|
return(MAXBASE);
|
||||||
|
else if (isupper(c))
|
||||||
|
return(c-'A'+10);
|
||||||
|
else
|
||||||
|
return(c-'a'+10);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
symchar(int dig)
|
||||||
|
{
|
||||||
|
if (lastc=='\\') {
|
||||||
|
readchar();
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
return(isalpha(lastc) || lastc>0x80 || lastc=='_' || dig && isdigit(lastc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
dbround(long a, long b)
|
||||||
|
{
|
||||||
|
long w;
|
||||||
|
|
||||||
|
w = (a/b)*b;
|
||||||
|
if (a!=w)
|
||||||
|
w += b;
|
||||||
|
return(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong
|
||||||
|
dbrget(Map *map, char *name)
|
||||||
|
{
|
||||||
|
ulong u;
|
||||||
|
|
||||||
|
USED(map);
|
||||||
|
if(rget(correg, name, &u) < 0)
|
||||||
|
return ~(ulong)0;
|
||||||
|
return u;
|
||||||
|
}
|
||||||
91
src/cmd/db/fns.h
Normal file
91
src/cmd/db/fns.h
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
void acommand(int);
|
||||||
|
void attachprocess(void);
|
||||||
|
void bkput(BKPT*, int);
|
||||||
|
void bpwait(void);
|
||||||
|
int charpos(void);
|
||||||
|
void chkerr(void);
|
||||||
|
void clrinp(void);
|
||||||
|
void cmdmap(Map*);
|
||||||
|
void cmdsrc(int, Map*);
|
||||||
|
void cmdwrite(int, Map*);
|
||||||
|
int command(char*, int);
|
||||||
|
int convdig(int);
|
||||||
|
void ctrace(int);
|
||||||
|
WORD defval(WORD);
|
||||||
|
void delbp(void);
|
||||||
|
ulong dbrget(Map*, char*);
|
||||||
|
void done(void);
|
||||||
|
int dprint(char*, ...);
|
||||||
|
Map* dumbmap(int);
|
||||||
|
void endline(void);
|
||||||
|
void endpcs(void);
|
||||||
|
int eol(int);
|
||||||
|
void error(char*);
|
||||||
|
void errors(char*, char*);
|
||||||
|
void execbkpt(BKPT*, int);
|
||||||
|
char* exform(int, int, char*, Map*, int, int);
|
||||||
|
int expr(int);
|
||||||
|
/*
|
||||||
|
void fixregs(Map*);
|
||||||
|
void adjustreg(char*, ulong, long);
|
||||||
|
*/
|
||||||
|
void flush(void);
|
||||||
|
void flushbuf(void);
|
||||||
|
char* getfname(void);
|
||||||
|
void getformat(char*);
|
||||||
|
int getnum(int (*)(void));
|
||||||
|
void grab(void);
|
||||||
|
void iclose(int, int);
|
||||||
|
ADDR inkdot(long);
|
||||||
|
int isfileref(void);
|
||||||
|
int item(int);
|
||||||
|
void killpcs(void);
|
||||||
|
void kmsys(void);
|
||||||
|
void main(int, char**);
|
||||||
|
int mapimage(void);
|
||||||
|
void newline(void);
|
||||||
|
int nextchar(void);
|
||||||
|
void notes(void);
|
||||||
|
void oclose(void);
|
||||||
|
void outputinit(void);
|
||||||
|
void printc(int);
|
||||||
|
void printdollar(int);
|
||||||
|
void printesc(int);
|
||||||
|
void printlocals(Symbol*, Regs*);
|
||||||
|
void printmap(char*, Map*);
|
||||||
|
void printparams(Symbol*, Regs*);
|
||||||
|
void printpc(void);
|
||||||
|
void printregs(int);
|
||||||
|
void prints(char*);
|
||||||
|
void printsource(long);
|
||||||
|
void printsym(void);
|
||||||
|
void printsyscall(void);
|
||||||
|
int quotchar(void);
|
||||||
|
int rdc(void);
|
||||||
|
int readchar(void);
|
||||||
|
void readsym(char*);
|
||||||
|
void redirin(int, char*);
|
||||||
|
void redirout(char*);
|
||||||
|
void readfname(char *);
|
||||||
|
void reread(void);
|
||||||
|
char* regname(int);
|
||||||
|
//vlong rget(Map*, char*);
|
||||||
|
Regdesc* rname(char*);
|
||||||
|
//void rput(Map*, char*, vlong);
|
||||||
|
int runpcs(int, int);
|
||||||
|
void runrun(int);
|
||||||
|
void runstep(ulong, int);
|
||||||
|
BKPT* scanbkpt(ADDR adr);
|
||||||
|
void scanform(long, int, char*, Map*, int);
|
||||||
|
void setbp(void);
|
||||||
|
void setcor(void);
|
||||||
|
void setsym(void);
|
||||||
|
void setup(void);
|
||||||
|
void setvec(void);
|
||||||
|
void shell(void);
|
||||||
|
void startpcs(void);
|
||||||
|
void subpcs(int);
|
||||||
|
int symchar(int);
|
||||||
|
int term(int);
|
||||||
|
void ungrab(void);
|
||||||
|
int valpr(long, int);
|
||||||
388
src/cmd/db/format.c
Normal file
388
src/cmd/db/format.c
Normal file
|
|
@ -0,0 +1,388 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* debugger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
scanform(long icount, int prt, char *ifp, Map *map, int literal)
|
||||||
|
{
|
||||||
|
char *fp;
|
||||||
|
char c;
|
||||||
|
int fcount;
|
||||||
|
ADDR savdot;
|
||||||
|
int firstpass;
|
||||||
|
|
||||||
|
firstpass = 1;
|
||||||
|
while (icount) {
|
||||||
|
fp=ifp;
|
||||||
|
savdot=dot;
|
||||||
|
/*now loop over format*/
|
||||||
|
while (*fp) {
|
||||||
|
if (!isdigit(*fp))
|
||||||
|
fcount = 1;
|
||||||
|
else {
|
||||||
|
fcount = 0;
|
||||||
|
while (isdigit(c = *fp++)) {
|
||||||
|
fcount *= 10;
|
||||||
|
fcount += c-'0';
|
||||||
|
}
|
||||||
|
fp--;
|
||||||
|
}
|
||||||
|
if (*fp==0)
|
||||||
|
break;
|
||||||
|
fp=exform(fcount,prt,fp,map,literal,firstpass);
|
||||||
|
firstpass = 0;
|
||||||
|
}
|
||||||
|
dotinc=dot-savdot;
|
||||||
|
dot=savdot;
|
||||||
|
if (--icount)
|
||||||
|
dot=inkdot(dotinc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
exform(int fcount, int prt, char *ifp, Map *map, int literal, int firstpass)
|
||||||
|
{
|
||||||
|
/* execute single format item `fcount' times
|
||||||
|
* sets `dotinc' and moves `dot'
|
||||||
|
* returns address of next format item
|
||||||
|
*/
|
||||||
|
vlong v;
|
||||||
|
WORD w;
|
||||||
|
ulong savdot;
|
||||||
|
u16int u2;
|
||||||
|
u32int u4;
|
||||||
|
u64int u8;
|
||||||
|
char *fp;
|
||||||
|
char c, modifier;
|
||||||
|
int i;
|
||||||
|
ushort sh, *sp;
|
||||||
|
uchar ch, *cp;
|
||||||
|
Symbol s;
|
||||||
|
char buf[512];
|
||||||
|
extern int printcol;
|
||||||
|
|
||||||
|
fp = 0;
|
||||||
|
while (fcount > 0) {
|
||||||
|
fp = ifp;
|
||||||
|
c = *fp;
|
||||||
|
modifier = *fp++;
|
||||||
|
if (firstpass) {
|
||||||
|
firstpass = 0;
|
||||||
|
if (!literal && (c == 'i' || c == 'I' || c == 'M')
|
||||||
|
&& (dot & (mach->pcquant-1))) {
|
||||||
|
dprint("warning: instruction not aligned");
|
||||||
|
printc('\n');
|
||||||
|
}
|
||||||
|
if (prt && modifier != 'a' && modifier != 'A') {
|
||||||
|
symoff(buf, 512, dot, CANY);
|
||||||
|
dprint("%s%c%16t", buf, map==symmap? '?':'/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (printcol==0 && modifier != 'a' && modifier != 'A')
|
||||||
|
dprint("\t\t");
|
||||||
|
switch(modifier) {
|
||||||
|
|
||||||
|
case SPC:
|
||||||
|
case TB:
|
||||||
|
dotinc = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
dprint("%*t", fcount);
|
||||||
|
dotinc = 0;
|
||||||
|
return(fp);
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
symoff(buf, sizeof(buf), dot, CANY);
|
||||||
|
dprint("%s%c%16t", buf, map==symmap? '?':'/');
|
||||||
|
dotinc = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'A':
|
||||||
|
dprint("%#lux%10t", dot);
|
||||||
|
dotinc = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
if (get4(map, dot, &u4) < 0)
|
||||||
|
error("%r");
|
||||||
|
w = u4;
|
||||||
|
symoff(buf, sizeof(buf), w, CANY);
|
||||||
|
dprint("%s%16t", buf);
|
||||||
|
dotinc = mach->szaddr;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
case 'd':
|
||||||
|
case 'x':
|
||||||
|
case 'o':
|
||||||
|
case 'q':
|
||||||
|
if (literal)
|
||||||
|
u2 = (ushort) dot;
|
||||||
|
else if (get2(map, dot, &u2) < 0)
|
||||||
|
error("%r");
|
||||||
|
w = u2;
|
||||||
|
dotinc = 2;
|
||||||
|
if (c == 'u')
|
||||||
|
dprint("%-8lud", w);
|
||||||
|
else if (c == 'x')
|
||||||
|
dprint("%-8#lux", w);
|
||||||
|
else if (c == 'd')
|
||||||
|
dprint("%-8ld", w);
|
||||||
|
else if (c == 'o')
|
||||||
|
dprint("%-8#luo", w);
|
||||||
|
else if (c == 'q')
|
||||||
|
dprint("%-8#lo", w);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'U':
|
||||||
|
case 'D':
|
||||||
|
case 'X':
|
||||||
|
case 'O':
|
||||||
|
case 'Q':
|
||||||
|
if (literal)
|
||||||
|
u4 = (long) dot;
|
||||||
|
else if (get4(map, dot, &u4) < 0)
|
||||||
|
error("%r");
|
||||||
|
dotinc = 4;
|
||||||
|
if (c == 'U')
|
||||||
|
dprint("%-16lud", u4);
|
||||||
|
else if (c == 'X')
|
||||||
|
dprint("%-16#lux", u4);
|
||||||
|
else if (c == 'D')
|
||||||
|
dprint("%-16ld", u4);
|
||||||
|
else if (c == 'O')
|
||||||
|
dprint("%-#16luo", u4);
|
||||||
|
else if (c == 'Q')
|
||||||
|
dprint("%-#16lo", u4);
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
case 'V':
|
||||||
|
case 'Y':
|
||||||
|
if (literal)
|
||||||
|
v = dot;
|
||||||
|
else if (get8(map, dot, &u8) < 0)
|
||||||
|
error("%r");
|
||||||
|
dotinc = 8;
|
||||||
|
if (c == 'Y')
|
||||||
|
dprint("%-20#llux", u8);
|
||||||
|
else if (c == 'V')
|
||||||
|
dprint("%-20lld", u8);
|
||||||
|
else if (c == 'Z')
|
||||||
|
dprint("%-20llud", u8);
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
case 'b':
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
if (literal)
|
||||||
|
ch = (uchar) dot;
|
||||||
|
else if (get1(map, dot, &ch, 1) < 0)
|
||||||
|
error("%r");
|
||||||
|
if (modifier == 'C')
|
||||||
|
printesc(ch);
|
||||||
|
else if (modifier == 'B' || modifier == 'b')
|
||||||
|
dprint("%-8#lux", (long) ch);
|
||||||
|
else
|
||||||
|
printc(ch);
|
||||||
|
dotinc = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
if (literal)
|
||||||
|
sh = (ushort) dot;
|
||||||
|
else if (get2(map, dot, &sh) < 0)
|
||||||
|
error("%r");
|
||||||
|
dprint("%C", sh);
|
||||||
|
dotinc = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'R':
|
||||||
|
if (literal) {
|
||||||
|
sp = (u16int*)(void*)˙
|
||||||
|
dprint("%C%C", sp[0], sp[1]);
|
||||||
|
endline();
|
||||||
|
dotinc = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
savdot=dot;
|
||||||
|
while ((i = get2(map, dot, &u2) > 0) && u2) {
|
||||||
|
dot=inkdot(2);
|
||||||
|
dprint("%C", u2);
|
||||||
|
endline();
|
||||||
|
}
|
||||||
|
if (i < 0)
|
||||||
|
error("%r");
|
||||||
|
dotinc = dot-savdot+2;
|
||||||
|
dot=savdot;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
if (literal) {
|
||||||
|
cp = (uchar*)(void*)˙
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
buf[i] = cp[i];
|
||||||
|
buf[i] = 0;
|
||||||
|
dprint("%s", buf);
|
||||||
|
endline();
|
||||||
|
dotinc = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
savdot = dot;
|
||||||
|
for(;;){
|
||||||
|
i = 0;
|
||||||
|
do{
|
||||||
|
if (get1(map, dot, (uchar*)(void*)&buf[i], 1) < 0)
|
||||||
|
error("%r");
|
||||||
|
dot = inkdot(1);
|
||||||
|
i++;
|
||||||
|
}while(!fullrune(buf, i));
|
||||||
|
if(buf[0] == 0)
|
||||||
|
break;
|
||||||
|
buf[i] = 0;
|
||||||
|
dprint("%s", buf);
|
||||||
|
endline();
|
||||||
|
}
|
||||||
|
dotinc = dot-savdot+1;
|
||||||
|
dot = savdot;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S':
|
||||||
|
if (literal) {
|
||||||
|
cp = (uchar*) ˙
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
printesc(cp[i]);
|
||||||
|
endline();
|
||||||
|
dotinc = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
savdot=dot;
|
||||||
|
while ((i = get1(map, dot, &ch, 1) > 0) && ch) {
|
||||||
|
dot=inkdot(1);
|
||||||
|
printesc(ch);
|
||||||
|
endline();
|
||||||
|
}
|
||||||
|
if (i < 0)
|
||||||
|
error("%r");
|
||||||
|
dotinc = dot-savdot+1;
|
||||||
|
dot=savdot;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'I':
|
||||||
|
case 'i':
|
||||||
|
dotinc = mach->das(map, dot, modifier, buf, sizeof(buf));
|
||||||
|
if (dotinc < 0)
|
||||||
|
error("%r");
|
||||||
|
dprint("%s\n", buf);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'M':
|
||||||
|
dotinc = mach->hexinst(map, dot, buf, sizeof(buf));
|
||||||
|
if (dotinc < 0)
|
||||||
|
error("%r");
|
||||||
|
dprint("%s", buf);
|
||||||
|
if (*fp) {
|
||||||
|
dotinc = 0;
|
||||||
|
dprint("%48t");
|
||||||
|
} else
|
||||||
|
dprint("\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
/* BUG: 'f' and 'F' assume szdouble is sizeof(vlong) in the literal case */
|
||||||
|
if (literal) {
|
||||||
|
v = mach->swap8((ulong)dot);
|
||||||
|
memmove(buf, &v, mach->szfloat);
|
||||||
|
}else if (get1(map, dot, (uchar*)buf, mach->szfloat) < 0)
|
||||||
|
error("%r");
|
||||||
|
mach->ftoa32(buf, sizeof(buf), (void*) buf);
|
||||||
|
dprint("%s\n", buf);
|
||||||
|
dotinc = mach->szfloat;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'F':
|
||||||
|
/* BUG: 'f' and 'F' assume szdouble is sizeof(vlong) in the literal case */
|
||||||
|
if (literal) {
|
||||||
|
v = mach->swap8(dot);
|
||||||
|
memmove(buf, &v, mach->szdouble);
|
||||||
|
}else if (get1(map, dot, (uchar*)buf, mach->szdouble) < 0)
|
||||||
|
error("%r");
|
||||||
|
mach->ftoa64(buf, sizeof(buf), (void*) buf);
|
||||||
|
dprint("%s\n", buf);
|
||||||
|
dotinc = mach->szdouble;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
case 'N':
|
||||||
|
printc('\n');
|
||||||
|
dotinc=0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
dotinc=0;
|
||||||
|
while (*fp != '"' && *fp)
|
||||||
|
printc(*fp++);
|
||||||
|
if (*fp)
|
||||||
|
fp++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '^':
|
||||||
|
dot=inkdot(-dotinc*fcount);
|
||||||
|
return(fp);
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
dot=inkdot((WORD)fcount);
|
||||||
|
return(fp);
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
dot=inkdot(-(WORD)fcount);
|
||||||
|
return(fp);
|
||||||
|
|
||||||
|
case 'z':
|
||||||
|
if (findsym(locaddr(dot), CTEXT, &s) >= 0)
|
||||||
|
dprint("%s() ", s.name);
|
||||||
|
printsource(dot);
|
||||||
|
printc(EOR);
|
||||||
|
return fp;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error("bad modifier");
|
||||||
|
}
|
||||||
|
if (map->seg[0].fd >= 0)
|
||||||
|
dot=inkdot(dotinc);
|
||||||
|
fcount--;
|
||||||
|
endline();
|
||||||
|
}
|
||||||
|
|
||||||
|
return(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printesc(int c)
|
||||||
|
{
|
||||||
|
static char hex[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
if (c < SPC || c >= 0177)
|
||||||
|
dprint("\\x%c%c", hex[(c&0xF0)>>4], hex[c&0xF]);
|
||||||
|
else
|
||||||
|
printc(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
ADDR
|
||||||
|
inkdot(WORD incr)
|
||||||
|
{
|
||||||
|
ADDR newdot;
|
||||||
|
|
||||||
|
newdot=dot+incr;
|
||||||
|
if ((incr >= 0 && newdot < dot)
|
||||||
|
|| (incr < 0 && newdot > dot))
|
||||||
|
error("address wraparound");
|
||||||
|
return(newdot);
|
||||||
|
}
|
||||||
169
src/cmd/db/input.c
Normal file
169
src/cmd/db/input.c
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* debugger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
Rune line[LINSIZ];
|
||||||
|
extern int infile;
|
||||||
|
Rune *lp;
|
||||||
|
int peekc,lastc = EOR;
|
||||||
|
int eof;
|
||||||
|
|
||||||
|
/* input routines */
|
||||||
|
|
||||||
|
int
|
||||||
|
eol(int c)
|
||||||
|
{
|
||||||
|
return(c==EOR || c==';');
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rdc(void)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
readchar();
|
||||||
|
} while (lastc==SPC || lastc==TB);
|
||||||
|
return(lastc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
reread(void)
|
||||||
|
{
|
||||||
|
peekc = lastc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clrinp(void)
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
lp = 0;
|
||||||
|
peekc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
readrune(int fd, Rune *r)
|
||||||
|
{
|
||||||
|
char buf[UTFmax];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<UTFmax && !fullrune(buf, i); i++)
|
||||||
|
if(read(fd, buf+i, 1) <= 0)
|
||||||
|
return -1;
|
||||||
|
chartorune(r, buf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
readchar(void)
|
||||||
|
{
|
||||||
|
Rune *p;
|
||||||
|
|
||||||
|
if (eof)
|
||||||
|
lastc=0;
|
||||||
|
else if (peekc) {
|
||||||
|
lastc = peekc;
|
||||||
|
peekc = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (lp==0) {
|
||||||
|
for (p = line; p < &line[LINSIZ-1]; p++) {
|
||||||
|
eof = readrune(infile, p) <= 0;
|
||||||
|
if (mkfault) {
|
||||||
|
eof = 0;
|
||||||
|
error(0);
|
||||||
|
}
|
||||||
|
if (eof) {
|
||||||
|
p--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*p == EOR) {
|
||||||
|
if (p <= line)
|
||||||
|
break;
|
||||||
|
if (p[-1] != '\\')
|
||||||
|
break;
|
||||||
|
p -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p[1] = 0;
|
||||||
|
lp = line;
|
||||||
|
}
|
||||||
|
if ((lastc = *lp) != 0)
|
||||||
|
lp++;
|
||||||
|
}
|
||||||
|
return(lastc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nextchar(void)
|
||||||
|
{
|
||||||
|
if (eol(rdc())) {
|
||||||
|
reread();
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
return(lastc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
quotchar(void)
|
||||||
|
{
|
||||||
|
if (readchar()=='\\')
|
||||||
|
return(readchar());
|
||||||
|
else if (lastc=='\'')
|
||||||
|
return(0);
|
||||||
|
else
|
||||||
|
return(lastc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
getformat(char *deformat)
|
||||||
|
{
|
||||||
|
char *fptr;
|
||||||
|
BOOL quote;
|
||||||
|
Rune r;
|
||||||
|
|
||||||
|
fptr=deformat;
|
||||||
|
quote=FALSE;
|
||||||
|
while ((quote ? readchar()!=EOR : !eol(readchar()))){
|
||||||
|
r = lastc;
|
||||||
|
fptr += runetochar(fptr, &r);
|
||||||
|
if (lastc == '"')
|
||||||
|
quote = ~quote;
|
||||||
|
}
|
||||||
|
lp--;
|
||||||
|
if (fptr!=deformat)
|
||||||
|
*fptr = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check if the input line if of the form:
|
||||||
|
* <filename>:<digits><verb> ...
|
||||||
|
*
|
||||||
|
* we handle this case specially because we have to look ahead
|
||||||
|
* at the token after the colon to decide if it is a file reference
|
||||||
|
* or a colon-command with a symbol name prefix.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
isfileref(void)
|
||||||
|
{
|
||||||
|
Rune *cp;
|
||||||
|
|
||||||
|
for (cp = lp-1; *cp && !strchr(CMD_VERBS, *cp); cp++)
|
||||||
|
if (*cp == '\\' && cp[1]) /* escape next char */
|
||||||
|
cp++;
|
||||||
|
if (*cp && cp > lp-1) {
|
||||||
|
while (*cp == ' ' || *cp == '\t')
|
||||||
|
cp++;
|
||||||
|
if (*cp++ == ':') {
|
||||||
|
while (*cp == ' ' || *cp == '\t')
|
||||||
|
cp++;
|
||||||
|
if (isdigit(*cp))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
262
src/cmd/db/main.c
Normal file
262
src/cmd/db/main.c
Normal file
|
|
@ -0,0 +1,262 @@
|
||||||
|
/*
|
||||||
|
* db - main command loop and error/interrupt handling
|
||||||
|
*/
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
int wtflag = OREAD;
|
||||||
|
BOOL kflag;
|
||||||
|
|
||||||
|
BOOL mkfault;
|
||||||
|
ADDR maxoff;
|
||||||
|
|
||||||
|
int xargc; /* bullshit */
|
||||||
|
|
||||||
|
extern BOOL executing;
|
||||||
|
extern int infile;
|
||||||
|
int exitflg;
|
||||||
|
extern int eof;
|
||||||
|
|
||||||
|
int alldigs(char*);
|
||||||
|
void fault(void*, char*);
|
||||||
|
|
||||||
|
extern char *Ipath;
|
||||||
|
jmp_buf env;
|
||||||
|
static char *errmsg;
|
||||||
|
|
||||||
|
Fhdr *symhdr, *corhdr;
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: db [-kw] [-m machine] [-I dir] [symfile] [pid]\n");
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i, omode;
|
||||||
|
char *s;
|
||||||
|
char *name;
|
||||||
|
Fhdr *hdr;
|
||||||
|
|
||||||
|
name = 0;
|
||||||
|
outputinit();
|
||||||
|
maxoff = MAXOFF;
|
||||||
|
omode = OREAD;
|
||||||
|
ARGBEGIN{
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
case 'A':
|
||||||
|
abort();
|
||||||
|
case 'k':
|
||||||
|
kflag = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
omode = ORDWR;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
s = ARGF();
|
||||||
|
if(s == 0)
|
||||||
|
dprint("missing -I argument\n");
|
||||||
|
else
|
||||||
|
Ipath = s;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
name = ARGF();
|
||||||
|
if(name == 0)
|
||||||
|
dprint("missing -m argument\n");
|
||||||
|
break;
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unix and Plan 9 differ on what the right order of pid, text, and core is.
|
||||||
|
* I never remember anyway. Let's just accept them in any order.
|
||||||
|
*/
|
||||||
|
for(i=0; i<argc; i++){
|
||||||
|
if(alldigs(argv[i])){
|
||||||
|
if(pid){
|
||||||
|
dprint("already have pid %d; ignoring pid %d\n", pid, argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(corhdr){
|
||||||
|
dprint("already have core %s; ignoring pid %d\n", corfil, pid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pid = atoi(argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if((hdr = crackhdr(argv[i], omode)) == nil){
|
||||||
|
dprint("crackhdr %s: %r\n", argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dprint("%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
|
||||||
|
if(hdr->ftype == FCORE){
|
||||||
|
if(pid){
|
||||||
|
dprint("already have pid %d; ignoring core %s\n", pid, argv[i]);
|
||||||
|
uncrackhdr(hdr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(corhdr){
|
||||||
|
dprint("already have core %s; ignoring core %s\n", corfil, argv[i]);
|
||||||
|
uncrackhdr(hdr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
corhdr = hdr;
|
||||||
|
corfil = argv[i];
|
||||||
|
}else{
|
||||||
|
if(symhdr){
|
||||||
|
dprint("already have text %s; ignoring text %s\n", symfil, argv[i]);
|
||||||
|
uncrackhdr(hdr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
symhdr = hdr;
|
||||||
|
symfil = argv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(symhdr==nil){
|
||||||
|
symfil = "a.out";
|
||||||
|
if(pid){
|
||||||
|
if((s = proctextfile(pid)) != nil){
|
||||||
|
dprint("pid %d: text %s\n", pid, s);
|
||||||
|
symfil = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* XXX pull command from core */
|
||||||
|
|
||||||
|
if((symhdr = crackhdr(symfil, omode)) == nil){
|
||||||
|
dprint("crackhdr %s: %r\n", symfil);
|
||||||
|
symfil = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mach)
|
||||||
|
mach = machcpu;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up maps.
|
||||||
|
*/
|
||||||
|
symmap = allocmap();
|
||||||
|
cormap = allocmap();
|
||||||
|
if(symmap == nil || cormap == nil)
|
||||||
|
sysfatal("allocating maps: %r");
|
||||||
|
|
||||||
|
if(symhdr){
|
||||||
|
if(mapfile(symhdr, 0, symmap, nil) < 0)
|
||||||
|
dprint("mapping %s: %r\n", symfil);
|
||||||
|
mapfile(symhdr, 0, cormap, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
dotmap = dumbmap(-1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* show initial state and drop into the execution loop.
|
||||||
|
*/
|
||||||
|
notify(fault);
|
||||||
|
setsym();
|
||||||
|
if(setjmp(env) == 0){
|
||||||
|
if (pid || corhdr)
|
||||||
|
setcor(); /* could get error */
|
||||||
|
if (correg) {
|
||||||
|
dprint("%s\n", mach->exc(cormap, correg));
|
||||||
|
printpc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setjmp(env);
|
||||||
|
if (executing)
|
||||||
|
delbp();
|
||||||
|
executing = FALSE;
|
||||||
|
for (;;) {
|
||||||
|
flushbuf();
|
||||||
|
if (errmsg) {
|
||||||
|
dprint(errmsg);
|
||||||
|
printc('\n');
|
||||||
|
errmsg = 0;
|
||||||
|
exitflg = 0;
|
||||||
|
}
|
||||||
|
if (mkfault) {
|
||||||
|
mkfault=0;
|
||||||
|
printc('\n');
|
||||||
|
prints(DBNAME);
|
||||||
|
}
|
||||||
|
clrinp();
|
||||||
|
rdc();
|
||||||
|
reread();
|
||||||
|
if (eof) {
|
||||||
|
if (infile == STDIN)
|
||||||
|
done();
|
||||||
|
iclose(-1, 0);
|
||||||
|
eof = 0;
|
||||||
|
longjmp(env, 1);
|
||||||
|
}
|
||||||
|
exitflg = 0;
|
||||||
|
command(0, 0);
|
||||||
|
reread();
|
||||||
|
if (rdc() != '\n')
|
||||||
|
error("newline expected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
alldigs(char *s)
|
||||||
|
{
|
||||||
|
while(*s){
|
||||||
|
if(*s<'0' || '9'<*s)
|
||||||
|
return 0;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
done(void)
|
||||||
|
{
|
||||||
|
if (pid)
|
||||||
|
endpcs();
|
||||||
|
exits(exitflg? "error": 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An error occurred; save the message for later printing,
|
||||||
|
* close open files, and reset to main command loop.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
error(char *n)
|
||||||
|
{
|
||||||
|
errmsg = n;
|
||||||
|
iclose(0, 1);
|
||||||
|
oclose();
|
||||||
|
flush();
|
||||||
|
delbp();
|
||||||
|
ending = 0;
|
||||||
|
longjmp(env, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
errors(char *m, char *n)
|
||||||
|
{
|
||||||
|
static char buf[128];
|
||||||
|
|
||||||
|
sprint(buf, "%s: %s", m, n);
|
||||||
|
error(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An interrupt occurred;
|
||||||
|
* seek to the end of the current file
|
||||||
|
* and remember that there was a fault.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fault(void *a, char *s)
|
||||||
|
{
|
||||||
|
USED(a);
|
||||||
|
if(strncmp(s, "interrupt", 9) == 0){
|
||||||
|
seek(infile, 0L, 2);
|
||||||
|
mkfault++;
|
||||||
|
noted(NCONT);
|
||||||
|
}
|
||||||
|
noted(NDFLT);
|
||||||
|
}
|
||||||
26
src/cmd/db/mkfile
Normal file
26
src/cmd/db/mkfile
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
|
TARG=db
|
||||||
|
OFILES=\
|
||||||
|
command.$O\
|
||||||
|
expr.$O\
|
||||||
|
format.$O\
|
||||||
|
input.$O\
|
||||||
|
main.$O\
|
||||||
|
output.$O\
|
||||||
|
pcs.$O\
|
||||||
|
runpcs.$O\
|
||||||
|
regs.$O\
|
||||||
|
trcrun.$O\
|
||||||
|
print.$O\
|
||||||
|
setup.$O\
|
||||||
|
|
||||||
|
HFILES=defs.h\
|
||||||
|
fns.h\
|
||||||
|
|
||||||
|
SHORTLIB=mach bio 9
|
||||||
|
|
||||||
|
<$PLAN9/src/mkone
|
||||||
|
|
||||||
|
CFLAGS=$CFLAGS -I../libmach2
|
||||||
|
|
||||||
159
src/cmd/db/output.c
Normal file
159
src/cmd/db/output.c
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* debugger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
int printcol = 0;
|
||||||
|
int infile = STDIN;
|
||||||
|
int maxpos = MAXPOS;
|
||||||
|
|
||||||
|
Biobuf bstdout;
|
||||||
|
|
||||||
|
void
|
||||||
|
printc(int c)
|
||||||
|
{
|
||||||
|
dprint("%c", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* was move to next f1-sized tab stop; now just print a tab */
|
||||||
|
int
|
||||||
|
tconv(Fmt *f)
|
||||||
|
{
|
||||||
|
return fmtstrcpy(f, "\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
flushbuf(void)
|
||||||
|
{
|
||||||
|
if (printcol != 0)
|
||||||
|
printc(EOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
prints(char *s)
|
||||||
|
{
|
||||||
|
dprint("%s",s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
newline(void)
|
||||||
|
{
|
||||||
|
printc(EOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAXIFD 5
|
||||||
|
struct {
|
||||||
|
int fd;
|
||||||
|
int r9;
|
||||||
|
} istack[MAXIFD];
|
||||||
|
int ifiledepth;
|
||||||
|
|
||||||
|
void
|
||||||
|
iclose(int stack, int err)
|
||||||
|
{
|
||||||
|
if (err) {
|
||||||
|
if (infile) {
|
||||||
|
close(infile);
|
||||||
|
infile=STDIN;
|
||||||
|
}
|
||||||
|
while (--ifiledepth >= 0)
|
||||||
|
if (istack[ifiledepth].fd)
|
||||||
|
close(istack[ifiledepth].fd);
|
||||||
|
ifiledepth = 0;
|
||||||
|
} else if (stack == 0) {
|
||||||
|
if (infile) {
|
||||||
|
close(infile);
|
||||||
|
infile=STDIN;
|
||||||
|
}
|
||||||
|
} else if (stack > 0) {
|
||||||
|
if (ifiledepth >= MAXIFD)
|
||||||
|
error("$<< nested too deeply");
|
||||||
|
istack[ifiledepth].fd = infile;
|
||||||
|
ifiledepth++;
|
||||||
|
infile = STDIN;
|
||||||
|
} else {
|
||||||
|
if (infile) {
|
||||||
|
close(infile);
|
||||||
|
infile=STDIN;
|
||||||
|
}
|
||||||
|
if (ifiledepth > 0) {
|
||||||
|
infile = istack[--ifiledepth].fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
oclose(void)
|
||||||
|
{
|
||||||
|
flushbuf();
|
||||||
|
Bterm(&bstdout);
|
||||||
|
Binit(&bstdout, 1, OWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
redirout(char *file)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (file == 0){
|
||||||
|
oclose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flushbuf();
|
||||||
|
if ((fd = open(file, 1)) >= 0)
|
||||||
|
seek(fd, 0L, 2);
|
||||||
|
else if ((fd = create(file, 1, 0666)) < 0)
|
||||||
|
error("cannot create");
|
||||||
|
Bterm(&bstdout);
|
||||||
|
Binit(&bstdout, fd, OWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
endline(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (maxpos <= printcol)
|
||||||
|
newline();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
flush(void)
|
||||||
|
{
|
||||||
|
Bflush(&bstdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
dprint(char *fmt, ...)
|
||||||
|
{
|
||||||
|
int n, w;
|
||||||
|
char *p;
|
||||||
|
char buf[4096];
|
||||||
|
Rune r;
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
if(mkfault)
|
||||||
|
return -1;
|
||||||
|
va_start(arg, fmt);
|
||||||
|
n = vseprint(buf, buf+sizeof buf, fmt, arg) - buf;
|
||||||
|
va_end(arg);
|
||||||
|
Bwrite(&bstdout, buf, n);
|
||||||
|
for(p=buf; *p; p+=w){
|
||||||
|
w = chartorune(&r, p);
|
||||||
|
if(r == '\n')
|
||||||
|
printcol = 0;
|
||||||
|
else
|
||||||
|
printcol++;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
outputinit(void)
|
||||||
|
{
|
||||||
|
Binit(&bstdout, 1, OWRITE);
|
||||||
|
fmtinstall('t', tconv);
|
||||||
|
}
|
||||||
177
src/cmd/db/pcs.c
Normal file
177
src/cmd/db/pcs.c
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* debugger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
char NOPCS[] = "no process";
|
||||||
|
|
||||||
|
/* sub process control */
|
||||||
|
|
||||||
|
void
|
||||||
|
subpcs(int modif)
|
||||||
|
{
|
||||||
|
int check;
|
||||||
|
int runmode;
|
||||||
|
int keepnote;
|
||||||
|
int n, r;
|
||||||
|
ulong line, curr;
|
||||||
|
BKPT *bk;
|
||||||
|
char *comptr;
|
||||||
|
|
||||||
|
runmode=SINGLE;
|
||||||
|
r = 0;
|
||||||
|
keepnote=0;
|
||||||
|
loopcnt=cntval;
|
||||||
|
switch (modif) {
|
||||||
|
|
||||||
|
/* delete breakpoint */
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
if ((bk=scanbkpt(dot)) == 0)
|
||||||
|
error("no breakpoint set");
|
||||||
|
bk->flag=BKPTCLR;
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* set breakpoint */
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
if (bk=scanbkpt(dot))
|
||||||
|
bk->flag=BKPTCLR;
|
||||||
|
for (bk=bkpthead; bk; bk=bk->nxtbkpt)
|
||||||
|
if (bk->flag == BKPTCLR)
|
||||||
|
break;
|
||||||
|
if (bk==0) {
|
||||||
|
bk = (BKPT *)malloc(sizeof(*bk));
|
||||||
|
if (bk == 0)
|
||||||
|
error("too many breakpoints");
|
||||||
|
bk->nxtbkpt=bkpthead;
|
||||||
|
bkpthead=bk;
|
||||||
|
}
|
||||||
|
bk->loc = dot;
|
||||||
|
bk->initcnt = bk->count = cntval;
|
||||||
|
bk->flag = modif == 'b' ? BKPTSET : BKPTTMP;
|
||||||
|
check=MAXCOM-1;
|
||||||
|
comptr=bk->comm;
|
||||||
|
rdc();
|
||||||
|
reread();
|
||||||
|
do {
|
||||||
|
*comptr++ = readchar();
|
||||||
|
} while (check-- && lastc!=EOR);
|
||||||
|
*comptr=0;
|
||||||
|
if(bk->comm[0] != EOR && cntflg == FALSE)
|
||||||
|
bk->initcnt = bk->count = HUGEINT;
|
||||||
|
reread();
|
||||||
|
if (check)
|
||||||
|
return;
|
||||||
|
error("bkpt command too long");
|
||||||
|
|
||||||
|
/* exit */
|
||||||
|
case 'k' :
|
||||||
|
case 'K':
|
||||||
|
if (pid == 0)
|
||||||
|
error(NOPCS);
|
||||||
|
dprint("%d: killed", pid);
|
||||||
|
pcsactive = 1; /* force 'kill' ctl */
|
||||||
|
endpcs();
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* run program */
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
endpcs();
|
||||||
|
setup();
|
||||||
|
runmode = CONTIN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* single step */
|
||||||
|
case 's':
|
||||||
|
if (pid == 0) {
|
||||||
|
setup();
|
||||||
|
loopcnt--;
|
||||||
|
}
|
||||||
|
runmode=SINGLE;
|
||||||
|
keepnote=defval(1);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
if (pid == 0) {
|
||||||
|
setup();
|
||||||
|
loopcnt--;
|
||||||
|
}
|
||||||
|
keepnote=defval(1);
|
||||||
|
if(pc2line(dbrget(cormap, mach->pc), &line) < 0)
|
||||||
|
error("%r");
|
||||||
|
n = loopcnt;
|
||||||
|
dprint("%s: running\n", symfil);
|
||||||
|
flush();
|
||||||
|
for (loopcnt = 1; n > 0; loopcnt = 1) {
|
||||||
|
r = runpcs(SINGLE, keepnote);
|
||||||
|
if(pc2line(dot, &curr) < 0)
|
||||||
|
error("%r");
|
||||||
|
if (line != curr) { /* on a new line of c */
|
||||||
|
line = curr;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loopcnt = 0;
|
||||||
|
break;
|
||||||
|
/* continue with optional note */
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
if (pid==0)
|
||||||
|
error(NOPCS);
|
||||||
|
runmode=CONTIN;
|
||||||
|
keepnote=defval(1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n': /* deal with notes */
|
||||||
|
if (pid==0)
|
||||||
|
error(NOPCS);
|
||||||
|
n=defval(-1);
|
||||||
|
if(n>=0 && n<nnote){
|
||||||
|
nnote--;
|
||||||
|
memmove(note[n], note[n+1], (nnote-n)*sizeof(note[0]));
|
||||||
|
}
|
||||||
|
notes();
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 'h': /* halt the current process */
|
||||||
|
if (adrflg && adrval == 0) {
|
||||||
|
if (pid == 0)
|
||||||
|
error(NOPCS);
|
||||||
|
ungrab();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
grab();
|
||||||
|
dprint("stopped at%16t");
|
||||||
|
goto Return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 'x': /* continue executing the current process */
|
||||||
|
if (pid == 0)
|
||||||
|
error(NOPCS);
|
||||||
|
ungrab();
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error("bad `:' command");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loopcnt>0) {
|
||||||
|
dprint("%s: running\n", symfil);
|
||||||
|
flush();
|
||||||
|
r = runpcs(runmode,keepnote);
|
||||||
|
}
|
||||||
|
if (r)
|
||||||
|
dprint("breakpoint%16t");
|
||||||
|
else
|
||||||
|
dprint("stopped at%16t");
|
||||||
|
Return:
|
||||||
|
delbp();
|
||||||
|
printpc();
|
||||||
|
notes();
|
||||||
|
}
|
||||||
406
src/cmd/db/print.c
Normal file
406
src/cmd/db/print.c
Normal file
|
|
@ -0,0 +1,406 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* debugger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
extern int infile;
|
||||||
|
extern int outfile;
|
||||||
|
extern int maxpos;
|
||||||
|
|
||||||
|
/* general printing routines ($) */
|
||||||
|
|
||||||
|
char *Ipath = INCDIR;
|
||||||
|
static int tracetype;
|
||||||
|
static void printfp(Map*, int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* callback on stack trace
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ptrace(Map *map, Regs *regs, ulong pc, ulong nextpc, Symbol *sym, int depth)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
USED(map);
|
||||||
|
if(sym){
|
||||||
|
dprint("%s(", sym->name);
|
||||||
|
printparams(sym, regs);
|
||||||
|
dprint(") ");
|
||||||
|
}else
|
||||||
|
dprint("%#lux ", pc);
|
||||||
|
printsource(pc);
|
||||||
|
|
||||||
|
dprint(" called from ");
|
||||||
|
symoff(buf, 512, nextpc, CTEXT);
|
||||||
|
dprint("%s ", buf);
|
||||||
|
/* printsource(nextpc); */
|
||||||
|
dprint("\n");
|
||||||
|
if(tracetype == 'C' && sym)
|
||||||
|
printlocals(sym, regs);
|
||||||
|
return depth<40;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ulong *adrregvals;
|
||||||
|
|
||||||
|
static int
|
||||||
|
adrrw(Regs *regs, char *name, ulong *val, int isr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if((i = windindex(name)) == -1)
|
||||||
|
return correg->rw(correg, name, val, isr);
|
||||||
|
if(isr){
|
||||||
|
*val = adrregvals[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
werrstr("saved registers are immutable");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Regs*
|
||||||
|
adrregs(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
static Regs r;
|
||||||
|
static u32int x;
|
||||||
|
|
||||||
|
if(adrregvals== nil){
|
||||||
|
adrregvals = malloc(mach->nwindreg*sizeof(adrregvals[0]));
|
||||||
|
if(adrregvals == nil)
|
||||||
|
error("%r");
|
||||||
|
}
|
||||||
|
for(i=0; i<mach->nwindreg; i++){
|
||||||
|
if(get4(cormap, adrval+4*i, &x) < 0)
|
||||||
|
error("%r");
|
||||||
|
adrregvals[i] = x;
|
||||||
|
}
|
||||||
|
r.rw = adrrw;
|
||||||
|
return &r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printdollar(int modif)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32int u4;
|
||||||
|
BKPT *bk;
|
||||||
|
Symbol s;
|
||||||
|
int stack;
|
||||||
|
char *fname;
|
||||||
|
char buf[512];
|
||||||
|
Regs *r;
|
||||||
|
|
||||||
|
if (cntflg==0)
|
||||||
|
cntval = -1;
|
||||||
|
switch (modif) {
|
||||||
|
|
||||||
|
case '<':
|
||||||
|
if (cntval == 0) {
|
||||||
|
while (readchar() != EOR)
|
||||||
|
;
|
||||||
|
reread();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rdc() == '<')
|
||||||
|
stack = 1;
|
||||||
|
else {
|
||||||
|
stack = 0;
|
||||||
|
reread();
|
||||||
|
}
|
||||||
|
fname = getfname();
|
||||||
|
redirin(stack, fname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
fname = getfname();
|
||||||
|
redirout(fname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
attachprocess();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'k':
|
||||||
|
kmsys();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'q':
|
||||||
|
case 'Q':
|
||||||
|
done();
|
||||||
|
|
||||||
|
case 'w':
|
||||||
|
maxpos=(adrflg?adrval:MAXPOS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'S':
|
||||||
|
printsym();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
maxoff=(adrflg?adrval:MAXOFF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
printmap("? map", symmap);
|
||||||
|
printmap("/ map", cormap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
case '?':
|
||||||
|
if (pid)
|
||||||
|
dprint("pid = %d\n",pid);
|
||||||
|
else
|
||||||
|
prints("no process\n");
|
||||||
|
flushbuf();
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
printregs(modif);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
printfp(cormap, modif);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
tracetype = modif;
|
||||||
|
if (adrflg)
|
||||||
|
r = adrregs();
|
||||||
|
else
|
||||||
|
r = correg;
|
||||||
|
if(stacktrace(cormap, correg, ptrace) <= 0)
|
||||||
|
error("no stack frame");
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*print externals*/
|
||||||
|
case 'e':
|
||||||
|
for (i = 0; indexsym(i, &s)>=0; i++) {
|
||||||
|
if (s.class==CDATA)
|
||||||
|
if (s.loc.type==LADDR)
|
||||||
|
if (get4(cormap, s.loc.addr, &u4) > 0)
|
||||||
|
dprint("%s/%12t%#lux\n", s.name, (ulong)u4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*print breakpoints*/
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
for (bk=bkpthead; bk; bk=bk->nxtbkpt)
|
||||||
|
if (bk->flag) {
|
||||||
|
symoff(buf, 512, (WORD)bk->loc, CTEXT);
|
||||||
|
dprint(buf);
|
||||||
|
if (bk->count != 1)
|
||||||
|
dprint(",%d", bk->count);
|
||||||
|
dprint(":%c %s", bk->flag == BKPTTMP ? 'B' : 'b', bk->comm);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'M':
|
||||||
|
fname = getfname();
|
||||||
|
if (machbyname(fname) == 0)
|
||||||
|
dprint("unknown name\n");;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("bad `$' command");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
getfname(void)
|
||||||
|
{
|
||||||
|
static char fname[ARB];
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (rdc() == EOR) {
|
||||||
|
reread();
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
p = fname;
|
||||||
|
do {
|
||||||
|
*p++ = lastc;
|
||||||
|
if (p >= &fname[ARB-1])
|
||||||
|
error("filename too long");
|
||||||
|
} while (rdc() != EOR);
|
||||||
|
*p = 0;
|
||||||
|
reread();
|
||||||
|
return (fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printfp(Map *map, int modif)
|
||||||
|
{
|
||||||
|
Regdesc *rp;
|
||||||
|
int i;
|
||||||
|
int ret;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
for (i = 0, rp = mach->reglist; rp->name; rp += ret) {
|
||||||
|
ret = 1;
|
||||||
|
if (!(rp->flags&RFLT))
|
||||||
|
continue;
|
||||||
|
ret = fpformat(map, rp, buf, sizeof(buf), modif);
|
||||||
|
if (ret < 0) {
|
||||||
|
werrstr("Register %s: %r", rp->name);
|
||||||
|
error("%r");
|
||||||
|
}
|
||||||
|
/* double column print */
|
||||||
|
if (i&0x01)
|
||||||
|
dprint("%40t%-8s%-12s\n", rp->name, buf);
|
||||||
|
else
|
||||||
|
dprint("\t%-8s%-12s", rp->name, buf);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
redirin(int stack, char *file)
|
||||||
|
{
|
||||||
|
char pfile[ARB];
|
||||||
|
|
||||||
|
if (file == 0) {
|
||||||
|
iclose(-1, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iclose(stack, 0);
|
||||||
|
if ((infile = open(file, 0)) < 0) {
|
||||||
|
strcpy(pfile, Ipath);
|
||||||
|
strcat(pfile, "/");
|
||||||
|
strcat(pfile, file);
|
||||||
|
if ((infile = open(pfile, 0)) < 0) {
|
||||||
|
infile = STDIN;
|
||||||
|
error("cannot open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printmap(char *s, Map *map)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!map)
|
||||||
|
return;
|
||||||
|
if (map == symmap)
|
||||||
|
dprint("%s%12t`%s'\n", s, symfil==nil ? "-" : symfil);
|
||||||
|
else if (map == cormap)
|
||||||
|
dprint("%s%12t`%s'\n", s, corfil==nil ? "-" : corfil);
|
||||||
|
else
|
||||||
|
dprint("%s\n", s);
|
||||||
|
for (i = 0; i < map->nseg; i++) {
|
||||||
|
dprint("%s%8t%-16#lux %-16#lux %-16#lux %s\n", map->seg[i].name,
|
||||||
|
map->seg[i].base, map->seg[i].base+map->seg[i].size, map->seg[i].offset,
|
||||||
|
map->seg[i].file ? map->seg[i].file : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dump the raw symbol table
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
printsym(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Symbol *sp, s;
|
||||||
|
|
||||||
|
for (i=0; indexsym(i, &s)>=0; i++){
|
||||||
|
sp = &s;
|
||||||
|
switch(sp->type) {
|
||||||
|
case 't':
|
||||||
|
case 'l':
|
||||||
|
dprint("%8#lux t %s\n", sp->loc.addr, sp->name);
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
case 'L':
|
||||||
|
dprint("%8#lux T %s\n", sp->loc.addr, sp->name);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
case 'd':
|
||||||
|
case 'B':
|
||||||
|
case 'b':
|
||||||
|
case 'a':
|
||||||
|
case 'p':
|
||||||
|
case 'm':
|
||||||
|
dprint("%8#lux %c %s\n", sp->loc.addr, sp->type, sp->name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STRINGSZ 128
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print the value of dot as file:line
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
printsource(long dot)
|
||||||
|
{
|
||||||
|
char str[STRINGSZ];
|
||||||
|
|
||||||
|
if (fileline(dot, str, STRINGSZ) >= 0)
|
||||||
|
dprint("%s", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printpc(void)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
ulong u;
|
||||||
|
|
||||||
|
if(rget(correg, mach->pc, &u) < 0)
|
||||||
|
error("%r");
|
||||||
|
dot = u;
|
||||||
|
if(dot){
|
||||||
|
printsource((long)dot);
|
||||||
|
printc(' ');
|
||||||
|
symoff(buf, sizeof(buf), (long)dot, CTEXT);
|
||||||
|
dprint("%s/", buf);
|
||||||
|
if (mach->das(cormap, dot, 'i', buf, sizeof(buf)) < 0)
|
||||||
|
error("%r");
|
||||||
|
dprint("%16t%s\n", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printlocals(Symbol *fn, Regs *regs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32int v;
|
||||||
|
Symbol s;
|
||||||
|
|
||||||
|
for (i = 0; indexlsym(fn, i, &s)>=0; i++) {
|
||||||
|
if (s.class != CAUTO)
|
||||||
|
continue;
|
||||||
|
if(lget4(cormap, correg, s.loc, &v) >= 0)
|
||||||
|
dprint("%8t%s.%s/%10t%#lux\n", fn->name, s.name, v);
|
||||||
|
else
|
||||||
|
dprint("%8t%s.%s/%10t?\n", fn->name, s.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printparams(Symbol *fn, Regs *regs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Symbol s;
|
||||||
|
u32int v;
|
||||||
|
int first = 0;
|
||||||
|
|
||||||
|
for (i = 0; indexlsym(fn, i, &s)>=0; i++) {
|
||||||
|
if (s.class != CPARAM)
|
||||||
|
continue;
|
||||||
|
if (first++)
|
||||||
|
dprint(", ");
|
||||||
|
if(lget4(cormap, correg, s.loc, &v) >= 0)
|
||||||
|
dprint("%s=%#lux", s.name, v);
|
||||||
|
else
|
||||||
|
dprint("%s=?", s.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/cmd/db/regs.c
Normal file
44
src/cmd/db/regs.c
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* code to keep track of registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print the registers
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
printregs(int c)
|
||||||
|
{
|
||||||
|
Regdesc *rp;
|
||||||
|
int i;
|
||||||
|
ulong u;
|
||||||
|
|
||||||
|
if(correg == nil){
|
||||||
|
dprint("registers not mapped\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1, rp = mach->reglist; rp->name; rp++, i++) {
|
||||||
|
if ((rp->flags & RFLT)) {
|
||||||
|
if (c != 'R')
|
||||||
|
continue;
|
||||||
|
if (rp->format == '8' || rp->format == '3')
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rget(correg, rp->name, &u);
|
||||||
|
if(rp->format == 'Y')
|
||||||
|
dprint("%-8s %-20#llux", rp->name, (uvlong)u);
|
||||||
|
else
|
||||||
|
dprint("%-8s %-12#lux", rp->name, (ulong)u);
|
||||||
|
if ((i % 3) == 0) {
|
||||||
|
dprint("\n");
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i != 1)
|
||||||
|
dprint("\n");
|
||||||
|
dprint ("%s\n", mach->exc(cormap, correg));
|
||||||
|
printpc();
|
||||||
|
}
|
||||||
205
src/cmd/db/runpcs.c
Normal file
205
src/cmd/db/runpcs.c
Normal file
|
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* debugger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
BKPT *bkpthead;
|
||||||
|
|
||||||
|
BOOL bpin;
|
||||||
|
|
||||||
|
int pid;
|
||||||
|
int nnote;
|
||||||
|
int ending;
|
||||||
|
char note[NNOTE][ERRMAX];
|
||||||
|
|
||||||
|
/* service routines for sub process control */
|
||||||
|
|
||||||
|
int
|
||||||
|
runpcs(int runmode, int keepnote)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
BKPT *bkpt;
|
||||||
|
ADDR x;
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
if (adrflg)
|
||||||
|
rput(correg, mach->pc, dot);
|
||||||
|
if(rget(correg, mach->pc, &dot) < 0)
|
||||||
|
error("%r");
|
||||||
|
flush();
|
||||||
|
while (--loopcnt >= 0) {
|
||||||
|
if(loopcnt != 0)
|
||||||
|
printpc();
|
||||||
|
if (runmode == SINGLE) {
|
||||||
|
bkpt = scanbkpt(dot);
|
||||||
|
if (bkpt) {
|
||||||
|
switch(bkpt->flag){
|
||||||
|
case BKPTTMP:
|
||||||
|
bkpt->flag = BKPTCLR;
|
||||||
|
break;
|
||||||
|
case BKPTSKIP:
|
||||||
|
bkpt->flag = BKPTSET;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runstep(dot, keepnote);
|
||||||
|
} else {
|
||||||
|
if(rget(correg, mach->pc, &x) < 0)
|
||||||
|
error("%r");
|
||||||
|
if ((bkpt = scanbkpt(x)) != 0) {
|
||||||
|
execbkpt(bkpt, keepnote);
|
||||||
|
keepnote = 0;
|
||||||
|
}
|
||||||
|
setbp();
|
||||||
|
runrun(keepnote);
|
||||||
|
}
|
||||||
|
keepnote = 0;
|
||||||
|
delbp();
|
||||||
|
if(rget(correg, mach->pc, &dot) < 0)
|
||||||
|
error("%r");
|
||||||
|
/* real note? */
|
||||||
|
if (nnote > 0) {
|
||||||
|
keepnote = 1;
|
||||||
|
rc = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bkpt = scanbkpt(dot);
|
||||||
|
if(bkpt == 0){
|
||||||
|
keepnote = 0;
|
||||||
|
rc = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* breakpoint */
|
||||||
|
if (bkpt->flag == BKPTTMP)
|
||||||
|
bkpt->flag = BKPTCLR;
|
||||||
|
else if (bkpt->flag == BKPTSKIP) {
|
||||||
|
execbkpt(bkpt, keepnote);
|
||||||
|
keepnote = 0;
|
||||||
|
loopcnt++; /* we didn't really stop */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bkpt->flag = BKPTSKIP;
|
||||||
|
--bkpt->count;
|
||||||
|
if ((bkpt->comm[0] == EOR || command(bkpt->comm, ':') != 0)
|
||||||
|
&& bkpt->count != 0) {
|
||||||
|
execbkpt(bkpt, keepnote);
|
||||||
|
keepnote = 0;
|
||||||
|
loopcnt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bkpt->count = bkpt->initcnt;
|
||||||
|
}
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
return(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* finish the process off;
|
||||||
|
* kill if still running
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
endpcs(void)
|
||||||
|
{
|
||||||
|
BKPT *bk;
|
||||||
|
|
||||||
|
if(ending)
|
||||||
|
return;
|
||||||
|
ending = 1;
|
||||||
|
if (pid) {
|
||||||
|
if(pcsactive){
|
||||||
|
killpcs();
|
||||||
|
pcsactive = 0;
|
||||||
|
}
|
||||||
|
pid=0;
|
||||||
|
nnote=0;
|
||||||
|
for (bk=bkpthead; bk; bk = bk->nxtbkpt)
|
||||||
|
if (bk->flag == BKPTTMP)
|
||||||
|
bk->flag = BKPTCLR;
|
||||||
|
else if (bk->flag != BKPTCLR)
|
||||||
|
bk->flag = BKPTSET;
|
||||||
|
}
|
||||||
|
bpin = FALSE;
|
||||||
|
ending = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* start up the program to be debugged in a child
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
setup(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
nnote = 0;
|
||||||
|
startpcs();
|
||||||
|
bpin = FALSE;
|
||||||
|
pcsactive = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* skip over a breakpoint:
|
||||||
|
* remove breakpoints, then single step
|
||||||
|
* so we can put it back
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
execbkpt(BKPT *bk, int keepnote)
|
||||||
|
{
|
||||||
|
runstep(bk->loc, keepnote);
|
||||||
|
bk->flag = BKPTSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find the breakpoint at adr, if any
|
||||||
|
*/
|
||||||
|
|
||||||
|
BKPT *
|
||||||
|
scanbkpt(ADDR adr)
|
||||||
|
{
|
||||||
|
BKPT *bk;
|
||||||
|
|
||||||
|
for (bk = bkpthead; bk; bk = bk->nxtbkpt)
|
||||||
|
if (bk->flag != BKPTCLR && bk->loc == adr)
|
||||||
|
break;
|
||||||
|
return(bk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* remove all breakpoints from the process' address space
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
delbp(void)
|
||||||
|
{
|
||||||
|
BKPT *bk;
|
||||||
|
|
||||||
|
if (bpin == FALSE || pid == 0)
|
||||||
|
return;
|
||||||
|
for (bk = bkpthead; bk; bk = bk->nxtbkpt)
|
||||||
|
if (bk->flag != BKPTCLR)
|
||||||
|
bkput(bk, 0);
|
||||||
|
bpin = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* install all the breakpoints
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
setbp(void)
|
||||||
|
{
|
||||||
|
BKPT *bk;
|
||||||
|
|
||||||
|
if (bpin == TRUE || pid == 0)
|
||||||
|
return;
|
||||||
|
for (bk = bkpthead; bk; bk = bk->nxtbkpt)
|
||||||
|
if (bk->flag != BKPTCLR)
|
||||||
|
bkput(bk, 1);
|
||||||
|
bpin = TRUE;
|
||||||
|
}
|
||||||
145
src/cmd/db/setup.c
Normal file
145
src/cmd/db/setup.c
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
/*
|
||||||
|
* init routines
|
||||||
|
*/
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
char *symfil;
|
||||||
|
char *corfil;
|
||||||
|
|
||||||
|
Map *symmap;
|
||||||
|
Map *cormap;
|
||||||
|
Regs *correg;
|
||||||
|
Map *dotmap;
|
||||||
|
|
||||||
|
void
|
||||||
|
setsym(void)
|
||||||
|
{
|
||||||
|
if(symhdr && syminit(symhdr) < 0)
|
||||||
|
dprint("syminit: %r\n");
|
||||||
|
/*
|
||||||
|
Symbol s;
|
||||||
|
if (mach->sbreg && lookup(0, mach->sbreg, &s) < 0)
|
||||||
|
mach->sb = s.loc.addr;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setcor(void)
|
||||||
|
{
|
||||||
|
unmapproc(cormap);
|
||||||
|
unmapfile(corhdr, cormap);
|
||||||
|
free(correg);
|
||||||
|
correg = nil;
|
||||||
|
|
||||||
|
if (pid > 0) {
|
||||||
|
if (mapproc(pid, cormap, &correg) < 0)
|
||||||
|
dprint("mapproc %d: %r\n", pid);
|
||||||
|
} else {
|
||||||
|
if (corhdr) {
|
||||||
|
if (mapfile(corhdr, 0, cormap, &correg) < 0)
|
||||||
|
dprint("mapfile %s: %r\n", corfil);
|
||||||
|
} else
|
||||||
|
dprint("no core image\n");
|
||||||
|
}
|
||||||
|
kmsys();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map*
|
||||||
|
dumbmap(int fd)
|
||||||
|
{
|
||||||
|
Map *dumb;
|
||||||
|
Seg s;
|
||||||
|
|
||||||
|
dumb = allocmap();
|
||||||
|
memset(&s, 0, sizeof s);
|
||||||
|
s.fd = fd;
|
||||||
|
s.base = 0;
|
||||||
|
s.offset = 0;
|
||||||
|
s.size = 0xFFFFFFFF;
|
||||||
|
s.name = "data";
|
||||||
|
s.file = "<dumb>";
|
||||||
|
if(addseg(dumb, s) < 0){
|
||||||
|
freemap(dumb);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(mach == nil)
|
||||||
|
mach = machcpu;
|
||||||
|
return dumb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set up maps for a direct process image (/proc)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cmdmap(Map *map)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char name[MAXSYM];
|
||||||
|
|
||||||
|
rdc();
|
||||||
|
readsym(name);
|
||||||
|
i = findseg(map, name, nil);
|
||||||
|
if (i < 0) /* not found */
|
||||||
|
error("Invalid map name");
|
||||||
|
|
||||||
|
if (expr(0)) {
|
||||||
|
// if (strcmp(name, "text") == 0)
|
||||||
|
// textseg(expv, &fhdr);
|
||||||
|
map->seg[i].base = expv;
|
||||||
|
} else
|
||||||
|
error("Invalid base address");
|
||||||
|
if (expr(0))
|
||||||
|
map->seg[i].size = expv - map->seg[i].base;
|
||||||
|
else
|
||||||
|
error("Invalid end address");
|
||||||
|
if (expr(0))
|
||||||
|
map->seg[i].offset = expv;
|
||||||
|
else
|
||||||
|
error("Invalid file offset");
|
||||||
|
/*
|
||||||
|
if (rdc()=='?' && map == cormap) {
|
||||||
|
if (fcor)
|
||||||
|
close(fcor);
|
||||||
|
fcor=fsym;
|
||||||
|
corfil = symfil;
|
||||||
|
cormap = symmap;
|
||||||
|
} else if (lastc == '/' && map == symmap) {
|
||||||
|
if (fsym)
|
||||||
|
close(fsym);
|
||||||
|
fsym=fcor;
|
||||||
|
symfil=corfil;
|
||||||
|
symmap=cormap;
|
||||||
|
} else
|
||||||
|
reread();
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kmsys(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = findseg(symmap, "text", symfil);
|
||||||
|
if (i >= 0) {
|
||||||
|
symmap->seg[i].base = symmap->seg[i].base&~mach->ktmask;
|
||||||
|
symmap->seg[i].size = -symmap->seg[i].base;
|
||||||
|
}
|
||||||
|
i = findseg(symmap, "data", symfil);
|
||||||
|
if (i >= 0) {
|
||||||
|
symmap->seg[i].base = symmap->seg[i].base&~mach->ktmask;
|
||||||
|
symmap->seg[i].size = -symmap->seg[i].base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
attachprocess(void)
|
||||||
|
{
|
||||||
|
if (!adrflg) {
|
||||||
|
dprint("used pid$a\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pid = adrval;
|
||||||
|
setcor();
|
||||||
|
}
|
||||||
288
src/cmd/db/trcrun.c
Normal file
288
src/cmd/db/trcrun.c
Normal file
|
|
@ -0,0 +1,288 @@
|
||||||
|
/*
|
||||||
|
* functions for running the debugged process
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
|
||||||
|
int child;
|
||||||
|
int msgfd = -1;
|
||||||
|
int notefd = -1;
|
||||||
|
int pcspid = -1;
|
||||||
|
int pcsactive = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
setpcs(void)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
|
if(pid && pid != pcspid){
|
||||||
|
if(msgfd >= 0){
|
||||||
|
close(msgfd);
|
||||||
|
msgfd = -1;
|
||||||
|
}
|
||||||
|
if(notefd >= 0){
|
||||||
|
close(notefd);
|
||||||
|
notefd = -1;
|
||||||
|
}
|
||||||
|
pcspid = -1;
|
||||||
|
sprint(buf, "/proc/%d/ctl", pid);
|
||||||
|
msgfd = open(buf, OWRITE);
|
||||||
|
if(msgfd < 0)
|
||||||
|
error("can't open control file");
|
||||||
|
sprint(buf, "/proc/%d/note", pid);
|
||||||
|
notefd = open(buf, ORDWR);
|
||||||
|
if(notefd < 0)
|
||||||
|
error("can't open note file");
|
||||||
|
pcspid = pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
msgpcs(char *msg)
|
||||||
|
{
|
||||||
|
char err[ERRMAX];
|
||||||
|
|
||||||
|
setpcs();
|
||||||
|
if(write(msgfd, msg, strlen(msg)) < 0 && !ending){
|
||||||
|
errstr(err, sizeof err);
|
||||||
|
if(strcmp(err, "interrupted") != 0)
|
||||||
|
endpcs();
|
||||||
|
errors("can't write control file", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* empty the note buffer and toss pending breakpoint notes
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
unloadnote(void)
|
||||||
|
{
|
||||||
|
char err[ERRMAX];
|
||||||
|
|
||||||
|
setpcs();
|
||||||
|
for(; nnote<NNOTE; nnote++){
|
||||||
|
switch(read(notefd, note[nnote], sizeof note[nnote])){
|
||||||
|
case -1:
|
||||||
|
errstr(err, sizeof err);
|
||||||
|
if(strcmp(err, "interrupted") != 0)
|
||||||
|
endpcs();
|
||||||
|
errors("can't read note file", err);
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
note[nnote][ERRMAX-1] = '\0';
|
||||||
|
if(strncmp(note[nnote], "sys: breakpoint", 15) == 0)
|
||||||
|
--nnote;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reload the note buffer
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
loadnote(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char err[ERRMAX];
|
||||||
|
|
||||||
|
setpcs();
|
||||||
|
for(i=0; i<nnote; i++){
|
||||||
|
if(write(notefd, note[i], strlen(note[i])) < 0){
|
||||||
|
errstr(err, sizeof err);
|
||||||
|
if(strcmp(err, "interrupted") != 0)
|
||||||
|
endpcs();
|
||||||
|
errors("can't write note file", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nnote = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
notes(void)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(nnote == 0)
|
||||||
|
return;
|
||||||
|
dprint("notes:\n");
|
||||||
|
for(n=0; n<nnote; n++)
|
||||||
|
dprint("%d:\t%s\n", n, note[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
killpcs(void)
|
||||||
|
{
|
||||||
|
msgpcs("kill");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
grab(void)
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
msgpcs("stop");
|
||||||
|
bpwait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ungrab(void)
|
||||||
|
{
|
||||||
|
msgpcs("start");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
doexec(void)
|
||||||
|
{
|
||||||
|
char *argl[MAXARG];
|
||||||
|
char args[LINSIZ];
|
||||||
|
char *p;
|
||||||
|
char **ap;
|
||||||
|
char *thisarg;
|
||||||
|
|
||||||
|
ap = argl;
|
||||||
|
p = args;
|
||||||
|
*ap++ = symfil;
|
||||||
|
for (rdc(); lastc != EOR;) {
|
||||||
|
thisarg = p;
|
||||||
|
if (lastc == '<' || lastc == '>') {
|
||||||
|
*p++ = lastc;
|
||||||
|
rdc();
|
||||||
|
}
|
||||||
|
while (lastc != EOR && lastc != SPC && lastc != TB) {
|
||||||
|
*p++ = lastc;
|
||||||
|
readchar();
|
||||||
|
}
|
||||||
|
if (lastc == SPC || lastc == TB)
|
||||||
|
rdc();
|
||||||
|
*p++ = 0;
|
||||||
|
if (*thisarg == '<') {
|
||||||
|
close(0);
|
||||||
|
if (open(&thisarg[1], OREAD) < 0) {
|
||||||
|
print("%s: cannot open\n", &thisarg[1]);
|
||||||
|
_exits(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*thisarg == '>') {
|
||||||
|
close(1);
|
||||||
|
if (create(&thisarg[1], OWRITE, 0666) < 0) {
|
||||||
|
print("%s: cannot create\n", &thisarg[1]);
|
||||||
|
_exits(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*ap++ = thisarg;
|
||||||
|
}
|
||||||
|
*ap = 0;
|
||||||
|
exec(symfil, argl);
|
||||||
|
perror(symfil);
|
||||||
|
}
|
||||||
|
|
||||||
|
char procname[100];
|
||||||
|
|
||||||
|
void
|
||||||
|
startpcs(void)
|
||||||
|
{
|
||||||
|
if ((pid = fork()) == 0) {
|
||||||
|
pid = getpid();
|
||||||
|
msgpcs("hang");
|
||||||
|
doexec();
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == -1)
|
||||||
|
error("can't fork");
|
||||||
|
child++;
|
||||||
|
sprint(procname, "/proc/%d/mem", pid);
|
||||||
|
corfil = procname;
|
||||||
|
msgpcs("waitstop");
|
||||||
|
bpwait();
|
||||||
|
if (adrflg)
|
||||||
|
rput(correg, mach->pc, adrval);
|
||||||
|
while (rdc() != EOR)
|
||||||
|
;
|
||||||
|
reread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runstep(ulong loc, int keepnote)
|
||||||
|
{
|
||||||
|
int nfoll;
|
||||||
|
ulong foll[3];
|
||||||
|
BKPT bkpt[3];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(mach->foll == 0){
|
||||||
|
dprint("stepping unimplemented; assuming not a branch\n");
|
||||||
|
nfoll = 1;
|
||||||
|
foll[0] = loc+mach->pcquant;
|
||||||
|
}else {
|
||||||
|
nfoll = mach->foll(cormap, correg, loc, foll);
|
||||||
|
if (nfoll < 0)
|
||||||
|
error("%r");
|
||||||
|
}
|
||||||
|
memset(bkpt, 0, sizeof bkpt);
|
||||||
|
for(i=0; i<nfoll; i++){
|
||||||
|
if(foll[i] == loc)
|
||||||
|
error("can't single step: next instruction is dot");
|
||||||
|
bkpt[i].loc = foll[i];
|
||||||
|
bkput(&bkpt[i], 1);
|
||||||
|
}
|
||||||
|
runrun(keepnote);
|
||||||
|
for(i=0; i<nfoll; i++)
|
||||||
|
bkput(&bkpt[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bpwait(void)
|
||||||
|
{
|
||||||
|
setcor();
|
||||||
|
unloadnote();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
runrun(int keepnote)
|
||||||
|
{
|
||||||
|
int on;
|
||||||
|
|
||||||
|
on = nnote;
|
||||||
|
unloadnote();
|
||||||
|
if(on != nnote){
|
||||||
|
notes();
|
||||||
|
error("not running: new notes pending");
|
||||||
|
}
|
||||||
|
if(keepnote)
|
||||||
|
loadnote();
|
||||||
|
else
|
||||||
|
nnote = 0;
|
||||||
|
flush();
|
||||||
|
msgpcs("startstop");
|
||||||
|
bpwait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bkput(BKPT *bp, int install)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
ulong loc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
errstr(buf, sizeof buf);
|
||||||
|
/*
|
||||||
|
if(mach->bpfix)
|
||||||
|
loc = (*mach->bpfix)(bp->loc);
|
||||||
|
else
|
||||||
|
*/
|
||||||
|
loc = bp->loc;
|
||||||
|
if(install){
|
||||||
|
ret = get1(cormap, loc, bp->save, mach->bpsize);
|
||||||
|
if (ret > 0)
|
||||||
|
ret = put1(cormap, loc, mach->bpinst, mach->bpsize);
|
||||||
|
}else
|
||||||
|
ret = put1(cormap, loc, bp->save, mach->bpsize);
|
||||||
|
if(ret < 0){
|
||||||
|
sprint(buf, "can't set breakpoint at %#llux: %r", bp->loc);
|
||||||
|
print(buf);
|
||||||
|
read(0, buf, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue