1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
|
/****************************************************************
* *
* Copyright (c) 2011-2017 Fidelity National Information *
* Services, Inc. and/or its subsidiaries. All rights reserved. *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include "gtm_stdio.h"
#include "gtm_string.h"
#include <rtnhdr.h>
#include "stack_frame.h"
#include "op.h"
#include "flush_jmp.h"
#include "dollar_zlevel.h"
#include "golevel.h"
#include <auto_zlink.h>
#include "error.h"
#include "gtmimagename.h"
#include "linktrc.h"
#ifdef UNIX
#include "gtm_unlink_all.h"
#endif
#ifdef GTM_TRIGGER
#include "gtm_trigger_trc.h"
#endif
#ifdef VMS
#include "pdscdef.h"
#include "proc_desc.h"
#endif
GBLREF stack_frame *frame_pointer;
#ifdef GTM_TRIGGER
GBLREF boolean_t goframes_unwound_trigger;
#endif
LITREF gtmImageName gtmImageNames[];
error_def(ERR_LABELUNKNOWN);
error_def(ERR_RTNNAME);
error_def(ERR_ZGOCALLOUTIN);
error_def(ERR_ZGOTOINVLVL);
error_def(ERR_ZGOTOINVLVL2);
error_def(ERR_ZGOTOLTZERO);
error_def(ERR_ZGOTOTOOBIG);
void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level)
{
stack_frame *fp, *fpprev;
int4 curlvl;
mval rtnname, lblname;
rhdtyp *rtnhdr;
lnr_tabent USHBIN_ONLY(*)*lnrptr;
void (*frame_func)();
char rtnname_buff[SIZEOF(mident_fixed)], lblname_buff[SIZEOF(mident_fixed)];
DEBUG_ONLY(int4 dlevel;)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
/* Validate level parm */
curlvl = dollar_zlevel();
if (0 > level)
{ /* Negative level specified, means to use relative level change */
if ((-level) > curlvl)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOLTZERO);
level += curlvl; /* Compute relative desired level */
} else
{ /* Else level is the level we wish to achieve - compute unrolls necessary */
if (0 > (curlvl - level))
/* Couldn't get to the level we were trying to unwind to */
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOTOOBIG);
}
/* Migrate mval parm contents to private buffers since the mvals could die as we unwind things */
MV_FORCE_STR(rtn_name);
MV_FORCE_STR(lbl_name);
rtnname = *rtn_name;
lblname = *lbl_name;
memcpy(rtnname_buff, rtnname.str.addr, rtnname.str.len);
rtnname.str.addr = rtnname_buff;
memcpy(lblname_buff, lblname.str.addr, lblname.str.len);
lblname.str.addr = lblname_buff;
DBGEHND((stderr, "op_zgoto: rtnname: %.*s lblname: %.*s offset: %d level: %d\n",
rtnname.str.len, rtnname.str.addr, lblname.str.len, lblname.str.addr, offset, level));
/* Validate entryref before do any unwinding */
if (0 == rtnname.str.len)
{ /* If no routine name given, take it from the currently running routine unless the label name
* is also NULL. In that case, we must be doing an indirect routine name only and the supplied name
* was NULL.
*/
if ((0 == lblname.str.len) && !offset)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RTNNAME);
rtnhdr = frame_pointer->rvector;
ARLINK_ONLY(TADR(lnk_proxy)->rtnhdr_adr = rtnhdr);
DBGINDCOMP((stderr, "op_zgoto: routine resolved to 0x"lvaddr" (1)\n", rtnhdr));
if (0 == level)
{ /* If doing unlink, recall name of routine as well as will need it later */
memcpy(rtnname_buff, rtnhdr->routine_name.addr, rtnhdr->routine_name.len);
rtnname.str.addr = rtnname_buff;
rtnname.str.len = rtnhdr->routine_name.len;
}
} else
{
# ifdef AUTORELINK_SUPPORTED
op_rhdaddr(&rtnname, -1); /* Does an autozlink if necessary */
rtnhdr = TADR(lnk_proxy)->rtnhdr_adr;
DBGINDCOMP((stderr, "op_zgoto: routine resolved to 0x"lvaddr" (2)\n", rtnhdr));
# else
rtnhdr = op_rhdaddr(&rtnname, NULL); /* Does an autozlink if necessary */
# endif
# ifdef VMS
if (PDSC_FLAGS == ((proc_desc *)rtnhdr)->flags) /* it's a procedure descriptor, not a routine header */
{
rtnhdr = (rhdtyp *)(((proc_desc *)rtnhdr)->code_address);
/* Make sure this if-test is sufficient to distinguish between procedure descriptors and routine headers */
assert(PDSC_FLAGS != ((proc_desc *)rtnhdr)->flags);
}
# endif
}
assert(NULL != rtnhdr);
# ifdef AUTORELINK_SUPPORTED
op_labaddr(0, &lblname, offset);
lnrptr = &TADR(lnk_proxy)->lnr_adr;
# else
lnrptr = op_labaddr(rtnhdr, &lblname, offset);
# endif
assert(NULL != lnrptr);
# ifdef VMS
/* VMS does not support unlink so any level 0 request that passes earlier checks just generates an error
* since the base frame cannot be rewritten as a GTM frame.
*/
if (0 == level)
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOINVLVL2);
# endif
# ifdef GTM_TRIGGER
if (!IS_GTM_IMAGE && (1 >= level))
/* In MUPIP (or other utility that gets trigger support in the future), levels 0 and 1 refer to
* the pseudo baseframe and initial stack levels which are not rewritable (in the case where an
* entry ref was coded) and are not resume-able (if no entry ref were specified) so we cannot
* permit ZGOTOs to these levels in a utility.
*/
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZGOTOINVLVL, 3, GTMIMAGENAMETXT(image_type), level);
# endif
# ifdef UNIX
/* One last check if we are unlinking, make sure no call-in frames exist on our stack */
if (0 == level)
{
for (fp = frame_pointer; NULL != fp; fp = fpprev)
{
fpprev = fp->old_frame_pointer;
if (!(fp->type & SFT_COUNT))
continue;
if (fp->flags & SFF_CI)
/* We have a call-in frame - cannot do unlink */
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOCALLOUTIN);
if (NULL == fpprev)
{ /* Next frame is some sort of base frame */
# ifdef GTM_TRIGGER
if (fp->type & SFT_TRIGR)
{ /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by
*base_frame() */
fpprev = *(stack_frame **)(fp + 1);
continue;
} else
# endif
break; /* Some other base frame that stops us */
}
}
/* Full unlink/unwind requested. First unlink everything, then relink our target entryref */
gtm_unlink_all();
frame_func = new_stack_frame;
/* Now that everything is unwound, frame_pointer is the base frame. This frame contains the same rvector pointer
* that the level 1 stack frame routine has so it needs to also be rewritten once we link our new "1st routine".
*/
assert((NULL != frame_pointer) && (NULL == frame_pointer->old_frame_pointer));
# ifdef AUTORELINK_SUPPORTED
op_rhdaddr(&rtnname, -1);
rtnhdr = TADR(lnk_proxy)->rtnhdr_adr;
# else
rtnhdr = op_rhdaddr(&rtnname, NULL);
# endif
assert(NULL != rtnhdr);
frame_pointer->rvector = rtnhdr;
# ifdef AUTORELINK_SUPPORTED
op_labaddr(0, &lblname, offset);
lnrptr = &TADR(lnk_proxy)->lnr_adr;
# else
lnrptr = op_labaddr(rtnhdr, &lblname, offset);
# endif
assert(NULL != lnrptr);
} else
# endif /* UNIX */
{ /* Unwind to our target level (UNIX if 0 != level and VMS [all]) */
GOLEVEL(level, TRUE); /* Unwind the trigger base frame if we run into one */
assert(level == dollar_zlevel());
frame_func = flush_jmp;
}
/* Convert current stack frame (flush_jmp) to the frame for the entry ref we want to branch to, or create a new level 1
* frame (new_stack_frame) after ZGOTO 0.
*/
USHBIN_ONLY((* frame_func)(rtnhdr, (unsigned char *)LINKAGE_ADR(rtnhdr), LINE_NUMBER_ADDR(rtnhdr, *lnrptr)));
/* on non-shared binary calculate the transfer address to be passed to flush_jmp as follows:
* 1) get the number stored at lnrptr; this is the offset to the line number entry
* 2) add the said offset to the address of the routine header; this is the address of line number entry
* 3) dereference the said address to get the line number of the actual program
* 4) add the said line number to the address of the routine header
*/
NON_USHBIN_ONLY((* frame_func)(rtnhdr, (unsigned char *)LINKAGE_ADR(rtnhdr),
(unsigned char *)((int)rtnhdr + *(int *)((int)rtnhdr + *lnrptr))));
DBGEHND((stderr, "op_zgoto: Resuming at frame 0x"lvaddr" with type 0x%04lx\n", frame_pointer, frame_pointer->type));
# ifdef GTM_TRIGGER
if (goframes_unwound_trigger)
{ /* If goframes() called by golevel unwound a trigger base frame, we must use MUM_TSTART to unroll the
* C stack before invoking the return frame. Otherwise we can just return and avoid the overhead that
* MUM_TSTART incurs.
*/
MUM_TSTART;
}
# endif
}
|