| 220 | } |
| 221 | |
| 222 | int |
| 223 | arm_predict_branch(void *cookie, u_int insn, register_t pc, register_t *new_pc, |
| 224 | u_int (*fetch_reg)(void*, int), |
| 225 | u_int (*read_int)(void*, vm_offset_t, u_int*)) |
| 226 | { |
| 227 | u_int addr, nregs, offset = 0; |
| 228 | int error = 0; |
| 229 | |
| 230 | switch ((insn >> 24) & 0xf) { |
| 231 | case 0x2: /* add pc, reg1, #value */ |
| 232 | case 0x0: /* add pc, reg1, reg2, lsl #offset */ |
| 233 | addr = fetch_reg(cookie, (insn >> 16) & 0xf); |
| 234 | if (((insn >> 16) & 0xf) == 15) |
| 235 | addr += 8; |
| 236 | if (insn & 0x0200000) { |
| 237 | offset = (insn >> 7) & 0x1e; |
| 238 | offset = (insn & 0xff) << (32 - offset) | |
| 239 | (insn & 0xff) >> offset; |
| 240 | } else { |
| 241 | offset = fetch_reg(cookie, insn & 0x0f); |
| 242 | if ((insn & 0x0000ff0) != 0x00000000) { |
| 243 | if (insn & 0x10) |
| 244 | nregs = fetch_reg(cookie, |
| 245 | (insn >> 8) & 0xf); |
| 246 | else |
| 247 | nregs = (insn >> 7) & 0x1f; |
| 248 | switch ((insn >> 5) & 3) { |
| 249 | case 0: |
| 250 | /* lsl */ |
| 251 | offset = offset << nregs; |
| 252 | break; |
| 253 | case 1: |
| 254 | /* lsr */ |
| 255 | offset = offset >> nregs; |
| 256 | break; |
| 257 | default: |
| 258 | break; /* XXX */ |
| 259 | } |
| 260 | } |
| 261 | *new_pc = addr + offset; |
| 262 | return (0); |
| 263 | } |
| 264 | |
| 265 | case 0xa: /* b ... */ |
| 266 | case 0xb: /* bl ... */ |
| 267 | addr = ((insn << 2) & 0x03ffffff); |
| 268 | if (addr & 0x02000000) |
| 269 | addr |= 0xfc000000; |
| 270 | *new_pc = (pc + 8 + addr); |
| 271 | return (0); |
| 272 | case 0x7: /* ldr pc, [pc, reg, lsl #2] */ |
| 273 | addr = fetch_reg(cookie, insn & 0xf); |
| 274 | addr = pc + 8 + (addr << 2); |
| 275 | error = read_int(cookie, addr, &addr); |
| 276 | *new_pc = addr; |
| 277 | return (error); |
| 278 | case 0x1: /* mov pc, reg */ |
| 279 | *new_pc = fetch_reg(cookie, insn & 0xf); |
no outgoing calls
no test coverage detected