boinc/lib/mac/QBacktrace.c
/*	Intel 32-Bit Signal Stack Frames
	--------------------------------
	Cross signal stack frames is much more reliable on Intel.  The parameters 
	to _sigtramp are stored on the stack, and you can reliably pick them up 
	from there.

					Size	Purpose
					----	-------
	low memory
	
	frame  ->		0x004	pre-signal frame pointer
					0x018	struct sigframe32
					0x020?	pad
					0x258	struct mcontext
								0x00c	x86_exception_state32_t
								0x040	x86_thread_state32_t
								0x20c	x86_float_state32_t
					0x040	siginfo_t
					0x020	struct ucontext
	high memory
	
	As for other architectures, the kernel aligns the stack such that the catcher 
    field of the (struct sigframe32) is aligned on a 16 byte boundary.  This means 
    that there's a variable amount of pad between the (struct sigframe32) and the 
    other fields.  However, for x86 this isn't a problem because the 
    (struct sigframe32) contains pointers to the other structures that we need.
    
    Another thing to note is that SA_64REGSET flag isn't significant on x86.  
    A 32-bit process will always get 32-bit structures and a 64-bit process will 
    always get 64-bit structures.  This makes things somewhat easier than on 
    PowerPC.
    
    The three values we need to get are:
    
    o pre-signal FP -- This is easy.  It's always pointed to by the current FP.
    
    o pre-signal PC -- This is hard because the obvious place that it's stored 
      (the si_addr field of the siginfo_t) isn't reliable.  Specifically, for 
      SIGBUS and SIGSEGV, this field holds the faulting address, not the faulting 
      instruction's address.  *sigh*  So, we get this value by following the 
      (struct sigframe32) to the (struct ucontext) to the (struct mcontext) to 
      the (x86_thread_state32_t) to the ebp field.  *phew*
    
    o pre-signal SP -- The kernel stores this in the pad[0] field of the siginfo_t, 
      so we use that.  We also check it against the esp from the thread state, 
      just 'cause that's easy.
    
	The sinfo field of the sigframe32 structure is at offset 0x10 and the uctx 
    field is at offset 0x14.  Once you account for the pre-signal frame pointer 
    that's pushed on to the stack by _sigtramp, you need to go 0x14 bytes up the 
    frame to get the sinfo field, which is a pointer to a siginfo_t structure.  
    The kernel places the pre-signal PC and SP in fields in that structure (si_addr 
    and pad[0], offset 0x18 and 0x24 respectively). 
    
	Finally, if we detect a frameless leaf routine past the signal frame, 
	we extract its return address from the top of stack.
*/
Intel 32-Bit Signal Stack Frames
Cross signal stack frames is much more reliable on Intel.  The parameters
to _sigtramp are stored on the stack, and you can reliably pick them up
from there.

Size    Purpose

low memory

frame  ->               0x004   pre-signal frame pointer
0x018   struct sigframe32
0x020.  pad
0x258   struct mcontext
0x00c   x86_exception_state32_t
0x040   x86_thread_state32_t
0x20c   x86_float_state32_t
0x040   siginfo_t
0x020   struct ucontext
high memory

As for other architectures, the kernel aligns the stack such that the catcher
field of the (struct sigframe32) is aligned on a 16 byte boundary.  This means
that there's a variable amount of pad between the (struct sigframe32) and the
other fields.  However, for x86 this isn't a problem because the
(struct sigframe32) contains pointers to the other structures that we need.

Another thing to note is that SA_64REGSET flag isn't significant on x86.
A 32-bit process will always get 32-bit structures and a 64-bit process will
always get 64-bit structures.  This makes things somewhat easier than on
PowerPC.

The three values we need to get are.

o pre-signal FP -- This is easy.  It's always pointed to by the current FP.

o pre-signal PC -- This is hard because the obvious place that it's stored
(the si_addr field of the siginfo_t) isn't reliable.  Specifically, for
SIGBUS and SIGSEGV, this field holds the faulting address, not the faulting
instruction's address.  *sigh*  So, we get this value by following the
(struct sigframe32) to the (struct ucontext) to the (struct mcontext) to
the (x86_thread_state32_t) to the ebp field.  *phew

o pre-signal SP -- The kernel stores this in the pad[0] field of the siginfo_t,
so we use that.  We also check it against the esp from the thread state,
just 'cause that's easy.

The sinfo field of the sigframe32 structure is at offset 0x10 and the uctx
field is at offset 0x14.  Once you account for the pre-signal frame pointer
that's pushed on to the stack by _sigtramp, you need to go 0x14 bytes up the
frame to get the sinfo field, which is a pointer to a siginfo_t structure.
The kernel places the pre-signal PC and SP in fields in that structure (si_addr
and pad[0], offset 0x18 and 0x24 respectively).

Finally, if we detect a frameless leaf routine past the signal frame,
we extract its return address from the top of stack.
Intel 32 - Bit Signal Stack Frames Cross signal stack frames is much more reliable on Intel . The parameters to _sigtramp are stored on the stack and you can reliably pick them up from there . Size Purpose low memory frame - > 0x004 pre - signal frame pointer 0x018 struct sigframe32 0x020 . pad 0x258 struct mcontext 0x00c x86_exception_state32_t 0x040 x86_thread_state32_t 0x20c x86_float_state32_t 0x040 siginfo_t 0x020 struct ucontext high memory As for other architectures the kernel aligns the stack such that the catcher field of the ( struct sigframe32 ) is aligned on a 16 byte boundary . This means that there ' s a variable amount of pad between the ( struct sigframe32 ) and the other fields . However for x86 this isn ' t a problem because the ( struct sigframe32 ) contains pointers to the other structures that we need . Another thing to note is that SA_64REGSET flag isn ' t significant on x86 . A 32 - bit process will always get 32 - bit structures and a 64 - bit process will always get 64 - bit structures . This makes things somewhat easier than on PowerPC . The three values we need to get are . o pre - signal FP -- This is easy . It ' s always pointed to by the current FP . o pre - signal PC -- This is hard because the obvious place that it ' s stored ( the si_addr field of the siginfo_t ) isn ' t reliable . Specifically for SIGBUS and SIGSEGV this field holds the faulting address not the faulting instruction ' s address . * sigh * So we get this value by following the ( struct sigframe32 ) to the ( struct ucontext ) to the ( struct mcontext ) to the ( x86_thread_state32_t ) to the ebp field . * phew o pre - signal SP -- The kernel stores this in the pad [ 0 ] field of the siginfo_t so we use that . We also check it against the esp from the thread state just ' cause that ' s easy . The sinfo field of the sigframe32 structure is at offset 0x10 and the uctx field is at offset 0x14 . Once you account for the pre - signal frame pointer that ' s pushed on to the stack by _sigtramp you need to go 0x14 bytes up the frame to get the sinfo field which is a pointer to a siginfo_t structure . The kernel places the pre - signal PC and SP in fields in that structure ( si_addr and pad [ 0 ] offset 0x18 and 0x24 respectively ) . Finally if we detect a frameless leaf routine past the signal frame we extract its return address from the top of stack .
static int Intel32CrossSignalFrame(QBTContext *context, QTMAddr thisFrame, QTMAddr *nextPCPtr, QTMAddr *nextFramePtr)
{
	int         err;
    QTMAddr     sigFrame;
	QTMAddr     sigInfo;
	QTMAddr     ucontext;
    QTMAddr     mcontext;
    QTMAddr     threadState;
	QTMAddr     preSignalFP;
	QTMAddr     preSignalSP;
    QTMAddr     preSignalFPFromMContext;
    QTMAddr     preSignalSPFromMContext;
    QTMAddr     preSignalPCFromMContext;
    sigFrame = thisFrame + 4;
    err = ReadAddr(context, thisFrame, &preSignalFP);
	if (err == 0) {
        err = ReadAddr(context, sigFrame + 0x10, &sigInfo);
	}
    if (err == 0) {
		err = ReadAddr(context, sigInfo + 0x24, &preSignalSP);
    }
	if (err == 0) {
		err = ReadAddr(context, sigFrame + 0x14, &ucontext);
	}
    if (err == 0) {
		err = ReadAddr(context, ucontext + 0x1c, &mcontext);
    }
    if (err == 0) {
        threadState = mcontext + 0x0c;
        err = ReadAddr(context, threadState + 0x18, &preSignalFPFromMContext);
        if (err == 0) {
            err = ReadAddr(context, threadState + 0x1c, &preSignalSPFromMContext);
        }
        if (err == 0) {
            err = ReadAddr(context, threadState + 0x28, &preSignalPCFromMContext);
        }
    }
    if (err == 0) {
        assert(preSignalFPFromMContext == preSignalFP);
        assert(preSignalSPFromMContext == preSignalSP);
        *nextFramePtr = preSignalFP;
        *nextPCPtr    = preSignalPCFromMContext;
    }
	if ( (err == 0) && IntelIsSystemCall(context, *nextPCPtr) ) {
		AddFrame(context, *nextPCPtr, 0, kQBTFrameBadMask);
        err = ReadAddr(context, preSignalSP, nextPCPtr);
	}
	return err;
}
static int Intel32CrossSignalFrame ( QBTContext * context , QTMAddr thisFrame , QTMAddr * nextPCPtr , QTMAddr * nextFramePtr ) { int err ; QTMAddr sigFrame ; QTMAddr sigInfo ; QTMAddr ucontext ; QTMAddr mcontext ; QTMAddr threadState ; QTMAddr preSignalFP ; QTMAddr preSignalSP ; QTMAddr preSignalFPFromMContext ; QTMAddr preSignalSPFromMContext ; QTMAddr preSignalPCFromMContext ; sigFrame = thisFrame + 4 ; err = ReadAddr ( context , thisFrame , & preSignalFP ) ; if ( err == 0 ) { err = ReadAddr ( context , sigFrame + 0x10 , & sigInfo ) ; } if ( err == 0 ) { err = ReadAddr ( context , sigInfo + 0x24 , & preSignalSP ) ; } if ( err == 0 ) { err = ReadAddr ( context , sigFrame + 0x14 , & ucontext ) ; } if ( err == 0 ) { err = ReadAddr ( context , ucontext + 0x1c , & mcontext ) ; } if ( err == 0 ) { threadState = mcontext + 0x0c ; err = ReadAddr ( context , threadState + 0x18 , & preSignalFPFromMContext ) ; if ( err == 0 ) { err = ReadAddr ( context , threadState + 0x1c , & preSignalSPFromMContext ) ; } if ( err == 0 ) { err = ReadAddr ( context , threadState + 0x28 , & preSignalPCFromMContext ) ; } } if ( err == 0 ) { assert ( preSignalFPFromMContext == preSignalFP ) ; assert ( preSignalSPFromMContext == preSignalSP ) ; * nextFramePtr = preSignalFP ; * nextPCPtr = preSignalPCFromMContext ; } if ( ( err == 0 ) && IntelIsSystemCall ( context , * nextPCPtr ) ) { AddFrame ( context , * nextPCPtr , 0 , kQBTFrameBadMask ) ; err = ReadAddr ( context , preSignalSP , nextPCPtr ) ; } return err ; }
Intel 32-Bit Signal Stack Frames
Cross signal stack frames is much more reliable on Intel.
Intel 32 - Bit Signal Stack Frames Cross signal stack frames is much more reliable on Intel .
// This is the crossSignalFrame routine for the Intel  // architecture.  See the description of  // QBTCrossSignalFrameProc for a detailed discussion  // of its parameters. // Get the pre-signal FP by simply reading from the frame pointer.  // Because of the way __sigtramp works, this ends up being correct. // Get the siginfo_t pointer from the parameters to _sigtramp  // (the sinfo field of sigframe32). // Get the pre-signal SP from the pad[0] field of the siginfo_t. // Get the ucontext address from the parameters to _sigtramp  // (the uctx field of the sigframe32). // Get the mcontext address from the uc_mcontext field of the ucontext. // Get the address of the ss field of the mcontext.  This is the  // x86_thread_state_32_t.  Then extract the ebp, esp, and eip fields from  // that. // Finally, if we detect a leaf routine, add a dummy frame for it  // and then get the pre-signal SP and, assuming that the top word on  // the stack is a return address, use it for the next PC.