home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Education Sampler 1992 [NeXTSTEP]
/
Education_1992_Sampler.iso
/
NeXT
/
GnuSource
/
cc-61.0.1
/
cc
/
config
/
m88k-trace.asm
< prev
next >
Wrap
Assembly Source File
|
1991-06-03
|
11KB
|
488 lines
; Source for routine to check for preserved registers being
; clobbered on the Motorola 88000.
;
; Copyright (C) 1989 Free Software Foundation, Inc.
;
; This file is part of GNU CC.
;
; GNU CC is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2, or (at your option)
; any later version.
;
; GNU CC is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with GNU CC; see the file COPYING. If not, write to
; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;
; Routine to find places where preserved registers aren't and other
; anonomilies. It is intended to be used with GCC's -mtrace-function
; which calls "__enter" at function prologue time, and "__leave" at
; function epilogue time, and uses the following calling sequence:
;
; r1 -- return address
; r2 - r9 -- caller parameter registers
; r10 -- pointer to a dope vector
; r11 -- not used (static chain if needed)
; r12 -- structure return address
; r13 -- return address of the caller (was r1)
; r14 - r31 -- preserved register set
;
; The dope vector has the following format:
;
; word 0 -- # words following (4 currently)
; word 1 -- pointer to function name string
; word 2 -- # bytes in the function name string
; word 3 -- bit mask of fixed register (normally 0, 30, 31)
; word 4 -- bit mask of call preserved registers
;
; Note, the Motorola Anglefire uses r24 as a temporary, which is
; normally a call used register in the GNU/Green Hills compilers.
; So we slow this routine down even more than it already is....
;
; Upon exit, r2-r9, r13-r31 should be the same as upon entry.
; The traceback code assumes a system V/ANSI style sprintf for
; simplicity sake (ie, r2 holds the # bytes in the message after
; the call, rather than the buffer pointer).
;
; Due to it's use of a global pointer, and an instruction window
; use of this routine within signal handlers is not recommended.
file "m88k-trace.s"
global __enter
global __leave
global __trace_ptr
global __trace_count
global __trace_temp
text ; error messages
align 4
fmt: string "%-33.32s(%.8x %.8x %.8x %.8x) %.8x\n"
align 4
enest: string "__enter: too many nested calls.\012\000"
align 4
ewrong: string "__leave: internal stack messed up.\012\000"
align 4
eret: string "__leave: return address trashed.\012\000"
align 4
e14: string "__leave: register r14 trashed.\012\000"
align 4
e15: string "__leave: register r15 trashed.\012\000"
align 4
e16: string "__leave: register r16 trashed.\012\000"
align 4
e17: string "__leave: register r17 trashed.\012\000"
align 4
e18: string "__leave: register r18 trashed.\012\000"
align 4
e19: string "__leave: register r19 trashed.\012\000"
align 4
e20: string "__leave: register r20 trashed.\012\000"
align 4
e21: string "__leave: register r21 trashed.\012\000"
align 4
e22: string "__leave: register r22 trashed.\012\000"
align 4
e23: string "__leave: register r23 trashed.\012\000"
align 4
e24: string "__leave: register r24 trashed.\012\000"
align 4
e25: string "__leave: register r25 trashed.\012\000"
align 4
e26: string "__leave: register r26 trashed.\012\000"
align 4
e27: string "__leave: register r27 trashed.\012\000"
align 4
e28: string "__leave: register r28 trashed.\012\000"
align 4
e29: string "__leave: register r29 trashed.\012\000"
align 4
e30: string "__leave: register r30 trashed.\012\000"
align 4
e31: string "__leave: register r31 trashed.\012\000"
def size,8192 ; define internal stack
bss save,size,8 ; to save preserved regs
def dope,0 ; offset for storing dope
def s2,dope+4 ; offset for storing r2
def s3,s2+4 ; offset for storing r3
def s4,s3+4 ; offset for storing r4
def s5,s4+4 ; offset for storing r5
def s6,s5+4 ; offset for storing r6
def s7,s6+4 ; offset for storing r7
def s8,s7+4 ; offset for storing r8
def s9,s8+4 ; offset for storing r9
def s13,s9+4 ; offset for storing r13
def s14,s13+4 ; offset for storing r14
def s15,s14+4 ; offset for storing r15
def s16,s15+4 ; offset for storing r16
def s17,s16+4 ; offset for storing r17
def s18,s17+4 ; offset for storing r18
def s19,s18+4 ; offset for storing r19
def s20,s19+4 ; offset for storing r20
def s21,s20+4 ; offset for storing r21
def s22,s21+4 ; offset for storing r22
def s23,s22+4 ; offset for storing r23
def s24,s23+4 ; offset for storing r24
def s25,s24+4 ; offset for storing r25
def s26,s25+4 ; offset for storing r26
def s27,s26+4 ; offset for storing r27
def s28,s27+4 ; offset for storing r28
def s29,s28+4 ; offset for storing r29
def s30,s29+4 ; offset for storing r30
def s31,s30+4 ; offset for storing r31
def blksize,s31+4 ; size of the block needed
def end,save+size-(2*blksize) ; end of the private stack
def dcount,0 ; dope offset for word count
def dname,dcount+4 ; dope offset for function name
def dlen,dname+4 ; dope offset for name length
def dfixed,dlen+4 ; dope offset for fixed regs
def dcall,dfixed+4 ; dope offset for call used regs
data
align 4
__trace_ptr: ; pointer to current save
word save-blksize ; area
__trace_temp:
word 0 ; temp for traceback
__trace_count:
word 0 ; # of trace calls
bss buffer,200,4 ; buffer for sprintf
text
align 4
__enter:
or.u r11,r0,hi16(__trace_ptr) ; allocate next block
ld r11,r11,lo16(__trace_ptr)
addu r11,r11,blksize
st r10,r11,dope ; save the dope vector
or.u r10,r0,hi16(__trace_ptr)
st r11,r10,lo16(__trace_ptr)
st r2,r11,s2 ; save the arguments
st r3,r11,s3
st r4,r11,s4
st r5,r11,s5
st r6,r11,s6
st r7,r11,s7
st r8,r11,s8
st r9,r11,s9
st r13,r11,s13 ; save the preserved registers
st r14,r11,s14
st r15,r11,s15
st r16,r11,s16
st r17,r11,s17
st r18,r11,s18
st r19,r11,s19
st r20,r11,s20
st r21,r11,s21
st r22,r11,s22
st r23,r11,s23
st r24,r11,s24
st r25,r11,s25
st r26,r11,s26
st r27,r11,s27
st r28,r11,s28
st r29,r11,s29
st r30,r11,s30
st r31,r11,s31
or.u r10,r0,hi16(end) ; too deeply nested?
or r10,r10,lo16(end)
cmp r10,r11,r10
bb1 ge,r10,anest ; abort if overflow
or.u r10,r0,hi16(__trace_count) ; bump # calls
ld r11,r10,lo16(__trace_count)
addu r11,r11,1
st r11,r10,lo16(__trace_count)
jmp r1 ; return to the caller
anest:
or.u r2,r0,hi16(enest) ; nesting overflow msg
or r2,r2,lo16(enest)
br abend
__leave:
or.u r11,r0,hi16(__trace_ptr) ; get the preserved regs
ld r11,r11,lo16(__trace_ptr)
ld r12,r11,dope ; now check everything's
cmp r12,r12,r10
bb1 ne,r12,awrong
; Get the fixed registers (those which should be ignored by this
; routine) and the call used registers (those which are ok to
; trash). Note the most significant bit (ie, the sign bit) represents
; r31, while the least significant bit represents r0. Even though
; r28-r26 are treated as fixed by GNU, we will consider them as not
; fixed to track down who might be modifying them, so we can use them
; for literal synthesis. At the moment, assume r29 is fixed because
; the Motorola 0.6 linker will use r29 as a general scratch register.
ld r10,r10,dfixed ; fixed registers
and.u r10,r10,hi16(0xe3ffffff) ; unfix special regs
ld r12,r11,s13
cmp r12,r12,r13
bb1 ne,r12,aret
bb1 14,r10,l15
ld r12,r11,s14
cmp r12,r12,r14
bb1 ne,r12,a14
l15: bb1 15,r10,l16
ld r12,r11,s15
cmp r12,r12,r15
bb1 ne,r12,a15
l16: bb1 16,r10,l17
ld r12,r11,s16
cmp r12,r12,r16
bb1 ne,r12,a16
l17: bb1 17,r10,l18
ld r12,r11,s17
cmp r12,r12,r17
bb1 ne,r12,a17
l18: bb1 18,r10,l19
ld r12,r11,s18
cmp r12,r12,r18
bb1 ne,r12,a18
l19: bb1 19,r10,l20
ld r12,r11,s19
cmp r12,r12,r19
bb1 ne,r12,a19
l20: bb1 20,r10,l21
ld r12,r11,s20
cmp r12,r12,r20
bb1 ne,r12,a20
l21: bb1 21,r10,l22
ld r12,r11,s21
cmp r12,r12,r21
bb1 ne,r12,a21
l22: bb1 22,r10,l23
ld r12,r11,s22
cmp r12,r12,r22
bb1 ne,r12,a22
l23: bb1 23,r10,l24
ld r12,r11,s23
cmp r12,r12,r23
bb1 ne,r12,a23
l24: bb1 24,r10,l25
ld r12,r11,s24
cmp r12,r12,r24
bb1 ne,r12,a24
l25: bb1 25,r10,l26
ld r12,r11,s25
cmp r12,r12,r25
bb1 ne,r12,a25
l26: bb1 26,r10,l27
ld r12,r11,s26
cmp r12,r12,r26
bb1 ne,r12,a26
l27: bb1 27,r10,l28
ld r12,r11,s27
cmp r12,r12,r27
bb1 ne,r12,a27
l28: bb1 28,r10,l29
ld r12,r11,s28
cmp r12,r12,r28
bb1 ne,r12,a28
l29: bb1 29,r10,l30
ld r12,r11,s29
cmp r12,r12,r29
bb1 ne,r12,a29
l30: bb1 30,r10,l31
ld r12,r11,s30
cmp r12,r12,r30
bb1 ne,r12,a30
l31: bb1 31,r10,lok
ld r12,r11,s31
cmp r12,r12,r31
bb1 ne,r12,a31
lok: subu r11,r11,blksize ; decrement stack now
or.u r12,r0,hi16(__trace_ptr)
st r11,r12,lo16(__trace_ptr)
jmp r1
; Labels to load r2 with the error message addres, and jump to
; common abort processing
awrong: or.u r2,r0,hi16(ewrong)
or r2,r2,lo16(ewrong)
br abend
aret: or.u r2,r0,hi16(eret)
or r2,r2,lo16(eret)
br abend
a14: or.u r2,r0,hi16(e14)
or r2,r2,lo16(e14)
br abend
a15: or.u r2,r0,hi16(e15)
or r2,r2,lo16(e15)
br abend
a16: or.u r2,r0,hi16(e16)
or r2,r2,lo16(e16)
br abend
a17: or.u r2,r0,hi16(e17)
or r2,r2,lo16(e17)
br abend
a18: or.u r2,r0,hi16(e18)
or r2,r2,lo16(e18)
br abend
a19: or.u r2,r0,hi16(e19)
or r2,r2,lo16(e19)
br abend
a20: or.u r2,r0,hi16(e20)
or r2,r2,lo16(e20)
br abend
a21: or.u r2,r0,hi16(e21)
or r2,r2,lo16(e21)
br abend
a22: or.u r2,r0,hi16(e22)
or r2,r2,lo16(e22)
br abend
a23: or.u r2,r0,hi16(e23)
or r2,r2,lo16(e23)
br abend
a24: or.u r2,r0,hi16(e24)
or r2,r2,lo16(e24)
br abend
a25: or.u r2,r0,hi16(e25)
or r2,r2,lo16(e25)
br abend
a26: or.u r2,r0,hi16(e26)
or r2,r2,lo16(e26)
br abend
a27: or.u r2,r0,hi16(e27)
or r2,r2,lo16(e27)
br abend
a28: or.u r2,r0,hi16(e28)
or r2,r2,lo16(e28)
br abend
a29: or.u r2,r0,hi16(e29)
or r2,r2,lo16(e29)
br abend
a30: or.u r2,r0,hi16(e30)
or r2,r2,lo16(e30)
br abend
a31: or.u r2,r0,hi16(e31)
or r2,r2,lo16(e31)
br abend
; Common abort processing, r2 = error message
abend: or r3,r2,r0 ; save for write sys call
aloop: ld.b r5,r2,r0 ; while (*p++) count++
addu r2,r2,1
bcnd ne0,r5,aloop
subu r4,r2,r3 ; # bytes
or r2,r0,2 ; stderr channel
bsr __write ; complain
; Print a stack traceback
or.u r13,r0,hi16(__trace_ptr)
ld r13,r13,lo16(__trace_ptr)
addu r13,r13,blksize ; offset for loop
or.u r10,r0,hi16(__trace_temp)
st r13,r10,lo16(__trace_temp)
atrace: or.u r10,r0,hi16(__trace_temp) ; format traceback
ld r13,r10,lo16(__trace_temp)
subu r13,r13,blksize ; go to previous frame
st r13,r10,lo16(__trace_temp)
or.u r10,r0,hi16(save)
or r10,r10,lo16(save)
tbnd r10,r13 ; trap if we are done
ld r9,r13,s31
ld r8,r13,s5
ld r7,r13,s4
ld r6,r13,s3
ld r5,r13,s2
ld r4,r13,dope
ld r4,r4,dname
or.u r3,r0,hi16(fmt)
or r3,r3,lo16(fmt)
or.u r2,r0,hi16(buffer)
or r2,r2,lo16(buffer)
bsr _sprintf
or.u r3,r0,hi16(buffer)
or r3,r3,lo16(buffer)
or r4,r2,r0 ; # bytes to write
or r2,r0,2 ; standard error
bsr __write ; write traceback
br atrace