typedef union thumb_insn {
- unsigned long val;
+ u32 val;
struct {
- unsigned short hw1;
- unsigned short hw2;
+ u16 hw1;
+ u16 hw2;
} __packed;
} thumb_insn_t;
typedef int (*decode_handler_t)(thumb_insn_t insn, struct decode_info *info);
-static void make_def(void *tramp, unsigned long insn,
- unsigned long vaddr, bool t2)
+static void make_def(void *tramp, u32 insn, u32 vaddr, bool t2)
{
- const unsigned long URET_BP = 0xdeff; /* breakpoint for uretprobe */
- unsigned long ret_addr;
- unsigned short *tr = tramp;
+ const u32 URET_BP = 0xdeff; /* breakpoint for uretprobe */
+ u32 ret_addr;
+ u16 *tr = tramp;
/*
* thumb - +2
tr[17] = ret_addr >> 16;
}
-static void tt_make_common(void *tramp, unsigned long insn,
- unsigned long vaddr, bool t2)
+static void tt_make_common(void *tramp, u32 insn, u32 vaddr, bool t2)
{
memcpy(tramp, gen_insn_execbuf_thumb, 4 * UPROBES_TRAMP_LEN);
make_def(tramp, insn, vaddr, t2);
}
-static void tt_make_pc_deps(void *tramp, unsigned long mod_insn,
- unsigned long vaddr, bool t2)
+static void tt_make_pc_deps(void *tramp, u32 mod_insn, u32 vaddr, bool t2)
{
- unsigned long pc_val = vaddr + 4;
- unsigned short *tr = tramp;
+ u32 pc_val = vaddr + 4;
+ u16 *tr = tramp;
memcpy(tramp, pc_dep_insn_execbuf_thumb, 4 * UPROBES_TRAMP_LEN);
make_def(tramp, mod_insn, vaddr, t2);
return thumb_not_implement(insn, info);
}
-static void t32_simulate_branch(unsigned long insn,
- struct arch_insn *ainsn,
+static void t32_simulate_branch(u32 insn, struct arch_insn *ainsn,
struct pt_regs *regs)
{
- unsigned long pc = regs->ARM_pc;
+ u32 pc = regs->ARM_pc;
thumb_insn_t i = { .val = insn };
- long offset = GET_FIELD(i.hw2, 0, 11); /* imm11 */
+ s32 offset = GET_FIELD(i.hw2, 0, 11); /* imm11 */
offset += GET_FIELD(i.hw1, 0, 10) << 11; /* imm10 */
offset += GET_BIT(i.hw2, 13) << 21; /* J1 */
offset += GET_BIT(i.hw2, 11) << 22; /* J2 */
static int t32_b1111_0xxx_xxxx_xxxx_1(thumb_insn_t insn,
struct decode_info *info)
{
- unsigned long s = GET_BIT(insn.hw2, 14) << 2 |
- GET_BIT(insn.hw2, 12) << 1 |
- GET_BIT(insn.hw2, 0);
+ u32 s = GET_BIT(insn.hw2, 14) << 2 |
+ GET_BIT(insn.hw2, 12) << 1 |
+ GET_BIT(insn.hw2, 0);
return table_branches[s](insn, info);
}
};
-int decode_thumb(unsigned long insn, struct decode_info *info)
+int decode_thumb(u32 insn, struct decode_info *info)
{
thumb_insn_t tinsn = { .val = insn };
#include "decode_thumb_old.h"
-static inline long branch_t16_dest(unsigned long insn, unsigned int insn_addr)
+static inline s32 branch_t16_dest(u32 insn, unsigned int insn_addr)
{
- long offset = insn & 0x3ff;
+ s32 offset = insn & 0x3ff;
offset -= insn & 0x400;
return insn_addr + 4 + offset * 2;
}
-static inline long branch_cond_t16_dest(unsigned long insn,
- unsigned int insn_addr)
+static inline s32 branch_cond_t16_dest(u32 insn, unsigned int insn_addr)
{
- long offset = insn & 0x7f;
+ s32 offset = insn & 0x7f;
offset -= insn & 0x80;
return insn_addr + 4 + offset * 2;
}
-static inline long branch_t32_dest(unsigned long insn, unsigned int insn_addr)
+static inline s32 branch_t32_dest(u32 insn, unsigned int insn_addr)
{
unsigned int poff = insn & 0x3ff;
unsigned int offset = (insn & 0x07fe0000) >> 17;
return (insn_addr + 4 + (poff << 12) + offset * 4) & ~3;
}
-static inline long cbz_t16_dest(unsigned long insn, unsigned int insn_addr)
+static inline s32 cbz_t16_dest(u32 insn, unsigned int insn_addr)
{
unsigned int i = (insn & 0x200) >> 3;
unsigned int offset = (insn & 0xf8) >> 2;
}
/* is instruction Thumb2 and NOT a branch, etc... */
-static int is_thumb2(unsigned long insn)
+static int is_thumb2(u32 insn)
{
return ((insn & 0xf800) == 0xe800 ||
(insn & 0xf800) == 0xf000 ||
(insn & 0xf800) == 0xf800);
}
-static int prep_pc_dep_insn_execbuf_thumb(unsigned long *insns,
- unsigned long insn, int uregs)
+static int prep_pc_dep_insn_execbuf_thumb(u32 *insns, u32 insn, int uregs)
{
unsigned char mreg = 0;
unsigned char reg = 0;
}
if (reg == 6 || reg == 7) {
- *((unsigned short *)insns + 0) =
- (*((unsigned short *)insns + 0) & 0x00ff) |
+ *((u16 *)insns + 0) =
+ (*((u16 *)insns + 0) & 0x00ff) |
((1 << mreg) | (1 << (mreg + 1)));
- *((unsigned short *)insns + 1) =
- (*((unsigned short *)insns + 1) & 0xf8ff) | (mreg << 8);
- *((unsigned short *)insns + 2) =
- (*((unsigned short *)insns + 2) & 0xfff8) | (mreg + 1);
- *((unsigned short *)insns + 3) =
- (*((unsigned short *)insns + 3) & 0xffc7) | (mreg << 3);
- *((unsigned short *)insns + 7) =
- (*((unsigned short *)insns + 7) & 0xf8ff) | (mreg << 8);
- *((unsigned short *)insns + 8) =
- (*((unsigned short *)insns + 8) & 0xffc7) | (mreg << 3);
- *((unsigned short *)insns + 9) =
- (*((unsigned short *)insns + 9) & 0xffc7) |
- ((mreg + 1) << 3);
- *((unsigned short *)insns + 10) =
- (*((unsigned short *)insns + 10) & 0x00ff) |
+ *((u16 *)insns + 1) =
+ (*((u16 *)insns + 1) & 0xf8ff) | (mreg << 8);
+ *((u16 *)insns + 2) =
+ (*((u16 *)insns + 2) & 0xfff8) | (mreg + 1);
+ *((u16 *)insns + 3) =
+ (*((u16 *)insns + 3) & 0xffc7) | (mreg << 3);
+ *((u16 *)insns + 7) =
+ (*((u16 *)insns + 7) & 0xf8ff) | (mreg << 8);
+ *((u16 *)insns + 8) =
+ (*((u16 *)insns + 8) & 0xffc7) | (mreg << 3);
+ *((u16 *)insns + 9) =
+ (*((u16 *)insns + 9) & 0xffc7) | ((mreg + 1) << 3);
+ *((u16 *)insns + 10) =
+ (*((u16 *)insns + 10) & 0x00ff) |
((1 << mreg) | (1 << (mreg + 1)));
}
if (THUMB_INSN_MATCH(APC, insn)) {
/* ADD Rd, PC, #immed_8*4 -> ADD Rd, SP, #immed_8*4 */
- *((unsigned short *)insns + 4) = ((insn & 0xffff) | 0x800);
+ *((u16 *)insns + 4) = ((insn & 0xffff) | 0x800);
} else if (THUMB_INSN_MATCH(LRO3, insn)) {
/* LDR Rd, [PC, #immed_8*4] ->
* LDR Rd, [SP, #immed_8*4] */
- *((unsigned short *)insns + 4) =
- ((insn & 0xffff) + 0x5000);
+ *((u16 *)insns + 4) = ((insn & 0xffff) + 0x5000);
} else if (THUMB_INSN_MATCH(MOV3, insn)) {
/* MOV Rd, PC -> MOV Rd, SP */
- *((unsigned short *)insns + 4) =
- ((insn & 0xffff) ^ 0x10);
+ *((u16 *)insns + 4) = ((insn & 0xffff) ^ 0x10);
} else if (THUMB2_INSN_MATCH(ADR, insn)) {
/* ADDW Rd,PC,#imm -> ADDW Rd,SP,#imm */
insns[2] = (insn & 0xfffffff0) | 0x0d;
return 0;
}
-static int arch_check_insn_thumb(unsigned long insn)
+static int arch_check_insn_thumb(u32 insn)
{
int ret = 0;
return ret;
}
-static int do_make_trampoline_thumb(unsigned long vaddr, unsigned long insn,
- unsigned long *tramp, size_t tramp_len)
+static int do_make_trampoline_thumb(u32 vaddr, u32 insn,
+ u32 *tramp, size_t tramp_len)
{
int ret;
int uregs = 0;
prep_pc_dep_insn_execbuf_thumb(tramp, insn, uregs);
addr = vaddr + 4;
- *((unsigned short *)tramp + 13) = 0xdeff;
- *((unsigned short *)tramp + 14) = addr & 0x0000ffff;
- *((unsigned short *)tramp + 15) = addr >> 16;
+ *((u16 *)tramp + 13) = 0xdeff;
+ *((u16 *)tramp + 14) = addr & 0x0000ffff;
+ *((u16 *)tramp + 15) = addr >> 16;
if (!is_thumb2(insn)) {
addr = vaddr + 2;
- *((unsigned short *)tramp + 16) =
- (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
+ *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 17) = addr >> 16;
} else {
addr = vaddr + 4;
- *((unsigned short *)tramp + 16) =
- (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
+ *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 17) = addr >> 16;
}
} else {
memcpy(tramp, gen_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
+ *((u16 *)tramp + 13) = 0xdeff;
if (!is_thumb2(insn)) {
addr = vaddr + 2;
- *((unsigned short *)tramp + 2) = insn;
- *((unsigned short *)tramp + 16) =
- (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
+ *((u16 *)tramp + 2) = insn;
+ *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 17) = addr >> 16;
} else {
addr = vaddr + 4;
tramp[1] = insn;
- *((unsigned short *)tramp + 16) =
- (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
+ *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 17) = addr >> 16;
}
}
if (THUMB_INSN_MATCH(B2, insn)) {
memcpy(tramp, b_off_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
+ *((u16 *)tramp + 13) = 0xdeff;
addr = branch_t16_dest(insn, vaddr);
- *((unsigned short *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 15) = addr >> 16;
- *((unsigned short *)tramp + 16) = 0;
- *((unsigned short *)tramp + 17) = 0;
+ *((u16 *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 15) = addr >> 16;
+ *((u16 *)tramp + 16) = 0;
+ *((u16 *)tramp + 17) = 0;
} else if (THUMB_INSN_MATCH(B1, insn)) {
memcpy(tramp, b_cond_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
- *((unsigned short *)tramp + 0) |= (insn & 0xf00);
+ *((u16 *)tramp + 13) = 0xdeff;
+ *((u16 *)tramp + 0) |= (insn & 0xf00);
addr = branch_cond_t16_dest(insn, vaddr);
- *((unsigned short *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 15) = addr >> 16;
+ *((u16 *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 15) = addr >> 16;
addr = vaddr + 2;
- *((unsigned short *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
+ *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 17) = addr >> 16;
} else if (THUMB_INSN_MATCH(BLX2, insn) ||
THUMB_INSN_MATCH(BX, insn)) {
memcpy(tramp, b_r_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
- *((unsigned short *)tramp + 4) = insn;
+ *((u16 *)tramp + 13) = 0xdeff;
+ *((u16 *)tramp + 4) = insn;
addr = vaddr + 2;
- *((unsigned short *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
+ *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 17) = addr >> 16;
} else if (THUMB_INSN_MATCH(CBZ, insn)) {
memcpy(tramp, cbz_insn_execbuf_thumb, tramp_len);
- *((unsigned short *)tramp + 13) = 0xdeff;
+ *((u16 *)tramp + 13) = 0xdeff;
/* zero out original branch displacement (imm5 = 0; i = 0) */
- *((unsigned short *)tramp + 0) = insn & (~0x2f8);
+ *((u16 *)tramp + 0) = insn & (~0x2f8);
/* replace it with 8 bytes offset in execbuf (imm5 = 0b00010) */
- *((unsigned short *)tramp + 0) |= 0x20;
+ *((u16 *)tramp + 0) |= 0x20;
addr = cbz_t16_dest(insn, vaddr);
- *((unsigned short *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 15) = addr >> 16;
+ *((u16 *)tramp + 14) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 15) = addr >> 16;
addr = vaddr + 2;
- *((unsigned short *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
- *((unsigned short *)tramp + 17) = addr >> 16;
+ *((u16 *)tramp + 16) = (addr & 0x0000ffff) | 0x1;
+ *((u16 *)tramp + 17) = addr >> 16;
}
return 0;
}
int make_trampoline_thumb(struct uprobe *p,
- unsigned long vaddr, unsigned long insn,
- unsigned long *tramp, size_t tramp_len)
+ u32 vaddr, u32 insn, u32 *tramp, size_t tramp_len)
{
int ret;
ret = decode_thumb(insn, &info);
if (info.handeler) {
- unsigned short *tr = (unsigned short *)tramp;
+ u16 *tr = (u16 *)tramp;
tr[13] = 0xdeff; /* breakpoint for uretprobe */
p->ainsn.handler = info.handeler;
}