aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/unwind.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/unwind.c')
-rw-r--r--arch/arm/kernel/unwind.c137
1 files changed, 100 insertions, 37 deletions
diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
index 00df012c4678..3c217694ebec 100644
--- a/arch/arm/kernel/unwind.c
+++ b/arch/arm/kernel/unwind.c
@@ -68,6 +68,12 @@ EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);
68struct unwind_ctrl_block { 68struct unwind_ctrl_block {
69 unsigned long vrs[16]; /* virtual register set */ 69 unsigned long vrs[16]; /* virtual register set */
70 const unsigned long *insn; /* pointer to the current instructions word */ 70 const unsigned long *insn; /* pointer to the current instructions word */
71 unsigned long sp_high; /* highest value of sp allowed */
72 /*
73 * 1 : check for stack overflow for each register pop.
74 * 0 : save overhead if there is plenty of stack remaining.
75 */
76 int check_each_pop;
71 int entries; /* number of entries left to interpret */ 77 int entries; /* number of entries left to interpret */
72 int byte; /* current byte number in the instructions word */ 78 int byte; /* current byte number in the instructions word */
73}; 79};
@@ -235,12 +241,85 @@ static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
235 return ret; 241 return ret;
236} 242}
237 243
244/* Before poping a register check whether it is feasible or not */
245static int unwind_pop_register(struct unwind_ctrl_block *ctrl,
246 unsigned long **vsp, unsigned int reg)
247{
248 if (unlikely(ctrl->check_each_pop))
249 if (*vsp >= (unsigned long *)ctrl->sp_high)
250 return -URC_FAILURE;
251
252 ctrl->vrs[reg] = *(*vsp)++;
253 return URC_OK;
254}
255
256/* Helper functions to execute the instructions */
257static int unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_block *ctrl,
258 unsigned long mask)
259{
260 unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
261 int load_sp, reg = 4;
262
263 load_sp = mask & (1 << (13 - 4));
264 while (mask) {
265 if (mask & 1)
266 if (unwind_pop_register(ctrl, &vsp, reg))
267 return -URC_FAILURE;
268 mask >>= 1;
269 reg++;
270 }
271 if (!load_sp)
272 ctrl->vrs[SP] = (unsigned long)vsp;
273
274 return URC_OK;
275}
276
277static int unwind_exec_pop_r4_to_rN(struct unwind_ctrl_block *ctrl,
278 unsigned long insn)
279{
280 unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
281 int reg;
282
283 /* pop R4-R[4+bbb] */
284 for (reg = 4; reg <= 4 + (insn & 7); reg++)
285 if (unwind_pop_register(ctrl, &vsp, reg))
286 return -URC_FAILURE;
287
288 if (insn & 0x80)
289 if (unwind_pop_register(ctrl, &vsp, 14))
290 return -URC_FAILURE;
291
292 ctrl->vrs[SP] = (unsigned long)vsp;
293
294 return URC_OK;
295}
296
297static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_block *ctrl,
298 unsigned long mask)
299{
300 unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
301 int reg = 0;
302
303 /* pop R0-R3 according to mask */
304 while (mask) {
305 if (mask & 1)
306 if (unwind_pop_register(ctrl, &vsp, reg))
307 return -URC_FAILURE;
308 mask >>= 1;
309 reg++;
310 }
311 ctrl->vrs[SP] = (unsigned long)vsp;
312
313 return URC_OK;
314}
315
238/* 316/*
239 * Execute the current unwind instruction. 317 * Execute the current unwind instruction.
240 */ 318 */
241static int unwind_exec_insn(struct unwind_ctrl_block *ctrl) 319static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
242{ 320{
243 unsigned long insn = unwind_get_byte(ctrl); 321 unsigned long insn = unwind_get_byte(ctrl);
322 int ret = URC_OK;
244 323
245 pr_debug("%s: insn = %08lx\n", __func__, insn); 324 pr_debug("%s: insn = %08lx\n", __func__, insn);
246 325
@@ -250,8 +329,6 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
250 ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4; 329 ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4;
251 else if ((insn & 0xf0) == 0x80) { 330 else if ((insn & 0xf0) == 0x80) {
252 unsigned long mask; 331 unsigned long mask;
253 unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
254 int load_sp, reg = 4;
255 332
256 insn = (insn << 8) | unwind_get_byte(ctrl); 333 insn = (insn << 8) | unwind_get_byte(ctrl);
257 mask = insn & 0x0fff; 334 mask = insn & 0x0fff;
@@ -261,29 +338,16 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
261 return -URC_FAILURE; 338 return -URC_FAILURE;
262 } 339 }
263 340
264 /* pop R4-R15 according to mask */ 341 ret = unwind_exec_pop_subset_r4_to_r13(ctrl, mask);
265 load_sp = mask & (1 << (13 - 4)); 342 if (ret)
266 while (mask) { 343 goto error;
267 if (mask & 1)
268 ctrl->vrs[reg] = *vsp++;
269 mask >>= 1;
270 reg++;
271 }
272 if (!load_sp)
273 ctrl->vrs[SP] = (unsigned long)vsp;
274 } else if ((insn & 0xf0) == 0x90 && 344 } else if ((insn & 0xf0) == 0x90 &&
275 (insn & 0x0d) != 0x0d) 345 (insn & 0x0d) != 0x0d)
276 ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f]; 346 ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f];
277 else if ((insn & 0xf0) == 0xa0) { 347 else if ((insn & 0xf0) == 0xa0) {
278 unsigned long *vsp = (unsigned long *)ctrl->vrs[SP]; 348 ret = unwind_exec_pop_r4_to_rN(ctrl, insn);
279 int reg; 349 if (ret)
280 350 goto error;
281 /* pop R4-R[4+bbb] */
282 for (reg = 4; reg <= 4 + (insn & 7); reg++)
283 ctrl->vrs[reg] = *vsp++;
284 if (insn & 0x80)
285 ctrl->vrs[14] = *vsp++;
286 ctrl->vrs[SP] = (unsigned long)vsp;
287 } else if (insn == 0xb0) { 351 } else if (insn == 0xb0) {
288 if (ctrl->vrs[PC] == 0) 352 if (ctrl->vrs[PC] == 0)
289 ctrl->vrs[PC] = ctrl->vrs[LR]; 353 ctrl->vrs[PC] = ctrl->vrs[LR];
@@ -291,8 +355,6 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
291 ctrl->entries = 0; 355 ctrl->entries = 0;
292 } else if (insn == 0xb1) { 356 } else if (insn == 0xb1) {
293 unsigned long mask = unwind_get_byte(ctrl); 357 unsigned long mask = unwind_get_byte(ctrl);
294 unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
295 int reg = 0;
296 358
297 if (mask == 0 || mask & 0xf0) { 359 if (mask == 0 || mask & 0xf0) {
298 pr_warning("unwind: Spare encoding %04lx\n", 360 pr_warning("unwind: Spare encoding %04lx\n",
@@ -300,14 +362,9 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
300 return -URC_FAILURE; 362 return -URC_FAILURE;
301 } 363 }
302 364
303 /* pop R0-R3 according to mask */ 365 ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask);
304 while (mask) { 366 if (ret)
305 if (mask & 1) 367 goto error;
306 ctrl->vrs[reg] = *vsp++;
307 mask >>= 1;
308 reg++;
309 }
310 ctrl->vrs[SP] = (unsigned long)vsp;
311 } else if (insn == 0xb2) { 368 } else if (insn == 0xb2) {
312 unsigned long uleb128 = unwind_get_byte(ctrl); 369 unsigned long uleb128 = unwind_get_byte(ctrl);
313 370
@@ -320,7 +377,8 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
320 pr_debug("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx\n", __func__, 377 pr_debug("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx\n", __func__,
321 ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]); 378 ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
322 379
323 return URC_OK; 380error:
381 return ret;
324} 382}
325 383
326/* 384/*
@@ -329,13 +387,13 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
329 */ 387 */
330int unwind_frame(struct stackframe *frame) 388int unwind_frame(struct stackframe *frame)
331{ 389{
332 unsigned long high, low; 390 unsigned long low;
333 const struct unwind_idx *idx; 391 const struct unwind_idx *idx;
334 struct unwind_ctrl_block ctrl; 392 struct unwind_ctrl_block ctrl;
335 393
336 /* only go to a higher address on the stack */ 394 /* store the highest address on the stack to avoid crossing it*/
337 low = frame->sp; 395 low = frame->sp;
338 high = ALIGN(low, THREAD_SIZE); 396 ctrl.sp_high = ALIGN(low, THREAD_SIZE);
339 397
340 pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__, 398 pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__,
341 frame->pc, frame->lr, frame->sp); 399 frame->pc, frame->lr, frame->sp);
@@ -382,11 +440,16 @@ int unwind_frame(struct stackframe *frame)
382 return -URC_FAILURE; 440 return -URC_FAILURE;
383 } 441 }
384 442
443 ctrl.check_each_pop = 0;
444
385 while (ctrl.entries > 0) { 445 while (ctrl.entries > 0) {
386 int urc = unwind_exec_insn(&ctrl); 446 int urc;
447 if ((ctrl.sp_high - ctrl.vrs[SP]) < sizeof(ctrl.vrs))
448 ctrl.check_each_pop = 1;
449 urc = unwind_exec_insn(&ctrl);
387 if (urc < 0) 450 if (urc < 0)
388 return urc; 451 return urc;
389 if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high) 452 if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= ctrl.sp_high)
390 return -URC_FAILURE; 453 return -URC_FAILURE;
391 } 454 }
392 455