fis-gtm/sr_port/op_setzbrk.c

213 lines
7.4 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 "gtm_stdio.h"
#include "cache.h"
#include <rtnhdr.h>
#include "zbreak.h"
#include "stack_frame.h"
#include "xfer_enum.h"
#include "indir_enum.h"
#include "cachectl.h"
#include "op.h"
#include "fix_pages.h"
#include "io.h"
#include "inst_flush.h"
#include "private_code_copy.h"
#include "iosp.h"
#include "gtm_text_alloc.h"
#include "srcline.h"
#ifdef GTM_TRIGGER
# include "trigger_source_read_andor_verify.h"
# include "gtm_trigger_trc.h"
#endif
GBLREF z_records zbrk_recs;
GBLREF mident_fixed zlink_mname;
GBLREF stack_frame frame_pointer;
GBLREF unsigned short proc_act_type;
error_def(ERR_COMMENT);
error_def(ERR_MEMORY);
error_def(ERR_NOPLACE);
error_def(ERR_NOZBRK);
error_def(ERR_TRIGNAMENF);
error_def(ERR_VMSMEMORY);
error_def(ERR_ZBREAKFAIL);
error_def(ERR_ZLINKFILE);
error_def(ERR_ZLMODULE);
void op_setzbrk(mval *rtn, mval *lab, int offset, mval *act, int cnt)
/* act == action associated with ZBREAK */
/* cnt == perform break after this many passes */
{
char *cp, zbloc_buff[MAX_ENTRYREF_LEN], *zbloc_end;
mident *lab_name, *dummy;
mident rname, lname;
mstr *obj;
rhdtyp *routine;
zb_code *addr, tmp_xf_code;
int4 *line_offset_addr, *next_line_offset_addr;
ssize_t addr_off;
zbrk_struct *z_ptr;
cache_entry *csp;
uint4 status;
int sstatus;
icode_str indir_src;
boolean_t deleted, is_trigger;
MV_FORCE_STR(rtn);
MV_FORCE_STR(lab);
MV_FORCE_STR(act);
if (NULL == zbrk_recs.beg)
{
assert(NULL == zbrk_recs.free);
assert(NULL == zbrk_recs.end);
zr_init(&zbrk_recs, INIT_NUM_ZBREAKS);
}
if (CANCEL_ALL == cnt)
zr_remove(NULL, NOBREAKMSG);
else
{
GTMTRIG_ONLY(IS_TRIGGER_RTN(&rtn->str, is_trigger));
GTMTRIG_ONLY(if (is_trigger) DBGTRIGR((stderr, "op_setzbrk: Setting/clearing a zbreak in a trigger\n")));
flush_pio();
if (NULL == (routine = find_rtn_hdr(&rtn->str))) /* Note assignment */
{
# ifdef GTM_TRIGGER
if (is_trigger)
{
sstatus = trigger_source_read_andor_verify(&rtn->str, TRIGGER_COMPILE);
if ((0 != sstatus) || (NULL == (routine = find_rtn_hdr(&rtn->str)))) /* Note assignment */
rts_error(VARLSTCNT(4) ERR_TRIGNAMENF, 2, rtn->str.len, rtn->str.addr);
} else
# endif
{
op_zlink(rtn, NULL);
routine = find_rtn_hdr(&rtn->str);
if (NULL == routine)
rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, rtn->str.len, rtn->str.addr,
ERR_ZLMODULE, 2, mid_len(&zlink_mname), &zlink_mname.c[0]);
}
}
lab_name = NULL;
if (NULL == (line_offset_addr = find_line_addr(routine, &lab->str, offset, &lab_name)))
dec_err(VARLSTCNT(1) ERR_NOPLACE);
else if (CANCEL_ONE == cnt) /* cancel zbreak */
{
addr = (zb_code *)LINE_NUMBER_ADDR(CURRENT_RHEAD_ADR(routine), line_offset_addr);
addr = find_line_call(addr);
if (NULL != (z_ptr = zr_find(&zbrk_recs, addr)))
zr_put_free(&zbrk_recs, z_ptr);
else
dec_err(VARLSTCNT(1) ERR_NOZBRK);
} else if (0 <= cnt) /* set zbreak */
{
# ifdef ZB_AT_COMMENT_INFO
dummy = NULL;
next_line_offset_addr = find_line_addr(routine, &lab->str, offset + 1, &dummy);
if (NULL != next_line_offset_addr && *next_line_offset_addr == *line_offset_addr)
{ /* we don't recognize the case of last line comment 'coz that line generates LINESTART, RET code */
dec_err(VARLSTCNT(1) ERR_COMMENT);
assert(lab_name == dummy);
}
# endif
op_commarg(act, indir_linetail); /* This puts entry in stack and also increments refcnt field */
indir_src.str = act->str;
indir_src.code = indir_linetail;
obj = cache_get(&indir_src);
assert(NULL != obj);
csp = ((ihdtyp *)(obj->addr))->indce; /* Cache entry for this object code */
csp->zb_refcnt++; /* This will keep it around */
op_unwind(); /* This removes entry from stack and decrements refcnt field */
addr = (zb_code *)LINE_NUMBER_ADDR(CURRENT_RHEAD_ADR(routine), line_offset_addr);
/* On HPPA (& other platforms) the addr returned is the address of the field in the instruction which is
* the offset of xfer table. But on IA64, as this field is set in the ADDS instruction as 14 bit immed
* value and this is written into 3 bitwise fields, we need to return the address of the whole instruction
* itself (in our case bundle as we are using a bundle for every instruction in the generated code.
*/
addr = find_line_call(addr);
if (NULL == (z_ptr = zr_find(&zbrk_recs, addr)))
{
# ifdef USHBIN_SUPPORTED
if (NULL != routine->shlib_handle && NULL == routine->shared_ptext_adr)
{ /* setting a breakpoint in a shared routine, need to make a private copy */
addr_off = (unsigned char *)addr - routine->ptext_adr;
if (SS_NORMAL == (status = cre_private_code_copy(routine)))
addr = (zb_code *)(routine->ptext_adr + addr_off);
else
{
assert(UNIX_ONLY(ERR_MEMORY) VMS_ONLY(ERR_VMSMEMORY) == status);
/* convert to label+offset^routine to be presented to the user */
rname.len = rtn->str.len;
rname.addr = rtn->str.addr;
lname.len = lab->str.len;
lname.addr = lab->str.addr;
zbloc_end = rtnlaboff2entryref(zbloc_buff, &rname, &lname, offset);
rts_error(VARLSTCNT(4) ERR_ZBREAKFAIL, 2, zbloc_end - zbloc_buff,
zbloc_buff);
}
}
# endif
z_ptr = zr_get_free(&zbrk_recs, addr);
NON_USHBIN_ONLY(fix_pages((unsigned char *)addr, (unsigned char *)addr));
/* save for later restore while cancelling breakpoint */
# ifdef COMPLEX_INSTRUCTION_UPDATE
EXTRACT_OFFSET_TO_M_OPCODE(z_ptr->m_opcode, addr);
# else
z_ptr->m_opcode = *addr; /* save for later restore while cancelling breakpoint */
# endif
tmp_xf_code = (z_ptr->m_opcode & ZB_CODE_MASK) >> ZB_CODE_SHIFT;
if (xf_linefetch * SIZEOF(UINTPTR_T) == tmp_xf_code)
{
# ifdef COMPLEX_INSTRUCTION_UPDATE
FIX_OFFSET_WITH_ZBREAK_OFFSET(addr, xf_zbfetch);
# else
*addr = (*addr & (zb_code)(~ZB_CODE_MASK)) |
((xf_zbfetch * SIZEOF(UINTPTR_T)) << ZB_CODE_SHIFT);
# endif
} else if (xf_linestart * SIZEOF(UINTPTR_T) == tmp_xf_code)
{
# ifdef COMPLEX_INSTRUCTION_UPDATE
FIX_OFFSET_WITH_ZBREAK_OFFSET(addr, xf_zbstart);
# else
*addr = (*addr & (zb_code)(~ZB_CODE_MASK)) |
((xf_zbstart * SIZEOF(UINTPTR_T)) << ZB_CODE_SHIFT);
# endif
} else if (((xf_zbstart * SIZEOF(UINTPTR_T)) != tmp_xf_code)
&& ((xf_zbfetch * SIZEOF(UINTPTR_T)) != tmp_xf_code))
GTMASSERT;
z_ptr->rtn = &(CURRENT_RHEAD_ADR(routine))->routine_name;
assert(lab_name != NULL);
z_ptr->lab = lab_name;
z_ptr->offset = offset;
z_ptr->mpc = (zb_code *)((unsigned char *)addr - SIZEOF_LA);
inst_flush(addr, SIZEOF(INST_TYPE));
}
if (z_ptr->action)
{ /* A zbreak command was already set for this line */
/* Note when new action is same as old action, no resultant changes in zb_refcnt */
assert(z_ptr->action->zb_refcnt > 0);
z_ptr->action->zb_refcnt--;
assert(z_ptr->action != csp || z_ptr->action->zb_refcnt > 0);
}
z_ptr->action = csp;
z_ptr->count = cnt;
} else
GTMASSERT;
}
}