/* Copyright (c) 1982 Regents of the University of California */
static char sccsid
[] = "@(#)vax.c 1.10 (Berkeley) %G%";
* Target machine dependent stuff.
typedef unsigned int Address
;
typedef unsigned char Byte
;
typedef unsigned int Word
;
#define BITSPERWORD (BITSPERBYTE * sizeof(Word))
#define nargspassed(frame) argn(0, frame)
private Address
printop();
* Decode and print the instructions within the given address range.
public printinst(lowaddr
, highaddr
)
for (addr
= lowaddr
; addr
<= highaddr
; ) {
* Another approach: print n instructions starting at the given address.
public printninst(count
, addr
)
register Address newaddr
;
error("non-positive repetition count");
for (i
= 0; i
< count
; i
++) {
newaddr
= printop(newaddr
);
* Hacked version of adb's VAX instruction decoder.
private Address
printop(addr
)
int argtype
, amode
, argno
, argval
;
iread(&ins
, addr
, sizeof(ins
));
for (argno
= 0; argno
< op
.numargs
; argno
++) {
argtype
= op
.argtype
[argno
];
if (is_branch_disp(argtype
)) {
mode
= 0xAF + (typelen(argtype
) << 5);
iread(&mode
, addr
, sizeof(mode
));
reg
= regname
[regnm(mode
)];
if (typelen(argtype
) == TYPF
|| typelen(argtype
) ==TYPD
)
printf("$%s", fltimm
[mode
]);
if (reg
!= regname
[PROGCTR
]) {
switch (typelen(argtype
)) {
argval
= printdisp(addr
, 1, reg
, amode
);
argval
= printdisp(addr
, 2, reg
, amode
);
argval
= printdisp(addr
, 4, reg
, amode
);
iread(&argval
, addr
, sizeof(argval
));
iread(&argval
, addr
, sizeof(argval
));
iread(&argval
, addr
+4, sizeof(argval
));
if (reg
== regname
[PROGCTR
]) {
argval
= printdisp(addr
, 4, reg
, amode
);
argval
= printdisp(addr
, 1, reg
, amode
);
argval
= printdisp(addr
, 1, reg
, amode
);
argval
= printdisp(addr
, 2, reg
, amode
);
argval
= printdisp(addr
, 2, reg
, amode
);
argval
= printdisp(addr
, 4, reg
, amode
);
argval
= printdisp(addr
, 4, reg
, amode
);
if (ins
== O_CASEB
|| ins
== O_CASEW
|| ins
== O_CASEL
) {
for (argno
= 0; argno
<= argval
; argno
++) {
iread(&offset
, addr
, sizeof(offset
));
printf("\n\t\t%d", offset
);
* Print the displacement of an instruction that uses displacement
private int printdisp(addr
, nbytes
, reg
, mode
)
iread(&byte
, addr
, sizeof(byte
));
iread(&hword
, addr
, sizeof(hword
));
iread(&argval
, addr
, sizeof(argval
));
if (reg
== regname
[PROGCTR
] && mode
>= BYTEDISP
) {
if (reg
== regname
[PROGCTR
]) {
f
= whatblock((Address
) argval
+ 2);
if (codeloc(f
) == argval
+ 2) {
printf("%s", symname(f
));
printf("%d(%s)", argval
, reg
);
* Print the contents of the addresses within the given range
* according to the given format.
{ "d", " %d", sizeof(short) },
{ "D", " %ld", sizeof(long) },
{ "o", " %o", sizeof(short) },
{ "O", " %lo", sizeof(long) },
{ "x", " %04x", sizeof(short) },
{ "X", " %08x", sizeof(long) },
{ "b", " \\%o", sizeof(char) },
{ "c", " '%c'", sizeof(char) },
{ "s", "%c", sizeof(char) },
{ "f", " %f", sizeof(float) },
{ "g", " %g", sizeof(double) },
private Format
*findformat(s
)
while (f
->name
!= nil
and not streq(f
->name
, s
)) {
error("bad print format \"%s\"", s
);
public Address
printdata(lowaddr
, highaddr
, format
)
if (lowaddr
> highaddr
) {
error("first address larger than second");
for (addr
= lowaddr
; addr
<= highaddr
; addr
+= f
->length
) {
dread(&value
, addr
, f
->length
);
printf(f
->printfstring
, value
);
if (n
>= (16 div f
->length
)) {
* The other approach is to print n items starting with a given address.
public printndata(count
, startaddr
, format
)
register Boolean isstring
;
error("non-positive repetition count");
isstring
= (Boolean
) streq(f
->name
, "s");
for (i
= 0; i
< count
; i
++) {
dread(&c
, addr
, sizeof(char));
dread(&c
, addr
, sizeof(char));
dread(&value
, addr
, f
->length
);
printf(f
->printfstring
, value
);
if (n
>= (16 div f
->length
)) {
* Print out a value according to the given format.
public printvalue(v
, format
)
if (streq(f
->name
, "s")) {
printf(f
->printfstring
, v
);
* Print out an execution time error.
* Assumes the source position of the error has been calculated.
* Have to check if the -r option was specified; if so then
* the object file information hasn't been read in yet.
extern String sys_siglist
[];
if (isfinished(process
)) {
printf("\"%s\" exits with code %d\n", objname
, exitcode(process
));
fprintf(stderr
, "Entering debugger ...");
fprintf(stderr
, " type 'help' for help\n");
printf("\n\ninterrupt ");
} else if (err
== SIGTRAP
) {
if (err
< 0 or err
> sys_nsig
) {
printf("\nsignal %d ", err
);
printf("\n%s ", sys_siglist
[err
]);
printlines(curline
, curline
);
* Note the termination of the program. We do this so as to avoid
* having the process exit, which would make the values of variables
* inaccessible. We do want to flush all output buffers here,
* otherwise it'll never get done.
stepto(nextaddr(pc
, true));
printf("\nexecution completed, exit code is %d\n", exitcode
);
* Single step the machine a source line (or instruction if "inst_tracing"
* is true). If "isnext" is true, skip over procedure calls.
private Address
getcall();
Address startaddr
, prevaddr
;
addr
= nextaddr(pc
, isnext
);
if (not inst_tracing
and nlhdr
.nlines
!= 0) {
addr
= nextaddr(addr
, isnext
);
filename
= srcfilename(addr
);
* Compute the next address that will be executed from the given one.
* If "isnext" is true then consider a procedure call as straight line code.
* We must unfortunately do much of the same work that is necessary
* to print instructions. In addition we have to deal with branches.
* Unconditional branches we just follow, for conditional branches
* we continue execution to the current location and then single step
* the machine. We assume that the last argument in an instruction
* that branches is the branch address (or relative offset).
private Address
findnextaddr();
public Address
nextaddr(startaddr
, isnext
)
if (addr
== 0 or addr
== 1) {
addr
= findnextaddr(startaddr
, isnext
);
private Address
findnextaddr(startaddr
, isnext
)
int argtype
, amode
, argno
, argval
;
enum { KNOWN
, SEQUENTIAL
, BRANCH
} addrstatus
;
iread(&ins
, addr
, sizeof(ins
));
setcurfunc(whatblock(pc
));
if (nosource(curfunc
) and canskip(curfunc
) and
callnews(/* iscall = */ true);
callnews(/* iscall = */ false);
if (addr
== pc
) { /* recursive ret to self */
case O_JMP
: /* because it may be jmp (r1) */
case O_BNEQ
: case O_BEQL
: case O_BGTR
:
case O_BLEQ
: case O_BGEQ
: case O_BLSS
:
case O_BGTRU
: case O_BLEQU
: case O_BVC
:
case O_BVS
: case O_BCC
: case O_BCS
:
case O_CASEB
: case O_CASEW
: case O_CASEL
:
case O_BBS
: case O_BBC
: case O_BBSS
: case O_BBCS
:
case O_BBSC
: case O_BBCC
: case O_BBSSI
:
case O_BBCCI
: case O_BLBS
: case O_BLBC
:
case O_ACBL
: case O_AOBLSS
: case O_AOBLEQ
:
case O_SOBGEQ
: case O_SOBGTR
:
if (addrstatus
!= KNOWN
) {
for (argno
= 0; argno
< op
.numargs
; argno
++) {
argtype
= op
.argtype
[argno
];
if (is_branch_disp(argtype
)) {
mode
= 0xAF + (typelen(argtype
) << 5);
iread(&mode
, addr
, sizeof(mode
));
r
= regname
[regnm(mode
)];
if (r
== regname
[PROGCTR
]) {
switch (typelen(argtype
)) {
argval
= getdisp(addr
, 1, r
, amode
);
argval
= getdisp(addr
, 2, r
, amode
);
argval
= getdisp(addr
, 4, r
, amode
);
iread(&argval
, addr
, sizeof(argval
));
iread(&argval
, addr
+4, sizeof(argval
));
if (r
== regname
[PROGCTR
]) {
argval
= getdisp(addr
, 4, r
, amode
);
argval
= getdisp(addr
, 1, r
, amode
);
argval
= getdisp(addr
, 2, r
, amode
);
argval
= getdisp(addr
, 4, r
, amode
);
if (ins
== O_CALLS
or ins
== O_CALLG
) {
if (addrstatus
== BRANCH
) {
* Get the displacement of an instruction that uses displacement addressing.
private int getdisp(addr
, nbytes
, reg
, mode
)
iread(&byte
, addr
, sizeof(byte
));
iread(&hword
, addr
, sizeof(hword
));
iread(&argval
, addr
, sizeof(argval
));
if (reg
== regname
[PROGCTR
] && mode
>= BYTEDISP
) {
#define BP_OP O_BPT /* breakpoint trap */
#define BP_ERRNO SIGTRAP /* signal received at a breakpoint */
* Setting a breakpoint at a location consists of saving
* the word at the location and poking a BP_OP there.
* We save the locations and words on a list for use in unsetting.
typedef struct Savelist
*Savelist
;
private Savelist savelist
;
* Set a breakpoint at the given address. Only save the word there
* if it's not already a breakpoint.
register Savelist newsave
, s
;
for (s
= savelist
; s
!= nil
; s
= s
->link
) {
if (s
->location
== addr
) {
iread(&save
, addr
, sizeof(save
));
newsave
->location
= addr
;
newsave
->link
= savelist
;
iwrite(&w
, addr
, sizeof(w
));
* Unset a breakpoint; unfortunately we have to search the SAVELIST
* to find the saved value. The assumption is that the SAVELIST will
* usually be quite small.
register Savelist s
, prev
;
for (s
= savelist
; s
!= nil
; s
= s
->link
) {
if (s
->location
== addr
) {
iwrite(&s
->save
, addr
, sizeof(s
->save
));
panic("unsetbp: couldn't find address %d", addr
);
* Predicate to test if the reason the process stopped was because
return (Boolean
) (not isfinished(process
) and errnum(process
) == SIGTRAP
);
* Enter a procedure by creating and executing a call instruction.
#define CALLSIZE 7 /* size of call instruction */
public beginproc(p
, argc
)
char addr
[sizeof(long)]; /* unaligned long */
iread(save
, pc
, sizeof(save
));
dest
= codeloc(p
) - 2 - (pc
+ 7);
mov(&dest
, call
.addr
, sizeof(call
.addr
));
iwrite(&call
, pc
, sizeof(call
));
iwrite(save
, pc
, sizeof(save
));