1672 lines
40 KiB
C
1672 lines
40 KiB
C
static char sccsid[] = "@(#)48 1.22 src/bos/kernel/db/POWER/dbbreak.c, sysdb, bos411, 9439C411a 9/29/94 17:44:58";
|
|
|
|
/*
|
|
* COMPONENT_NAME: (SYSDB) Kernel Debugger
|
|
*
|
|
* FUNCTIONS: set_breakpoint_traps, set_step_traps, set_this_step,
|
|
* remove_breakpoint_traps, remove_step_traps, replace_trap
|
|
* new_step, remove_this_step, is_continue, new_breakpoint,
|
|
* new_watchpoint, new_brat, set_watch_regs, set_brat_regs,
|
|
* clear_breakpoint, clear_watch_regs,
|
|
* clear_brat_regs, clear_watchpoint, clear_brat,
|
|
* remove_break, display_watch_brat_break, display_breakpoints,
|
|
* is_break, is_break_for_me, new_local_breakpoint,
|
|
* is_static_break, is_step_for_me, is_step, is_watch_step,
|
|
* is_brat_step, getaprsegid
|
|
*
|
|
* ORIGINS: 27 83
|
|
*
|
|
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
|
|
* combined with the aggregated modules for this product)
|
|
* SOURCE MATERIALS
|
|
* (C) COPYRIGHT International Business Machines Corp. 1988, 1989
|
|
* All Rights Reserved
|
|
*
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*/
|
|
/*
|
|
* LEVEL 1, 5 Years Bull Confidential Information
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/ppda.h>
|
|
#include <sys/seg.h>
|
|
#include "vdberr.h" /* Error message stuff */
|
|
#include "parse.h" /* parser structure */
|
|
#include "debaddr.h" /* debugger address structure */
|
|
#include "debvars.h"
|
|
#include "dbdebug.h" /* descr struct */
|
|
#include "dbbreak.h" /* constants and structures */
|
|
#include <sys/systemcfg.h>
|
|
|
|
/*
|
|
* EXTERNAL PROCEDURES CALLED:
|
|
*/
|
|
|
|
extern int cmderror();
|
|
extern clrdsp();
|
|
extern debug_xlate();
|
|
extern debug_opcode();
|
|
extern get_from_memory();
|
|
extern write_to_memory();
|
|
extern lqra();
|
|
extern char *getterm ();
|
|
|
|
#ifdef _POWER_MP
|
|
/* We need some macros to retrieve the segment register value */
|
|
/* These macros already defined at many places (in .c, not .h) */
|
|
#define SREG(x) ((x)>>SEGSHIFT) /* Segment reg. # */
|
|
#define SEG(x) (SRTOSID(debvars[IDSEGS+SREG(x)].hv)) /* seg. id. */
|
|
/* We need to use mst declared global only in dbdebug.c */
|
|
extern struct mstsave *mst; /* global mst area ptr */
|
|
#define CURCPU db_get_processor_num()
|
|
#else /* _POWER_MP */
|
|
#define CURCPU 0
|
|
#endif /* _POWER_MP */
|
|
|
|
struct steptab stepstoptable = {
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
#ifdef _POWER_MP
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
#endif /* POWER_MP */
|
|
0,
|
|
-1,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,
|
|
-1,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,
|
|
0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,
|
|
0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,
|
|
0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,0x13ffc,
|
|
0
|
|
};
|
|
|
|
struct watch_data watch_data = {
|
|
NULL,NULL,BOTH,WP_OFF
|
|
};
|
|
|
|
struct brat_data brat_data = {
|
|
NULL,NULL,BP_OFF
|
|
};
|
|
|
|
#define WRITE 1
|
|
|
|
/*
|
|
* NAME: dbbreak
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* VRM Debugger breakpoint and step functions
|
|
*
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* INTERNAL FUNCTIONS:
|
|
*/
|
|
|
|
ulong getaprsegid(); /* get the appropriate seg id */
|
|
uchar is_break(); /* is this addr a breakpoint? */
|
|
uchar new_breakpoint(); /* add a new bp to the table */
|
|
uchar new_watchpoint(); /* set a new wp */
|
|
int display_watch_brat_break(); /* display wp, btp, bp's from tables */
|
|
int display_breakpoints(); /* display the bp's from the table */
|
|
void set_breakpoint_traps(); /* remove entries from break table */
|
|
void set_this_step(); /* remove entries from step table */
|
|
void set_step_traps(); /* replace instruct with trap */
|
|
void remove_breakpoint_traps(); /* restore instruct from break tab */
|
|
void remove_step_traps(); /* restore instruct from step tab */
|
|
void replace_trap(); /* replace trap with correct inst */
|
|
void remove_this_step(); /* free entry in step in use array */
|
|
uchar is_continue(); /* is ste_continue true or false */
|
|
int clear_breakpoint(); /* remove a breakpoint */
|
|
int remove_break(); /* actually deletes the break */
|
|
int is_step(); /* is the trap a step ? */
|
|
int is_static_break(); /* is trap a static break ? */
|
|
#ifdef _POWER_MP
|
|
uchar is_step_for_me(); /* is this step for this debug session */
|
|
uchar is_break_for_me();
|
|
uchar new_local_breakpoint();
|
|
#endif /* POWER_MP */
|
|
|
|
|
|
|
|
#ifdef _POWER
|
|
ulong bp=0x7c800008; /* user breakpoint */
|
|
#endif /* _POWER */
|
|
|
|
/* FYI - static breakpoint 7c810808 */
|
|
|
|
/*
|
|
* NAME: set_breakpoint_traps
|
|
*
|
|
* FUNCTION: This function is the driver for moving the trap instruction
|
|
* into memory. The step traps are moved in first then the
|
|
* breakpoint traps are handled.
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: the 32 bit virt or real address
|
|
* OUTPUT: step traps are set in memory
|
|
*
|
|
* RETURN VALUE: 0 is always returned to the caller
|
|
*
|
|
*/
|
|
|
|
void
|
|
set_breakpoint_traps(addr)
|
|
ulong addr;
|
|
{
|
|
register int i,loopin_off;
|
|
ulong addr_segid,bpaddr,t_bit;
|
|
|
|
/*
|
|
* set the step traps before the break point traps
|
|
*/
|
|
|
|
#ifdef _POWER_MP
|
|
set_step_traps(addr); /* set step traps on exit */
|
|
#else
|
|
set_step_traps(); /* set step traps on exit */
|
|
#endif /* POWER_MP */
|
|
if (loop_count > 0)
|
|
loopin_off = 0; /* looping is active */
|
|
else {
|
|
if (nbreaks == 0)
|
|
return; /* no breakpoints so exit routine */
|
|
else
|
|
loopin_off = 1; /* start with regular breaks */
|
|
}
|
|
|
|
#ifdef _POWER
|
|
t_bit = INSTT_BIT;
|
|
#endif /* _POWER */
|
|
/* there are breakpoints to set */
|
|
if (addr != -1) /* if address compare */
|
|
addr_segid = getaprsegid(addr, t_bit);
|
|
|
|
for (i=loopin_off; i<=nbreaks; i++)
|
|
{
|
|
/* Paged-Out flag only valid for current invocation */
|
|
stop_flags(i) &= ~PAGED_OUT;
|
|
|
|
if((bpaddr=lqra(SRTOSID(stop_segid(i)),SEGOFFSET(stop_addr(i))))==-1)
|
|
{
|
|
/* error:this address paged out or no such real memory*/
|
|
/* NOTE: Change This Error Msg - it is no longer correct ! */
|
|
#if 0
|
|
sprintf(errst,"%x",bpaddr);
|
|
vdbperr(page_not_in_real1, errst, page_not_in_real2);
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
/* else if stop table address is paged in */
|
|
/* looping */
|
|
if (((loopin_off==0)&&(i>0)) && (stop_segid(i)==stop_segid(0))
|
|
&& ((SEGOFFSET(stop_addr(i)))==(SEGOFFSET(stop_addr(0))))) {
|
|
/* save from loop's save */
|
|
stop_save(i) = stop_save(0);
|
|
}
|
|
|
|
/* not looping */
|
|
else {
|
|
/* get the 2 or 4 bytes at this addr in real memory */
|
|
pre_get_put_aligned(stop_addr(i),!WRITE,(char *)&stop_save(i),
|
|
stop_segid(i),t_bit,sizeof(INSTSIZ));
|
|
|
|
/*
|
|
* don't set a breakpoint if it is at the
|
|
* current address
|
|
* or if we are looping and this isn't the
|
|
* loop point
|
|
*/
|
|
if (((addr != -1) &&(stop_segid(i) == addr_segid)
|
|
&&(SEGOFFSET(stop_addr(i))==SEGOFFSET(addr)))
|
|
|| ((loopin_off==0) && (i>0)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* set a breakpoint,
|
|
* write trap to break location
|
|
*/
|
|
pre_get_put_aligned(stop_addr(i),WRITE,(char *)&bp,
|
|
stop_segid(i),t_bit,sizeof(INSTSIZ));
|
|
} /* else if (!loopin_off etc.) */
|
|
|
|
} /* for */
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* NAME: set_step_traps
|
|
*
|
|
* FUNCTION: this routine will replace the original instructions with trap
|
|
* instructions. The area table field should be marked in use if a
|
|
* step pt is to be inserted into memory. The step table is intialized
|
|
* to NULLC.
|
|
*
|
|
* PARAMETERS: all data areas used are global
|
|
* INPUT: the 32 bit virt or real address (if _POWER_MP only)
|
|
* OUTPUT: step traps are set in memory
|
|
*
|
|
* RETURN VALUE: 0 is always returned to the caller
|
|
*
|
|
*/
|
|
#ifdef _POWER_MP
|
|
void
|
|
set_step_traps(addr)
|
|
ulong addr;
|
|
#else
|
|
void
|
|
set_step_traps()
|
|
#endif /* POWER_MP */
|
|
{
|
|
register int i;
|
|
|
|
/*
|
|
* set the step traps in the reverse order from when saved
|
|
*/
|
|
|
|
#ifdef _POWER_MP
|
|
ulong addr_segid;
|
|
if (addr != -1) /* if address compare */
|
|
addr_segid = getaprsegid(addr, INSTT_BIT);
|
|
#endif /* POWER_MP */
|
|
for (i=LASTSTEP-1; i>=0; i--) { /* don't use pos 0 in array */
|
|
if (step_i(i) == 1) { /* go on if step not in use */
|
|
|
|
/*
|
|
* set trap 1 if step 1 valid
|
|
*/
|
|
|
|
if (step1(i) != -1) /* step pt active */
|
|
#ifdef _POWER_MP
|
|
/*
|
|
* don't set a step breakpoint if it is at the
|
|
* current address for an other ctxt than the
|
|
* current one.
|
|
*/
|
|
if ((addr == -1) ||
|
|
((addr != -1) &&
|
|
((step_seg1(i) != addr_segid) ||
|
|
(SEGOFFSET(step1(i))!=SEGOFFSET(addr)) ||
|
|
((step_local_mst_addr(i) == (ulong)mst) &&
|
|
(step_local_mst_sregval(i) == SEG((ulong)mst))))))
|
|
set_this_step((SEGOFFSET(step1(i))),
|
|
step_seg1(i),&step_save1(i));
|
|
#else /* POWER_MP */
|
|
set_this_step((SEGOFFSET(step1(i))),
|
|
step_seg1(i),&step_save1(i));
|
|
#endif /* POWER_MP */
|
|
|
|
/*
|
|
* set trap 2 if step 2 valid
|
|
*/
|
|
|
|
if (step2(i) != -1) /* set secondary step pt */
|
|
#ifdef _POWER_MP
|
|
/*
|
|
* don't set a step breakpoint if it is at the
|
|
* current address
|
|
*/
|
|
if ((addr == -1) ||
|
|
((addr != -1) &&
|
|
((step_seg2(i) != addr_segid) ||
|
|
(SEGOFFSET(step2(i))!=SEGOFFSET(addr)))))
|
|
set_this_step((SEGOFFSET(step2(i))),
|
|
step_seg2(i),&step_save2(i));
|
|
#else /* POWER_MP */
|
|
set_this_step((SEGOFFSET(step2(i))),
|
|
step_seg2(i),&step_save2(i));
|
|
#endif /* POWER_MP */
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* NAME: set_this_step
|
|
*
|
|
* FUNCTION: this routine will get the instruction at the address to be
|
|
* stepped to; save this data in the area called save and then write
|
|
* the trap instruction out to memory.
|
|
*
|
|
* PARAMETERS: all data areas used are global
|
|
* INPUT: address displacement
|
|
* segment id
|
|
* pointer to the instruction save area in the stepstoptable
|
|
* OUTPUT: step traps are set in memory
|
|
*
|
|
* RETURN VALUE: 0 is always returned to the caller
|
|
*
|
|
*/
|
|
|
|
void
|
|
set_this_step(disp,segval,save)
|
|
ulong disp; /* displacement */
|
|
ulong segval; /* segment id */
|
|
INSTSIZ *save; /* ptr to save area */
|
|
{
|
|
ulong bpaddr;
|
|
INSTSIZ data; /* temporary data save area */
|
|
|
|
/*
|
|
* check that the address is valid
|
|
*/
|
|
|
|
if ((bpaddr=lqra(SRTOSID(segval),disp)) == -1) {
|
|
#ifdef this_msg_not_needed
|
|
/* if this addr paged out then we don't need to replace
|
|
* the step anyway. If the user just tried to place this
|
|
* this step then it failed before getting here anyway.
|
|
*/
|
|
sprintf(errst,"segval:0x%x,displacement:0x%x",segval,disp);
|
|
vdbperr(page_not_in_real1, errst, page_not_in_real2);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/* save the contents */
|
|
pre_get_put_aligned(disp,!WRITE,(char *)&data,segval,
|
|
1,sizeof(INSTSIZ));
|
|
*save = data;
|
|
|
|
/* and set the step */
|
|
pre_get_put_aligned(disp,WRITE,(char *)&bp,segval,
|
|
1,sizeof(INSTSIZ));
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* NAME: remove_breakpoint_traps
|
|
*
|
|
* FUNCTION: remove trap instructions for breakpoints, restoring the
|
|
* original opcodes. This is done before the step traps are
|
|
* restored.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: none
|
|
* OUTPUT: breakpoint traps are removed and replaced by the orig instr
|
|
*
|
|
* RETURN VALUE: 0 is always returned to the caller
|
|
*
|
|
*/
|
|
|
|
void
|
|
remove_breakpoint_traps()
|
|
{
|
|
register int i;
|
|
|
|
if (loop_count > 0) /* remove loop point */
|
|
i = 0; /* loop active, remove trap */
|
|
else
|
|
i = 1; /* no loop, keep going */
|
|
|
|
for ( ; i<=nbreaks; i++) /* replace breaks with orig data */
|
|
{
|
|
/* If the trap can be replaced, it will */
|
|
replace_trap(stop_addr(i),stop_segid(i),
|
|
stop_save(i));
|
|
|
|
/* Otherwise, it will be marked paged out */
|
|
if (lqra (SRTOSID(stop_segid(i)), stop_addr(i)) ==
|
|
-1)
|
|
{
|
|
/* Not Paged In */
|
|
stop_flags(i) |= PAGED_OUT;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
Only after the trap has been replaced
|
|
can it safely be removed. If this breakpoint
|
|
has been marked for removal, then remove
|
|
it now.
|
|
*/
|
|
|
|
if (stop_flags (i) & CANNOT_CLEAR)
|
|
{
|
|
remove_break (i);
|
|
/*
|
|
Since the step/stop table has
|
|
been closed up, i must be decremented
|
|
in order to avoid skipping an entry.
|
|
*/
|
|
i--;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
remove_step_traps(); /* replace the step table traps */
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* NAME: remove_step_traps
|
|
*
|
|
* FUNCTION: remove trap instructions for steps. This must occur after
|
|
* breakpoint traps are removed.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: none
|
|
* OUTPUT: step traps are removed and replaced by the orig instruction
|
|
*
|
|
* RETURN VALUE: 0 is always returned to the caller
|
|
*
|
|
*/
|
|
|
|
void
|
|
remove_step_traps()
|
|
{
|
|
register int i;
|
|
|
|
for (i=0; i<LASTSTEP; i++) { /* for each step in use */
|
|
if (step_i(i) == 1) { /* if step is inuse */
|
|
if (step1(i) != -1) /* check the step table addr */
|
|
replace_trap(step1(i),
|
|
step_seg1(i),step_save1(i));
|
|
if (step2(i) != -1)
|
|
replace_trap(step2(i),
|
|
step_seg2(i),step_save2(i));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* NAME: replace_trap
|
|
*
|
|
* FUNCTION: replace a trap at the displacement within the segment
|
|
* with the data, if the address is valid.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: none
|
|
* OUTPUT: traps are removed and replaced by the orig instruction
|
|
*
|
|
* RETURN VALUE: 0 is always returned to the caller
|
|
*
|
|
*/
|
|
|
|
void
|
|
replace_trap(disp,segval,data)
|
|
ulong disp; /* displacement */
|
|
ulong segval; /* segment register contents */
|
|
INSTSIZ data; /* 2 or 4 bytes of original data */
|
|
{
|
|
|
|
ulong bpaddr;
|
|
INSTSIZ tmpdata;
|
|
|
|
/* if paged out, return without replacing */
|
|
if ((bpaddr=lqra(SRTOSID(segval),SEGOFFSET(disp))) == -1)
|
|
return;
|
|
|
|
/*
|
|
* make sure the instruction at the addr is a trap
|
|
*/
|
|
pre_get_put_aligned(disp,!WRITE,(char *)&tmpdata,segval,
|
|
1,sizeof(INSTSIZ));
|
|
|
|
if (tmpdata == BREAKTRAP)
|
|
pre_get_put_aligned(disp,WRITE,(char *)&data,segval,
|
|
1,sizeof(INSTSIZ));
|
|
}
|
|
|
|
/*
|
|
* NAME: new_step
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: none
|
|
* OUTPUT: traps are removed and replaced by the orig instruction
|
|
*
|
|
* RETURN VALUE: 0 is always returned to the caller
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
new_step(procede,step_s,step_watch) /* return a true or false */
|
|
uchar procede; /* 1=step after break */
|
|
uchar step_s; /* 1=execute whole subroutine */
|
|
uchar step_watch; /* 1=watchpoint step */
|
|
|
|
|
|
{
|
|
register int i;
|
|
uchar flag=TRUE;
|
|
struct descr descr; /* opcode description structure */
|
|
char temp[20];
|
|
char *p1, *p2;
|
|
|
|
/* check to make sure the iar contains a valid instruction */
|
|
if (!debug_opcode(debvars[IDIAR].hv,&descr)) /* possible I-stream */
|
|
flag = FALSE; /* directions */
|
|
else {
|
|
for (i=0; i<LASTSTEP; i++) { /* find a step in table */
|
|
if (step_i(i) == 0) /* found a step */
|
|
break; /* leave the for loop */
|
|
else if (i >= LASTSTEP) /* table is full */
|
|
flag = FALSE;
|
|
}
|
|
|
|
step1(i) = (ulong) descr.D_NSI; /* fall thru address:next-seq-inst */
|
|
|
|
if (flag) {
|
|
/* don't set target address if branch instruction and
|
|
step-around-sub is set */
|
|
#ifdef _POWER
|
|
if (descr.D_Brbit) {
|
|
p1 = descr.D_Mnemonic;
|
|
while (*p1 == ' ') /* skip leading blanks */
|
|
p1++;
|
|
p2 = temp;
|
|
while (*p1 != ' ') /* copy the instruction */
|
|
if (*p1 == 0)
|
|
break;
|
|
else
|
|
*p2++ = *p1++;
|
|
*p2 = 0;
|
|
|
|
if (step_s &&
|
|
((strcmp(temp, "bccl") == 0) ||
|
|
(strcmp(temp, "bcl" ) == 0) ||
|
|
(strcmp(temp, "bcla") == 0) ||
|
|
(strcmp(temp, "bcrl") == 0) ||
|
|
(strcmp(temp, "bl" ) == 0) ||
|
|
(strcmp(temp, "bla" ) == 0)))
|
|
step2(i) = -1;
|
|
else
|
|
step2(i) = (ulong) descr.D_Target;
|
|
}
|
|
else
|
|
step2(i) = -1;
|
|
|
|
#endif /* _POWER */
|
|
#ifdef _POWER
|
|
if (DATAT_BIT) {
|
|
if (!debug_xlate(step1(i),-1))
|
|
flag = FALSE;
|
|
if (step2(i) != -1)
|
|
if (!debug_xlate(step2(i),-1))
|
|
flag = FALSE;
|
|
}
|
|
|
|
if (flag) {
|
|
step_i(i) = TRUE; /* mark it in use */
|
|
/* keep going if step-aft-bk */
|
|
step_continue(i) = procede;
|
|
/* get seg reg */
|
|
step_seg1(i) = getaprsegid(step1(i),DATAT_BIT);
|
|
step_seg2(i) = getaprsegid(step2(i),DATAT_BIT);
|
|
#ifdef _POWER_MP
|
|
step_local_mst_addr(i) = (ulong)mst;
|
|
step_local_mst_sregval(i) = SEG((ulong)mst) ;
|
|
#endif /* POWER_MP */
|
|
}
|
|
if (step_watch) step_wb(i) = TRUE; /* mark watch step*/
|
|
else step_wb(i) = FALSE;
|
|
#endif /* _POWER */
|
|
}
|
|
}
|
|
return(flag);
|
|
}
|
|
|
|
/*
|
|
* NAME: remove_this_step
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: none
|
|
* OUTPUT: the input index into the step_inuse table is set to false
|
|
* meaning that field is now open
|
|
*
|
|
* RETURN VALUE: no return value
|
|
*
|
|
*/
|
|
|
|
void
|
|
remove_this_step(i)
|
|
int i; /* location of step in step table */
|
|
{
|
|
step_i(i) = FALSE; /* remove this step */
|
|
step_wb(i) = FALSE;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* NAME: is_continue
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: index into the step_continue table
|
|
* OUTPUT: true or false whether the step is a continue or not. A step
|
|
* continue is an under the covers step, where the debugger
|
|
* doesn't really let the user know he stepped. This is used
|
|
* to step over breakpoints.
|
|
*
|
|
* RETURN VALUE: true or false
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
is_continue(i)
|
|
int i; /* location of step in step table */
|
|
|
|
{
|
|
return(step_continue(i));
|
|
}
|
|
|
|
/*
|
|
* NAME: new_breakpoint
|
|
*
|
|
* FUNCTION: this function will add another entry to the debugger
|
|
* breakpoint table (stepstoptable).
|
|
* accepts to enter a break at this address if a local breakpoint
|
|
* exist.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: addr: 32 bit address
|
|
* type: breakpoint or loop point
|
|
* virt: either true or false (virt or real)
|
|
* OUTPUT: the input index into the step_inuse table is set to false
|
|
* meaning that field is now open
|
|
*
|
|
* RETURN VALUE: no return value
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
new_breakpoint(addr, type, virt)
|
|
ulong addr;
|
|
uchar type;
|
|
ulong virt;
|
|
{
|
|
uchar returnval=TRUE;
|
|
register int i,k;
|
|
ulong addr_segid;
|
|
|
|
addr_segid = getaprsegid(addr,virt); /* get the seg id */
|
|
if (type!=LOOP) { /* find space the bk table */
|
|
for (i=1; i<=nbreaks; i++) { /* check if already in table*/
|
|
if ((SEGOFFSET(stop_addr(i))==SEGOFFSET(addr)) &&
|
|
#ifdef _POWER_MP
|
|
(! is_local_break(i)) &&
|
|
#endif /* POWER_MP */
|
|
(stop_segid(i)==addr_segid)) {
|
|
printf ("breakpoint already set\n");
|
|
return(TRUE); /* addr already in bkpt tab */
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((nbreaks>=LASTSTOP) && (type!=LOOP)) { /* bkpt table is full */
|
|
vdbperr(brktablefull);
|
|
returnval = FALSE;
|
|
}
|
|
else {
|
|
if (type!=LOOP) { /* increment bkpt total */
|
|
nbreaks++;
|
|
k = nbreaks; /* set index variable */
|
|
}
|
|
else
|
|
/* 0 is index of loop count in bkpt table */
|
|
k = 0;
|
|
|
|
stop_addr(k) = addr; /* insert addr into table */
|
|
stop_segid(k) = addr_segid; /* insert seg id into tab */
|
|
stop_type(k) = type; /* insert bkpt type in tab */
|
|
stop_flags(k) = 0; /* reset all flags */
|
|
#ifdef _POWER_MP
|
|
stop_local_mst_addr(k) = 0; /* Mark breakpoint as global */
|
|
stop_local_mst_sregval(k) = 0;
|
|
#endif /* POWER_MP */
|
|
}
|
|
return(returnval);
|
|
}
|
|
|
|
/*
|
|
* NAME: new_watchpoint
|
|
*
|
|
* FUNCTION: This function will set a watchpoint in the watchpoint table,
|
|
* watch_data.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: addr: 32 bit address
|
|
* virt: either true or false (virt or real)
|
|
* OUTPUT: none
|
|
*
|
|
* RETURN VALUE: 0 if successful
|
|
* 1 if failure
|
|
*
|
|
*/
|
|
|
|
#if defined(_POWER_RS2) || defined(_POWER_601)
|
|
uchar
|
|
new_watchpoint(addr,type)
|
|
caddr_t addr;
|
|
uchar type;
|
|
{
|
|
uchar returnval=TRUE;
|
|
ulong addr_segid;
|
|
ulong virt=1;
|
|
|
|
if (!(__power_rs2() || __power_601())) {
|
|
printf("Watchpoints not supported by hardware\n");
|
|
return(1);
|
|
}
|
|
addr_segid = getaprsegid(addr,virt); /* get the seg id */
|
|
|
|
/* set up data in watchpoint table */
|
|
watch_data.addr = addr; /* insert addr into table */
|
|
watch_data.segid = addr_segid; /* insert segreg id into table */
|
|
watch_data.wtype = type; /* insert wp type into table */
|
|
watch_data.active = WP_ON; /* turn wp on */
|
|
return(returnval);
|
|
}
|
|
#endif /* _POWER_RS2 || _POWER_601 */
|
|
|
|
|
|
/*
|
|
* NAME: new_brat
|
|
*
|
|
* FUNCTION: This function will set a bratpoint in the bratpoint table,
|
|
* watch_data.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: addr: 32 bit address
|
|
* virt: either true or false (virt or real)
|
|
* OUTPUT: none
|
|
*
|
|
* RETURN VALUE: 0 if successful
|
|
* 1 if failure
|
|
*
|
|
*/
|
|
|
|
#ifdef _POWER_601
|
|
uchar
|
|
new_brat(addr)
|
|
caddr_t addr;
|
|
|
|
{
|
|
uchar returnval=TRUE;
|
|
ulong addr_segid;
|
|
ulong virt=1;
|
|
|
|
if (!__power_601()) {
|
|
printf("Bratpoints not supported by hardware\n");
|
|
return(1);
|
|
}
|
|
|
|
addr_segid = getaprsegid(addr,virt); /* get the seg id */
|
|
|
|
/* set up data in bratpoint table */
|
|
brat_data.addr = addr; /* insert addr into table */
|
|
brat_data.segid = addr_segid; /* insert segreg id into table */
|
|
brat_data.active = BP_ON; /* turn bp on */
|
|
return(returnval);
|
|
}
|
|
#endif /* _POWER_601 */
|
|
|
|
|
|
/*
|
|
* NAME: set_watch_regs
|
|
*
|
|
* FUNCTION: This function will set a watchpoint in the dabr register.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: addr: 32 bit address
|
|
* virt: either true or false (virt or real)
|
|
* OUTPUT: none
|
|
*
|
|
* RETURN VALUE: 0 if successful
|
|
* 1 if failure
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
set_watch_regs()
|
|
{
|
|
int temp;
|
|
uchar returnval=TRUE;
|
|
if (watch_data.wtype == 'l') {
|
|
/* enable for load accesses only */
|
|
if ( __power_rs2() )
|
|
mtdabr( (int) watch_data.addr | 0x1);
|
|
else
|
|
if ( __power_601() )
|
|
mtdabr601( (int) watch_data.addr | 0x1);
|
|
}
|
|
else
|
|
{
|
|
if (watch_data.wtype == 's') {
|
|
/* enable for store accesses only */
|
|
if ( __power_rs2() )
|
|
mtdabr( (int) watch_data.addr | 0x2);
|
|
else if ( __power_601() )
|
|
mtdabr601( (int) watch_data.addr | 0x2);
|
|
}
|
|
else
|
|
{
|
|
/* enable for load and store accesses */
|
|
if ( __power_rs2() )
|
|
mtdabr( (int) watch_data.addr | 0x3);
|
|
else if ( __power_601() )
|
|
mtdabr601( (int) watch_data.addr | 0x3);
|
|
}
|
|
}
|
|
|
|
return(returnval);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: set_brat_regs
|
|
*
|
|
* FUNCTION: This function will set a brathpoint in the hid registers.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: addr: 32 bit address
|
|
* virt: either true or false (virt or real)
|
|
* OUTPUT: none
|
|
*
|
|
* RETURN VALUE: 0 if successful
|
|
* 1 if failure
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
set_brat_regs()
|
|
{
|
|
int temp;
|
|
uchar returnval=TRUE;
|
|
if ( __power_601() ) {
|
|
mthid2(brat_data.addr);
|
|
mthid1(0x70800000);
|
|
}
|
|
|
|
return(returnval);
|
|
}
|
|
|
|
/*
|
|
/*
|
|
* NAME: clear_breakpoint
|
|
*
|
|
* FUNCTION: clear a breakpoint or clear all breakpoints.
|
|
* Return a FALSE if an error occurred.
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: ps: a pointer to the parser structure
|
|
* OUTPUT: the input index into the step_inuse table is set to false
|
|
* meaning that field is now open
|
|
*
|
|
* RETURN VALUE: true or false whether the bkpt was deleted or not
|
|
*
|
|
*/
|
|
|
|
int
|
|
clear_breakpoint(ps)
|
|
struct parse_out *ps; /* pointer to parser structure */
|
|
{
|
|
register int returnval=TRUE, i;
|
|
uchar type;
|
|
ulong virt, num, num_segid;
|
|
int found = 0;
|
|
#ifdef _POWER_MP
|
|
int found_a_local =0;
|
|
#endif /* POWER_MP */
|
|
|
|
/* check for clear all breakpoints "CL *" */
|
|
if ((ps->num_tok >= 1) && (ps->token[1].sv[0] == ASTRISK))
|
|
{
|
|
if (ps->num_tok >= 2) /* "CL * T" or CL * B" */
|
|
{
|
|
if (((ps->token[2].sv[0])==CLEARB)||
|
|
((ps->token[2].sv[0])==CLEART))
|
|
{
|
|
if ((ps->token[2].sv[0]) == CLEARB)
|
|
type = BRKPT;
|
|
else
|
|
type = TRACEPT;
|
|
for (i=nbreaks; i>=1; i--)
|
|
/* check break type */
|
|
if (type==stop_type(i))
|
|
returnval = returnval &&
|
|
remove_break(i);
|
|
}
|
|
else
|
|
{
|
|
printf ("Third token wrong\n");
|
|
returnval = FALSE;
|
|
}
|
|
}
|
|
else { /* user entered "CL *": clear all */
|
|
for (i=nbreaks; i>=1; i--)
|
|
returnval = returnval && remove_break(i);
|
|
}
|
|
}
|
|
else {
|
|
/* clear by address */
|
|
if (ps->num_tok < 1) { /* clear by address */
|
|
num = debvars[IDIAR].hv;/* default address is the IAR */
|
|
#ifdef _POWER
|
|
virt = INSTT_BIT;
|
|
#endif /* _POWER */
|
|
}
|
|
else {
|
|
num = ps->token[1].hv; /* get the user addr */
|
|
virt = ps->token[1].debaddr->virt;
|
|
}
|
|
num_segid = getaprsegid(num,virt); /* get the segment id */
|
|
for (i=nbreaks; i>=1; i--)
|
|
{
|
|
if ((SEGOFFSET(stop_addr(i)) == SEGOFFSET(num)) &&
|
|
(! (stop_flags (i) & CANNOT_CLEAR)))
|
|
found++;
|
|
#ifdef _POWER_MP
|
|
if (is_local_break(i) &&
|
|
(stop_local_mst_addr(i) == mst) &&
|
|
(stop_local_mst_sregval(i) == SEG((ulong)mst)))
|
|
found_a_local = TRUE;
|
|
#endif /* POWER_MP */
|
|
}
|
|
|
|
/* find the break address in the table */
|
|
for (i=nbreaks; i>=1; i--)
|
|
{
|
|
if (SEGOFFSET(stop_addr(i)) == SEGOFFSET(num))
|
|
{
|
|
/* only 1 address found */
|
|
if (found == 1)
|
|
break;
|
|
#ifdef _POWER_MP
|
|
/* If several breaks at the same address and
|
|
a local breakopoint for the current mst
|
|
found in the table, remove this one
|
|
without asking questions
|
|
(kdbx does not like questions !)
|
|
*/
|
|
if (found_a_local && is_local_break(i) &&
|
|
(stop_local_mst_addr(i) == mst) &&
|
|
(stop_local_mst_sregval(i) == SEG((ulong)mst)))
|
|
break;
|
|
#endif /* POWER_MP */
|
|
|
|
/* several breakpoints at same offset */
|
|
printf ("Seg ID: 0x%08x Addr: 0x%08x (n)",
|
|
stop_segid(i), stop_addr(i));
|
|
if (*getterm() == 'y')
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i>=1)
|
|
{
|
|
returnval = remove_break(i); /* remove the break */
|
|
}
|
|
else
|
|
{
|
|
printf ("Breakpoint not in step/stop table\n");
|
|
returnval = FALSE; /* value not found in table */
|
|
}
|
|
}
|
|
return(returnval);
|
|
}
|
|
|
|
/*
|
|
* NAME: clear_watch_regs
|
|
*
|
|
* FUNCTION: Machine dependent portion of the clear watchpoint function which
|
|
* checks to see which processor the kernel debugger is running
|
|
* on and clears the approriate dabr register/registers.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: none
|
|
* OUTPUT: none
|
|
*
|
|
* RETURN VALUE: 0 if successful
|
|
* 1 if failure
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
clear_watch_regs()
|
|
{
|
|
uchar returnval=TRUE;
|
|
/* Check which processor type kernel debugger is running on */
|
|
|
|
|
|
if ( __power_rs2() ) {
|
|
/* set dabr register for rios2 */
|
|
mtdabr(0);
|
|
}
|
|
else if ( __power_601() ) {
|
|
/* set hid5 register for 601 */
|
|
mtdabr601(0);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* NAME: clear_brat_regs
|
|
*
|
|
* FUNCTION: Machine dependent portion of the clear watchpoint function which
|
|
* checks to see which processor the kernel debugger is running
|
|
* on and clears the approriate dabr register/registers.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: none
|
|
* OUTPUT: none
|
|
*
|
|
* RETURN VALUE: 0 if successful
|
|
* 1 if failure
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
clear_brat_regs()
|
|
{
|
|
uchar returnval=TRUE;
|
|
/* Check which processor type kernel debugger is running on */
|
|
|
|
|
|
if ( __power_601() ) {
|
|
/* clear hid1 and hid2 registers for 601 */
|
|
mthid1(0);
|
|
mthid2(0);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
* NAME: clear_watchpoint
|
|
*
|
|
* FUNCTION: This function will clear a watchpoint if one is set.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: none
|
|
* OUTPUT: flag in watch_data structure is reset.
|
|
*
|
|
* RETURN VALUE: 0 if successful
|
|
* 1 if failure
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
clear_watchpoint()
|
|
{
|
|
uchar returnval=TRUE;
|
|
|
|
watch_data.active = WP_OFF; /* turn wp off */
|
|
return(returnval);
|
|
}
|
|
|
|
/*
|
|
* NAME: clear_brat
|
|
*
|
|
* FUNCTION: This function will clear a watchpoint if one is set.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: none
|
|
* OUTPUT: flag in watch_data structure is reset.
|
|
*
|
|
* RETURN VALUE: 0 if successful
|
|
* 1 if failure
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
clear_brat()
|
|
{
|
|
uchar returnval=TRUE;
|
|
|
|
brat_data.active = BP_OFF; /* turn bp off */
|
|
return(returnval);
|
|
}
|
|
|
|
/*
|
|
* NAME: remove_break
|
|
*
|
|
* FUNCTION: This function will remove a breakpoint from the breakpoint
|
|
* table and then close up the table.
|
|
*
|
|
* PARAMETERS: i is the index into the bkpt table
|
|
* INPUT:
|
|
* OUTPUT: the # of breakpoints is decremented by 1 and the entry in
|
|
* the table is removed and the table compressed
|
|
*
|
|
* RETURN VALUE: true or false whether the breakpoint removed successfully
|
|
* or not
|
|
*
|
|
*/
|
|
|
|
int
|
|
remove_break(i)
|
|
int i; /* location in break table */
|
|
{
|
|
ulong bpaddr;
|
|
|
|
/* check that breakpoint is in memory */
|
|
if((bpaddr=lqra(SRTOSID(stop_segid(i)),SEGOFFSET(stop_addr(i))))!= -1)
|
|
{
|
|
nbreaks--; /* remove entry; close up tab */
|
|
for ( ; i<=nbreaks; i++) /* close up the bkprt table */
|
|
{
|
|
stop_addr(i) = stop_addr(i+1);
|
|
stop_segid(i) = stop_segid(i+1);
|
|
stop_type(i) = stop_type(i+1);
|
|
stop_flags(i) = stop_flags(i+1);
|
|
#ifdef _POWER_MP
|
|
stop_local_mst_addr(i) = stop_local_mst_addr(i+1);
|
|
stop_local_mst_sregval(i) = stop_local_mst_sregval(i+1);
|
|
#endif /* POWER_MP */
|
|
}
|
|
}
|
|
else /* breakpoint paged out */
|
|
stop_flags(i) |= CANNOT_CLEAR;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: display_watch_brat_break
|
|
*
|
|
* FUNCTION: This function will display the contents of the watchpoint table,
|
|
* bratpoint table and breakpoint table.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT:
|
|
* OUTPUT: display of entries in the watchpoint structure,
|
|
* bratpoint structure and stepstoptable.
|
|
*
|
|
* RETURN VALUE: always return a 0
|
|
*
|
|
*/
|
|
|
|
int
|
|
display_watch_brat_break()
|
|
{
|
|
|
|
/* display breakpoints first */
|
|
display_breakpoints();
|
|
|
|
/* display watchpoints second */
|
|
#if defined(_POWER_RS2) || defined(_POWER_601)
|
|
if (__power_rs2() || __power_601()) /* Only if watches supported */
|
|
if (watch_data.active == WP_ON) { /* is there a wp active? */
|
|
printf("watchpoint: %08x (srval:%08x) ",
|
|
watch_data.addr,watch_data.segid);
|
|
switch(watch_data.wtype) {
|
|
case 'l':
|
|
printf("load\n");
|
|
break;
|
|
case 's':
|
|
printf("store\n");
|
|
break;
|
|
default:
|
|
printf("load/store\n");
|
|
}
|
|
}
|
|
#endif /* _POWER_RS2 || POWER_601 */
|
|
|
|
/* display bratpoints third */
|
|
#if defined(_POWER_601)
|
|
if (__power_601()) /* Only if brats supported */
|
|
if (brat_data.active == BP_ON) /* is there a bp active? */
|
|
printf("bratpoint: %08x (srval:%08x)\n",
|
|
brat_data.addr,brat_data.segid);
|
|
#endif /* _POWER_601 */
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* NAME: display_breakpoints
|
|
*
|
|
* FUNCTION: This function will simply display the contents of the
|
|
* breakpoint table.
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT:
|
|
* OUTPUT: display of all entries in the stepstoptable
|
|
*
|
|
* RETURN VALUE: always return a 0
|
|
*
|
|
*/
|
|
|
|
int
|
|
display_breakpoints()
|
|
{
|
|
register int i;
|
|
|
|
if (nbreaks == 0) /* break table empty */
|
|
vdbperr(no_breaks_set); /* display msg */
|
|
else {
|
|
for (i=1; i<=nbreaks; i++) { /* slot 0 not used */
|
|
printf("%08x (srval:%08x)", stop_addr(i),
|
|
stop_segid(i));
|
|
if (stop_flags(i) & CANNOT_CLEAR)
|
|
printf (" Cleared");
|
|
else if (stop_flags(i) & PAGED_OUT)
|
|
printf (" Paged ");
|
|
else
|
|
printf (" ");
|
|
printf(" ");
|
|
if ((i%2) == 0) printf("\n"); /* 2 cols per line */
|
|
}
|
|
printf("\n");
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* NAME: is_break
|
|
*
|
|
* FUNCTION:
|
|
* This function will check if the address passed in is a breakpoint
|
|
* that is in the breakpoint table. A return code of true or false
|
|
* will be passed back to the calling routine.
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: addr: the 32 bit address
|
|
* virt: virt or real (true or false)
|
|
* srval: (-1 if in debugger, else the one associated)
|
|
* OUTPUT: a true or false value is returned to the caller
|
|
*
|
|
* RETURN VALUE: true if input addr found in bkpt table
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
is_break(addr,virt,srval)
|
|
ulong addr;
|
|
ulong virt;
|
|
int srval;
|
|
{
|
|
ulong addr_segid;
|
|
ulong cur_addr;
|
|
register int i=0;
|
|
uchar returnval=FALSE; /* type returned to caller */
|
|
|
|
if (srval == FROMDEBVARS)
|
|
addr_segid = getaprsegid(addr,virt); /* get the seg id */
|
|
else{
|
|
cur_addr = (ppda[CURCPU])._csa->prev->iar;
|
|
srval = ((ppda[CURCPU])._csa->prev->as).srval[(cur_addr)>>SEGSHIFT];
|
|
addr_segid = srval & segid_mask;
|
|
}
|
|
|
|
if (loop_count==0) i = 1; /* LOOP is at position 0 */
|
|
|
|
for ( ; i<=nbreaks; i++) { /* search stop table */
|
|
if ((SEGOFFSET(addr)==SEGOFFSET(stop_addr(i))) &&
|
|
(addr_segid==stop_segid(i))) {
|
|
returnval = stop_type(i); /* set the return type */
|
|
break; /* breakpoint FOUND! */
|
|
}
|
|
}
|
|
return(returnval);
|
|
}
|
|
|
|
|
|
#ifdef _POWER_MP
|
|
/*
|
|
* NAME: is_break_for_me
|
|
*
|
|
* FUNCTION:
|
|
* This function will check if the address passed in is a breakpoint
|
|
* that is in the breakpoint table. A return code of true or false
|
|
* will be passed back to the calling routine.
|
|
* checks against locality if the breakpoint is local.
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: addr: the 32 bit address
|
|
* virt: virt or real (true or false)
|
|
* OUTPUT: a true or false value is returned to the caller
|
|
*
|
|
* RETURN VALUE: true if input addr found in bkpt table
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
is_break_for_me(addr,virt)
|
|
ulong addr;
|
|
ulong virt;
|
|
{
|
|
ulong addr_segid;
|
|
register int i=0;
|
|
uchar returnval=FALSE; /* type returned to caller */
|
|
|
|
addr_segid = getaprsegid(addr,virt); /* get the seg id */
|
|
if (loop_count==0) i = 1; /* LOOP is at position 0 */
|
|
|
|
for ( ; i<=nbreaks; i++) { /* search stop table */
|
|
if ((SEGOFFSET(addr)==SEGOFFSET(stop_addr(i))) &&
|
|
(addr_segid==stop_segid(i))) {
|
|
if (is_local_break(i)) {
|
|
/* Is this local breakpoint for the cur. mst */
|
|
if ((stop_local_mst_addr(i) == mst) &&
|
|
(stop_local_mst_sregval(i) == SEG((ulong)mst))){
|
|
returnval = stop_type(i); /* set the return type */
|
|
break; /* breakpoint FOUND! */
|
|
} else {
|
|
/* Local breakpoint for an other
|
|
thread: continue the search */
|
|
}
|
|
} else {
|
|
/* Normal breakpoint */
|
|
returnval = stop_type(i); /* set the return type */
|
|
break; /* breakpoint FOUND! */
|
|
}
|
|
}
|
|
}
|
|
return(returnval);
|
|
}
|
|
|
|
/*
|
|
* NAME: new_local_breakpoint
|
|
Same as new_breakpoint, except that there is no type parameter.
|
|
Accepts to set a local breakpoint, even if a breakpoint already exists
|
|
at this address (global or for an other context).
|
|
*
|
|
*
|
|
* PARAMETERS: none
|
|
* INPUT: addr: 32 bit address
|
|
* type: breakpoint or loop point
|
|
* virt: either true or false (virt or real)
|
|
* OUTPUT: the input index into the step_inuse table is set to false
|
|
* meaning that field is now open
|
|
*
|
|
* RETURN VALUE: no return value
|
|
*
|
|
*/
|
|
uchar
|
|
new_local_breakpoint(addr, virt)
|
|
ulong addr;
|
|
ulong virt;
|
|
{
|
|
uchar returnval=TRUE;
|
|
register int i,k;
|
|
ulong addr_segid;
|
|
|
|
addr_segid = getaprsegid(addr,virt); /* get the seg id */
|
|
for (i=1; i<=nbreaks; i++) { /* check if already in table*/
|
|
if ((SEGOFFSET(stop_addr(i))==SEGOFFSET(addr)) &&
|
|
(stop_segid(i)==addr_segid) &&
|
|
(stop_local_mst_addr(i) == mst) &&
|
|
(stop_local_mst_sregval(i) == SEG((ulong)mst))) {
|
|
printf ("breakpoint already set\n");
|
|
return(TRUE); /* addr already in bkpt tab */
|
|
}
|
|
}
|
|
|
|
if (nbreaks>=LASTSTOP) { /* bkpt table is full */
|
|
vdbperr(brktablefull);
|
|
returnval = FALSE;
|
|
}
|
|
else {
|
|
/* increment bkpt total */
|
|
nbreaks++;
|
|
k = nbreaks; /* set index variable */
|
|
|
|
stop_addr(k) = addr; /* insert addr into table */
|
|
stop_segid(k) = addr_segid; /* insert seg id into tab */
|
|
stop_type(k) = BRKPT; /* insert bkpt type in tab */
|
|
stop_flags(k) = 0; /* reset all flags */
|
|
stop_local_mst_addr(k) = mst; /* Set locality information */
|
|
stop_local_mst_sregval(k) = SEG((ulong)mst);
|
|
}
|
|
return(returnval);
|
|
}
|
|
|
|
#endif /* POWER_MP */
|
|
|
|
/*
|
|
* NAME: is_static_break
|
|
*
|
|
* FUNCTION: this function will check if the address passed in is a
|
|
* static breakpoint. Compare the contents of the address with
|
|
* a static breakpoint.
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: addr: the 32 bit address
|
|
* virt: virt or real (true or false)
|
|
* OUTPUT: a true or false value is returned to the caller
|
|
*
|
|
* RETURN VALUE: true if address is a static bkpt
|
|
*
|
|
*/
|
|
|
|
int
|
|
is_static_break(addr,virt)
|
|
caddr_t addr;
|
|
int virt;
|
|
{
|
|
INSTSIZ data;
|
|
int returnval=FALSE;
|
|
|
|
if (get_from_memory(addr,virt,&data,sizeof(data))) {
|
|
if (data==STATIC_BREAK_TRAP)
|
|
returnval = TRUE;
|
|
else
|
|
returnval = FALSE;
|
|
}
|
|
else {
|
|
sprintf(errst,"%x",addr);
|
|
vdbperr(page_not_in_real1, errst, page_not_in_real2);
|
|
}
|
|
return(returnval);
|
|
}
|
|
|
|
#ifdef _POWER_MP
|
|
/*
|
|
* NAME: is_step_for_me
|
|
*
|
|
* FUNCTION: This function checks the address against the step_trap table
|
|
* to see if the address is a step trap. The Step_id is returned
|
|
* to the caller. It checks against locality.
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: addr: the 32 bit address
|
|
* virt: virt or real (true or false)
|
|
* step_id:
|
|
* cont:
|
|
* OUTPUT:
|
|
*
|
|
* RETURN VALUE: index into bkpt table is returned via step_id and returnval
|
|
* either returns a true or false if the addr is a step pt
|
|
*
|
|
*/
|
|
|
|
uchar
|
|
is_step_for_me(addr,virt,step_id)
|
|
ulong addr;
|
|
ulong virt;
|
|
int *step_id;
|
|
{
|
|
int returnval=FALSE;
|
|
ulong addr_segid;
|
|
register int i;
|
|
|
|
addr_segid = getaprsegid(addr, virt); /* get the IAR's seg id */
|
|
/* look for this address in the step table */
|
|
for (i=0; i<LASTSTEP; i++) {
|
|
if ((step_i(i)==TRUE) && /* stepinuse bit set? */
|
|
(((SEGOFFSET(addr)==SEGOFFSET(step1(i)))&&
|
|
(addr_segid==step_seg1(i)))||
|
|
((SEGOFFSET(addr)==SEGOFFSET(step2(i)))&&
|
|
(addr_segid==step_seg2(i))))
|
|
&& (step_local_mst_addr(i) == mst)
|
|
&& (step_local_mst_sregval(i) == SEG((ulong)mst))
|
|
) {
|
|
returnval = TRUE;
|
|
*step_id = i; /* loc in the bkpt tab */
|
|
break; /* address FOUND! */
|
|
}
|
|
}
|
|
return(returnval);
|
|
}
|
|
#endif /* _POWER_MP */
|
|
|
|
/*
|
|
* NAME: is_step
|
|
*
|
|
* FUNCTION: This function checks the address against the step_trap table
|
|
* to see if the address is a step trap for an other debug session.
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: addr: the 32 bit address
|
|
* virt: virt or real (true or false)
|
|
* step_id:
|
|
* srval: (-1 if in debugger, else the one to take into account)
|
|
*
|
|
* OUTPUT:
|
|
*
|
|
* RETURN VALUE: index into bkpt table is returned via step_id and returnval
|
|
* either returns a true or false if the addr is a step pt
|
|
*
|
|
*/
|
|
|
|
int
|
|
is_step(addr,virt,step_id,srval)
|
|
ulong addr;
|
|
ulong virt;
|
|
int *step_id;
|
|
int srval;
|
|
{
|
|
int returnval=FALSE;
|
|
ulong addr_segid;
|
|
ulong cur_addr;
|
|
register int i;
|
|
|
|
if (srval == FROMDEBVARS)
|
|
addr_segid = getaprsegid(addr, virt); /* get the IAR's seg id */
|
|
else{
|
|
cur_addr = (ppda[CURCPU])._csa->prev->iar;
|
|
srval = ((ppda[CURCPU])._csa->prev->as).srval[(cur_addr)>>SEGSHIFT];
|
|
addr_segid = srval & segid_mask;
|
|
}
|
|
|
|
/* look for this address in the step table */
|
|
for (i=0; i<LASTSTEP; i++) {
|
|
if ((step_i(i)==TRUE) && /* stepinuse bit set? */
|
|
(((SEGOFFSET(addr)==SEGOFFSET(step1(i)))&&
|
|
(addr_segid==step_seg1(i)))||
|
|
((SEGOFFSET(addr)==SEGOFFSET(step2(i)))&&
|
|
(addr_segid==step_seg2(i))))
|
|
) {
|
|
returnval = TRUE;
|
|
*step_id = i; /* loc in the bkpt tab */
|
|
break; /* address FOUND! */
|
|
}
|
|
}
|
|
return(returnval);
|
|
}
|
|
|
|
/*
|
|
* NAME: is_watch_step
|
|
*
|
|
* FUNCTION: This function checks the address against the step_trap table
|
|
* to see if the address is a step trap. The Step_id is returned
|
|
* to the caller
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: addr: the 32 bit address
|
|
* virt: virt or real (true or false)
|
|
* step_id:
|
|
* cont:
|
|
* OUTPUT:
|
|
*
|
|
* RETURN VALUE: index into bkpt table is returned via step_id and returnval
|
|
* either returns a true or false if the addr is a step pt
|
|
*
|
|
*/
|
|
|
|
int
|
|
is_watch_step(step_id)
|
|
int *step_id;
|
|
{
|
|
/* check if this is a watch type of step */
|
|
if (step_wb(*step_id) == 1)
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: is_brat_step
|
|
*
|
|
* FUNCTION: This function checks the address against the step_trap table
|
|
* to see if the address is a step trap. The Step_id is returned
|
|
* to the caller
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: addr: the 32 bit address
|
|
* virt: virt or real (true or false)
|
|
* step_id:
|
|
* cont:
|
|
* OUTPUT:
|
|
*
|
|
* RETURN VALUE: index into bkpt table is returned via step_id and returnval
|
|
* either returns a true or false if the addr is a step pt
|
|
*
|
|
*/
|
|
|
|
int
|
|
is_brat_step(step_id)
|
|
int *step_id;
|
|
{
|
|
/* check if this is a watch type of step */
|
|
if (step_wb(*step_id) == 2)
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: getaprsegid
|
|
*
|
|
* FUNCTION: This function will return the 32 bit contents of the segment
|
|
* register. If a virtual address is passed then get the segment
|
|
* register number and then bitwise and it with the segment id mask.
|
|
*
|
|
* PARAMETERS:
|
|
* INPUT: addr: the 32 bit address
|
|
* virt: virt or real (true or false)
|
|
* OUTPUT:
|
|
*
|
|
* RETURN VALUE: 24-bit segment id
|
|
*
|
|
*/
|
|
|
|
ulong
|
|
getaprsegid(addr,virt)
|
|
ulong addr; /* raw 32-bit address */
|
|
ulong virt; /* virt or real mode */
|
|
{
|
|
ulong addr_segid; /* contents of seg reg */
|
|
|
|
if (virt) /* get from seg reg */
|
|
addr_segid = debvars[IDSEGS+(addr>>SEGSHIFT)].hv;
|
|
else
|
|
addr_segid = KERNELSEGVAL;
|
|
|
|
return(addr_segid & segid_mask);
|
|
|
|
}
|