1169689Skan/* DWARF2 EH unwinding support for TPF OS. 2169689Skan Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3169689Skan Contributed by P.J. Darcy (darcypj@us.ibm.com). 4169689Skan 5169689SkanThis file is part of GCC. 6169689Skan 7169689SkanGCC is free software; you can redistribute it and/or modify it under 8169689Skanthe terms of the GNU General Public License as published by the Free 9169689SkanSoftware Foundation; either version 2, or (at your option) any later 10169689Skanversion. 11169689Skan 12169689SkanIn addition to the permissions in the GNU General Public License, the 13169689SkanFree Software Foundation gives you unlimited permission to link the 14169689Skancompiled version of this file into combinations with other programs, 15169689Skanand to distribute those combinations without any restriction coming 16169689Skanfrom the use of this file. (The General Public License restrictions 17169689Skando apply in other respects; for example, they cover modification of 18169689Skanthe file, and distribution when not linked into a combined 19169689Skanexecutable.) 20169689Skan 21169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 22169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 23169689SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24169689Skanfor more details. 25169689Skan 26169689SkanYou should have received a copy of the GNU General Public License 27169689Skanalong with GCC; see the file COPYING. If not, write to the Free 28169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 29169689Skan02110-1301, USA. */ 30169689Skan 31169689Skan#include <dlfcn.h> 32169689Skan 33169689Skan/* Function Name: __isPATrange 34169689Skan Parameters passed into it: address to check 35169689Skan Return Value: A 1 if address is in pat code "range", 0 if not 36169689Skan Description: This function simply checks to see if the address 37169689Skan passed to it is in the CP pat code range. */ 38169689Skan 39169689Skan#define MIN_PATRANGE 0x10000 40169689Skan#define MAX_PATRANGE 0x800000 41169689Skan 42169689Skanstatic inline unsigned int 43169689Skan__isPATrange (void *addr) 44169689Skan{ 45169689Skan if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE) 46169689Skan return 1; 47169689Skan else 48169689Skan return 0; 49169689Skan} 50169689Skan 51169689Skan/* TPF return address offset from start of stack frame. */ 52169689Skan#define TPFRA_OFFSET 168 53169689Skan 54169689Skan/* Exceptions macro defined for TPF so that functions without 55169689Skan dwarf frame information can be used with exceptions. */ 56169689Skan#define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state 57169689Skan 58169689Skanstatic _Unwind_Reason_Code 59169689Skans390_fallback_frame_state (struct _Unwind_Context *context, 60169689Skan _Unwind_FrameState *fs) 61169689Skan{ 62169689Skan unsigned long int regs; 63169689Skan unsigned long int new_cfa; 64169689Skan int i; 65169689Skan 66169689Skan regs = *((unsigned long int *) 67169689Skan (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET)); 68169689Skan 69169689Skan /* Are we going through special linkage code? */ 70169689Skan if (__isPATrange (context->ra)) 71169689Skan { 72169689Skan 73169689Skan /* Our return register isn't zero for end of stack, so 74169689Skan check backward stackpointer to see if it is zero. */ 75169689Skan if (regs == NULL) 76169689Skan return _URC_END_OF_STACK; 77169689Skan 78169689Skan /* No stack frame. */ 79169689Skan fs->cfa_how = CFA_REG_OFFSET; 80169689Skan fs->cfa_reg = 15; 81169689Skan fs->cfa_offset = STACK_POINTER_OFFSET; 82169689Skan 83169689Skan /* All registers remain unchanged ... */ 84169689Skan for (i = 0; i < 32; i++) 85169689Skan { 86169689Skan fs->regs.reg[i].how = REG_SAVED_REG; 87169689Skan fs->regs.reg[i].loc.reg = i; 88169689Skan } 89169689Skan 90169689Skan /* ... except for %r14, which is stored at CFA-112 91169689Skan and used as return address. */ 92169689Skan fs->regs.reg[14].how = REG_SAVED_OFFSET; 93169689Skan fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET; 94169689Skan fs->retaddr_column = 14; 95169689Skan 96169689Skan return _URC_NO_REASON; 97169689Skan } 98169689Skan 99169689Skan regs = *((unsigned long int *) 100169689Skan (((unsigned long int) context->cfa) - STACK_POINTER_OFFSET)); 101169689Skan new_cfa = regs + STACK_POINTER_OFFSET; 102169689Skan 103169689Skan fs->cfa_how = CFA_REG_OFFSET; 104169689Skan fs->cfa_reg = 15; 105169689Skan fs->cfa_offset = new_cfa - 106169689Skan (unsigned long int) context->cfa + STACK_POINTER_OFFSET; 107169689Skan 108169689Skan for (i = 0; i < 16; i++) 109169689Skan { 110169689Skan fs->regs.reg[i].how = REG_SAVED_OFFSET; 111169689Skan fs->regs.reg[i].loc.offset = regs + i*8 - new_cfa; 112169689Skan } 113169689Skan 114169689Skan for (i = 0; i < 4; i++) 115169689Skan { 116169689Skan fs->regs.reg[16 + i].how = REG_SAVED_OFFSET; 117169689Skan fs->regs.reg[16 + i].loc.offset = regs + 16*8 + i*8 - new_cfa; 118169689Skan } 119169689Skan 120169689Skan fs->retaddr_column = 14; 121169689Skan 122169689Skan return _URC_NO_REASON; 123169689Skan} 124169689Skan 125169689Skan/* Function Name: __tpf_eh_return 126169689Skan Parameters passed into it: Destination address to jump to. 127169689Skan Return Value: Converted Destination address if a Pat Stub exists. 128169689Skan Description: This function swaps the unwinding return address 129169689Skan with the cp stub code. The original target return address is 130169689Skan then stored into the tpf return address field. The cp stub 131169689Skan code is searched for by climbing back up the stack and 132169689Skan comparing the tpf stored return address object address to 133169689Skan that of the targets object address. */ 134169689Skan 135169689Skan#define CURRENT_STACK_PTR() \ 136169689Skan ({ register unsigned long int *stack_ptr asm ("%r15"); stack_ptr; }) 137169689Skan 138169689Skan#define PREVIOUS_STACK_PTR() \ 139169689Skan ((unsigned long int *)(*(CURRENT_STACK_PTR()))) 140169689Skan 141169689Skan#define RA_OFFSET 112 142169689Skan#define R15_OFFSET 120 143169689Skan#define TPFAREA_OFFSET 160 144169689Skan#define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET 145169689Skan#define INVALID_RETURN 0 146169689Skan 147169689Skanvoid * __tpf_eh_return (void *target); 148169689Skan 149169689Skanvoid * 150169689Skan__tpf_eh_return (void *target) 151169689Skan{ 152169689Skan Dl_info targetcodeInfo, currentcodeInfo; 153169689Skan int retval; 154169689Skan void *current, *stackptr, *destination_frame; 155169689Skan unsigned long int shifter, is_a_stub; 156169689Skan 157169689Skan is_a_stub = 0; 158169689Skan 159169689Skan /* Get code info for target return's address. */ 160169689Skan retval = dladdr (target, &targetcodeInfo); 161169689Skan 162169689Skan /* Ensure the code info is valid (for target). */ 163169689Skan if (retval != INVALID_RETURN) 164169689Skan { 165169689Skan 166169689Skan /* Get the stack pointer of the stack frame to be modified by 167169689Skan the exception unwinder. So that we can begin our climb 168169689Skan there. */ 169169689Skan stackptr = (void *) *((unsigned long int *) (*(PREVIOUS_STACK_PTR()))); 170169689Skan 171169689Skan /* Begin looping through stack frames. Stop if invalid 172169689Skan code information is retrieved or if a match between the 173169689Skan current stack frame iteration shared object's address 174169689Skan matches that of the target, calculated above. */ 175169689Skan do 176169689Skan { 177169689Skan /* Get return address based on our stackptr iterator. */ 178169689Skan current = (void *) *((unsigned long int *) 179169689Skan (stackptr+RA_OFFSET)); 180169689Skan 181169689Skan /* Is it a Pat Stub? */ 182169689Skan if (__isPATrange (current)) 183169689Skan { 184169689Skan /* Yes it was, get real return address 185169689Skan in TPF stack area. */ 186169689Skan current = (void *) *((unsigned long int *) 187169689Skan (stackptr+TPFRA_OFFSET)); 188169689Skan is_a_stub = 1; 189169689Skan } 190169689Skan 191169689Skan /* Get codeinfo on RA so that we can figure out 192169689Skan the module address. */ 193169689Skan retval = dladdr (current, ¤tcodeInfo); 194169689Skan 195169689Skan /* Check that codeinfo for current stack frame is valid. 196169689Skan Then compare the module address of current stack frame 197169689Skan to target stack frame to determine if we have the pat 198169689Skan stub address we want. Also ensure we are dealing 199169689Skan with a module crossing, stub return address. */ 200169689Skan if (is_a_stub && retval != INVALID_RETURN 201169689Skan && targetcodeInfo.dli_fbase == currentcodeInfo.dli_fbase) 202169689Skan { 203169689Skan /* Yes! They are in the same module. 204169689Skan Force copy of TPF private stack area to 205169689Skan destination stack frame TPF private area. */ 206169689Skan destination_frame = (void *) *((unsigned long int *) 207169689Skan (*PREVIOUS_STACK_PTR() + R15_OFFSET)); 208169689Skan 209169689Skan /* Copy TPF linkage area from current frame to 210169689Skan destination frame. */ 211169689Skan memcpy((void *) (destination_frame + TPFAREA_OFFSET), 212169689Skan (void *) (stackptr + TPFAREA_OFFSET), TPFAREA_SIZE); 213169689Skan 214169689Skan /* Now overlay the 215169689Skan real target address into the TPF stack area of 216169689Skan the target frame we are jumping to. */ 217169689Skan *((unsigned long int *) (destination_frame + 218169689Skan TPFRA_OFFSET)) = (unsigned long int) target; 219169689Skan 220169689Skan /* Before returning the desired pat stub address to 221169689Skan the exception handling unwinder so that it can 222169689Skan actually do the "leap" shift out the low order 223169689Skan bit designated to determine if we are in 64BIT mode. 224169689Skan This is necessary for CTOA stubs. 225169689Skan Otherwise we leap one byte past where we want to 226169689Skan go to in the TPF pat stub linkage code. */ 227169689Skan shifter = *((unsigned long int *) 228169689Skan (stackptr + RA_OFFSET)); 229169689Skan 230169689Skan shifter &= ~1ul; 231169689Skan 232169689Skan /* Store Pat Stub Address in destination Stack Frame. */ 233169689Skan *((unsigned long int *) (destination_frame + 234169689Skan RA_OFFSET)) = shifter; 235169689Skan 236169689Skan /* Re-adjust pat stub address to go to correct place 237169689Skan in linkage. */ 238169689Skan shifter = shifter - 4; 239169689Skan 240169689Skan return (void *) shifter; 241169689Skan } 242169689Skan 243169689Skan /* Desired module pat stub not found ... 244169689Skan Bump stack frame iterator. */ 245169689Skan stackptr = (void *) *(unsigned long int *) stackptr; 246169689Skan 247169689Skan is_a_stub = 0; 248169689Skan 249169689Skan } while (stackptr && retval != INVALID_RETURN 250169689Skan && targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase); 251169689Skan } 252169689Skan 253169689Skan /* No pat stub found, could be a problem? Simply return unmodified 254169689Skan target address. */ 255169689Skan return target; 256169689Skan} 257169689Skan 258