📄 dbgarmlib.c
字号:
/* * Now examine the instruction * First, check the current condition codes against the condition * field of the instruction since, if this instruction is not going * to be executed, we can return immediately * * The following code is a translation of the code supplied by ARM * for instruction decoding (EAN-26). Note that this version, unlike * the original assembly language version cannot generate unaligned * accesses which might be faulted by some systems. * * Briefly, there are 16 entries in ccTable, one for each possible * value of the condition part of an instruction. Each entry has one * bit for each possible value of the flags in the PSR. The table * entry is extracted using the condition part of the instruction and * the bits are indexed using the value obtained by extracting the * flags from the PSR. If the bit so obtained is 1, the instruction * will be executed. */ if (((ccTable[(instr >> 28) & 0xF] >> (pRegs->cpsr >> 28)) & 1) == 0) return (INSTR *)nPc; /* instruction will not be executed */ /* * This instruction WILL be executed so look at its type * We're looking for anything that affects the PC e.g. * B * BL * any data processing op where PC is the destination * any LDR with the PC as the destination * any LDM with the PC in the list of registers to be loaded * * Following code is derived from the ARM symbolic debugger. */ switch (BITS(instr, 24, 27)) { case 1: /* check for halfword or signed byte load to PC */ if (BITSET(instr, 4) && BITSET(instr, 7) && BITSET(instr, 20) && BITS(instr, 5, 6) != 0 && BITS(instr, 12, 15) == 15) break; /* bad instruction */ /* FALL THROUGH */ case 0: /* data processing */ case 2: case 3: { UINT32 rn, op1, op2, cFlag; if (BITS(instr, 12, 15) != 15) /* Rd */ /* operation does not affect PC */ break; if (BITS(instr, 22, 25) == 0 && BITS(instr, 4, 7) == 9) /* multiply with PC as destination not allowed */ break; if (BITS(instr, 4, 23) == 0x2FFF1) { /* BX */ rn = BITS(instr, 0, 3); nPc = (rn == 15 ? pc + 8 : pRegs->r[rn]) & ~1; break; } cFlag = BITSET(pRegs->cpsr, 29); rn = BITS(instr, 16, 19); op1 = rn == 15 ? pc + 8 : pRegs->r[rn]; if (BITSET(instr, 25)) { UINT32 immVal, rotate; immVal = BITS(instr, 0, 7); rotate = 2 * BITS(instr, 8, 11); op2 = (immVal >> rotate) | (immVal << (32 - rotate)); } else op2 = armShiftedRegVal(pRegs, instr, cFlag); switch (BITS(instr, 21, 24)) { case 0x0: /* AND */ nPc = op1 & op2; break; case 0x1: /* EOR */ nPc = op1 ^ op2; break; case 0x2: /* SUB */ nPc = op1 - op2; break; case 0x3: /* RSB */ nPc = op2 - op1; break; case 0x4: /* ADD */ nPc = op1 + op2; break; case 0x5: /* ADC */ nPc = op1 + op2 + cFlag; break; case 0x6: /* SBC */ nPc = op1 - op2 + cFlag; break; case 0x7: /* RSC */ nPc = op2 - op1 + cFlag; break; case 0x8: /* TST */ case 0x9: /* TEQ */ case 0xa: /* CMP */ case 0xb: /* CMN */ break; case 0xc: /* ORR */ nPc = op1 | op2; break; case 0xd: /* MOV */ nPc = op2; break; case 0xe: /* BIC */ nPc = op1 & ~op2; break; case 0xf: /* MVN */ nPc = ~op2; break; } } break; case 4: /* data transfer */ case 5: case 6: case 7: if (BITSET(instr, 20) && BITS(instr, 12, 15) == 15 && !BITSET(instr, 22)) /* load, PC and not a byte load */ { UINT32 rn, cFlag, base; INT32 offset; rn = BITS(instr, 16, 19); base = rn == 15 ? pc + 8 : pRegs->r[rn]; cFlag = BITSET(pRegs->cpsr, 29); offset = BITSET(instr, 25) ? armShiftedRegVal(pRegs, instr, cFlag) : BITS(instr, 0, 11); if (!BITSET(instr, 23)) /* down */ offset = -offset; if (BITSET(instr, 24)) /* pre-indexed */ base += offset; nPc = *(INSTR *)base; /* * don't check for nPc == pc like the ARM debugger does but * let the higher level (or user) notice. */ } break; case 8: case 9: /* block transfer */ if (BITSET(instr, 20) && BITSET(instr, 15)) /* loading PC */ { UINT32 rn; INT32 offset = 0; rn = BITS(instr, 16, 19); if (BITSET(instr, 23)) /* up */ { UINT32 regBit, regList; for (regList = BITS(instr, 0, 14); regList != 0; regList &= ~regBit) { regBit = regList & (-regList); offset += 4; } if (BITSET(instr, 24)) /* preincrement */ offset += 4; } else /* down */ if (BITSET(instr, 24)) /* predecrement */ offset = -4; nPc = *(UINT32 *)(pRegs->r[rn] + offset); /* * don't check for nPc == pc like the ARM debugger does but * let the higher level (or user) notice. */ } break; case 0xA: /* branch */ case 0xB: /* branch & link */ /* * extract offset, sign extend it and add it to current PC, * adjusting for the pipeline */ nPc = pc + 8 + ((INT32)(instr << 8) >> 6); break; case 0xC: case 0xD: case 0xE: /* coproc ops */ case 0xF: /* SWI */ break; } return (INSTR *)nPc; } /* armGetNpc() */#endif /* (ARM_THUMB) */#if (ARM_THUMB)/********************************************************************************* thumbInstrChangesPc - determine if current instruction changes PC** RETURNS: TRUE if the current instruction changes the PC**/BOOL thumbInstrChangesPc ( INSTR * pc /* pointer to instruction */ ) { INSTR instr; /* the instruction, itself */ BOOL res; pc = (INSTR *)((UINT32)pc & ~1); /* align pc */ instr = *pc; /* get instruction */ res = FALSE; /* assume PC is not affected */ /* * Examine the instruction to determine whether it changes the PC * other than in the usual incremental fashion. Note that we don't have * the CPSR value so we just assume the instruction will be executed. * * The following code is a cut-down version of the code used by * thumbGetNpc (above). */ switch (BITS(instr, 12, 15)) { case 0x0: case 0x1: case 0x2: case 0x3: case 0x5: case 0x6: case 0x7: case 0x8: case 0x9: case 0xA: case 0xC: /* no effect on PC - next instruction executes */ break; case 4: if (BITS(instr, 7, 11) == 0x0E) res = TRUE; /* BX */ else if (BITSET(instr, 7) && (BITS(instr, 0, 11) & 0xC07) == 0x407 && BITS(instr, 8, 9) != 1) res = TRUE; /* does something to PC and is not CMP */ break; case 0xB: if (BITS(instr, 8, 11) == 0xD) res = TRUE; /* POP {rlist, pc} */ break; case 0xD: if (((instr >> 8) & 0xF) != 0xF) res = TRUE; /* conditional branch, not SWI */ break; case 0xE: if (BITSET(instr, 11) == 0) res = TRUE; /* unconditional branch */ break; case 0xF: if (BITSET(instr, 11) == 0) res = TRUE; /* first half of BL */ break; } /* switch */ return res; } /* thumbInstrChangesPc() */#else /* (ARM_THUMB) *//********************************************************************************* armInstrChangesPc - determine if current instruction changes PC** RETURNS: TRUE if the current instruction changes the PC**/BOOL armInstrChangesPc ( INSTR * pc /* pointer to instruction */ ) { UINT32 instr; /* the instruction, itself */ BOOL res; instr = *pc; /* get instruction */ res = FALSE; /* assume PC is not affected */ /* * Examine the instruction to determine whether it changes the PC * other than in the usual incremental fashion. Note that we don't have * the CPSR value so we just assume the instruction will be executed. * * The following code is a cut-down version of the code used by * armGetNpc (above). */ switch (BITS(instr, 24, 27)) { case 0: /* data processing */ case 1: /* includes signed byte/halfword loads */ case 2: case 3: /* includes MUL, BX */ if (BITS(instr, 12, 15) == 15) /* Rd */ res = TRUE; break; case 4: /* data transfer */ case 5: case 6: case 7: if (BITSET(instr, 20) && BITS(instr, 12, 15) == 15 && !BITSET(instr, 22)) /* load, PC and not a byte load */ res = TRUE; break; case 8: case 9: /* block transfer */ if (BITSET(instr, 20) && BITSET(instr, 15)) /* loading PC */ res = TRUE; break; case 0xA: /* branch */ case 0xB: /* branch & link */ res = TRUE; break; case 0xC: case 0xD: case 0xE: /* coproc ops */ case 0xF: /* SWI */ break; } return res; } /* armInstrChangesPc() */#endif /* (ARM_THUMB) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -