237 lines
8.6 KiB
C
237 lines
8.6 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2011 Fidelity Information Services, Inc *
|
|
* *
|
|
* 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 "rtnhdr.h"
|
|
#include "stack_frame.h"
|
|
#include "hashtab_mname.h"
|
|
#include "fix_pages.h"
|
|
#include "zbreak.h"
|
|
#include "private_code_copy.h"
|
|
#include "urx.h"
|
|
#include "min_max.h"
|
|
#include "stringpool.h"
|
|
#include "gtm_text_alloc.h"
|
|
#ifdef UNIX
|
|
#include "srcline.h"
|
|
#endif
|
|
|
|
#define S_CUTOFF 7
|
|
#define FREE_RTNTBL_SPACE 17
|
|
#define RTNTBL_EXP_MIN (SIZEOF(rtn_tabent) * FREE_RTNTBL_SPACE) /* never expand the routine name table by less than 17 entries */
|
|
#define RTNTBL_EXP_MAX ((16 * 1024) + 1) /* never expand the routine name table by more than 16KB (at one time) */
|
|
|
|
GBLREF rtn_tabent *rtn_fst_table, *rtn_names, *rtn_names_end, *rtn_names_top;
|
|
GBLREF stack_frame *frame_pointer;
|
|
|
|
bool zlput_rname (rhdtyp *hdr)
|
|
{
|
|
rhdtyp *old_rhead, *rhead;
|
|
rtn_tabent *rbot, *mid, *rtop;
|
|
stack_frame *fp, *fpprev;
|
|
char *src, *new, *old_table;
|
|
int comp;
|
|
ht_ent_mname *tabent;
|
|
mname_entry key;
|
|
uint4 entries;
|
|
mstr *curline;
|
|
mident *rtn_name;
|
|
size_t size, src_len;
|
|
# ifdef VMS
|
|
uint4 *src_tbl;
|
|
# else
|
|
routine_source *src_tbl;
|
|
# endif
|
|
DCL_THREADGBL_ACCESS;
|
|
|
|
SETUP_THREADGBL_ACCESS;
|
|
rtn_name = &hdr->routine_name;
|
|
rbot = rtn_names;
|
|
rtop = rtn_names_end;
|
|
for (;;)
|
|
{ /* See if routine exists in list via a binary search which reverts to serial
|
|
search when # of items drops below the threshold S_CUTOFF.
|
|
*/
|
|
if ((rtop - rbot) < S_CUTOFF)
|
|
{
|
|
comp = -1;
|
|
for (mid = rbot; mid <= rtop ; mid++)
|
|
{
|
|
MIDENT_CMP(&mid->rt_name, rtn_name, comp);
|
|
if (0 <= comp)
|
|
break;
|
|
}
|
|
break;
|
|
} else
|
|
{ mid = rbot + (rtop - rbot)/2;
|
|
MIDENT_CMP(&mid->rt_name, rtn_name, comp);
|
|
if (0 == comp)
|
|
break;
|
|
else if (0 > comp)
|
|
{
|
|
rbot = mid + 1;
|
|
continue;
|
|
} else
|
|
{
|
|
rtop = mid - 1;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (comp)
|
|
{ /* Entry was not found. Add in a new one */
|
|
old_table = NULL;
|
|
src = (char *)mid;
|
|
src_len = (char *)rtn_names_end - (char *)mid + SIZEOF(rtn_tabent);
|
|
if (rtn_names_end >= rtn_names_top)
|
|
{ /* Not enough room, recreate table in larger area, try to expand exponentially */
|
|
size = (char *)rtn_names_end - (char *)rtn_names;
|
|
size = ROUND_UP(size +
|
|
((RTNTBL_EXP_MIN > size) ? RTNTBL_EXP_MIN : ((RTNTBL_EXP_MAX < size) ? RTNTBL_EXP_MAX : size)),
|
|
SIZEOF(rtn_tabent));
|
|
new = malloc(size);
|
|
memcpy(new, rtn_names, (char *)mid - (char *)rtn_names);
|
|
mid = (rtn_tabent *)((char *)mid + (new - (char *)rtn_names));
|
|
old_table = (char *)rtn_names;
|
|
/* Adjust rtn_named_end to point into new table by applying offset to new block */
|
|
rtn_names_end = (rtn_tabent *)((char *)rtn_names_end + (new - (char *)rtn_names));
|
|
rtn_names = (rtn_tabent *)new;
|
|
rtn_names_top = (rtn_tabent *)(new + size - SIZEOF(rtn_tabent));
|
|
memset(rtn_names_end + 1, 0, size - ((char *)(rtn_names_end + 1) - new));
|
|
}
|
|
memmove(mid + 1, src, src_len);
|
|
mid->rt_name = *rtn_name;
|
|
rtn_names_end++;
|
|
if (old_table && old_table != (char *)rtn_fst_table)
|
|
free(old_table); /* original table can't be freed */
|
|
assert(NON_USHBIN_ONLY(!hdr->old_rhead_ptr) USHBIN_ONLY(!hdr->old_rhead_adr));
|
|
} else
|
|
{ /* Entry exists. Update it */
|
|
old_rhead = (rhdtyp *)mid->rt_adr;
|
|
/* Verify routine is not currently active. If it is, we cannot replace it */
|
|
for (fp = frame_pointer; fp ; fp = fpprev)
|
|
{
|
|
fpprev = fp->old_frame_pointer;
|
|
# ifdef GTM_TRIGGER
|
|
if (NULL != fpprev && SFT_TRIGR & fpprev->type)
|
|
fpprev = *(stack_frame **)(fpprev + 1);
|
|
# endif
|
|
/* Check all possible versions of each routine header */
|
|
for (rhead = CURRENT_RHEAD_ADR(old_rhead); rhead;
|
|
rhead = (rhdtyp *)NON_USHBIN_ONLY(rhead->old_rhead_ptr)USHBIN_ONLY(rhead->old_rhead_adr))
|
|
if (fp->rvector == rhead)
|
|
return FALSE;
|
|
}
|
|
zr_remove(old_rhead, NOBREAKMSG); /* get rid of the inactive breakpoints and release private code section */
|
|
|
|
/* If source has been read in for old routine, free space. Since routine name is the key, do this before
|
|
(in USHBIN builds) we release the literal text section as part of the releasable read-only section.
|
|
*/
|
|
tabent = NULL;
|
|
if (NULL != (TREF(rt_name_tbl)).base)
|
|
{
|
|
key.var_name = mid->rt_name;
|
|
COMPUTE_HASH_MNAME(&key);
|
|
if (NULL != (tabent = lookup_hashtab_mname(TADR(rt_name_tbl), &key)) && tabent->value)
|
|
{
|
|
# ifdef VMS
|
|
src_tbl = (uint4 *)tabent->value;
|
|
/* Must delete the entries piece-meal */
|
|
entries = *(src_tbl + 1);
|
|
if (0 != entries)
|
|
/* Don't count line 0 which we bypass */
|
|
entries--;
|
|
/* curline start is 2 uint4s into src_tbl and then space past line 0 or
|
|
we end up freeing the storage for line 0/1 twice since they have the
|
|
same pointers.
|
|
*/
|
|
for (curline = RECAST(mstr *)(src_tbl + 2) + 1; 0 != entries; --entries, ++curline)
|
|
{
|
|
assert(curline->len);
|
|
free(curline->addr);
|
|
}
|
|
free(tabent->value);
|
|
# elif defined(UNIX)
|
|
/* Entries and source are malloc'd in two blocks on UNIX */
|
|
src_tbl = (routine_source *)tabent->value;
|
|
if (NULL != src_tbl->srcbuff)
|
|
free(src_tbl->srcbuff);
|
|
free(src_tbl);
|
|
# else
|
|
# error "unsupported platform"
|
|
# endif
|
|
/* Note that there are two possible ways to proceed here to clear this entry:
|
|
* 1. Just clear the value as we do below.
|
|
* 2. Use the DELETE_HTENT() macro to remove the entry entirely from the hash table.
|
|
*
|
|
* We choose #1 since a routine that had had its source loaded is likely to have it reloaded
|
|
* and if the source load rtn has to re-add the key, it won't reuse the deleted key (if it
|
|
* remained a deleted key) until all other hashtable slots have been used up (creating a long
|
|
* collision chain). A deleted key may not remain a deleted key if it was reached with no
|
|
* collisions but will instead be turned into an unused key and be immediately reusable.
|
|
* But since it is likely to be reused, we just zero the entry but this creates a necessity
|
|
* that the key be maintained. If this is a non-USBHIN platform, everything stays around
|
|
* anyway so that's not an issue. However, in a USHBIN platform, the literal storage the key
|
|
* is pointing to gets released. For that reason, in the USHBIN processing section below, we
|
|
* update the key to point to the newly loaded module's routine name.
|
|
*/
|
|
tabent->value = NULL;
|
|
}
|
|
}
|
|
NON_USHBIN_ONLY(
|
|
hdr->old_rhead_ptr = (int4)old_rhead;
|
|
if (!old_rhead->old_rhead_ptr)
|
|
{
|
|
fix_pages((unsigned char *)old_rhead, (unsigned char *)LNRTAB_ADR(old_rhead)
|
|
+ (SIZEOF(lnr_tabent) * old_rhead->lnrtab_len));
|
|
}
|
|
)
|
|
USHBIN_ONLY(
|
|
if (!old_rhead->shlib_handle)
|
|
{ /* Migrate text literals pointing into text area we are about to throw away into the stringpool.
|
|
We also can release the read-only releasable segment as it is no longer needed.
|
|
*/
|
|
stp_move((char *)old_rhead->literal_text_adr,
|
|
(char *)(old_rhead->literal_text_adr + old_rhead->literal_text_len));
|
|
if (tabent)
|
|
{ /* There was (at one time) a $TEXT source section for this routine. We may have just
|
|
released it but whether the source was for the routine just replaced or for an earlier
|
|
replacement, the key for that segment is pointing into the readonly storage we
|
|
are just about to release. Replace the key with the current one for this routine.
|
|
*/
|
|
assert(MSTR_EQ(&tabent->key.var_name, rtn_name));
|
|
tabent->key.var_name = *rtn_name; /* Update key with newly saved mident */
|
|
}
|
|
zlmov_lnames(old_rhead); /* copy the label names from literal pool to malloc'd area */
|
|
GTM_TEXT_FREE(old_rhead->ptext_adr);
|
|
/* Reset the routine header pointers to the sections we just freed up.
|
|
* NOTE: literal_text_adr shouldn't be reset as it points to the label area malloc'd
|
|
* in zlmov_lnames() */
|
|
old_rhead->ptext_adr = old_rhead->ptext_end_adr = NULL;
|
|
old_rhead->lnrtab_adr = NULL;
|
|
}
|
|
urx_remove(old_rhead);
|
|
free(old_rhead->literal_adr); /* Release the read-write releasable segments */
|
|
old_rhead->literal_adr = NULL;
|
|
old_rhead->vartab_adr = NULL;
|
|
|
|
free(old_rhead->linkage_adr); /* Release the old linkage section */
|
|
old_rhead->linkage_adr = NULL;
|
|
hdr->old_rhead_adr = old_rhead;
|
|
)
|
|
mid->rt_name = *rtn_name;
|
|
}
|
|
mid->rt_adr= hdr;
|
|
return TRUE;
|
|
}
|