Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2011-09-15 09:30:03 +0200
committerJan Beulich <jbeulich@novell.com>2011-09-15 09:30:03 +0200
commit4d917a5987c8da82c544ba0ae9a797181715d08b (patch)
tree58ecd134090a2e94d87001a5f6bdf24dc9c38263
parent165c304c9a1ef1d5f3875e10e1161c67b7fc720e (diff)
- patches.arch/x86_64-unwind-annotations: Fix unwinding through
interrupt frames, requiring ... - patches.suse/stack-unwind: ... support for DW_CFA_def_cfa_expression.
-rw-r--r--patches.arch/x86_64-unwind-annotations56
-rw-r--r--patches.suse/stack-unwind374
2 files changed, 398 insertions, 32 deletions
diff --git a/patches.arch/x86_64-unwind-annotations b/patches.arch/x86_64-unwind-annotations
index 26ff36acd1..b00d82713b 100644
--- a/patches.arch/x86_64-unwind-annotations
+++ b/patches.arch/x86_64-unwind-annotations
@@ -3,6 +3,30 @@ Subject: fix unwind annotations
Patch-mainline: tbd
References: bnc#472783, bnc#588458
+---
+ arch/x86/include/asm/dwarf2.h | 2
+ arch/x86/kernel/entry_64.S | 115 ++++++++++++++++++++++--------------------
+ arch/x86/kernel/head_64.S | 13 ++++
+ 3 files changed, 77 insertions(+), 53 deletions(-)
+
+--- a/arch/x86/include/asm/dwarf2.h
++++ b/arch/x86/include/asm/dwarf2.h
+@@ -27,6 +27,7 @@
+ #define CFI_REMEMBER_STATE .cfi_remember_state
+ #define CFI_RESTORE_STATE .cfi_restore_state
+ #define CFI_UNDEFINED .cfi_undefined
++#define CFI_ESCAPE .cfi_escape
+
+ #ifdef CONFIG_AS_CFI_SIGNAL_FRAME
+ #define CFI_SIGNAL_FRAME .cfi_signal_frame
+@@ -69,6 +70,7 @@
+ #define CFI_REMEMBER_STATE cfi_ignore
+ #define CFI_RESTORE_STATE cfi_ignore
+ #define CFI_UNDEFINED cfi_ignore
++#define CFI_ESCAPE cfi_ignore
+ #define CFI_SIGNAL_FRAME cfi_ignore
+
+ #endif
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -238,21 +238,21 @@ ENDPROC(native_usergs_sysret64)
@@ -61,7 +85,7 @@ References: bnc#472783, bnc#588458
CFI_REL_OFFSET rbx, RBX+\offset
CFI_REL_OFFSET rbp, RBP+\offset
CFI_REL_OFFSET r12, R12+\offset
-@@ -331,23 +334,24 @@ ENDPROC(native_usergs_sysret64)
+@@ -331,23 +334,28 @@ ENDPROC(native_usergs_sysret64)
1: incl PER_CPU_VAR(irq_count)
jne 2f
mov PER_CPU_VAR(irq_stack_ptr),%rsp
@@ -70,7 +94,11 @@ References: bnc#472783, bnc#588458
2: /* Store previous stack value */
pushq %rsi
-+ /* XXX CFI_DEF_CFA_... (%rsp) */
++ CFI_ESCAPE 0x0f /* DW_CFA_def_cfa_expression */, 6, \
++ 0x77 /* DW_OP_breg7 */, 0, \
++ 0x06 /* DW_OP_deref */, \
++ 0x08 /* DW_OP_const1u */, SS+8-RBP, \
++ 0x22 /* DW_OP_plus */
/* We entered an interrupt context - irqs are off: */
TRACE_IRQS_OFF
.endm
@@ -94,7 +122,7 @@ References: bnc#472783, bnc#588458
movq %r11, 8(%rsp) /* return address */
FIXUP_TOP_OF_STACK %r11, 16
ret
-@@ -357,23 +361,23 @@ END(save_rest)
+@@ -357,23 +365,23 @@ END(save_rest)
/* save complete stack frame */
.pushsection .kprobes.text, "ax"
ENTRY(save_paranoid)
@@ -130,7 +158,7 @@ References: bnc#472783, bnc#588458
movl $1,%ebx
movl $MSR_GS_BASE,%ecx
rdmsr
-@@ -675,7 +679,7 @@ ENTRY(\label)
+@@ -675,7 +683,7 @@ ENTRY(\label)
subq $REST_SKIP, %rsp
CFI_ADJUST_CFA_OFFSET REST_SKIP
call save_rest
@@ -139,7 +167,7 @@ References: bnc#472783, bnc#588458
leaq 8(%rsp), \arg /* pt_regs pointer */
call \func
jmp ptregscall_common
-@@ -788,7 +792,6 @@ END(interrupt)
+@@ -788,7 +796,6 @@ END(interrupt)
subq $ORIG_RAX-RBP, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-RBP
SAVE_ARGS_IRQ
@@ -147,7 +175,7 @@ References: bnc#472783, bnc#588458
call \func
.endm
-@@ -813,10 +816,10 @@ ret_from_intr:
+@@ -813,10 +820,10 @@ ret_from_intr:
/* Restore saved previous stack */
popq %rsi
@@ -161,7 +189,7 @@ References: bnc#472783, bnc#588458
exit_intr:
GET_THREAD_INFO(%rcx)
-@@ -1016,7 +1019,7 @@ ENTRY(\sym)
+@@ -1016,7 +1023,7 @@ ENTRY(\sym)
subq $ORIG_RAX-R15, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
call error_entry
@@ -170,7 +198,7 @@ References: bnc#472783, bnc#588458
movq %rsp,%rdi /* pt_regs pointer */
xorl %esi,%esi /* no error code */
call \do_sym
-@@ -1033,6 +1036,7 @@ ENTRY(\sym)
+@@ -1033,6 +1040,7 @@ ENTRY(\sym)
subq $ORIG_RAX-R15, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
call save_paranoid
@@ -178,7 +206,7 @@ References: bnc#472783, bnc#588458
TRACE_IRQS_OFF
movq %rsp,%rdi /* pt_regs pointer */
xorl %esi,%esi /* no error code */
-@@ -1051,6 +1055,7 @@ ENTRY(\sym)
+@@ -1051,6 +1059,7 @@ ENTRY(\sym)
subq $ORIG_RAX-R15, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
call save_paranoid
@@ -186,7 +214,7 @@ References: bnc#472783, bnc#588458
TRACE_IRQS_OFF
movq %rsp,%rdi /* pt_regs pointer */
xorl %esi,%esi /* no error code */
-@@ -1069,7 +1074,7 @@ ENTRY(\sym)
+@@ -1069,7 +1078,7 @@ ENTRY(\sym)
subq $ORIG_RAX-R15, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
call error_entry
@@ -195,7 +223,7 @@ References: bnc#472783, bnc#588458
movq %rsp,%rdi /* pt_regs pointer */
movq ORIG_RAX(%rsp),%rsi /* get error code */
movq $-1,ORIG_RAX(%rsp) /* no syscall to restart */
-@@ -1087,7 +1092,7 @@ ENTRY(\sym)
+@@ -1087,7 +1096,7 @@ ENTRY(\sym)
subq $ORIG_RAX-R15, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
call save_paranoid
@@ -204,7 +232,7 @@ References: bnc#472783, bnc#588458
TRACE_IRQS_OFF
movq %rsp,%rdi /* pt_regs pointer */
movq ORIG_RAX(%rsp),%rsi /* get error code */
-@@ -1431,25 +1436,24 @@ END(paranoid_exit)
+@@ -1431,25 +1440,24 @@ END(paranoid_exit)
* returns in "no swapgs flag" in %ebx.
*/
ENTRY(error_entry)
@@ -245,7 +273,7 @@ References: bnc#472783, bnc#588458
xorl %ebx,%ebx
testl $3,CS+8(%rsp)
je error_kernelspace
-@@ -1467,6 +1471,7 @@ error_sti:
+@@ -1467,6 +1475,7 @@ error_sti:
* compat mode. Check for these here too.
*/
error_kernelspace:
@@ -253,7 +281,7 @@ References: bnc#472783, bnc#588458
incl %ebx
leaq irq_return(%rip),%rcx
cmpq %rcx,RIP+8(%rsp)
-@@ -1514,7 +1519,7 @@ ENTRY(nmi)
+@@ -1514,7 +1523,7 @@ ENTRY(nmi)
subq $ORIG_RAX-R15, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
call save_paranoid
diff --git a/patches.suse/stack-unwind b/patches.suse/stack-unwind
index 1646feae99..a71f0b5435 100644
--- a/patches.suse/stack-unwind
+++ b/patches.suse/stack-unwind
@@ -9,6 +9,8 @@ Update Jan 17 2009 jeffm:
that up.
Update Jul 02 2010 jbeulich:
- fix after upstream commit 9e565292270a2d55524be38835104c564ac8f795
+Update Sep 15 2011 jbeulich:
+- add support for DW_CFA_def_cfa_expression (needed by x86-64)
---
Makefile | 5
@@ -17,22 +19,22 @@ Update Jul 02 2010 jbeulich:
arch/x86/include/asm/dwarf2.h | 3
arch/x86/include/asm/stacktrace.h | 4
arch/x86/include/asm/system.h | 10
- arch/x86/include/asm/unwind.h | 163 ++++
arch/x86/kernel/dumpstack.c | 89 ++
- arch/x86/kernel/dumpstack_32.c | 5
- arch/x86/kernel/dumpstack_64.c | 8
- arch/x86/kernel/entry_32.S | 35 +
+ arch/x86/kernel/dumpstack_32.c | 4
+ arch/x86/kernel/dumpstack_64.c | 7
+ arch/x86/kernel/entry_32.S | 35
arch/x86/kernel/entry_64.S | 34
arch/x86/kernel/vmlinux.lds.S | 2
+ b/arch/x86/include/asm/unwind.h | 163 +++
+ b/include/linux/unwind.h | 135 +++
+ b/kernel/unwind.c | 1641 ++++++++++++++++++++++++++++++++++++++
include/asm-generic/vmlinux.lds.h | 22
include/linux/module.h | 3
- include/linux/unwind.h | 135 +++
init/main.c | 3
kernel/Makefile | 1
kernel/module.c | 32
- kernel/unwind.c | 1303 ++++++++++++++++++++++++++++++++++++++
lib/Kconfig.debug | 18
- 21 files changed, 1874 insertions(+), 5 deletions(-)
+ 21 files changed, 2212 insertions(+), 3 deletions(-)
--- a/Makefile
+++ b/Makefile
@@ -843,7 +845,7 @@ Update Jul 02 2010 jbeulich:
mod->symtab = mod->core_symtab;
--- /dev/null
+++ b/kernel/unwind.c
-@@ -0,0 +1,1305 @@
+@@ -0,0 +1,1641 @@
+/*
+ * Copyright (C) 2002-2006 Novell, Inc.
+ * Jan Beulich <jbeulich@novell.com>
@@ -939,6 +941,62 @@ Update Jul 02 2010 jbeulich:
+#define DW_EH_PE_indirect 0x80
+#define DW_EH_PE_omit 0xff
+
++#define DW_OP_addr 0x03
++#define DW_OP_deref 0x06
++#define DW_OP_const1u 0x08
++#define DW_OP_const1s 0x09
++#define DW_OP_const2u 0x0a
++#define DW_OP_const2s 0x0b
++#define DW_OP_const4u 0x0c
++#define DW_OP_const4s 0x0d
++#define DW_OP_const8u 0x0e
++#define DW_OP_const8s 0x0f
++#define DW_OP_constu 0x10
++#define DW_OP_consts 0x11
++#define DW_OP_dup 0x12
++#define DW_OP_drop 0x13
++#define DW_OP_over 0x14
++#define DW_OP_pick 0x15
++#define DW_OP_swap 0x16
++#define DW_OP_rot 0x17
++#define DW_OP_xderef 0x18
++#define DW_OP_abs 0x19
++#define DW_OP_and 0x1a
++#define DW_OP_div 0x1b
++#define DW_OP_minus 0x1c
++#define DW_OP_mod 0x1d
++#define DW_OP_mul 0x1e
++#define DW_OP_neg 0x1f
++#define DW_OP_not 0x20
++#define DW_OP_or 0x21
++#define DW_OP_plus 0x22
++#define DW_OP_plus_uconst 0x23
++#define DW_OP_shl 0x24
++#define DW_OP_shr 0x25
++#define DW_OP_shra 0x26
++#define DW_OP_xor 0x27
++#define DW_OP_bra 0x28
++#define DW_OP_eq 0x29
++#define DW_OP_ge 0x2a
++#define DW_OP_gt 0x2b
++#define DW_OP_le 0x2c
++#define DW_OP_lt 0x2d
++#define DW_OP_ne 0x2e
++#define DW_OP_skip 0x2f
++#define DW_OP_lit0 0x30
++#define DW_OP_lit31 0x4f
++#define DW_OP_reg0 0x50
++#define DW_OP_reg31 0x6f
++#define DW_OP_breg0 0x70
++#define DW_OP_breg31 0x8f
++#define DW_OP_regx 0x90
++#define DW_OP_fbreg 0x91
++#define DW_OP_bregx 0x92
++#define DW_OP_piece 0x93
++#define DW_OP_deref_size 0x94
++#define DW_OP_xderef_size 0x95
++#define DW_OP_nop 0x96
++
+typedef unsigned long uleb128_t;
+typedef signed long sleb128_t;
+#define sleb128abs __builtin_labs
@@ -972,7 +1030,8 @@ Update Jul 02 2010 jbeulich:
+ uleb128_t codeAlign;
+ sleb128_t dataAlign;
+ struct cfa {
-+ uleb128_t reg, offs;
++ uleb128_t reg, offs, elen;
++ const u8 *expr;
+ } cfa;
+ struct unwind_item regs[ARRAY_SIZE(reg_info)];
+ unsigned stackDepth:8;
@@ -1586,6 +1645,8 @@ Update Jul 02 2010 jbeulich:
+ value = get_uleb128(&ptr.p8, end);
+ set_rule(value, Value, get_sleb128(&ptr.p8, end), state);
+ break;
++ /*todo case DW_CFA_expression: */
++ /*todo case DW_CFA_val_expression: */
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
@@ -1627,12 +1688,14 @@ Update Jul 02 2010 jbeulich:
+ break;
+ case DW_CFA_def_cfa:
+ state->cfa.reg = get_uleb128(&ptr.p8, end);
++ state->cfa.elen = 0;
+ /*nobreak*/
+ case DW_CFA_def_cfa_offset:
+ state->cfa.offs = get_uleb128(&ptr.p8, end);
+ break;
+ case DW_CFA_def_cfa_sf:
+ state->cfa.reg = get_uleb128(&ptr.p8, end);
++ state->cfa.elen = 0;
+ /*nobreak*/
+ case DW_CFA_def_cfa_offset_sf:
+ state->cfa.offs = get_sleb128(&ptr.p8, end)
@@ -1640,10 +1703,17 @@ Update Jul 02 2010 jbeulich:
+ break;
+ case DW_CFA_def_cfa_register:
+ state->cfa.reg = get_uleb128(&ptr.p8, end);
++ state->cfa.elen = 0;
++ break;
++ case DW_CFA_def_cfa_expression:
++ state->cfa.elen = get_uleb128(&ptr.p8, end);
++ if (!state->cfa.elen) {
++ dprintk(1, "Zero-length CFA expression.");
++ return 0;
++ }
++ state->cfa.expr = ptr.p8;
++ ptr.p8 += state->cfa.elen;
+ break;
-+ /*todo case DW_CFA_def_cfa_expression: */
-+ /*todo case DW_CFA_expression: */
-+ /*todo case DW_CFA_val_expression: */
+ case DW_CFA_GNU_args_size:
+ get_uleb128(&ptr.p8, end);
+ break;
@@ -1691,6 +1761,265 @@ Update Jul 02 2010 jbeulich:
+ targetLoc < state->loc &&*/ state->label == NULL));
+}
+
++static unsigned long evaluate(const u8 *expr, const u8 *end,
++ const struct unwind_frame_info *frame)
++{
++ union {
++ const u8 *pu8;
++ const s8 *ps8;
++ const u16 *pu16;
++ const s16 *ps16;
++ const u32 *pu32;
++ const s32 *ps32;
++ const u64 *pu64;
++ const s64 *ps64;
++ } ptr = { expr };
++ unsigned long stack[8], val1, val2;
++ unsigned int stidx = 0;
++#define PUSH(v) ({ unsigned long v__ = (v); if (stidx >= ARRAY_SIZE(stack)) return 0; stack[stidx++] = v__; })
++#define POP() ({ if (!stidx) return 0; stack[--stidx]; })
++
++ while (ptr.pu8 < end) {
++ switch (*ptr.pu8++) {
++ /*todo case DW_OP_addr: */
++ case DW_OP_deref:
++ val1 = POP();
++ if (probe_kernel_address(val1, val2)) {
++ dprintk(1, "Cannot de-reference %lx (%p,%p).", val1, ptr.pu8 - 1, end);
++ return 0;
++ }
++ PUSH(val2);
++ break;
++ /*todo? case DW_OP_xderef: */
++ /*todo case DW_OP_deref_size: */
++ /*todo? case DW_OP_xderef_size: */
++ case DW_OP_const1u:
++ if (ptr.pu8 < end)
++ PUSH(*ptr.pu8);
++ ++ptr.pu8;
++ break;
++ case DW_OP_const1s:
++ if (ptr.pu8 < end)
++ PUSH(*ptr.ps8);
++ ++ptr.ps8;
++ break;
++ case DW_OP_const2u:
++ if (ptr.pu8 + 1 < end)
++ PUSH(*ptr.pu16);
++ ++ptr.pu16;
++ break;
++ case DW_OP_const2s:
++ if (ptr.pu8 + 1 < end)
++ PUSH(*ptr.ps16);
++ ++ptr.ps16;
++ break;
++ case DW_OP_const4u:
++ if (ptr.pu8 + 3 < end)
++ PUSH(*ptr.pu32);
++ ++ptr.pu32;
++ break;
++ case DW_OP_const4s:
++ if (ptr.pu8 + 3 < end)
++ PUSH(*ptr.ps32);
++ ++ptr.ps32;
++ break;
++ case DW_OP_const8u:
++ if (ptr.pu8 + 7 < end)
++ PUSH(*ptr.pu64);
++ ++ptr.pu64;
++ break;
++ case DW_OP_const8s:
++ if (ptr.pu8 + 7 < end)
++ PUSH(*ptr.ps64);
++ ++ptr.ps64;
++ break;
++ case DW_OP_constu:
++ PUSH(get_uleb128(&ptr.pu8, end));
++ break;
++ case DW_OP_consts:
++ PUSH(get_sleb128(&ptr.pu8, end));
++ break;
++ case DW_OP_dup:
++ if (!stidx)
++ return 0;
++ PUSH(stack[stidx - 1]);
++ break;
++ case DW_OP_drop:
++ (void)POP();
++ break;
++ case DW_OP_over:
++ if (stidx <= 1)
++ return 0;
++ PUSH(stack[stidx - 2]);
++ break;
++ case DW_OP_pick:
++ if (ptr.pu8 < end) {
++ if (stidx <= *ptr.pu8)
++ return 0;
++ PUSH(stack[stidx - *ptr.pu8 - 1]);
++ }
++ ++ptr.pu8;
++ break;
++ case DW_OP_swap:
++ if (stidx <= 1)
++ return 0;
++ val1 = stack[stidx - 1];
++ stack[stidx - 1] = stack[stidx - 2];
++ stack[stidx - 2] = val1;
++ break;
++ case DW_OP_rot:
++ if (stidx <= 2)
++ return 0;
++ val1 = stack[stidx - 1];
++ stack[stidx - 1] = stack[stidx - 2];
++ stack[stidx - 2] = stack[stidx - 3];
++ stack[stidx - 3] = val1;
++ break;
++ case DW_OP_abs:
++ PUSH(__builtin_labs(POP()));
++ break;
++ case DW_OP_and:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 & val1);
++ break;
++ case DW_OP_div:
++ val1 = POP();
++ if (!val1)
++ return 0;
++ val2 = POP();
++ PUSH(val2 / val1);
++ break;
++ case DW_OP_minus:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 - val1);
++ break;
++ case DW_OP_mod:
++ val1 = POP();
++ if (!val1)
++ return 0;
++ val2 = POP();
++ PUSH(val2 % val1);
++ break;
++ case DW_OP_mul:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 * val1);
++ break;
++ case DW_OP_neg:
++ PUSH(-(long)POP());
++ break;
++ case DW_OP_not:
++ PUSH(~POP());
++ break;
++ case DW_OP_or:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 | val1);
++ break;
++ case DW_OP_plus:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 + val1);
++ break;
++ case DW_OP_plus_uconst:
++ PUSH(POP() + get_uleb128(&ptr.pu8, end));
++ break;
++ case DW_OP_shl:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val1 < BITS_PER_LONG ? val2 << val1 : 0);
++ break;
++ case DW_OP_shr:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val1 < BITS_PER_LONG ? val2 >> val1 : 0);
++ break;
++ case DW_OP_shra:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val1 < BITS_PER_LONG ? (long)val2 >> val1 : (val2 < 0 ? -1 : 0));
++ break;
++ case DW_OP_xor:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 ^ val1);
++ break;
++ case DW_OP_bra:
++ if (!POP()) {
++ ++ptr.ps16;
++ break;
++ }
++ /*nobreak*/
++ case DW_OP_skip:
++ if (ptr.pu8 + 1 < end) {
++ ptr.pu8 += *ptr.ps16;
++ if (ptr.pu8 < expr)
++ return 0;
++ } else
++ ++ptr.ps16;
++ break;
++ case DW_OP_eq:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 == val1);
++ break;
++ case DW_OP_ne:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 != val1);
++ break;
++ case DW_OP_lt:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 < val1);
++ break;
++ case DW_OP_le:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 <= val1);
++ case DW_OP_ge:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 >= val1);
++ break;
++ case DW_OP_gt:
++ val1 = POP();
++ val2 = POP();
++ PUSH(val2 > val1);
++ break;
++ case DW_OP_lit0 ... DW_OP_lit31:
++ PUSH(ptr.pu8[-1] - DW_OP_lit0);
++ break;
++ case DW_OP_breg0 ... DW_OP_breg31:
++ val1 = ptr.pu8[-1] - DW_OP_breg0;
++ if (0)
++ case DW_OP_bregx:
++ val1 = get_uleb128(&ptr.pu8, end);
++ if (val1 >= ARRAY_SIZE(reg_info)
++ || reg_info[val1].width != sizeof(unsigned long))
++ return 0;
++ PUSH(((const unsigned long *)frame)[reg_info[val1].offs]
++ + get_sleb128(&ptr.pu8, end));
++ break;
++ /*todo? case DW_OP_fbreg: */
++ /*todo? case DW_OP_piece: */
++ case DW_OP_nop:
++ break;
++ default:
++ dprintk(1, "Unsupported expression op %02x (%p,%p).", ptr.pu8[-1], ptr.pu8 - 1, end);
++ return 0;
++ }
++ }
++ if (ptr.pu8 > end)
++ return 0;
++ val1 = POP();
++#undef POP
++#undef PUSH
++ return val1;
++}
++
+/* Unwind to previous to frame. Returns 0 if successful, negative
+ * number in case of an error. */
+int unwind(struct unwind_frame_info *frame)
@@ -1947,21 +2276,30 @@ Update Jul 02 2010 jbeulich:
+ /* process instructions */
+ if (!processCFI(ptr, end, pc, ptrType, &state)
+ || state.loc > endLoc
-+ || state.regs[retAddrReg].where == Nowhere
-+ || state.cfa.reg >= ARRAY_SIZE(reg_info)
-+ || reg_info[state.cfa.reg].width != sizeof(unsigned long)
-+ || FRAME_REG(state.cfa.reg, unsigned long) % sizeof(unsigned long)
-+ || state.cfa.offs % sizeof(unsigned long)) {
++ || state.regs[retAddrReg].where == Nowhere) {
+ dprintk(1, "Unusable unwind info (%p,%p).", ptr, end);
+ return -EIO;
+ }
++ if (state.cfa.elen) {
++ cfa = evaluate(state.cfa.expr, state.cfa.expr + state.cfa.elen, frame);
++ if (!cfa) {
++ dprintk(1, "Bad CFA expr (%p:%lu).", state.cfa.expr, state.cfa.elen);
++ return -EIO;
++ }
++ } else if (state.cfa.reg >= ARRAY_SIZE(reg_info)
++ || reg_info[state.cfa.reg].width != sizeof(unsigned long)
++ || FRAME_REG(state.cfa.reg, unsigned long) % sizeof(unsigned long)
++ || state.cfa.offs % sizeof(unsigned long)) {
++ dprintk(1, "Bad CFA (%lu,%lx).", state.cfa.reg, state.cfa.offs);
++ return -EIO;
++ } else
++ cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
+ /* update frame */
+#ifndef CONFIG_AS_CFI_SIGNAL_FRAME
+ if (frame->call_frame
+ && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
+ frame->call_frame = 0;
+#endif
-+ cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
+ startLoc = min((unsigned long)UNW_SP(frame), cfa);
+ endLoc = max((unsigned long)UNW_SP(frame), cfa);
+ if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {