Page MenuHomeFreeBSD

D4021.diff
No OneTemporary

D4021.diff

Index: head/sys/arm/arm/db_interface.c
===================================================================
--- head/sys/arm/arm/db_interface.c
+++ head/sys/arm/arm/db_interface.c
@@ -53,6 +53,7 @@
#include <vm/vm_extern.h>
#include <machine/db_machdep.h>
+#include <machine/machdep.h>
#include <machine/vmparam.h>
#include <machine/cpu.h>
@@ -291,94 +292,35 @@
}
}
+static u_int
+db_branch_taken_read_int(void *cookie __unused, vm_offset_t offset, u_int *val)
+{
+ u_int ret;
+
+ db_read_bytes(offset, 4, (char *)&ret);
+ *val = ret;
+
+ return (0);
+}
+
+static u_int
+db_branch_taken_fetch_reg(void *cookie __unused, int reg)
+{
+
+ return (db_fetch_reg(reg));
+}
+
u_int
branch_taken(u_int insn, db_addr_t pc)
{
- u_int addr, nregs, offset = 0;
+ register_t new_pc;
+ int ret;
- switch ((insn >> 24) & 0xf) {
- case 0x2: /* add pc, reg1, #value */
- case 0x0: /* add pc, reg1, reg2, lsl #offset */
- addr = db_fetch_reg((insn >> 16) & 0xf);
- if (((insn >> 16) & 0xf) == 15)
- addr += 8;
- if (insn & 0x0200000) {
- offset = (insn >> 7) & 0x1e;
- offset = (insn & 0xff) << (32 - offset) |
- (insn & 0xff) >> offset;
- } else {
-
- offset = db_fetch_reg(insn & 0x0f);
- if ((insn & 0x0000ff0) != 0x00000000) {
- if (insn & 0x10)
- nregs = db_fetch_reg((insn >> 8) & 0xf);
- else
- nregs = (insn >> 7) & 0x1f;
- switch ((insn >> 5) & 3) {
- case 0:
- /* lsl */
- offset = offset << nregs;
- break;
- case 1:
- /* lsr */
- offset = offset >> nregs;
- break;
- default:
- break; /* XXX */
- }
- }
- return (addr + offset);
- }
- case 0xa: /* b ... */
- case 0xb: /* bl ... */
- addr = ((insn << 2) & 0x03ffffff);
- if (addr & 0x02000000)
- addr |= 0xfc000000;
- return (pc + 8 + addr);
- case 0x7: /* ldr pc, [pc, reg, lsl #2] */
- addr = db_fetch_reg(insn & 0xf);
- addr = pc + 8 + (addr << 2);
- db_read_bytes(addr, 4, (char *)&addr);
- return (addr);
- case 0x1: /* mov pc, reg */
- addr = db_fetch_reg(insn & 0xf);
- return (addr);
- case 0x4:
- case 0x5: /* ldr pc, [reg] */
- addr = db_fetch_reg((insn >> 16) & 0xf);
- /* ldr pc, [reg, #offset] */
- if (insn & (1 << 24))
- offset = insn & 0xfff;
- if (insn & 0x00800000)
- addr += offset;
- else
- addr -= offset;
- db_read_bytes(addr, 4, (char *)&addr);
- return (addr);
- case 0x8: /* ldmxx reg, {..., pc} */
- case 0x9:
- addr = db_fetch_reg((insn >> 16) & 0xf);
- nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555);
- nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333);
- nregs = (nregs + (nregs >> 4)) & 0x0f0f;
- nregs = (nregs + (nregs >> 8)) & 0x001f;
- switch ((insn >> 23) & 0x3) {
- case 0x0: /* ldmda */
- addr = addr - 0;
- break;
- case 0x1: /* ldmia */
- addr = addr + 0 + ((nregs - 1) << 2);
- break;
- case 0x2: /* ldmdb */
- addr = addr - 4;
- break;
- case 0x3: /* ldmib */
- addr = addr + 4 + ((nregs - 1) << 2);
- break;
- }
- db_read_bytes(addr, 4, (char *)&addr);
- return (addr);
- default:
- panic("branch_taken: botch");
- }
+ ret = arm_predict_branch(NULL, insn, (register_t)pc, &new_pc,
+ db_branch_taken_fetch_reg, db_branch_taken_read_int);
+
+ if (ret != 0)
+ kdb_reenter();
+
+ return (new_pc);
}
Index: head/sys/arm/arm/machdep.c
===================================================================
--- head/sys/arm/arm/machdep.c
+++ head/sys/arm/arm/machdep.c
@@ -95,6 +95,7 @@
#include <machine/atags.h>
#include <machine/cpu.h>
#include <machine/cpuinfo.h>
+#include <machine/db_machdep.h>
#include <machine/devmap.h>
#include <machine/frame.h>
#include <machine/intr.h>
@@ -627,11 +628,81 @@
return proc_rwmem(td->td_proc, &uio);
}
+static u_int
+ptrace_get_usr_reg(void *cookie, int reg)
+{
+ int ret;
+ struct thread *td = cookie;
+
+ KASSERT(((reg >= 0) && (reg <= ARM_REG_NUM_PC)),
+ ("reg is outside range"));
+
+ switch(reg) {
+ case ARM_REG_NUM_PC:
+ ret = td->td_frame->tf_pc;
+ break;
+ case ARM_REG_NUM_LR:
+ ret = td->td_frame->tf_usr_lr;
+ break;
+ case ARM_REG_NUM_SP:
+ ret = td->td_frame->tf_usr_sp;
+ break;
+ default:
+ ret = *((register_t*)&td->td_frame->tf_r0 + reg);
+ break;
+ }
+
+ return (ret);
+}
+
+static u_int
+ptrace_get_usr_int(void* cookie, vm_offset_t offset, u_int* val)
+{
+ struct thread *td = cookie;
+ u_int error;
+
+ error = ptrace_read_int(td, offset, val);
+
+ return (error);
+}
+
+/**
+ * This function parses current instruction opcode and decodes
+ * any possible jump (change in PC) which might occur after
+ * the instruction is executed.
+ *
+ * @param td Thread structure of analysed task
+ * @param cur_instr Currently executed instruction
+ * @param alt_next_address Pointer to the variable where
+ * the destination address of the
+ * jump instruction shall be stored.
+ *
+ * @return <0> when jump is possible
+ * <EINVAL> otherwise
+ */
+static int
+ptrace_get_alternative_next(struct thread *td, uint32_t cur_instr,
+ uint32_t *alt_next_address)
+{
+ int error;
+
+ if (inst_branch(cur_instr) || inst_call(cur_instr) ||
+ inst_return(cur_instr)) {
+ error = arm_predict_branch(td, cur_instr, td->td_frame->tf_pc,
+ alt_next_address, ptrace_get_usr_reg, ptrace_get_usr_int);
+
+ return (error);
+ }
+
+ return (EINVAL);
+}
+
int
ptrace_single_step(struct thread *td)
{
struct proc *p;
- int error;
+ int error, error_alt;
+ uint32_t cur_instr, alt_next = 0;
/* TODO: This needs to be updated for Thumb-2 */
if ((td->td_frame->tf_spsr & PSR_T) != 0)
@@ -639,20 +710,48 @@
KASSERT(td->td_md.md_ptrace_instr == 0,
("Didn't clear single step"));
+ KASSERT(td->td_md.md_ptrace_instr_alt == 0,
+ ("Didn't clear alternative single step"));
p = td->td_proc;
PROC_UNLOCK(p);
- error = ptrace_read_int(td, td->td_frame->tf_pc + 4,
- &td->td_md.md_ptrace_instr);
+
+ error = ptrace_read_int(td, td->td_frame->tf_pc,
+ &cur_instr);
if (error)
goto out;
- error = ptrace_write_int(td, td->td_frame->tf_pc + 4,
- PTRACE_BREAKPOINT);
- if (error)
- td->td_md.md_ptrace_instr = 0;
- td->td_md.md_ptrace_addr = td->td_frame->tf_pc + 4;
+
+ error = ptrace_read_int(td, td->td_frame->tf_pc + INSN_SIZE,
+ &td->td_md.md_ptrace_instr);
+ if (error == 0) {
+ error = ptrace_write_int(td, td->td_frame->tf_pc + INSN_SIZE,
+ PTRACE_BREAKPOINT);
+ if (error) {
+ td->td_md.md_ptrace_instr = 0;
+ } else {
+ td->td_md.md_ptrace_addr = td->td_frame->tf_pc +
+ INSN_SIZE;
+ }
+ }
+
+ error_alt = ptrace_get_alternative_next(td, cur_instr, &alt_next);
+ if (error_alt == 0) {
+ error_alt = ptrace_read_int(td, alt_next,
+ &td->td_md.md_ptrace_instr_alt);
+ if (error_alt) {
+ td->td_md.md_ptrace_instr_alt = 0;
+ } else {
+ error_alt = ptrace_write_int(td, alt_next,
+ PTRACE_BREAKPOINT);
+ if (error_alt)
+ td->td_md.md_ptrace_instr_alt = 0;
+ else
+ td->td_md.md_ptrace_addr_alt = alt_next;
+ }
+ }
+
out:
PROC_LOCK(p);
- return (error);
+ return ((error != 0) && (error_alt != 0));
}
int
@@ -664,7 +763,7 @@
if ((td->td_frame->tf_spsr & PSR_T) != 0)
return (EINVAL);
- if (td->td_md.md_ptrace_instr) {
+ if (td->td_md.md_ptrace_instr != 0) {
p = td->td_proc;
PROC_UNLOCK(p);
ptrace_write_int(td, td->td_md.md_ptrace_addr,
@@ -672,6 +771,16 @@
PROC_LOCK(p);
td->td_md.md_ptrace_instr = 0;
}
+
+ if (td->td_md.md_ptrace_instr_alt != 0) {
+ p = td->td_proc;
+ PROC_UNLOCK(p);
+ ptrace_write_int(td, td->td_md.md_ptrace_addr_alt,
+ td->td_md.md_ptrace_instr_alt);
+ PROC_LOCK(p);
+ td->td_md.md_ptrace_instr_alt = 0;
+ }
+
return (0);
}
@@ -1074,6 +1183,111 @@
pcpup->pc_curpcb = thread0.td_pcb;
}
+int
+arm_predict_branch(void *cookie, u_int insn, register_t pc, register_t *new_pc,
+ u_int (*fetch_reg)(void*, int), u_int (*read_int)(void*, vm_offset_t, u_int*))
+{
+ u_int addr, nregs, offset = 0;
+ int error = 0;
+
+ switch ((insn >> 24) & 0xf) {
+ case 0x2: /* add pc, reg1, #value */
+ case 0x0: /* add pc, reg1, reg2, lsl #offset */
+ addr = fetch_reg(cookie, (insn >> 16) & 0xf);
+ if (((insn >> 16) & 0xf) == 15)
+ addr += 8;
+ if (insn & 0x0200000) {
+ offset = (insn >> 7) & 0x1e;
+ offset = (insn & 0xff) << (32 - offset) |
+ (insn & 0xff) >> offset;
+ } else {
+
+ offset = fetch_reg(cookie, insn & 0x0f);
+ if ((insn & 0x0000ff0) != 0x00000000) {
+ if (insn & 0x10)
+ nregs = fetch_reg(cookie,
+ (insn >> 8) & 0xf);
+ else
+ nregs = (insn >> 7) & 0x1f;
+ switch ((insn >> 5) & 3) {
+ case 0:
+ /* lsl */
+ offset = offset << nregs;
+ break;
+ case 1:
+ /* lsr */
+ offset = offset >> nregs;
+ break;
+ default:
+ break; /* XXX */
+ }
+
+ }
+ *new_pc = addr + offset;
+ return (0);
+
+ }
+
+ case 0xa: /* b ... */
+ case 0xb: /* bl ... */
+ addr = ((insn << 2) & 0x03ffffff);
+ if (addr & 0x02000000)
+ addr |= 0xfc000000;
+ *new_pc = (pc + 8 + addr);
+ return (0);
+ case 0x7: /* ldr pc, [pc, reg, lsl #2] */
+ addr = fetch_reg(cookie, insn & 0xf);
+ addr = pc + 8 + (addr << 2);
+ error = read_int(cookie, addr, &addr);
+ *new_pc = addr;
+ return (error);
+ case 0x1: /* mov pc, reg */
+ *new_pc = fetch_reg(cookie, insn & 0xf);
+ return (0);
+ case 0x4:
+ case 0x5: /* ldr pc, [reg] */
+ addr = fetch_reg(cookie, (insn >> 16) & 0xf);
+ /* ldr pc, [reg, #offset] */
+ if (insn & (1 << 24))
+ offset = insn & 0xfff;
+ if (insn & 0x00800000)
+ addr += offset;
+ else
+ addr -= offset;
+ error = read_int(cookie, addr, &addr);
+ *new_pc = addr;
+
+ return (error);
+ case 0x8: /* ldmxx reg, {..., pc} */
+ case 0x9:
+ addr = fetch_reg(cookie, (insn >> 16) & 0xf);
+ nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555);
+ nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333);
+ nregs = (nregs + (nregs >> 4)) & 0x0f0f;
+ nregs = (nregs + (nregs >> 8)) & 0x001f;
+ switch ((insn >> 23) & 0x3) {
+ case 0x0: /* ldmda */
+ addr = addr - 0;
+ break;
+ case 0x1: /* ldmia */
+ addr = addr + 0 + ((nregs - 1) << 2);
+ break;
+ case 0x2: /* ldmdb */
+ addr = addr - 4;
+ break;
+ case 0x3: /* ldmib */
+ addr = addr + 4 + ((nregs - 1) << 2);
+ break;
+ }
+ error = read_int(cookie, addr, &addr);
+ *new_pc = addr;
+
+ return (error);
+ default:
+ return (EINVAL);
+ }
+}
+
#ifdef ARM_NEW_PMAP
void
set_stackptrs(int cpu)
Index: head/sys/arm/include/armreg.h
===================================================================
--- head/sys/arm/include/armreg.h
+++ head/sys/arm/include/armreg.h
@@ -444,6 +444,12 @@
#define INSN_COND_MASK 0xf0000000 /* Condition mask */
#define INSN_COND_AL 0xe0000000 /* Always condition */
+/* ARM register defines */
+#define ARM_REG_SIZE 4
+#define ARM_REG_NUM_PC 15
+#define ARM_REG_NUM_LR 14
+#define ARM_REG_NUM_SP 13
+
#define THUMB_INSN_SIZE 2 /* Some are 4 bytes. */
#endif /* !MACHINE_ARMREG_H */
Index: head/sys/arm/include/db_machdep.h
===================================================================
--- head/sys/arm/include/db_machdep.h
+++ head/sys/arm/include/db_machdep.h
@@ -74,7 +74,7 @@
#define inst_branch(ins) (((ins) & 0x0f000000) == 0x0a000000 || \
((ins) & 0x0fdffff0) == 0x079ff100 || \
- ((ins) & 0x0cf0f000) == 0x0490f000 || \
+ ((ins) & 0x0cd0f000) == 0x0490f000 || \
((ins) & 0x0ffffff0) == 0x012fff30 || /* blx */ \
((ins) & 0x0de0f000) == 0x0080f000)
@@ -90,7 +90,7 @@
int db_validate_address(vm_offset_t);
-u_int branch_taken (u_int insn, u_int pc);
+u_int branch_taken (u_int insn, db_addr_t pc);
#ifdef __ARMEB__
#define BYTE_MSF (1)
Index: head/sys/arm/include/machdep.h
===================================================================
--- head/sys/arm/include/machdep.h
+++ head/sys/arm/include/machdep.h
@@ -43,4 +43,7 @@
void board_set_serial(uint64_t);
void board_set_revision(uint32_t);
+int arm_predict_branch(void *, u_int, register_t, register_t *,
+ u_int (*)(void*, int), u_int (*)(void*, vm_offset_t, u_int*));
+
#endif /* !_MACHINE_MACHDEP_H_ */
Index: head/sys/arm/include/proc.h
===================================================================
--- head/sys/arm/include/proc.h
+++ head/sys/arm/include/proc.h
@@ -51,6 +51,8 @@
register_t md_spurflt_addr; /* (k) Spurious page fault address. */
int md_ptrace_instr;
int md_ptrace_addr;
+ int md_ptrace_instr_alt;
+ int md_ptrace_addr_alt;
register_t md_tp;
void *md_ras_start;
void *md_ras_end;

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 18, 6:57 AM (11 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29889122
Default Alt Text
D4021.diff (12 KB)

Event Timeline