/* Workaround for CR JAGab60546 setjmp/longjmp and
JAGad55982 sigsetjmp/siglongjmp from shared libraries. */
/*
* tabstop=4
*
* _setjmp/setjmp/sigsetjmp and
*_longjmp/longjmp/siglongjmp.
*
* Written by Mark Klein, 10 October, 2000
* Updated for gcc 3.x 6 October, 2005
*
* These routines are GCC specific and MUST BE COMPILED
* WITH -O2
*
* The existing setjmp/longjmp code in both libc.a and XL.PUB.SYS
* are not SR4 aware and cause problems when working with shared
* libraries (XLs), especially when executing a longjmp between
* XLs. This code preserves SR4 and will successfully handle
* a cross space longjmp. However, the setjmp code must be
* bound into each XL from which it will be called as well as
* being bound into the main program.
*/
/*
* The following macro takes the contents of the jmpbuf and
* restores the registers from them. There is other code
* elsewhere that ensures that __jmpbuf is %r26 at this
* point in time. If it becomes some other register, that
* register must be the last restored. At the end will
* be a branch external that will cause a cross space
* return if needed.
*/
#define RESTORE_REGS_AND_RETURN(__jmpbuf, __retval) \
({ \
__asm__ __volatile__ ( \
" ldw 0(%%sr0, %0), %%rp\n" \
"\t ldw 4(%%sr0, %0), %%sp\n" \
"\t ldw 16(%%sr0, %0), %%r3\n" \
"\t ldw 20(%%sr0, %0), %%r4\n" \
"\t ldw 24(%%sr0, %0), %%r5\n" \
"\t ldw 28(%%sr0, %0), %%r6\n" \
"\t ldw 32(%%sr0, %0), %%r7\n" \
"\t ldw 36(%%sr0, %0), %%r8\n" \
"\t ldw 40(%%sr0, %0), %%r9\n" \
"\t ldw 44(%%sr0, %0), %%r10\n" \
"\t ldw 48(%%sr0, %0), %%r11\n" \
"\t ldw 52(%%sr0, %0), %%r12\n" \
"\t ldw 56(%%sr0, %0), %%r13\n" \
"\t ldw 60(%%sr0, %0), %%r14\n" \
"\t ldw 64(%%sr0, %0), %%r15\n" \
"\t ldw 68(%%sr0, %0), %%r16\n" \
"\t ldw 72(%%sr0, %0), %%r17\n" \
"\t ldw 76(%%sr0, %0), %%r18\n" \
"\t ldw 80(%%sr0, %0), %%r19\n" \
"\t ldw 84(%%sr0, %0), %%r20\n" \
"\t ldw 88(%%sr0, %0), %%r21\n" \
"\t ldw 92(%%sr0, %0), %%r22\n" \
"\t ldw 96(%%sr0, %0), %%r23\n" \
"\t ldw 100(%%sr0, %0), %%r24\n" \
"\t ldw 104(%%sr0, %0), %%r25\n" \
"\t ldw 112(%%sr0, %0), %%r27\n" \
"\t ldw 116(%%sr0, %0), %%r1\n" \
"\t mtsp %%r1, %%sr3\n" \
"\t ldw 120(%%sr0, %0), %%r1\n" \
"\t mtsp %%r1, %%sr1\n" \
"\t or,<> %%r0, %1, %%r0\n" \
"\t ldi 1, %%r28\n" \
"\t ldw 108(%%sr0, %0), %%r26\n" \
"\t be 0(%%sr1, %%rp)\n" \
"\t mtsp %%r1, %%sr4\n" \
: \
: "r" (__jmpbuf), \
"r" (__retval)); \
})
/*
* The following macro extracts the signal mask
* from __jmpbuf from the 3rd and 4th words and
* if non-zero, calls sigprocmask with that value
* to set the signal mask. This macro is usually
* invoked before the registers are restored in
* the longjmp routines and it can clobber things
* without needing to spill them as a result.
* A quick frame is built before making the
* call and cut back just afterwards.
* The ldi 2, %r26 is actually SIG_SETMASK from
* /usr/include/signal.h.
*/
#define RESTORE_SIGNAL_MASK(__jmpbuf) \
({ \
__asm__ __volatile__ ( \
" ldw 8(%0), %%r26\n" \
"\t comibt,=,n 0,%%r26,.+36\n" \
"\t ldo 64(%%sp), %%sp\n" \
"\t stw %0, -28(%%sp)\n" \
"\t ldi 0, %%r24\n" \
"\t ldo 8(%0), %%r25\n" \
"\t .import sigprocmask,code\n" \
"\t bl sigprocmask,%%rp\n" \
"\t ldi 2, %%r26\n" \
"\t ldw -28(%%sr0, %%sp), %0\n" \
"\t ldo -64(%%sp), %%sp\n" \
: \
: "r" (__jmpbuf)); \
})
/*
* This macro saves the current contents of the
* registers to __jmpbuf. Note that __jmpbuf is
* guaranteed elsewhere to be in %r26. We do not
* want it spilled, nor do we want a new frame
* built.
*/
#define SAVE_REGS(__jmpbuf) \
({ \
__asm__ __volatile__ ( \
" stw %%rp, 0(%%sr0, %0)\n" \
"\t stw %%sp, 4(%%sr0, %0)\n" \
"\t stw %%r0, 8(%%sr0, %0)\n" \
"\t stw %%r3, 16(%%sr0, %0)\n" \
"\t stw %%r4, 20(%%sr0, %0)\n" \
"\t stw %%r5, 24(%%sr0, %0)\n" \
"\t stw %%r6, 28(%%sr0, %0)\n" \
"\t stw %%r7, 32(%%sr0, %0)\n" \
"\t stw %%r8, 36(%%sr0, %0)\n" \
"\t stw %%r9, 40(%%sr0, %0)\n" \
"\t stw %%r10, 44(%%sr0, %0)\n" \
"\t stw %%r11, 48(%%sr0, %0)\n" \
"\t stw %%r12, 52(%%sr0, %0)\n" \
"\t stw %%r13, 56(%%sr0, %0)\n" \
"\t stw %%r14, 60(%%sr0, %0)\n" \
"\t stw %%r15, 64(%%sr0, %0)\n" \
"\t stw %%r16, 68(%%sr0, %0)\n" \
"\t stw %%r17, 72(%%sr0, %0)\n" \
"\t stw %%r18, 76(%%sr0, %0)\n" \
"\t stw %%r19, 80(%%sr0, %0)\n" \
"\t stw %%r20, 84(%%sr0, %0)\n" \
"\t stw %%r21, 88(%%sr0, %0)\n" \
"\t stw %%r22, 92(%%sr0, %0)\n" \
"\t stw %%r23, 96(%%sr0, %0)\n" \
"\t stw %%r24, 100(%%sr0, %0)\n" \
"\t stw %%r25, 104(%%sr0, %0)\n" \
"\t stw %%r26, 108(%%sr0, %0)\n" \
"\t stw %%r27, 112(%%sr0, %0)\n" \
"\t mfsp %%sr3, %%r1\n" \
"\t stw %%r1, 116(%%sr0, %0)\n" \
"\t mfsp %%sr4, %%r1\n" \
"\t stw %%r1, 120(%%sr0, %0)\n" \
: \
: "r" (__jmpbuf)); \
})
/*
* This macro will save the signal mask to the
* __jmpbuf if __savemask is non-zero. By this
* point in time, the other resisters have been
* saved into the __jmpbuf.
* The ldi 0, %r26 is actually SIG_BLOCK from
* /usr/include/signal.h. Since the block is
* an OR of the bits, this does not change the
* mask, but returns it into the double word at
* the address in %r24.
*/
#define SAVE_SIGNAL_MASK(__jmpbuf,__savemask) \
({ \
__asm__ __volatile__ ( \
" comibt,=,n 0,%1,.+36\n" \
"\t stw %%rp, -20(%%sr0, %%sp)\n" \
"\t ldo 64(%%sp), %%sp\n" \
"\t ldo 8(%0), %%r24\n" \
"\t ldi 0, %%r25\n" \
"\t .import sigprocmask,code\n" \
"\t bl sigprocmask,%%rp\n" \
"\t ldi 0, %%r26\n" \
"\t ldo -64(%%sp), %%sp\n" \
"\t ldw -20(%%sr0, %%sp), %%rp\n" \
: \
: "r" (__jmpbuf), \
"r" (__savemask)); \
})
/*
* Construct a jump buffer and unconditionally save
* the signal mask. Return a 0 unconditionally.
* Care is taken here and in the macros to assume
* the __jumpbuf is in %r26 and that the return
* value will be in %r28. It is done this way to
* prevent a frame from being built and any registers
* from being spilled.
*/
int setjmp(register void *jmpbuf)
{
register int __jmpbuf asm ("%r26");
SAVE_REGS(__jmpbuf);
SAVE_SIGNAL_MASK(__jmpbuf, 1);
return 0;
}
/*
* Construct a jump buffer but do not save the
* signal mask.
*/
int _setjmp(register void *jmpbuf)
{
register int __jmpbuf asm ("%r26");
SAVE_REGS(__jmpbuf);
return 0;
}
/*
* Construct a jump buffer and conditionally save
* the signal mask. The mask is saved if the
* savemask parameter is non-zero.
*/
int sigsetjmp(register void *jmpbuf, register int savemask)
{
register int __jmpbuf asm ("%r26");
register int __savemask asm ("%r25");
SAVE_REGS(__jmpbuf);
SAVE_SIGNAL_MASK(__jmpbuf, __savemask);
return 0;
}
/*
* Return to the location established in the jmpbuf,
* and place the value in i2 in %r28. Registers
* %r4 and %r5 are co-opted to save the address and
* value of jmpbuf and the return value. The signal
* mask is re-established if needed, then the
* address of jmpbuf and value of retval are placed
* into %r26 and %r28 correspondingly. This routine
* will never return to its caller and the stack
* will be cut back to whatever exists in the jmpbuf.
*/
void longjmp(register void *jmpbuf, register int i2)
{
register int __jmpbuf asm ("%r26");
register int __retval asm ("%r28");
__asm__ __volatile__ (
" copy %0, %%r4\n"
"\t copy %1, %%r5\n"
:
: "r" (jmpbuf),
"r" (i2));
RESTORE_SIGNAL_MASK (__jmpbuf);
__asm__ __volatile__ (
" copy %%r4, %0\n"
"\t copy %%r5, %1\n"
: "=r" (__jmpbuf),
"=r" (__retval));
RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
}
/*
* Return to the location established in the jmpbuf,
* but do not restore the signal mask.
*/
void _longjmp(register void *jmpbuf, register int i2)
{
register int __retval asm ("%r28");
register int __jmpbuf asm ("%r26");
__jmpbuf = (int)jmpbuf;
__retval = i2;
RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
}
/*
* Return to the location established in the jmpbuf,
* and conditionally re-establish the signal mask.
*/
void siglongjmp(register void *jmpbuf, register int i2)
{
register int __jmpbuf asm ("%r26");
register int __retval asm ("%r28");
__asm__ __volatile__ (
" copy %0, %%r4\n"
"\t copy %1, %%r5\n"
:
: "r" (jmpbuf),
"r" (i2));
RESTORE_SIGNAL_MASK (__jmpbuf);
__asm__ __volatile__ (
" copy %%r4, %0\n"
"\t copy %%r5, %1\n"
: "=r" (__jmpbuf),
"=r" (__retval));
RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
}
#ifdef TEST
int buf1[50];
int buf2[50];
foo() {
printf("In routine foo(). Doing Longjmp.\n");
longjmp(buf1, 123);
printf("This is in foo after the longjmp() call. Should not reach here.\n");
}
bar(int ret) {
printf("In routine bar(%d). Doing siglongjmp.\n",ret);
siglongjmp(buf2, ret);
printf("This is in bar after the siglongjmp() call. Should not reach here.\n");
}
main() {
int i;
if ((i = setjmp(buf1)))
{
printf("This is the return from the longjmp. i: %d\n",i);
}
else
{
printf("Jump buffer established, i: %d. Calling foo()\n",i);
foo();
printf("This is in main after the foo() call. Should not reach here.\n ");
}
if ((i = sigsetjmp(buf2,0)))
{
printf("This is the return from the longjmp. i: %d\n",i);
}
else
{
printf("Jump buffer established, i: %d. Calling bar(456)\n",i);
bar(456);
printf("This is in main after the bar(456) call. Should not reach here.\n");
}
if ((i = sigsetjmp(buf2,1)))
{
printf("This is the return from the longjmp. i: %d\n",i);
}
else
{
printf("Jump buffer established, i: %d. Calling bar(789)\n",i);
bar(789);
printf("This is in main after the bar(789) call. Should not reach here.\n");
}
}
#endif