File: auto_zlink.c

package info (click to toggle)
fis-gtm 7.0-005-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 32,264 kB
  • sloc: ansic: 336,687; asm: 5,184; csh: 4,823; sh: 1,945; awk: 291; makefile: 72; sed: 13
file content (201 lines) | stat: -rw-r--r-- 8,709 bytes parent folder | download | duplicates (4)
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
/****************************************************************
 *								*
 * Copyright (c) 2003-2019 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_string.h"

#include "urx.h"
#include <rtnhdr.h>
#include "stack_frame.h"
#include "op.h"
#include <auto_zlink.h>
#include "arlinkdbg.h"
#include "linktrc.h"

#ifndef AUTORELINK_SUPPORTED
# error "Routine should not be built by non-autorelink-enabled platforms"
#endif

GBLREF stack_frame	*frame_pointer;

/* Routine to locate the entry being linked from generated code and link it in and return to the glue code
 * code to drive it.
 *
 * Arguments:
 *
 *   rtnhdridx  - Index into linkage table for the routine that needs linking.
 */
void auto_zlink(int rtnhdridx)
{
	mstr		rname;
	mident_fixed	rname_buff;
	mval		rtn;
	rhdtyp		*rhd;

	assert(0 <= rtnhdridx);			/* rtnhdridx must never be negative */
	assert(rtnhdridx <= frame_pointer->rvector->linkage_len);
	assert(NULL == frame_pointer->rvector->linkage_adr[rtnhdridx].ext_ref);
	rname = frame_pointer->rvector->linkage_names[rtnhdridx];
	rname.addr += (INTPTR_T)frame_pointer->rvector->literal_text_adr;	/* Perform relocation on name */
	memcpy(rname_buff.c, rname.addr, rname.len);
	memset(rname_buff.c + rname.len, 0, SIZEOF(rname_buff) - rname.len);	/* Clear rest of mident_fixed */
	rname.addr = rname_buff.c;
	assert(rname.len <= MAX_MIDENT_LEN);
	assert(NULL == find_rtn_hdr(&rname));
	rtn.mvtype = MV_STR;
	rtn.str.len = rname.len;
	rtn.str.addr = rname.addr;
	op_zlink(&rtn, NULL);			/* op_zlink() takes care of '%' -> '_' translation of routine name */
	if ('_' == rname_buff.c[0]) rname_buff.c[0] = '%';
	if ((NULL == (rhd = find_rtn_hdr(&rname))) && (op_rhdaddr(&rtn, -1)))
		assert(FALSE && rname.addr); 	/* if the routine is not found, op_rhdaddr should give and error & return FALSE */
	DBGARLNK((stderr, "auto_zlink: Linked in rtn %.*s to "lvaddr"\n", rname.len, rname.addr, find_rtn_hdr(&rname)));
	return;
}

/* Routine to check routine if autorelink is needed.
 *
 * Arguments:
 *
 *   rtnhdridx  - Index into linkage table for the routine that may need re-linking.
 *   lbltblidx  - Index into linkage table for the label table entry needed to get label offset. Main purpose of using this
 *		  routine is it is the indicator for when indirect code is using the lnk_proxy mechanism to pass in entries
 *		  because indirects have no linkage table of their own.
 */
void auto_relink_check(int rtnhdridx, int lbltblidx)
{
	rhdtyp		*rhd, *callerrhd;
	int		nameoff, clen;
	unsigned char	*cptr;
	boolean_t	fnddot, valid_calling_seq;
	DEBUG_ONLY(int	rtnname_len;)
	DEBUG_ONLY(char	*rtnname_adr;);
	DEBUG_ONLY(mident_fixed rtnname;)
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(0 <= rtnhdridx);
	if ((frame_pointer->flags & SFF_INDCE) || (0 > lbltblidx))
		return;		/* Don't deal with indirects - just let them use the vars they received from op_rhd/labaddr */
	assert(rtnhdridx <= frame_pointer->rvector->linkage_len);
	assert(lbltblidx <= frame_pointer->rvector->linkage_len);
	/* If routine hasn't been linked yet, drive auto_zlink() to pull it in and return (no further checking needed since
	 * it was just linked).
	 */
	if (NULL == frame_pointer->rvector->linkage_adr[rtnhdridx].ext_ref)
	{
		auto_zlink(rtnhdridx);
		return;
	}
	callerrhd = frame_pointer->rvector;				/* rtnhdr of routine doing the calling */
	rhd = (rhdtyp *)callerrhd->linkage_adr[rtnhdridx].ext_ref;	/* rtnhdr of routine being called */
#	ifdef DEBUG
	/* Validate name of routine is as we expect it to be */
	assert(NULL != rhd);
	rtnname_adr = (INTPTR_T)callerrhd->linkage_names[rtnhdridx].addr + (char *)callerrhd->literal_text_adr;
	rtnname_len = callerrhd->linkage_names[rtnhdridx].len;
	memcpy(rtnname.c, rtnname_adr, rtnname_len);
	if ('_' == rtnname.c[0])
		rtnname.c[0] = '%';
	assert((rtnname_len == rhd->routine_name.len)
	       && (0 == memcmp(rtnname.c, rhd->routine_name.addr, rtnname_len)));
#	endif
	DBGARLNK((stderr, "auto_relink_check: rtn %.*s calling rtn: %.*s - arlink_enabled: %d  arlink_loaded: %d\n",
		  callerrhd->routine_name.len, callerrhd->routine_name.addr,
		  rhd->routine_name.len, rhd->routine_name.addr, TREF(arlink_enabled), TREF(arlink_loaded)));
	explicit_relink_check(rhd, FALSE);
}

/* Routine called when have routine name and need to do an explicit autorelink check - either from above or from
 * $TEXT(), ZPRINT or any future users of get_src_line().
 *
 * Argument:
 *
 *   rhd       - routine header of routine to be checked if needs to be relinked.
 *   setproxy  - TRUE if need to set old/new routine header into TABENT_PROXY
 *
 * Routine is already linked, but we need to check if a new version is available. This involves traversing the
 * "validation linked list", looking for changes in different $ZROUTINES entries. But we also need to base our
 * checks on the most recent version of the routine loaded. Note autorelink is only allowed when no ZBREAKs are
 * defined in the given routine.
 */
void explicit_relink_check(rhdtyp *rhd, boolean_t setproxy)
{
	mval		rtnname;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(NULL != rhd);
	assert(!rhd->rtn_relinked);	/* Should never be calling recursively linked routine. All such calls should be going
					 * to the new current routine instead of the recursively linked copy rtnhdr.
					 */
	/* Routine is already linked, but we need to check if a new version is available. This involves traversing the
	 * "validation linked list", looking for changes in different $ZROUTINES entries. But we also need to base our
	 * checks on the most recent version of the routine loaded. Note autorelink is only possible when no ZBREAKs are
	 * defined in the given routine.
	 *
	 * Note the following section is very similar to code in op_rhdaddr.c. Any changes made here need to be echoed there
	 */
 	if (!CURRENT_RHEAD_ADR(rhd)->has_ZBREAK)
	{
		rhd = rhd->current_rhead_adr;		/* Update rhd to most currently linked version */
#		ifdef DEBUG_ARLINK
		DBGARLNK((stderr, "explicit_relink_check: rtn: %.*s  rtnhdr: 0x"lvaddr"  zhist: 0x"lvaddr,
			  rhd->routine_name.len, rhd->routine_name.addr, rhd, rhd->zhist));
		if (NULL != rhd->zhist)
		{
			DBGARLNK((stderr, "  zhist->cycle: %d  zrtns cycle: %d\n", rhd->zhist->zroutines_cycle,
				  TREF(set_zroutines_cycle)));
		} else
		{
			DBGARLNK((stderr, "\n"));
		}
#		endif
		if ((NULL != rhd->zhist) && need_relink(rhd, (zro_hist *)rhd->zhist))
		{	/* Relink appears to be needed. Note we have the routine name from the passed in header address so
			 * only debug builds fetch/compare it against the expected value from the name table.
			 */
			rtnname.mvtype = MV_STR;
			rtnname.str = rhd->routine_name;
			DBGARLNK((stderr,"explicit_relink_check: Routine needs relinking: %.*s\n",
				  rtnname.str.len, rtnname.str.addr));
			op_zlink(&rtnname, NULL);	/* op_zlink() takes care of '%' -> '_' translation of routine name */
			/* Use the fastest way to pickup the routine header address of the current copy. The linker would have
			 * updated the current rtnhdr address in our routine header so this provides the easiest way to find
			 * the newly linked header whether the link was bypassed or not. The only exception to this is when
			 * the current routine is a recursively linked copy routine whose current rtnhdr address always points
			 * to itself but those routines cannot end up here so this is the best way.
			 */
			rhd = rhd->current_rhead_adr;
			/* Note it is possible for multiple processes to interfere with each other and cause the below assert
			 * to fail. Should that happen, the assert can be removed but to date it has not failed so am leaving
			 * it in.
			 */
			assert((NULL == rhd->zhist) || (((zro_hist *)(rhd->zhist))->zroutines_cycle == TREF(set_zroutines_cycle)));
		} else
		{
			DBGARLNK((stderr,"explicit_relink_check: Routine does NOT need relinking: %.*s\n", rhd->routine_name.len,
				  rhd->routine_name.addr));
		}
	} else
	{
		DBGARLNK((stderr,"explicit_relink_check: Routine relink bypassed - has ZBREAKs: %.*s\n", rhd->routine_name.len,
			  rhd->routine_name.addr));
	}
	if (setproxy)
	{
		DBGINDCOMP((stderr, "explicit_relink_check: Indirect call to routine %.*s resolved to 0x"lvaddr"\n",
			    rhd->routine_name.len, rhd->routine_name.addr, rhd));
		(TABENT_PROXY).rtnhdr_adr = rhd;
	}
}