* Copyright (c) 1985 The Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)tahoe.c 5.8 (Berkeley) %G%";
* Target machine dependent stuff.
typedef unsigned int Address
;
typedef unsigned char Byte
;
typedef unsigned int Word
;
#define BITSPERWORD (BITSPERBYTE * sizeof(Word))
* This magic macro enables us to look at the process' registers
#define regloc(reg) (ctob(UPAGES) + (sizeof(Word) * (reg)))
#define nargspassed(frame) (((argn(-1, frame)&0xffff)-4)/4)
#define SYSBASE 0xc0000000 /* base of system address space */
#define physaddr(a) ((a) &~ 0xc0000000)
* Indices into u. for use in collecting registers values.
{ R0
, R1
, R2
, R3
, R4
, R5
, R6
, R7
, R8
, R9
, R10
, R11
, R12
, FP
, SP
, PC
};
private Address
printop();
Optab
*ioptab
[256]; /* index by opcode to optab */
* Initialize the opcode lookup table.
for (p
= optab
; p
->iname
; p
++)
ioptab
[p
->val
& 0xff] = p
;
* Decode and print the instructions within the given address range.
public printinst(lowaddr
, highaddr
)
Address 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 (newaddr
= addr
, i
= 0; i
< count
; i
++)
newaddr
= printop(newaddr
);
* Hacked version of adb's instruction decoder.
private Address
printop(addr
)
int argtype
, amode
, argno
, argval
, r
;
iread(&ins
, addr
, sizeof(ins
));
for (argno
= 0; argno
< op
->numargs
; argno
++) {
printf(argno
== 0 ? "\t" : ",");
argtype
= op
->argtype
[argno
];
if (is_branch_disp(argtype
))
mode
= 0xAF + (typelen(argtype
) << 5);
iread(&mode
, addr
, sizeof(mode
)), addr
+= 1;
reg
= regname
[regnm(mode
)];
case LITSHORT
: case LITUPTO31
:
case LITUPTO47
: case LITUPTO63
:
if (ins
== O_KCALL
&& mode
>= 0 && mode
< SYSSIZE
&&
printf("$%s", systab
[mode
]);
if (r
== 0xf || r
== 8 || r
== 9) {
int size
= (mode
&03) + 1;
argval
= printdisp(addr
, size
,
regname
[PROGCTR
], amode
);
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
);
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
);
* 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
)
for (f
= &fmt
[0]; f
->name
!= nil
&& !streq(f
->name
, s
); f
++)
error("bad print format \"%s\"", s
);
public Address
printdata(lowaddr
, highaddr
, format
)
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")) {
for (p
= (char *) &v
, q
= p
+ sizeof(v
); p
< q
; ++p
)
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 abnormally (exit code %d)\n",
printf("\"%s\" terminated normally\n", objname
);
fprintf(stderr
, "Entering debugger ...\n");
printlines(curline
, curline
);
private String illinames
[] = {
"reserved addressing fault",
"privileged instruction fault",
#define NILLINAMES (sizeof (illinames) / sizeof (illinames[0]))
private String fpenames
[] = {
"integer divide by zero trap",
"floating point divide by zero trap",
"floating point overflow trap",
"floating point underflow trap",
#define NFPENAMES (sizeof (fpenames) / sizeof (fpenames[0]))
if (signo
< 0 or signo
> sys_nsig
)
printf("[signal %d]", signo
);
printf("%s", sys_siglist
[signo
]);
if (code
>= 0 && code
< NILLINAMES
)
printf(" (%s)", illinames
[code
]);
if (code
> 0 and code
< NFPENAMES
)
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");
private Address
getcall();
* Single step the machine a source line (or instruction if "inst_tracing"
* is true). If "isnext" is true, skip over procedure calls.
addr
= nextaddr(pc
, isnext
);
if (!inst_tracing
&& nlhdr
.nlines
!= 0) {
for (; line
== 0; line
= linelookup(addr
))
addr
= nextaddr(addr
, isnext
);
filename
= srcfilename(addr
);
private Address
findnextaddr();
* 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).
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.
private boolean
skipfunc(ins
, f
)
return ((boolean
) (!inst_tracing
&& nlhdr
.nlines
!= 0 &&
nosource(curfunc
) && canskip(curfunc
)));
private Address
findnextaddr(startaddr
, isnext
)
int argtype
, amode
, argno
, argval
, nib
;
enum { KNOWN
, SEQUENTIAL
, BRANCH
} addrstatus
;
iread(&ins
, addr
, sizeof(ins
));
setcurfunc(whatblock(pc
));
if (isnext
or skipfunc(ins
, curfunc
)) {
callnews(/* iscall = */ true);
callnews(/* iscall = */ false);
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
)), addr
+= 1;
r
= regname
[regnm(mode
)];
if (nib
== 0xf || nib
== 8 || nib
== 9) {
argval
= getdisp(addr
, size
,
regname
[PROGCTR
], amode
);
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_CALLF
or ins
== O_CALLS
)
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
);
* 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 */
error("too many parameters (max %d)", 256/4 - 1);
iread(save
, pc
, sizeof(save
));
call
.mode
= 0xef; /* longword relative */
dest
= codeloc(p
) - 2 - (pc
+ CALLSIZE
);
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
& ~0xc0000000, 0);
printf("p0br %lx p0lr %lx p2br %lx p2lr %lx\n",
pcb
.pcb_p0br
, pcb
.pcb_p0lr
, pcb
.pcb_p2br
, pcb
.pcb_p2lr
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 (oldaddr
&0xc0000000) {
* In system space get system pte. If
* valid or reclaimable then physical address
* is combination of its page number and the page
* offset of the original address.
addr
= ((long)(sbr
+v
)) &~ 0xc0000000;
* In p2 spce must not be in shadow region.
addr
= (long)(pcb
.pcb_p2br
+v
);
* In p1 space everything is verboten (for now).
* In p0 space must not be off end of region.
addr
= (long)(pcb
.pcb_p0br
+v
);
error("address out of segment");
* For p0/p1/p2 address, user-level page table should
* be in kernel vm. Do second-level indirect by recursing.
if ((addr
& 0xc0000000) != 0xc0000000)
error("bad p0br, p1br, or p2br in pcb");
* Addr is now address of the pte of the page we
* are interested in; get the pte and paste up the
fseek(corefile
, addr
, 0);
if (fread(&pte
, sizeof (pte
), 1, corefile
) != 1)
error("page table botch");
/* SHOULD CHECK NOT I/O ADDRESS; NEED CPU TYPE! */
if (pte
.pg_v
== 0 && (pte
.pg_fod
|| pte
.pg_pfnum
== 0))
error("page not valid/reclaimable");
return ((long)(ptob(pte
.pg_pfnum
) + (oldaddr
& PGOFSET
)));
* Extract a bit field from an integer.
public integer
extractField (s
)
integer nbytes
, nbits
, n
, r
, off
, len
;
off
= s
->symvalue
.field
.offset
;
len
= s
->symvalue
.field
.length
;
if (nbytes
> sizeof(n
)) {
printf("[bad size in extractField -- word assumed]\n");
popn(nbytes
, ((char *) &n
) + (sizeof(Word
) - nbytes
));
nbits
= nbytes
* BITSPERBYTE
;
r
= n
>> (nbits
- ((off mod nbits
) + len
));
* 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
= oldlen
- 1; i
>= 0; i
--) {
for (i
= 0; i
< n
; i
++) {
for (i
= 0; i
< newlen
; i
++) {