From: Don Zickus <dzickus@redhat.com> Subject: [RHEL-5 PATCH 1/2] remove unwinder patches from x86/x86_64 Date: Tue, 2 Jan 2007 17:08:23 -0500 Bugzilla: 220238 Message-Id: <20070102220823.GL5381@redhat.com> Changelog: x86: remove unwinder patches from x86/x86_64 bugzilla: 220238 The unwinder patches were dropped upstream, no need to support them in RHEL-5 either. I tested the changes by running them through the normal kernel level testing, the rhts kexec/kdump testing, and some manual panicing. No ill effects were noticed. The config changes: #Index: configs/config-generic #=================================================================== #RCS file: /cvs/dist/rpms/kernel/RHEL-5/configs/config-generic,v #retrieving revision 1.262 #diff -u -r1.262 config-generic #--- configs/config-generic 15 Dec 2006 23:48:13 -0000 1.262 #+++ configs/config-generic 2 Jan 2007 22:02:36 -0000 #@@ -2841,9 +2841,6 @@ ## END of ISA options. -CONFIG_UNWIND_INFO=y -CONFIG_STACK_UNWIND=y - # CONFIG_FORCED_INLINING is not set CONFIG_MIGRATION=y The upstream stream changed (modified for RHEL-5) and the xen part: Index: latest/Makefile =================================================================== --- latest.orig/Makefile +++ latest/Makefile @@ -487,10 +487,6 @@ else CFLAGS += -fomit-frame-pointer endif -ifdef CONFIG_UNWIND_INFO -CFLAGS += -fasynchronous-unwind-tables -endif - ifdef CONFIG_DEBUG_INFO CFLAGS += -g endif Index: latest/arch/i386/kernel/entry.S =================================================================== --- latest.orig/arch/i386/kernel/entry.S +++ latest/arch/i386/kernel/entry.S @@ -927,37 +927,6 @@ ENTRY(spurious_interrupt_bug) jmp error_code CFI_ENDPROC -#ifdef CONFIG_STACK_UNWIND -ENTRY(arch_unwind_init_running) - CFI_STARTPROC - movl 4(%esp), %edx - movl (%esp), %ecx - leal 4(%esp), %eax - movl %ebx, EBX(%edx) - xorl %ebx, %ebx - movl %ebx, ECX(%edx) - movl %ebx, EDX(%edx) - movl %esi, ESI(%edx) - movl %edi, EDI(%edx) - movl %ebp, EBP(%edx) - movl %ebx, EAX(%edx) - movl $__USER_DS, DS(%edx) - movl $__USER_DS, ES(%edx) - movl %ebx, ORIG_EAX(%edx) - movl %ecx, EIP(%edx) - movl 12(%esp), %ecx - movl $__KERNEL_CS, CS(%edx) - movl %ebx, EFLAGS(%edx) - movl %eax, OLDESP(%edx) - movl 8(%esp), %eax - movl %ecx, 8(%esp) - movl EBX(%edx), %ebx - movl $__KERNEL_DS, OLDSS(%edx) - jmpl *%eax - CFI_ENDPROC -ENDPROC(arch_unwind_init_running) -#endif - ENTRY(kernel_thread_helper) pushl $0 # fake return address for unwinder CFI_STARTPROC Index: latest/arch/i386/kernel/traps.c =================================================================== --- latest.orig/arch/i386/kernel/traps.c +++ latest/arch/i386/kernel/traps.c @@ -94,11 +94,6 @@ asmlinkage void spurious_interrupt_bug(v asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; -#ifdef CONFIG_STACK_UNWIND -static int call_trace = 1; -#else -#define call_trace (-1) -#endif ATOMIC_NOTIFIER_HEAD(i386die_chain); extern char last_sysfs_file[]; @@ -150,26 +145,6 @@ static inline unsigned long print_contex return ebp; } -struct ops_and_data { - struct stacktrace_ops *ops; - void *data; -}; - -static asmlinkage int -dump_trace_unwind(struct unwind_frame_info *info, void *data) -{ - struct ops_and_data *oad = (struct ops_and_data *)data; - int n = 0; - - while (unwind(info) == 0 && UNW_PC(info)) { - n++; - oad->ops->address(oad->data, UNW_PC(info)); - if (arch_unw_user_mode(info)) - break; - } - return n; -} - void dump_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *stack, struct stacktrace_ops *ops, void *data) @@ -179,39 +154,6 @@ void dump_trace(struct task_struct *task if (!task) task = current; - if (call_trace >= 0) { - int unw_ret = 0; - struct unwind_frame_info info; - struct ops_and_data oad = { .ops = ops, .data = data }; - - if (regs) { - if (unwind_init_frame_info(&info, task, regs) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } else if (task == current) - unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); - else { - if (unwind_init_blocked(&info, task) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } - if (unw_ret > 0) { - if (call_trace == 1 && !arch_unw_user_mode(&info)) { - ops->warning_symbol(data, "DWARF2 unwinder stuck at %s", - UNW_PC(&info)); - if (UNW_SP(&info) >= PAGE_OFFSET) { - ops->warning(data, "Leftover inexact backtrace:"); - stack = (void *)UNW_SP(&info); - if (!stack) - return; - ebp = UNW_FP(&info); - } else - ops->warning(data, "Full inexact backtrace again:"); - } else if (call_trace >= 1) - return; - else - ops->warning(data, "Full inexact backtrace again:"); - } else - ops->warning(data, "Inexact backtrace:"); - } if (!stack) { unsigned long dummy; stack = &dummy; @@ -1392,18 +1334,3 @@ static int __init kstack_setup(char *s) } __setup("kstack=", kstack_setup); -#ifdef CONFIG_STACK_UNWIND -static int __init call_trace_setup(char *s) -{ - if (strcmp(s, "old") == 0) - call_trace = -1; - else if (strcmp(s, "both") == 0) - call_trace = 0; - else if (strcmp(s, "newfallback") == 0) - call_trace = 1; - else if (strcmp(s, "new") == 2) - call_trace = 2; - return 1; -} -__setup("call_trace=", call_trace_setup); -#endif Index: latest/arch/x86_64/Makefile =================================================================== --- latest.orig/arch/x86_64/Makefile +++ latest/arch/x86_64/Makefile @@ -45,9 +45,7 @@ cflags-kernel-$(CONFIG_REORDER) += -ffun # actually it makes the kernel smaller too. cflags-y += -fno-reorder-blocks cflags-y += -Wno-sign-compare -ifneq ($(CONFIG_UNWIND_INFO),y) cflags-y += -fno-asynchronous-unwind-tables -endif ifneq ($(CONFIG_DEBUG_INFO),y) # -fweb shrinks the kernel a bit, but the difference is very small # it also messes up debugging, so don't use it for now. Index: latest/arch/x86_64/kernel/entry.S =================================================================== --- latest.orig/arch/x86_64/kernel/entry.S +++ latest/arch/x86_64/kernel/entry.S @@ -1171,35 +1171,3 @@ ENTRY(call_softirq) CFI_ENDPROC ENDPROC(call_softirq) -#ifdef CONFIG_STACK_UNWIND -ENTRY(arch_unwind_init_running) - CFI_STARTPROC - movq %r15, R15(%rdi) - movq %r14, R14(%rdi) - xchgq %rsi, %rdx - movq %r13, R13(%rdi) - movq %r12, R12(%rdi) - xorl %eax, %eax - movq %rbp, RBP(%rdi) - movq %rbx, RBX(%rdi) - movq (%rsp), %rcx - movq %rax, R11(%rdi) - movq %rax, R10(%rdi) - movq %rax, R9(%rdi) - movq %rax, R8(%rdi) - movq %rax, RAX(%rdi) - movq %rax, RCX(%rdi) - movq %rax, RDX(%rdi) - movq %rax, RSI(%rdi) - movq %rax, RDI(%rdi) - movq %rax, ORIG_RAX(%rdi) - movq %rcx, RIP(%rdi) - leaq 8(%rsp), %rcx - movq $__KERNEL_CS, CS(%rdi) - movq %rax, EFLAGS(%rdi) - movq %rcx, RSP(%rdi) - movq $__KERNEL_DS, SS(%rdi) - jmpq *%rdx - CFI_ENDPROC -ENDPROC(arch_unwind_init_running) -#endif Index: latest/arch/x86_64/kernel/traps.c =================================================================== --- latest.orig/arch/x86_64/kernel/traps.c +++ latest/arch/x86_64/kernel/traps.c @@ -110,11 +110,6 @@ static inline void preempt_conditional_c } static int kstack_depth_to_print = 12; -#ifdef CONFIG_STACK_UNWIND -static int call_trace = 1; -#else -#define call_trace (-1) -#endif #ifdef CONFIG_KALLSYMS # include <linux/kallsyms.h> @@ -237,25 +232,6 @@ static unsigned long *in_exception_stack return NULL; } -struct ops_and_data { - struct stacktrace_ops *ops; - void *data; -}; - -static int dump_trace_unwind(struct unwind_frame_info *info, void *context) -{ - struct ops_and_data *oad = (struct ops_and_data *)context; - int n = 0; - - while (unwind(info) == 0 && UNW_PC(info)) { - n++; - oad->ops->address(oad->data, UNW_PC(info)); - if (arch_unw_user_mode(info)) - break; - } - return n; -} - /* * x86-64 can have upto three kernel stacks: * process stack @@ -273,38 +249,6 @@ void dump_trace(struct task_struct *tsk, if (!tsk) tsk = current; - if (call_trace >= 0) { - int unw_ret = 0; - struct unwind_frame_info info; - struct ops_and_data oad = { .ops = ops, .data = data }; - - if (regs) { - if (unwind_init_frame_info(&info, tsk, regs) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } else if (tsk == current) - unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); - else { - if (unwind_init_blocked(&info, tsk) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } - if (unw_ret > 0) { - if (call_trace == 1 && !arch_unw_user_mode(&info)) { - ops->warning_symbol(data, "DWARF2 unwinder stuck at %s", - UNW_PC(&info)); - if ((long)UNW_SP(&info) < 0) { - ops->warning(data, "Leftover inexact backtrace:"); - stack = (unsigned long *)UNW_SP(&info); - if (!stack) - return; - } else - ops->warning(data, "Full inexact backtrace again:"); - } else if (call_trace >= 1) - return; - else - ops->warning(data, "Full inexact backtrace again:"); - } else - ops->warning(data, "Inexact backtrace:"); - } if (!stack) { unsigned long dummy; stack = &dummy; @@ -1176,18 +1120,3 @@ static int __init kstack_setup(char *s) } __setup("kstack=", kstack_setup); -#ifdef CONFIG_STACK_UNWIND -static int __init call_trace_setup(char *s) -{ - if (strcmp(s, "old") == 0) - call_trace = -1; - else if (strcmp(s, "both") == 0) - call_trace = 0; - else if (strcmp(s, "newfallback") == 0) - call_trace = 1; - else if (strcmp(s, "new") == 0) - call_trace = 2; - return 1; -} -__setup("call_trace=", call_trace_setup); -#endif Index: latest/arch/x86_64/kernel/vmlinux.lds.S =================================================================== --- latest.orig/arch/x86_64/kernel/vmlinux.lds.S +++ latest/arch/x86_64/kernel/vmlinux.lds.S @@ -239,9 +239,7 @@ SECTIONS /* Sections to be discarded */ /DISCARD/ : { *(.exitcall.exit) -#ifndef CONFIG_UNWIND_INFO *(.eh_frame) -#endif } STABS_DEBUG Index: latest/include/asm-i386/unwind.h =================================================================== --- latest.orig/include/asm-i386/unwind.h +++ latest/include/asm-i386/unwind.h @@ -1,93 +1,6 @@ #ifndef _ASM_I386_UNWIND_H #define _ASM_I386_UNWIND_H -/* - * Copyright (C) 2002-2006 Novell, Inc. - * Jan Beulich <jbeulich@novell.com> - * This code is released under version 2 of the GNU GPL. - */ - -#ifdef CONFIG_STACK_UNWIND - -#include <linux/sched.h> -#include <asm/fixmap.h> -#include <asm/ptrace.h> -#include <asm/uaccess.h> - -struct unwind_frame_info -{ - struct pt_regs regs; - struct task_struct *task; -}; - -#define UNW_PC(frame) (frame)->regs.eip -#define UNW_SP(frame) (frame)->regs.esp -#ifdef CONFIG_FRAME_POINTER -#define UNW_FP(frame) (frame)->regs.ebp -#define FRAME_RETADDR_OFFSET 4 -#define FRAME_LINK_OFFSET 0 -#define STACK_BOTTOM(tsk) STACK_LIMIT((tsk)->thread.esp0) -#define STACK_TOP(tsk) ((tsk)->thread.esp0) -#else -#define UNW_FP(frame) ((void)(frame), 0) -#endif -#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) - -#define UNW_REGISTER_INFO \ - PTREGS_INFO(eax), \ - PTREGS_INFO(ecx), \ - PTREGS_INFO(edx), \ - PTREGS_INFO(ebx), \ - PTREGS_INFO(esp), \ - PTREGS_INFO(ebp), \ - PTREGS_INFO(esi), \ - PTREGS_INFO(edi), \ - PTREGS_INFO(eip) - -static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, - /*const*/ struct pt_regs *regs) -{ - if (user_mode_vm(regs)) - info->regs = *regs; - else { - memcpy(&info->regs, regs, offsetof(struct pt_regs, esp)); - info->regs.esp = (unsigned long)®s->esp; - info->regs.xss = __KERNEL_DS; - } -} - -static inline void arch_unw_init_blocked(struct unwind_frame_info *info) -{ - memset(&info->regs, 0, sizeof(info->regs)); - info->regs.eip = info->task->thread.eip; - info->regs.xcs = __KERNEL_CS; - __get_user(info->regs.ebp, (long *)info->task->thread.esp); - info->regs.esp = info->task->thread.esp; - info->regs.xss = __KERNEL_DS; - info->regs.xds = __USER_DS; - info->regs.xes = __USER_DS; -} - -extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *, - asmlinkage int (*callback)(struct unwind_frame_info *, - void *arg), - void *arg); - -static inline int arch_unw_user_mode(const struct unwind_frame_info *info) -{ -#if 0 /* This can only work when selector register and EFLAGS saves/restores - are properly annotated (and tracked in UNW_REGISTER_INFO). */ - return user_mode_vm(&info->regs); -#else - return info->regs.eip < PAGE_OFFSET - || (info->regs.eip >= __fix_to_virt(FIX_VDSO) - && info->regs.eip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE) - || info->regs.esp < PAGE_OFFSET; -#endif -} - -#else - #define UNW_PC(frame) ((void)(frame), 0) #define UNW_SP(frame) ((void)(frame), 0) #define UNW_FP(frame) ((void)(frame), 0) @@ -97,6 +10,4 @@ static inline int arch_unw_user_mode(con return 0; } -#endif - #endif /* _ASM_I386_UNWIND_H */ Index: latest/include/asm-x86_64/unwind.h =================================================================== --- latest.orig/include/asm-x86_64/unwind.h +++ latest/include/asm-x86_64/unwind.h @@ -1,99 +1,6 @@ #ifndef _ASM_X86_64_UNWIND_H #define _ASM_X86_64_UNWIND_H -/* - * Copyright (C) 2002-2006 Novell, Inc. - * Jan Beulich <jbeulich@novell.com> - * This code is released under version 2 of the GNU GPL. - */ - -#ifdef CONFIG_STACK_UNWIND - -#include <linux/sched.h> -#include <asm/ptrace.h> -#include <asm/uaccess.h> -#include <asm/vsyscall.h> - -struct unwind_frame_info -{ - struct pt_regs regs; - struct task_struct *task; -}; - -#define UNW_PC(frame) (frame)->regs.rip -#define UNW_SP(frame) (frame)->regs.rsp -#ifdef CONFIG_FRAME_POINTER -#define UNW_FP(frame) (frame)->regs.rbp -#define FRAME_RETADDR_OFFSET 8 -#define FRAME_LINK_OFFSET 0 -#define STACK_BOTTOM(tsk) (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1)) -#define STACK_TOP(tsk) ((tsk)->thread.rsp0) -#endif -/* Might need to account for the special exception and interrupt handling - stacks here, since normally - EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER, - but the construct is needed only for getting across the stack switch to - the interrupt stack - thus considering the IRQ stack itself is unnecessary, - and the overhead of comparing against all exception handling stacks seems - not desirable. */ -#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1)) - -#define UNW_REGISTER_INFO \ - PTREGS_INFO(rax), \ - PTREGS_INFO(rdx), \ - PTREGS_INFO(rcx), \ - PTREGS_INFO(rbx), \ - PTREGS_INFO(rsi), \ - PTREGS_INFO(rdi), \ - PTREGS_INFO(rbp), \ - PTREGS_INFO(rsp), \ - PTREGS_INFO(r8), \ - PTREGS_INFO(r9), \ - PTREGS_INFO(r10), \ - PTREGS_INFO(r11), \ - PTREGS_INFO(r12), \ - PTREGS_INFO(r13), \ - PTREGS_INFO(r14), \ - PTREGS_INFO(r15), \ - PTREGS_INFO(rip) - -static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, - /*const*/ struct pt_regs *regs) -{ - info->regs = *regs; -} - -static inline void arch_unw_init_blocked(struct unwind_frame_info *info) -{ - extern const char thread_return[]; - - memset(&info->regs, 0, sizeof(info->regs)); - info->regs.rip = (unsigned long)thread_return; - info->regs.cs = __KERNEL_CS; - __get_user(info->regs.rbp, (unsigned long *)info->task->thread.rsp); - info->regs.rsp = info->task->thread.rsp; - info->regs.ss = __KERNEL_DS; -} - -extern int arch_unwind_init_running(struct unwind_frame_info *, - int (*callback)(struct unwind_frame_info *, - void *arg), - void *arg); - -static inline int arch_unw_user_mode(const struct unwind_frame_info *info) -{ -#if 0 /* This can only work when selector register saves/restores - are properly annotated (and tracked in UNW_REGISTER_INFO). */ - return user_mode(&info->regs); -#else - return (long)info->regs.rip >= 0 - || (info->regs.rip >= VSYSCALL_START && info->regs.rip < VSYSCALL_END) - || (long)info->regs.rsp >= 0; -#endif -} - -#else - #define UNW_PC(frame) ((void)(frame), 0UL) #define UNW_SP(frame) ((void)(frame), 0UL) @@ -102,6 +9,4 @@ static inline int arch_unw_user_mode(con return 0; } -#endif - #endif /* _ASM_X86_64_UNWIND_H */ Index: latest/include/linux/unwind.h =================================================================== --- latest.orig/include/linux/unwind.h +++ latest/include/linux/unwind.h @@ -14,62 +14,6 @@ struct module; -#ifdef CONFIG_STACK_UNWIND - -#include <asm/unwind.h> - -#ifndef ARCH_UNWIND_SECTION_NAME -#define ARCH_UNWIND_SECTION_NAME ".eh_frame" -#endif - -/* - * Initialize unwind support. - */ -extern void unwind_init(void); - -#ifdef CONFIG_MODULES - -extern void *unwind_add_table(struct module *, - const void *table_start, - unsigned long table_size); - -extern void unwind_remove_table(void *handle, int init_only); - -#endif - -extern int unwind_init_frame_info(struct unwind_frame_info *, - struct task_struct *, - /*const*/ struct pt_regs *); - -/* - * Prepare to unwind a blocked task. - */ -extern int unwind_init_blocked(struct unwind_frame_info *, - struct task_struct *); - -/* - * Prepare to unwind the currently running thread. - */ -extern int unwind_init_running(struct unwind_frame_info *, - asmlinkage int (*callback)(struct unwind_frame_info *, - void *arg), - void *arg); - -/* - * Unwind to previous to frame. Returns 0 if successful, negative - * number in case of an error. - */ -extern int unwind(struct unwind_frame_info *); - -/* - * Unwind until the return pointer is in user-land (or until an error - * occurs). Returns 0 if successful, negative number in case of - * error. - */ -extern int unwind_to_user(struct unwind_frame_info *); - -#else - struct unwind_frame_info {}; static inline void unwind_init(void) {} @@ -83,12 +27,12 @@ static inline void *unwind_add_table(str return NULL; } -#endif - static inline void unwind_remove_table(void *handle, int init_only) { } +#endif + static inline int unwind_init_frame_info(struct unwind_frame_info *info, struct task_struct *tsk, const struct pt_regs *regs) @@ -120,6 +64,4 @@ static inline int unwind_to_user(struct return -ENOSYS; } -#endif - #endif /* _LINUX_UNWIND_H */ Index: latest/kernel/Makefile =================================================================== --- latest.orig/kernel/Makefile +++ latest/kernel/Makefile @@ -32,7 +32,6 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o module-verify.o obj-$(CONFIG_MODULE_SIG) += module-verify-sig.o obj-$(CONFIG_KALLSYMS) += kallsyms.o -obj-$(CONFIG_STACK_UNWIND) += unwind.o obj-$(CONFIG_PM) += power/ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_KEXEC) += kexec.o Index: latest/kernel/unwind.c =================================================================== --- latest.orig/kernel/unwind.c +++ /dev/null @@ -1,920 +0,0 @@ -/* - * Copyright (C) 2002-2006 Novell, Inc. - * Jan Beulich <jbeulich@novell.com> - * This code is released under version 2 of the GNU GPL. - * - * A simple API for unwinding kernel stacks. This is used for - * debugging and error reporting purposes. The kernel doesn't need - * full-blown stack unwinding with all the bells and whistles, so there - * is not much point in implementing the full Dwarf2 unwind API. - */ - -#include <linux/unwind.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/stop_machine.h> -#include <asm/sections.h> -#include <asm/uaccess.h> -#include <asm/unaligned.h> - -extern char __start_unwind[], __end_unwind[]; - -#define MAX_STACK_DEPTH 8 - -#define EXTRA_INFO(f) { \ - BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \ - % FIELD_SIZEOF(struct unwind_frame_info, f)) \ - + offsetof(struct unwind_frame_info, f) \ - / FIELD_SIZEOF(struct unwind_frame_info, f), \ - FIELD_SIZEOF(struct unwind_frame_info, f) \ - } -#define PTREGS_INFO(f) EXTRA_INFO(regs.f) - -static const struct { - unsigned offs:BITS_PER_LONG / 2; - unsigned width:BITS_PER_LONG / 2; -} reg_info[] = { - UNW_REGISTER_INFO -}; - -#undef PTREGS_INFO -#undef EXTRA_INFO - -#ifndef REG_INVALID -#define REG_INVALID(r) (reg_info[r].width == 0) -#endif - -#define DW_CFA_nop 0x00 -#define DW_CFA_set_loc 0x01 -#define DW_CFA_advance_loc1 0x02 -#define DW_CFA_advance_loc2 0x03 -#define DW_CFA_advance_loc4 0x04 -#define DW_CFA_offset_extended 0x05 -#define DW_CFA_restore_extended 0x06 -#define DW_CFA_undefined 0x07 -#define DW_CFA_same_value 0x08 -#define DW_CFA_register 0x09 -#define DW_CFA_remember_state 0x0a -#define DW_CFA_restore_state 0x0b -#define DW_CFA_def_cfa 0x0c -#define DW_CFA_def_cfa_register 0x0d -#define DW_CFA_def_cfa_offset 0x0e -#define DW_CFA_def_cfa_expression 0x0f -#define DW_CFA_expression 0x10 -#define DW_CFA_offset_extended_sf 0x11 -#define DW_CFA_def_cfa_sf 0x12 -#define DW_CFA_def_cfa_offset_sf 0x13 -#define DW_CFA_val_offset 0x14 -#define DW_CFA_val_offset_sf 0x15 -#define DW_CFA_val_expression 0x16 -#define DW_CFA_lo_user 0x1c -#define DW_CFA_GNU_window_save 0x2d -#define DW_CFA_GNU_args_size 0x2e -#define DW_CFA_GNU_negative_offset_extended 0x2f -#define DW_CFA_hi_user 0x3f - -#define DW_EH_PE_FORM 0x07 -#define DW_EH_PE_native 0x00 -#define DW_EH_PE_leb128 0x01 -#define DW_EH_PE_data2 0x02 -#define DW_EH_PE_data4 0x03 -#define DW_EH_PE_data8 0x04 -#define DW_EH_PE_signed 0x08 -#define DW_EH_PE_ADJUST 0x70 -#define DW_EH_PE_abs 0x00 -#define DW_EH_PE_pcrel 0x10 -#define DW_EH_PE_textrel 0x20 -#define DW_EH_PE_datarel 0x30 -#define DW_EH_PE_funcrel 0x40 -#define DW_EH_PE_aligned 0x50 -#define DW_EH_PE_indirect 0x80 -#define DW_EH_PE_omit 0xff - -typedef unsigned long uleb128_t; -typedef signed long sleb128_t; - -static struct unwind_table { - struct { - unsigned long pc; - unsigned long range; - } core, init; - const void *address; - unsigned long size; - struct unwind_table *link; - const char *name; -} root_table; - -struct unwind_item { - enum item_location { - Nowhere, - Memory, - Register, - Value - } where; - uleb128_t value; -}; - -struct unwind_state { - uleb128_t loc, org; - const u8 *cieStart, *cieEnd; - uleb128_t codeAlign; - sleb128_t dataAlign; - struct cfa { - uleb128_t reg, offs; - } cfa; - struct unwind_item regs[ARRAY_SIZE(reg_info)]; - unsigned stackDepth:8; - unsigned version:8; - const u8 *label; - const u8 *stack[MAX_STACK_DEPTH]; -}; - -static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 }; - -static struct unwind_table *find_table(unsigned long pc) -{ - struct unwind_table *table; - - for (table = &root_table; table; table = table->link) - if ((pc >= table->core.pc - && pc < table->core.pc + table->core.range) - || (pc >= table->init.pc - && pc < table->init.pc + table->init.range)) - break; - - return table; -} - -static void init_unwind_table(struct unwind_table *table, - const char *name, - const void *core_start, - unsigned long core_size, - const void *init_start, - unsigned long init_size, - const void *table_start, - unsigned long table_size) -{ - table->core.pc = (unsigned long)core_start; - table->core.range = core_size; - table->init.pc = (unsigned long)init_start; - table->init.range = init_size; - table->address = table_start; - table->size = table_size; - table->link = NULL; - table->name = name; -} - -void __init unwind_init(void) -{ - init_unwind_table(&root_table, "kernel", - _text, _end - _text, - NULL, 0, - __start_unwind, __end_unwind - __start_unwind); -} - -#ifdef CONFIG_MODULES - -static struct unwind_table *last_table; - -/* Must be called with module_mutex held. */ -void *unwind_add_table(struct module *module, - const void *table_start, - unsigned long table_size) -{ - struct unwind_table *table; - - if (table_size <= 0) - return NULL; - - table = kmalloc(sizeof(*table), GFP_KERNEL); - if (!table) - return NULL; - - init_unwind_table(table, module->name, - module->module_core, module->core_size, - module->module_init, module->init_size, - table_start, table_size); - - if (last_table) - last_table->link = table; - else - root_table.link = table; - last_table = table; - - return table; -} - -struct unlink_table_info -{ - struct unwind_table *table; - int init_only; -}; - -static int unlink_table(void *arg) -{ - struct unlink_table_info *info = arg; - struct unwind_table *table = info->table, *prev; - - for (prev = &root_table; prev->link && prev->link != table; prev = prev->link) - ; - - if (prev->link) { - if (info->init_only) { - table->init.pc = 0; - table->init.range = 0; - info->table = NULL; - } else { - prev->link = table->link; - if (!prev->link) - last_table = prev; - } - } else - info->table = NULL; - - return 0; -} - -/* Must be called with module_mutex held. */ -void unwind_remove_table(void *handle, int init_only) -{ - struct unwind_table *table = handle; - struct unlink_table_info info; - - if (!table || table == &root_table) - return; - - if (init_only && table == last_table) { - table->init.pc = 0; - table->init.range = 0; - return; - } - - info.table = table; - info.init_only = init_only; - stop_machine_run(unlink_table, &info, NR_CPUS); - - if (info.table) - kfree(table); -} - -#endif /* CONFIG_MODULES */ - -static uleb128_t get_uleb128(const u8 **pcur, const u8 *end) -{ - const u8 *cur = *pcur; - uleb128_t value; - unsigned shift; - - for (shift = 0, value = 0; cur < end; shift += 7) { - if (shift + 7 > 8 * sizeof(value) - && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) { - cur = end + 1; - break; - } - value |= (uleb128_t)(*cur & 0x7f) << shift; - if (!(*cur++ & 0x80)) - break; - } - *pcur = cur; - - return value; -} - -static sleb128_t get_sleb128(const u8 **pcur, const u8 *end) -{ - const u8 *cur = *pcur; - sleb128_t value; - unsigned shift; - - for (shift = 0, value = 0; cur < end; shift += 7) { - if (shift + 7 > 8 * sizeof(value) - && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) { - cur = end + 1; - break; - } - value |= (sleb128_t)(*cur & 0x7f) << shift; - if (!(*cur & 0x80)) { - value |= -(*cur++ & 0x40) << shift; - break; - } - } - *pcur = cur; - - return value; -} - -static unsigned long read_pointer(const u8 **pLoc, - const void *end, - signed ptrType) -{ - unsigned long value = 0; - union { - const u8 *p8; - const u16 *p16u; - const s16 *p16s; - const u32 *p32u; - const s32 *p32s; - const unsigned long *pul; - } ptr; - - if (ptrType < 0 || ptrType == DW_EH_PE_omit) - return 0; - ptr.p8 = *pLoc; - switch(ptrType & DW_EH_PE_FORM) { - case DW_EH_PE_data2: - if (end < (const void *)(ptr.p16u + 1)) - return 0; - if(ptrType & DW_EH_PE_signed) - value = get_unaligned(ptr.p16s++); - else - value = get_unaligned(ptr.p16u++); - break; - case DW_EH_PE_data4: -#ifdef CONFIG_64BIT - if (end < (const void *)(ptr.p32u + 1)) - return 0; - if(ptrType & DW_EH_PE_signed) - value = get_unaligned(ptr.p32s++); - else - value = get_unaligned(ptr.p32u++); - break; - case DW_EH_PE_data8: - BUILD_BUG_ON(sizeof(u64) != sizeof(value)); -#else - BUILD_BUG_ON(sizeof(u32) != sizeof(value)); -#endif - case DW_EH_PE_native: - if (end < (const void *)(ptr.pul + 1)) - return 0; - value = get_unaligned(ptr.pul++); - break; - case DW_EH_PE_leb128: - BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value)); - value = ptrType & DW_EH_PE_signed - ? get_sleb128(&ptr.p8, end) - : get_uleb128(&ptr.p8, end); - if ((const void *)ptr.p8 > end) - return 0; - break; - default: - return 0; - } - switch(ptrType & DW_EH_PE_ADJUST) { - case DW_EH_PE_abs: - break; - case DW_EH_PE_pcrel: - value += (unsigned long)*pLoc; - break; - default: - return 0; - } - if ((ptrType & DW_EH_PE_indirect) - && __get_user(value, (unsigned long *)value)) - return 0; - *pLoc = ptr.p8; - - return value; -} - -static signed fde_pointer_type(const u32 *cie) -{ - const u8 *ptr = (const u8 *)(cie + 2); - unsigned version = *ptr; - - if (version != 1) - return -1; /* unsupported */ - if (*++ptr) { - const char *aug; - const u8 *end = (const u8 *)(cie + 1) + *cie; - uleb128_t len; - - /* check if augmentation size is first (and thus present) */ - if (*ptr != 'z') - return -1; - /* check if augmentation string is nul-terminated */ - if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL) - return -1; - ++ptr; /* skip terminator */ - get_uleb128(&ptr, end); /* skip code alignment */ - get_sleb128(&ptr, end); /* skip data alignment */ - /* skip return address column */ - version <= 1 ? (void)++ptr : (void)get_uleb128(&ptr, end); - len = get_uleb128(&ptr, end); /* augmentation length */ - if (ptr + len < ptr || ptr + len > end) - return -1; - end = ptr + len; - while (*++aug) { - if (ptr >= end) - return -1; - switch(*aug) { - case 'L': - ++ptr; - break; - case 'P': { - signed ptrType = *ptr++; - - if (!read_pointer(&ptr, end, ptrType) || ptr > end) - return -1; - } - break; - case 'R': - return *ptr; - default: - return -1; - } - } - } - return DW_EH_PE_native|DW_EH_PE_abs; -} - -static int advance_loc(unsigned long delta, struct unwind_state *state) -{ - state->loc += delta * state->codeAlign; - - return delta > 0; -} - -static void set_rule(uleb128_t reg, - enum item_location where, - uleb128_t value, - struct unwind_state *state) -{ - if (reg < ARRAY_SIZE(state->regs)) { - state->regs[reg].where = where; - state->regs[reg].value = value; - } -} - -static int processCFI(const u8 *start, - const u8 *end, - unsigned long targetLoc, - signed ptrType, - struct unwind_state *state) -{ - union { - const u8 *p8; - const u16 *p16; - const u32 *p32; - } ptr; - int result = 1; - - if (start != state->cieStart) { - state->loc = state->org; - result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state); - if (targetLoc == 0 && state->label == NULL) - return result; - } - for (ptr.p8 = start; result && ptr.p8 < end; ) { - switch(*ptr.p8 >> 6) { - uleb128_t value; - - case 0: - switch(*ptr.p8++) { - case DW_CFA_nop: - break; - case DW_CFA_set_loc: - if ((state->loc = read_pointer(&ptr.p8, end, ptrType)) == 0) - result = 0; - break; - case DW_CFA_advance_loc1: - result = ptr.p8 < end && advance_loc(*ptr.p8++, state); - break; - case DW_CFA_advance_loc2: - result = ptr.p8 <= end + 2 - && advance_loc(*ptr.p16++, state); - break; - case DW_CFA_advance_loc4: - result = ptr.p8 <= end + 4 - && advance_loc(*ptr.p32++, state); - break; - case DW_CFA_offset_extended: - value = get_uleb128(&ptr.p8, end); - set_rule(value, Memory, get_uleb128(&ptr.p8, end), state); - break; - case DW_CFA_val_offset: - value = get_uleb128(&ptr.p8, end); - set_rule(value, Value, get_uleb128(&ptr.p8, end), state); - break; - case DW_CFA_offset_extended_sf: - value = get_uleb128(&ptr.p8, end); - set_rule(value, Memory, get_sleb128(&ptr.p8, end), state); - break; - case DW_CFA_val_offset_sf: - value = get_uleb128(&ptr.p8, end); - set_rule(value, Value, get_sleb128(&ptr.p8, end), state); - break; - case DW_CFA_restore_extended: - case DW_CFA_undefined: - case DW_CFA_same_value: - set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state); - break; - case DW_CFA_register: - value = get_uleb128(&ptr.p8, end); - set_rule(value, - Register, - get_uleb128(&ptr.p8, end), state); - break; - case DW_CFA_remember_state: - if (ptr.p8 == state->label) { - state->label = NULL; - return 1; - } - if (state->stackDepth >= MAX_STACK_DEPTH) - return 0; - state->stack[state->stackDepth++] = ptr.p8; - break; - case DW_CFA_restore_state: - if (state->stackDepth) { - const uleb128_t loc = state->loc; - const u8 *label = state->label; - - state->label = state->stack[state->stackDepth - 1]; - memcpy(&state->cfa, &badCFA, sizeof(state->cfa)); - memset(state->regs, 0, sizeof(state->regs)); - state->stackDepth = 0; - result = processCFI(start, end, 0, ptrType, state); - state->loc = loc; - state->label = label; - } else - return 0; - break; - case DW_CFA_def_cfa: - state->cfa.reg = get_uleb128(&ptr.p8, end); - /*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); - /*nobreak*/ - case DW_CFA_def_cfa_offset_sf: - state->cfa.offs = get_sleb128(&ptr.p8, end) - * state->dataAlign; - break; - case DW_CFA_def_cfa_register: - state->cfa.reg = get_uleb128(&ptr.p8, end); - 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; - case DW_CFA_GNU_negative_offset_extended: - value = get_uleb128(&ptr.p8, end); - set_rule(value, - Memory, - (uleb128_t)0 - get_uleb128(&ptr.p8, end), state); - break; - case DW_CFA_GNU_window_save: - default: - result = 0; - break; - } - break; - case 1: - result = advance_loc(*ptr.p8++ & 0x3f, state); - break; - case 2: - value = *ptr.p8++ & 0x3f; - set_rule(value, Memory, get_uleb128(&ptr.p8, end), state); - break; - case 3: - set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state); - break; - } - if (ptr.p8 > end) - result = 0; - if (result && targetLoc != 0 && targetLoc < state->loc) - return 1; - } - - return result - && ptr.p8 == end - && (targetLoc == 0 - || (/*todo While in theory this should apply, gcc in practice omits - everything past the function prolog, and hence the location - never reaches the end of the function. - targetLoc < state->loc &&*/ state->label == NULL)); -} - -/* Unwind to previous to frame. Returns 0 if successful, negative - * number in case of an error. */ -int unwind(struct unwind_frame_info *frame) -{ -#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) - const u32 *fde = NULL, *cie = NULL; - const u8 *ptr = NULL, *end = NULL; - unsigned long startLoc = 0, endLoc = 0, cfa; - unsigned i; - signed ptrType = -1; - uleb128_t retAddrReg = 0; - struct unwind_table *table; - struct unwind_state state; - - if (UNW_PC(frame) == 0) - return -EINVAL; - if ((table = find_table(UNW_PC(frame))) != NULL - && !(table->size & (sizeof(*fde) - 1))) { - unsigned long tableSize = table->size; - - for (fde = table->address; - tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde; - tableSize -= sizeof(*fde) + *fde, - fde += 1 + *fde / sizeof(*fde)) { - if (!*fde || (*fde & (sizeof(*fde) - 1))) - break; - if (!fde[1]) - continue; /* this is a CIE */ - if ((fde[1] & (sizeof(*fde) - 1)) - || fde[1] > (unsigned long)(fde + 1) - - (unsigned long)table->address) - continue; /* this is not a valid FDE */ - cie = fde + 1 - fde[1] / sizeof(*fde); - if (*cie <= sizeof(*cie) + 4 - || *cie >= fde[1] - sizeof(*fde) - || (*cie & (sizeof(*cie) - 1)) - || cie[1] - || (ptrType = fde_pointer_type(cie)) < 0) { - cie = NULL; /* this is not a (valid) CIE */ - continue; - } - ptr = (const u8 *)(fde + 2); - startLoc = read_pointer(&ptr, - (const u8 *)(fde + 1) + *fde, - ptrType); - endLoc = startLoc - + read_pointer(&ptr, - (const u8 *)(fde + 1) + *fde, - ptrType & DW_EH_PE_indirect - ? ptrType - : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed)); - if (UNW_PC(frame) >= startLoc && UNW_PC(frame) < endLoc) - break; - cie = NULL; - } - } - if (cie != NULL) { - memset(&state, 0, sizeof(state)); - state.cieEnd = ptr; /* keep here temporarily */ - ptr = (const u8 *)(cie + 2); - end = (const u8 *)(cie + 1) + *cie; - if ((state.version = *ptr) != 1) - cie = NULL; /* unsupported version */ - else if (*++ptr) { - /* check if augmentation size is first (and thus present) */ - if (*ptr == 'z') { - /* check for ignorable (or already handled) - * nul-terminated augmentation string */ - while (++ptr < end && *ptr) - if (strchr("LPR", *ptr) == NULL) - break; - } - if (ptr >= end || *ptr) - cie = NULL; - } - ++ptr; - } - if (cie != NULL) { - /* get code aligment factor */ - state.codeAlign = get_uleb128(&ptr, end); - /* get data aligment factor */ - state.dataAlign = get_sleb128(&ptr, end); - if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end) - cie = NULL; - else { - retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end); - /* skip augmentation */ - if (((const char *)(cie + 2))[1] == 'z') - ptr += get_uleb128(&ptr, end); - if (ptr > end - || retAddrReg >= ARRAY_SIZE(reg_info) - || REG_INVALID(retAddrReg) - || reg_info[retAddrReg].width != sizeof(unsigned long)) - cie = NULL; - } - } - if (cie != NULL) { - state.cieStart = ptr; - ptr = state.cieEnd; - state.cieEnd = end; - end = (const u8 *)(fde + 1) + *fde; - /* skip augmentation */ - if (((const char *)(cie + 2))[1] == 'z') { - uleb128_t augSize = get_uleb128(&ptr, end); - - if ((ptr += augSize) > end) - fde = NULL; - } - } - if (cie == NULL || fde == NULL) { -#ifdef CONFIG_FRAME_POINTER - unsigned long top, bottom; -#endif - -#ifdef CONFIG_FRAME_POINTER - top = STACK_TOP(frame->task); - bottom = STACK_BOTTOM(frame->task); -# if FRAME_RETADDR_OFFSET < 0 - if (UNW_SP(frame) < top - && UNW_FP(frame) <= UNW_SP(frame) - && bottom < UNW_FP(frame) -# else - if (UNW_SP(frame) > top - && UNW_FP(frame) >= UNW_SP(frame) - && bottom > UNW_FP(frame) -# endif - && !((UNW_SP(frame) | UNW_FP(frame)) - & (sizeof(unsigned long) - 1))) { - unsigned long link; - - if (!__get_user(link, - (unsigned long *)(UNW_FP(frame) - + FRAME_LINK_OFFSET)) -# if FRAME_RETADDR_OFFSET < 0 - && link > bottom && link < UNW_FP(frame) -# else - && link > UNW_FP(frame) && link < bottom -# endif - && !(link & (sizeof(link) - 1)) - && !__get_user(UNW_PC(frame), - (unsigned long *)(UNW_FP(frame) - + FRAME_RETADDR_OFFSET))) { - UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET -# if FRAME_RETADDR_OFFSET < 0 - - -# else - + -# endif - sizeof(UNW_PC(frame)); - UNW_FP(frame) = link; - return 0; - } - } -#endif - return -ENXIO; - } - state.org = startLoc; - memcpy(&state.cfa, &badCFA, sizeof(state.cfa)); - /* process instructions */ - if (!processCFI(ptr, end, UNW_PC(frame), 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) - || state.cfa.offs % sizeof(unsigned long)) - return -EIO; - /* update frame */ - 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)) { - startLoc = min(STACK_LIMIT(cfa), cfa); - endLoc = max(STACK_LIMIT(cfa), cfa); - } -#ifndef CONFIG_64BIT -# define CASES CASE(8); CASE(16); CASE(32) -#else -# define CASES CASE(8); CASE(16); CASE(32); CASE(64) -#endif - for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { - if (REG_INVALID(i)) { - if (state.regs[i].where == Nowhere) - continue; - return -EIO; - } - switch(state.regs[i].where) { - default: - break; - case Register: - if (state.regs[i].value >= ARRAY_SIZE(reg_info) - || REG_INVALID(state.regs[i].value) - || reg_info[i].width > reg_info[state.regs[i].value].width) - return -EIO; - switch(reg_info[state.regs[i].value].width) { -#define CASE(n) \ - case sizeof(u##n): \ - state.regs[i].value = FRAME_REG(state.regs[i].value, \ - const u##n); \ - break - CASES; -#undef CASE - default: - return -EIO; - } - break; - } - } - for (i = 0; i < ARRAY_SIZE(state.regs); ++i) { - if (REG_INVALID(i)) - continue; - switch(state.regs[i].where) { - case Nowhere: - if (reg_info[i].width != sizeof(UNW_SP(frame)) - || &FRAME_REG(i, __typeof__(UNW_SP(frame))) - != &UNW_SP(frame)) - continue; - UNW_SP(frame) = cfa; - break; - case Register: - switch(reg_info[i].width) { -#define CASE(n) case sizeof(u##n): \ - FRAME_REG(i, u##n) = state.regs[i].value; \ - break - CASES; -#undef CASE - default: - return -EIO; - } - break; - case Value: - if (reg_info[i].width != sizeof(unsigned long)) - return -EIO; - FRAME_REG(i, unsigned long) = cfa + state.regs[i].value - * state.dataAlign; - break; - case Memory: { - unsigned long addr = cfa + state.regs[i].value - * state.dataAlign; - - if ((state.regs[i].value * state.dataAlign) - % sizeof(unsigned long) - || addr < startLoc - || addr + sizeof(unsigned long) < addr - || addr + sizeof(unsigned long) > endLoc) - return -EIO; - switch(reg_info[i].width) { -#define CASE(n) case sizeof(u##n): \ - __get_user(FRAME_REG(i, u##n), (u##n *)addr); \ - break - CASES; -#undef CASE - default: - return -EIO; - } - } - break; - } - } - - return 0; -#undef CASES -#undef FRAME_REG -} -EXPORT_SYMBOL(unwind); - -int unwind_init_frame_info(struct unwind_frame_info *info, - struct task_struct *tsk, - /*const*/ struct pt_regs *regs) -{ - info->task = tsk; - arch_unw_init_frame_info(info, regs); - - return 0; -} -EXPORT_SYMBOL(unwind_init_frame_info); - -/* - * Prepare to unwind a blocked task. - */ -int unwind_init_blocked(struct unwind_frame_info *info, - struct task_struct *tsk) -{ - info->task = tsk; - arch_unw_init_blocked(info); - - return 0; -} -EXPORT_SYMBOL(unwind_init_blocked); - -/* - * Prepare to unwind the currently running thread. - */ -int unwind_init_running(struct unwind_frame_info *info, - asmlinkage int (*callback)(struct unwind_frame_info *, - void *arg), - void *arg) -{ - info->task = current; - - return arch_unwind_init_running(info, callback, arg); -} -EXPORT_SYMBOL(unwind_init_running); - -/* - * Unwind until the return pointer is in user-land (or until an error - * occurs). Returns 0 if successful, negative number in case of - * error. - */ -int unwind_to_user(struct unwind_frame_info *info) -{ - while (!arch_unw_user_mode(info)) { - int err = unwind(info); - - if (err < 0) - return err; - } - - return 0; -} -EXPORT_SYMBOL(unwind_to_user); Index: latest/lib/Kconfig.debug =================================================================== --- latest.orig/lib/Kconfig.debug +++ latest/lib/Kconfig.debug @@ -332,24 +332,6 @@ config FRAME_POINTER some architectures or if you use external debuggers. If you don't debug the kernel, you can say N. -config UNWIND_INFO - bool "Compile the kernel with frame unwind information" - depends on !IA64 && !PARISC && !X86_64_XEN - depends on !MODULES || !(MIPS || PPC || SUPERH || V850) - help - If you say Y here the resulting kernel image will be slightly larger - but not slower, and it will give very useful debugging information. - If you don't debug the kernel, you can say N, but we may not be able - to solve problems without frame unwind information or frame pointers. - -config STACK_UNWIND - bool "Stack unwind support" - depends on UNWIND_INFO - depends on X86 - help - This enables more precise stack traces, omitting all unrelated - occurrences of pointers into kernel code from the dump. - config FORCED_INLINING bool "Force gcc to inline functions marked 'inline'" depends on DEBUG_KERNEL From: Don Zickus <dzickus@redhat.com> Subject: [RHEL-5 PATCH 2/2] remove unwinder patches from x86/x86_64 Date: Tue, 2 Jan 2007 17:09:47 -0500 Bugzilla: NONE Message-Id: <20070102220947.GM5381@redhat.com> The xen part of the stack unwinder removal. Index: latest/arch/i386/kernel/entry-xen.S =================================================================== --- latest.orig/arch/i386/kernel/entry-xen.S +++ latest/arch/i386/kernel/entry-xen.S @@ -1173,37 +1173,6 @@ ENTRY(fixup_4gb_segment) jmp error_code CFI_ENDPROC -#ifdef CONFIG_STACK_UNWIND -ENTRY(arch_unwind_init_running) - CFI_STARTPROC - movl 4(%esp), %edx - movl (%esp), %ecx - leal 4(%esp), %eax - movl %ebx, EBX(%edx) - xorl %ebx, %ebx - movl %ebx, ECX(%edx) - movl %ebx, EDX(%edx) - movl %esi, ESI(%edx) - movl %edi, EDI(%edx) - movl %ebp, EBP(%edx) - movl %ebx, EAX(%edx) - movl $__USER_DS, DS(%edx) - movl $__USER_DS, ES(%edx) - movl %ebx, ORIG_EAX(%edx) - movl %ecx, EIP(%edx) - movl 12(%esp), %ecx - movl $__KERNEL_CS, CS(%edx) - movl %ebx, EFLAGS(%edx) - movl %eax, OLDESP(%edx) - movl 8(%esp), %eax - movl %ecx, 8(%esp) - movl EBX(%edx), %ebx - movl $__KERNEL_DS, OLDSS(%edx) - jmpl *%eax - CFI_ENDPROC -ENDPROC(arch_unwind_init_running) -#endif - .section .rodata,"a" #include "syscall_table.S" Index: latest/arch/i386/kernel/traps-xen.c =================================================================== --- latest.orig/arch/i386/kernel/traps-xen.c +++ latest/arch/i386/kernel/traps-xen.c @@ -100,11 +100,6 @@ asmlinkage void fixup_4gb_segment(void); asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; -#ifdef CONFIG_STACK_UNWIND -static int call_trace = 1; -#else -#define call_trace (-1) -#endif ATOMIC_NOTIFIER_HEAD(i386die_chain); extern char last_sysfs_file[]; @@ -156,26 +151,6 @@ static inline unsigned long print_contex return ebp; } -struct ops_and_data { - struct stacktrace_ops *ops; - void *data; -}; - -static asmlinkage int -dump_trace_unwind(struct unwind_frame_info *info, void *data) -{ - struct ops_and_data *oad = (struct ops_and_data *)data; - int n = 0; - - while (unwind(info) == 0 && UNW_PC(info)) { - n++; - oad->ops->address(oad->data, UNW_PC(info)); - if (arch_unw_user_mode(info)) - break; - } - return n; -} - void dump_trace(struct task_struct *task, struct pt_regs *regs, unsigned long *stack, struct stacktrace_ops *ops, void *data) @@ -185,37 +160,7 @@ void dump_trace(struct task_struct *task if (!task) task = current; - if (call_trace >= 0) { - int unw_ret = 0; - struct unwind_frame_info info; - struct ops_and_data oad = { .ops = ops, .data = data }; - - if (regs) { - if (unwind_init_frame_info(&info, task, regs) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } else if (task == current) - unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); - else { - if (unwind_init_blocked(&info, task) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } - if (unw_ret > 0) { - if (call_trace == 1 && !arch_unw_user_mode(&info)) { - ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", - UNW_PC(&info)); - if (UNW_SP(&info) >= PAGE_OFFSET) { - ops->warning(data, "Leftover inexact backtrace:\n"); - stack = (void *)UNW_SP(&info); - } else - ops->warning(data, "Full inexact backtrace again:\n"); - } else if (call_trace >= 1) - return; - else - ops->warning(data, "Full inexact backtrace again:\n"); - } else - ops->warning(data, "Inexact backtrace:\n"); - - } else if (!stack) { + if (!stack) { unsigned long dummy; stack = &dummy; if (task && task != current) @@ -1321,18 +1266,3 @@ static int __init kstack_setup(char *s) } __setup("kstack=", kstack_setup); -#ifdef CONFIG_STACK_UNWIND -static int __init call_trace_setup(char *s) -{ - if (strcmp(s, "old") == 0) - call_trace = -1; - else if (strcmp(s, "both") == 0) - call_trace = 0; - else if (strcmp(s, "newfallback") == 0) - call_trace = 1; - else if (strcmp(s, "new") == 2) - call_trace = 2; - return 1; -} -__setup("call_trace=", call_trace_setup); -#endif Index: latest/arch/x86_64/kernel/entry-xen.S =================================================================== --- latest.orig/arch/x86_64/kernel/entry-xen.S +++ latest/arch/x86_64/kernel/entry-xen.S @@ -1179,35 +1179,3 @@ ENTRY(call_softirq) CFI_ENDPROC ENDPROC(call_softirq) -#ifdef CONFIG_STACK_UNWIND -ENTRY(arch_unwind_init_running) - CFI_STARTPROC - movq %r15, R15(%rdi) - movq %r14, R14(%rdi) - xchgq %rsi, %rdx - movq %r13, R13(%rdi) - movq %r12, R12(%rdi) - xorl %eax, %eax - movq %rbp, RBP(%rdi) - movq %rbx, RBX(%rdi) - movq (%rsp), %rcx - movq %rax, R11(%rdi) - movq %rax, R10(%rdi) - movq %rax, R9(%rdi) - movq %rax, R8(%rdi) - movq %rax, RAX(%rdi) - movq %rax, RCX(%rdi) - movq %rax, RDX(%rdi) - movq %rax, RSI(%rdi) - movq %rax, RDI(%rdi) - movq %rax, ORIG_RAX(%rdi) - movq %rcx, RIP(%rdi) - leaq 8(%rsp), %rcx - movq $__KERNEL_CS, CS(%rdi) - movq %rax, EFLAGS(%rdi) - movq %rcx, RSP(%rdi) - movq $__KERNEL_DS, SS(%rdi) - jmpq *%rdx - CFI_ENDPROC -ENDPROC(arch_unwind_init_running) -#endif Index: latest/arch/x86_64/kernel/traps-xen.c =================================================================== --- latest.orig/arch/x86_64/kernel/traps-xen.c +++ latest/arch/x86_64/kernel/traps-xen.c @@ -109,12 +109,6 @@ static inline void preempt_conditional_c } static int kstack_depth_to_print = 10; -#ifdef CONFIG_STACK_UNWIND -static int call_trace = 1; -#else -#define call_trace (-1) -#endif - #ifdef CONFIG_KALLSYMS # include <linux/kallsyms.h> @@ -239,25 +233,6 @@ static unsigned long *in_exception_stack return NULL; } -struct ops_and_data { - struct stacktrace_ops *ops; - void *data; -}; - -static int dump_trace_unwind(struct unwind_frame_info *info, void *context) -{ - struct ops_and_data *oad = (struct ops_and_data *)context; - int n = 0; - - while (unwind(info) == 0 && UNW_PC(info)) { - if (arch_unw_user_mode(info)) - break; - n++; - oad->ops->address(oad->data, UNW_PC(info)); - } - return n; -} - /* * x86-64 can have upto three kernel stacks: * process stack @@ -275,36 +250,6 @@ void dump_trace(struct task_struct *tsk, if (!tsk) tsk = current; - if (call_trace >= 0) { - int unw_ret = 0; - struct unwind_frame_info info; - struct ops_and_data oad = { .ops = ops, .data = data }; - - if (regs) { - if (unwind_init_frame_info(&info, tsk, regs) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } else if (tsk == current) - unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); - else { - if (unwind_init_blocked(&info, tsk) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } - if (unw_ret > 0) { - if (call_trace == 1 && !arch_unw_user_mode(&info)) { - ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", - UNW_PC(&info)); - if ((long)UNW_SP(&info) < 0) { - ops->warning(data, "Leftover inexact backtrace:\n"); - stack = (unsigned long *)UNW_SP(&info); - } else - ops->warning(data, "Full inexact backtrace again:\n"); - } else if (call_trace >= 1) - return; - else - ops->warning(data, "Full inexact backtrace again:\n"); - } else - ops->warning(data, "Inexact backtrace:\n"); - } if (!stack) { unsigned long dummy; stack = &dummy; @@ -1207,18 +1152,3 @@ static int __init kstack_setup(char *s) } __setup("kstack=", kstack_setup); -#ifdef CONFIG_STACK_UNWIND -static int __init call_trace_setup(char *s) -{ - if (strcmp(s, "old") == 0) - call_trace = -1; - else if (strcmp(s, "both") == 0) - call_trace = 0; - else if (strcmp(s, "newfallback") == 0) - call_trace = 1; - else if (strcmp(s, "new") == 0) - call_trace = 2; - return 1; -} -__setup("call_trace=", call_trace_setup); -#endif