📄 ppc_stub.c
字号:
memcpy (value, (char *)_registers + offset, REGSIZE(which));
return 1;
}
// Alter the contents of saved register WHICH to contain VALUE. This
// is only used for registers larger than sizeof(target_register_t).
// Return non-zero if it is a valid register.
int
put_register_as_bytes (regnames_t which, char *value)
{
int offset = reg_offset(which);
memcpy ((char *)_registers + offset, value, REGSIZE(which));
return 1;
}
#endif
/*----------------------------------------------------------------------
* Single-step support
*/
/* Set things up so that the next user resume will execute one instruction.
This may be done by setting breakpoints or setting a single step flag
in the saved user registers, for example. */
#ifdef USE_BREAKPOINTS_FOR_SINGLE_STEP
#if (HAL_BREAKINST_SIZE == 1)
typedef cyg_uint8 t_inst;
#elif (HAL_BREAKINST_SIZE == 2)
typedef cyg_uint16 t_inst;
#elif (HAL_BREAKINST_SIZE == 4)
typedef cyg_uint32 t_inst;
#else
#error "Don't know how to handle that size"
#endif
typedef struct
{
t_inst *targetAddr;
t_inst savedInstr;
} instrBuffer;
static instrBuffer sstep_instr[2];
static target_register_t irq_state = 0;
static void
__insert_break(int indx, target_register_t pc)
{
sstep_instr[indx].targetAddr = (t_inst *)pc;
sstep_instr[indx].savedInstr = *(t_inst *)pc;
*(t_inst*)pc = (t_inst)HAL_BREAKINST;
__data_cache(CACHE_FLUSH);
__instruction_cache(CACHE_FLUSH);
}
static void
__remove_break(int indx)
{
if (sstep_instr[indx].targetAddr != 0) {
*(sstep_instr[indx].targetAddr) = sstep_instr[indx].savedInstr;
sstep_instr[indx].targetAddr = 0;
__data_cache(CACHE_FLUSH);
__instruction_cache(CACHE_FLUSH);
}
}
int
__is_single_step(target_register_t pc)
{
return (sstep_instr[0].targetAddr == (t_inst *)pc) ||
(sstep_instr[1].targetAddr == (t_inst *)pc);
}
// Compute the target address for this instruction, if the instruction
// is some sort of branch/flow change.
struct xl_form {
unsigned int op : 6;
unsigned int bo : 5;
unsigned int bi : 5;
unsigned int reserved : 5;
unsigned int xo : 10;
unsigned int lk : 1;
};
struct i_form {
unsigned int op : 6;
signed int li : 24;
unsigned int aa : 1;
unsigned int lk : 1;
};
struct b_form {
unsigned int op : 6;
unsigned int bo : 5;
unsigned int bi : 5;
signed int bd : 14;
unsigned int aa : 1;
unsigned int lk : 1;
};
union ppc_insn {
unsigned int word;
struct i_form i;
struct b_form b;
struct xl_form xl;
};
static target_register_t
__branch_pc(target_register_t pc)
{
union ppc_insn insn;
insn.word = *(t_inst *)pc;
// Decode the instruction to determine the instruction which will follow
// Note: there are holes in this process, but the important ones work
switch (insn.i.op) {
case 16:
/* bcx */
if (insn.b.aa) {
return (target_register_t)(insn.b.bd << 2);
} else {
return (target_register_t)((insn.b.bd << 2) + (long)pc);
}
case 18:
/* bx */
if (insn.i.aa) {
return (target_register_t)(insn.i.li << 2);
} else {
return (target_register_t)((insn.i.li << 2) + (long)pc);
}
case 19:
if (insn.xl.reserved == 0) {
if (insn.xl.xo == 528) {
/* bcctrx */
return (target_register_t)(get_register(CNT) & ~3);
} else if (insn.xl.xo == 16) {
/* bclrx */
return (target_register_t)(get_register(LR) & ~3);
}
}
break;
default:
break;
}
return (pc+4);
}
void __single_step(void)
{
target_register_t msr = get_register(PS);
target_register_t pc = get_register(PC);
target_register_t next_pc = __branch_pc(pc);
// Disable interrupts.
irq_state = msr & MSR_EE;
msr &= ~MSR_EE;
put_register (PS, msr);
// Set a breakpoint at the next instruction
__insert_break(0, pc+4);
if (next_pc != (pc+4)) {
__insert_break(1, next_pc);
}
}
/* Clear the single-step state. */
void __clear_single_step(void)
{
target_register_t msr = get_register (PS);
// Restore interrupt state.
// FIXME: Should check whether the executed instruction changed the
// interrupt state - or single-stepping a MSR changing instruction
// may result in a wrong EE. Not a very likely scenario though.
msr |= irq_state;
// This function is called much more than its counterpart
// __single_step. Only re-enable interrupts if they where
// disabled during the previous cal to __single_step. Otherwise,
// this function only makes "extra sure" that no trace or branch
// exception will happen.
irq_state = 0;
put_register (PS, msr);
// Remove breakpoints
__remove_break(0);
__remove_break(1);
}
#else
static target_register_t irq_state = 0;
void __single_step (void)
{
target_register_t msr = get_register (PS);
// Set single-step flag in the exception context.
msr |= (MSR_SE | MSR_BE);
// Disable interrupts.
irq_state = msr & MSR_EE;
msr &= ~MSR_EE;
put_register (PS, msr);
}
/* Clear the single-step state. */
void __clear_single_step (void)
{
target_register_t msr = get_register (PS);
// Clear single-step flag in the exception context.
msr &= ~(MSR_SE | MSR_BE);
// Restore interrupt state.
// FIXME: Should check whether the executed instruction changed the
// interrupt state - or single-stepping a MSR changing instruction
// may result in a wrong EE. Not a very likely scenario though.
msr |= irq_state;
// This function is called much more than its counterpart
// __single_step. Only re-enable interrupts if they where
// disabled during the previous cal to __single_step. Otherwise,
// this function only makes "extra sure" that no trace or branch
// exception will happen.
irq_state = 0;
put_register (PS, msr);
}
#endif
void __install_breakpoints (void)
{
/* NOP since single-step HW exceptions are used instead of
breakpoints. */
}
void __clear_breakpoints (void)
{
}
/* If the breakpoint we hit is in the breakpoint() instruction, return a
non-zero value. */
int
__is_breakpoint_function ()
{
return get_register (PC) == (target_register_t)&_breakinst;
}
/* Skip the current instruction. Since this is only called by the
stub when the PC points to a breakpoint or trap instruction,
we can safely just skip 4. */
void __skipinst (void)
{
put_register (PC, get_register (PC) + 4);
}
#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -