* 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
[] = "@(#)iris.c 5.1 (Berkeley) %G%";
static char rcsid
[] = "$Header: machine.c,v 1.2 87/03/26 14:54:55 donn Exp $";
* Target machine dependent stuff.
typedef unsigned int Address
;
typedef unsigned char Byte
;
typedef unsigned int Word
;
* On the 68000, the pc isn't in a register, but we make believe
* so there's one more register.
* Note that there's also no argument pointer, this means code
* involving "ARGP" should always be #ifdef'd.
* The address corresponding to the beginning of a function is recorded
* as the address + FUNCOFFSET (skip the link instruction so that
* local information is available).
#define CALL_RETADDR 0x800c /* Return address for 'call' command */
# define CODESTART 0x8000
# define CODESTART 0x1000
#define BITSPERWORD (BITSPERBYTE * sizeof(Word))
* This magic macro enables us to look at the process' registers
#define regloc(reg) (ctob(UPAGES) + (sizeof(Word) * ((reg) - PC)) - 10)
* Indices into u. for use in collecting registers values.
R0
, R1
, R2
, R3
, R4
, R5
, R6
, R7
, AR0
, AR1
, AR2
, AR3
, AR4
, AR5
, AR6
, AR7
, PC
R0
, R1
, R2
, R3
, R4
, R5
, R6
, R7
, AR0
, AR1
, AR2
, AR3
, AR4
, AR5
, AR6
, AR7
, 16
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
);
* 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_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
);
* Instruction decoding routines for 68000, derived from adb.
* The shared boolean variable "printing" is true if the decoded
* instruction is to be printed, false if not. In either case,
* the address of the next instruction after the given one is returned.
private Boolean printing
;
private Boolean following
;
private Boolean followcalls
;
private Address instaddr
;
iread(&var, instaddr, sizeof(var)); \
instaddr += sizeof(var); \
private Optab
*decode(inst
, addr
)
while (o
->mask
!= 0 and (inst
&o
->mask
) != o
->match
) {
private Address
printop(addr
)
iread(&inst
, addr
, sizeof(inst
));
instaddr
= addr
+ sizeof(inst
);
instaddr
= addr
+ sizeof(inst
);
(*o
->opfun
)(inst
, o
->farg
);
* Quickly find the return address of the current procedure or function
* while single stepping. Just get the word pointed at by sp.
private Address
currtnaddr ()
dread(&retaddr
, reg(STKP
), sizeof(retaddr
));
* Print out the effective address for the given parameters.
private printea(mode
, reg
, size
)
static char *aregs
[] = { "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp" };
printf("%s", aregs
[reg
]);
printf("%s@", aregs
[reg
]);
printf("%s@+", aregs
[reg
]);
printf("%s@-", aregs
[reg
]);
printf("%s@(%D)", aregs
[reg
], w
);
disp
= (char)(index
&0377);
printf("%s@(%d,%c%D:%c)", aregs
[reg
], disp
,
(index
&0100000)?'a':'d',(index
>>12)&07,
psymoff(disp
+ instaddr
);
disp
= (char)(index
&0377);
printf("pc@(%D,%c%D:%c)", disp
,
(index
&0100000)?'a':'d',(index
>>12)&07,
printf("unexpected size %d in printea\n", size
);
private printEA(ea
, size
)
printea((ea
>>3)&07, ea
&07, size
);
private char suffix(size
)
panic("bad size %d in suffix", size
);
* Print an address offset. Eventually this should attempt to be symbolic,
* but for now its just printed in hex.
f
= whatblock((Address
) (off
+ FUNCOFFSET
));
if (codeloc(f
) == off
+ FUNCOFFSET
) {
printf("%s", symname(f
));
* Instruction class specific routines.
size
= ((c
== 'b') ? 1 : (c
== 'w') ? 2 : 4);
printea((inst
>>3)&07, inst
&07, size
);
printea((inst
>>6)&07, (inst
>>9)&07, size
);
* Two types: bsr (4 bytes) and bsrs (2 bytes)
public obranch(inst
, dummy
)
Address startingaddr
; /* address of branch instruction */
int branchtype
; /* type of branch (0 = unconditional) */
Address retaddr
; /* for bsr instruction */
startingaddr
= instaddr
- 2;
retaddr
= startingaddr
+ 4;
retaddr
= startingaddr
+ 2;
branchtype
= (int)((inst
>>8)&017);
dest
= startingaddr
+ 2 + disp
;
printf("\tb%s%s\t", bname
[branchtype
], s
);
* If we're to follow the dynamic flow of instructions,
* we must see where the branch leads. A branchtype of 0
* indicates an unconditional branch which we simply take
* as the new instruction address. For a conditional branch,
* we continue execution up to the current address, single step,
} else if (branchtype
== 01) { /* bsr */
curfunc
= whatblock(pc
, true);
if (nosource(curfunc
) and canskip(curfunc
) and
callnews(/* iscall = */ true);
printf(form
, dbname
[(int)((inst
>>8)&017)], inst
&07);
printf("\ts%s\t", cname
[(int)((inst
>>8)&017)]);
printea((inst
>>3)&07, inst
&07, 1);
printf("\t%s\t", bit
[(int)((inst
>>6)&03)]);
public opmode(inst
, opcode
)
opmode
= (int)((inst
>>6) & 07);
reg
= (int)((inst
>>9) & 07);
if (opmode
== 0 or opmode
== 4) {
} else if (opmode
== 1 or opmode
== 3 or opmode
== 5) {
printf("\t%s%c\t", opcode
, suffix(size
));
if (opmode
>= 4 and opmode
<= 6) {
printea((inst
>>3)&07, inst
&07, size
);
printea((inst
>>3)&07, inst
&07, size
);
printf(",%c%d",(opmode
<=2) ? 'd' : 'a', reg
);
if ((inst
& 0xC0) == 0xC0) {
opcode
= shro
[(int)((inst
>>9)&03)];
printf("\t%s%s\t", opcode
, ds
);
opcode
= shro
[(int)((inst
>>3)&03)];
printf("\t%s%s%c\t", opcode
, ds
, suffix(mapsize(inst
)));
rx
= (int)((inst
>>9)&07); ry
= (int)(inst
&07);
printf("d%d,d%d", rx
, ry
);
printf(IMDF
, (rx
? rx
: 8));
public oimmed(inst
, opcode
)
printf("\t%s%c\t", opcode
, suffix(size
));
public oreg(inst
, opcode
)
printf(opcode
, (inst
& 07));
public extend(inst
, opcode
)
c
= ((inst
& 0x1000) ? suffix(size
) : ' ');
printf("\t%s%c\t", opcode
, c
);
printf("d%D,a%D", rx
, ry
);
} else if (inst
& 0x0008) {
printf("a%D,a%D", rx
, ry
);
printf("d%D,d%D", rx
, ry
);
} else if ((inst
& 0xF000) == 0xB000) {
printf("a%D@+,a%D@+", ry
, rx
);
printf("a%D@-,a%D@-", ry
, rx
);
printf("d%D,d%D", ry
, rx
);
public olink(inst
, dummy
)
printf("\tlink\ta%D,", inst
&07);
public otrap(inst
, dummy
)
public oneop(inst
, opcode
)
public jsrop(inst
, opcode
)
Address startingaddr
; /* beginning of jsr instruction */
Address retaddr
; /* can't call return_addr (frame not set up yet) */
startingaddr
= instaddr
- 2;
switch ((inst
>> 3) & 07) {
retaddr
= instaddr
; /* two byte instruction */
retaddr
= instaddr
+ 2; /* four byte instruction */
retaddr
= instaddr
+ 4; /* six byte instruction */
if (following
and followcalls
) {
curfunc
= whatblock(pc
, true);
if (nosource(curfunc
) and canskip(curfunc
) and nlhdr
.nlines
!= 0) {
callnews(/* iscall = */ true);
public jmpop(inst
, opcode
)
Address startingaddr
; /* beginning of jump instruction */
startingaddr
= instaddr
- 2;
printf("%c%d",(i
<8) ? 'd' : 'a', i
&07);
public omovem(inst
, dummy
)
register int i
, list
, mask
;
if ((inst
& 070) == 040) { /* predecrement */
for (i
= 15; i
> 0; i
-= 2) {
list
|= ((mask
& reglist
) >> i
);
for (i
= 1; i
< 16; i
+= 2) {
list
|= ((mask
& reglist
) << i
);
printf("\tmovem%c\t",(inst
&100)?'l':'w');
public ochk(inst
, opcode
)
printf("\t%s\t", opcode
);
printEA(inst
, sizeof(Byte
));
printf(",%c%D", (opcode
[0] == 'l') ? 'a' : 'd', (inst
>>9)&07);
public soneop(inst
, opcode
)
printf("\t%s%c\t", opcode
, suffix(size
));
public oquick(inst
, opcode
)
data
= (int)((inst
>>9) & 07);
printf("\t%s%c\t", opcode
, suffix(size
));
public omoveq(inst
, dummy
)
data
= (int)(inst
& 0377);
printf(",d%D", (inst
>>9)&07);
public oprint(inst
, opcode
)
public ostop(inst
, opcode
)
public orts(inst
, opcode
)
callnews(/* iscall = */ false);
* Not used by C compiler; does an rts but before doing so, pops
* arg bytes from the stack.
public ortspop(inst
, opcode
)
callnews(/* iscall = */ false);
public omovs(inst
, opcode
)
register unsigned int controlword
;
printf("\t%s%c\t", opcode
, suffix(size
));
printf((controlword
&0x8) ? "a%D," : "d%D,", controlword
&7 );
printEA(inst
&0xff, size
);
printEA(inst
&0xff, size
);
printf((controlword
&0x8) ? ",a%D" : ",d%D", controlword
&7);
public omovc(inst
, opcode
)
register unsigned int controlword
;
switch (controlword
& 0xfff) {
printf((controlword
&0x8) ? "%sa%D,%s" : "%sd%D,%s",
opcode
, controlword
&7, creg
);
printf((controlword
&0x8) ? "%s%s,a%D" : "%s%s,d%D",
opcode
, creg
, controlword
&7 );
* 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.
* Unconditional branches we just follow, for conditional branches
* we continue execution to the current location and then single step
public Address
nextaddr(startaddr
, isnext
)
instaddr
= usignal(process
);
if (instaddr
== 0 or instaddr
== 1) {
followcalls
= (Boolean
) (not isnext
);
iread(&inst
, startaddr
, sizeof(inst
));
instaddr
= startaddr
+ sizeof(inst
);
o
= decode(inst
, startaddr
);
"[internal error: undecodable op at 0x%x]\n", startaddr
);
(*o
->opfun
)(inst
, o
->farg
);
* Step to the given address and then execute one instruction past it.
* Set instaddr to the new instruction address.
* Enter a procedure by creating and executing a call instruction.
#define CALLSIZE 6 /* size of call instruction */
char addr
[sizeof(long)]; /* unaligned long */
iread(save
, pc
, sizeof(save
));
call
.op
= 0x4eb9; /* jsr */
dest
= codeloc(p
) - FUNCOFFSET
;
mov(&dest
, call
.addr
, sizeof(call
.addr
));
iwrite(&call
, pc
, sizeof(call
));
iwrite(save
, pc
, sizeof(save
));
* Execute link instruction so the return addr is visible.
* 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
for (i
= 0; i
< 14; i
++) {
setreg(i
, pcb
.pcb_regs
.val
[i
]);
for (i
= 0; i
< 14; i
++) {
setreg(i
, pcb
.pcb_regs
[i
]);
public copyregs (savreg
, reg
)
reg
[PROGCTR
] = savreg
[PC
];
* Map a virtual address to a physical address.
* XXX THIS CAN'T BE RIGHT... XXX
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
)
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
++) {