* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char sccsid
[] = "@(#)vax.c 5.5 (Berkeley) %G%";
static char rcsid
[] = "$Header: vax.c,v 1.2 88/10/26 18:50:53 donn Exp $";
* Target machine dependent stuff.
typedef unsigned int Address
;
typedef unsigned char Byte
;
typedef unsigned int Word
;
#define nargspassed(frame) argn(0, frame)
#define BITSPERWORD (BITSPERBYTE * sizeof(Word))
* This magic macro enables us to look at the process' registers
#define regloc(reg) (ctob(UPAGES) + (sizeof(Word) * (reg)))
* Indices into u. for use in collecting registers values.
R0
, R1
, R2
, R3
, R4
, R5
, R6
, R7
, R8
, R9
, R10
, R11
, AP
, FP
, SP
, PC
private Address
printop();
private Optab
*ioptab
[256]; /* index by opcode to optab */
private Optab
*esctab
[256]; /* for extended opcodes */
* Initialize the opcode lookup table.
for (p
= optab
; p
->iname
; p
++) {
if (p
->format
== O_ESCD
) {
} else if (p
->format
!= O_ESCD
&& p
->format
!= O_ESCE
) {
* 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
);
* 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
);
* Retrieve and print out the appropriate data in the given format.
* Floats have to be handled specially to allow the compiler to
* convert them to doubles when passing to printf.
private printformat (f
, addr
)
dread(&value
, addr
, f
->length
);
if (streq(f
->name
, "f")) {
printf(f
->printfstring
, value
.floatv
);
printf(f
->printfstring
, value
);
public Address
printdata(lowaddr
, highaddr
, format
)
if (lowaddr
> highaddr
) {
error("first address larger than second");
for (addr
= lowaddr
; addr
<= highaddr
; addr
+= f
->length
) {
if (n
>= (16 div f
->length
)) {
* The other approach is to print n items starting with a given address.
public printndata(count
, startaddr
, format
)
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));
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\" terminated normally\n", objname
);
printf("\"%s\" terminated abnormally (exit code %d)\n",
printlines(curline
, curline
);
private String illinames
[] = {
"reserved addressing fault",
"privileged instruction fault",
private String fpenames
[] = {
"integer divide by zero trap",
"floating overflow trap",
"floating/decimal divide by zero trap",
"floating underflow trap",
"subscript out of range trap",
"floating overflow fault",
"floating divide by zero fault",
"floating underflow fault"
if (signo
< 0 or signo
> sys_nsig
) {
printf("[signal %d]", signo
);
printf("%s", sys_siglist
[signo
]);
if (code
>= 0 and code
< sizeof(illinames
) / sizeof(illinames
[0])) {
printf(" (%s)", illinames
[code
]);
} else if (signo
== SIGFPE
) {
if (code
> 0 and code
< sizeof(fpenames
) / sizeof(fpenames
[0])) {
printf(" (%s)", fpenames
[code
]);
* 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 %d)\n", exitcode
);
printf("\nexecution completed\n");
* 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();
addr
= nextaddr(pc
, isnext
);
if (not inst_tracing
and nlhdr
.nlines
!= 0) {
addr
= nextaddr(addr
, isnext
);
filename
= srcfilename(addr
);
#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
);
* VAX instruction decoder, derived from adb.
private Address
printop(addr
)
int argtype
, amode
, argno
, argval
;
iread(&ins
, addr
, sizeof(ins
));
iread(&ins
, addr
, sizeof(ins
));
} else if (ins
== O_ESCD
) {
iread(&ins
, addr
, sizeof(ins
));
printf("[unrecognized opcode %#0x]\n", 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
||
typelen(argtype
) == TYPG
|| typelen(argtype
) == TYPH
)
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
));
if ((argval
& 0xffff007f) == 0x8000) {
printf("[reserved operand]");
printf("%g", *(float *)&argval
);
/* XXX this bags the low order bits */
iread(&argval
, addr
, sizeof(argval
));
if ((argval
& 0xffff007f) == 0x8000) {
printf("[reserved operand]");
printf("%g", *(float *)&argval
);
iread(&argval
, addr
+4, sizeof(argval
));
iread(&argval
, addr
, sizeof(argval
));
iread(&argval
, addr
+12, sizeof(argval
));
iread(&argval
, addr
+8, sizeof(argval
));
iread(&argval
, addr
+4, sizeof(argval
));
iread(&argval
, addr
, 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
));
if (varIsSet("$hexoffsets")) {
printf("-%x(%s)", -(argval
), reg
);
printf("%x(%s)", argval
, reg
);
printf("%d(%s)", argval
, reg
);
* 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
);
* Determine if it's ok to skip function f entered by instruction ins.
* If so, we're going to compute the return address and step to it.
* Therefore we cannot skip over a function entered by a jsb or bsb,
* since the return address is not easily computed for them.
private boolean
skipfunc (ins
, f
)
ins
!= O_JSB
and ins
!= O_BSBB
and ins
!= O_BSBW
and
not inst_tracing
and nlhdr
.nlines
!= 0 and
nosource(curfunc
) and canskip(curfunc
)
private Address
findnextaddr(startaddr
, isnext
)
int argtype
, amode
, argno
, argval
;
enum { KNOWN
, SEQUENTIAL
, BRANCH
} addrstatus
;
iread(&ins
, addr
, sizeof(ins
));
* It used to be that unconditional jumps and branches were handled
* by taking their destination address as the next address. While
* saving the cost of starting up the process, this approach
* doesn't work when jumping indirect (since the value in the
* register might not yet have been set).
* So unconditional jumps and branches are now handled the same way
* as conditional jumps and branches.
setcurfunc(whatblock(pc
));
if (isnext
or skipfunc(ins
, curfunc
)) {
callnews(/* iscall = */ true);
callnews(/* iscall = */ false);
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
:
case O_ESCF
: /* bugchecks */
iread(&ins2
, addr
+1, sizeof(ins2
));
if (ins2
== O_ACBF
|| ins2
== O_ACBD
)
/* actually ACBG and ACBH */
if (addrstatus
!= KNOWN
) {
printf("[bad extended opcode %#x in findnextaddr]\n", ins
);
printf("[bad opcode %#x in findnextaddr]\n", 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
));
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
));
iread(&argval
, addr
+12, 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
) {
* 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
));
* Special variables for debugging the kernel.
public integer masterpcbb
;
fseek(corefile
, masterpcbb
& ~0x80000000, 0);
pcb
.pcb_p0lr
&= ~AST_CLR
;
printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n",
pcb
.pcb_p0br
, pcb
.pcb_p0lr
, pcb
.pcb_p1br
, pcb
.pcb_p1lr
setreg(ARGP
, pcb
.pcb_ap
);
setreg(STKP
, pcb
.pcb_ksp
);
setreg(PROGCTR
, pcb
.pcb_pc
);
public copyregs (savreg
, reg
)
reg
[PROGCTR
] = savreg
[PC
];
* Map a virtual address to a physical address.
public Address
vmap (addr
)
switch (addr
&0xc0000000) {
* In system space, so get system pte.
* If it is valid or reclaimable then the physical address
* is the combination of its page number and the page offset
* of the original address.
error("address %x out of segment", addr
);
r
= ((long) (sbr
+ v
)) & ~0x80000000;
* In p1 space, must not be in shadow region.
error("address %x out of segment", addr
);
r
= (Address
) (pcb
.pcb_p1br
+ v
);
* In p0 space, must not be off end of region.
error("address %x out of segment", addr
);
r
= (Address
) (pcb
.pcb_p0br
+ v
);
* For p0/p1 address, user-level page table should be in
* kernel virtual memory. Do second-level indirect by recursing.
if ((r
& 0x80000000) == 0) {
error("bad p0br or p1br in pcb");
* "r" is now the address of the pte of the page
* we are interested in; get the pte and paste up the physical address.
n
= fread(&pte
, sizeof(pte
), 1, corefile
);
error("page table botch (fread at %x returns %d)", r
, n
);
if (pte
.pg_v
== 0 and (pte
.pg_fod
!= 0 or pte
.pg_pfnum
== 0)) {
error("page no valid or reclamable");
return (addr
&PGOFSET
) + ((Address
) ptob(pte
.pg_pfnum
));
* Extract a bit field from an integer.
public integer
extractField (s
)
if (nbytes
> sizeof(n
)) {
printf("[bad size in extractField -- word assumed]\n");
r
= n
>> (s
->symvalue
.field
.offset mod BITSPERBYTE
);
r
&= ((1 << s
->symvalue
.field
.length
) - 1);
* Change the length of a value in memory according to a given difference
* in the lengths of its new and old types.
public loophole (oldlen
, newlen
)
for (i
= 0; i
< n
; i
++) {