* Execute the current unwind instruction. */
| 284 | * Execute the current unwind instruction. |
| 285 | */ |
| 286 | static int unwind_exec_insn(struct unwind_ctrl_block *ctrl) |
| 287 | { |
| 288 | unsigned long insn = unwind_get_byte(ctrl); |
| 289 | int ret = URC_OK; |
| 290 | |
| 291 | LOG_D("%s: insn = %08lx", __func__, insn); |
| 292 | |
| 293 | if ((insn & 0xc0) == 0x00) |
| 294 | ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4; |
| 295 | else if ((insn & 0xc0) == 0x40) |
| 296 | ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4; |
| 297 | else if ((insn & 0xf0) == 0x80) |
| 298 | { |
| 299 | unsigned long mask; |
| 300 | |
| 301 | insn = (insn << 8) | unwind_get_byte(ctrl); |
| 302 | mask = insn & 0x0fff; |
| 303 | if (mask == 0) |
| 304 | { |
| 305 | LOG_W("unwind: 'Refuse to unwind' instruction %04lx", |
| 306 | insn); |
| 307 | return -URC_FAILURE; |
| 308 | } |
| 309 | |
| 310 | ret = unwind_exec_pop_subset_r4_to_r13(ctrl, mask); |
| 311 | if (ret) |
| 312 | goto error; |
| 313 | } |
| 314 | else if ((insn & 0xf0) == 0x90 && |
| 315 | (insn & 0x0d) != 0x0d) |
| 316 | ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f]; |
| 317 | else if ((insn & 0xf0) == 0xa0) |
| 318 | { |
| 319 | ret = unwind_exec_pop_r4_to_rN(ctrl, insn); |
| 320 | if (ret) |
| 321 | goto error; |
| 322 | } |
| 323 | else if (insn == 0xb0) |
| 324 | { |
| 325 | if (ctrl->vrs[PC] == 0) |
| 326 | ctrl->vrs[PC] = ctrl->vrs[LR]; |
| 327 | /* no further processing */ |
| 328 | ctrl->entries = 0; |
| 329 | } |
| 330 | else if (insn == 0xb1) |
| 331 | { |
| 332 | unsigned long mask = unwind_get_byte(ctrl); |
| 333 | |
| 334 | if (mask == 0 || mask & 0xf0) |
| 335 | { |
| 336 | LOG_W("unwind: Spare encoding %04lx", |
| 337 | (insn << 8) | mask); |
| 338 | return -URC_FAILURE; |
| 339 | } |
| 340 | |
| 341 | ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask); |
| 342 | if (ret) |
| 343 | goto error; |
no test coverage detected