x86-64: separate unwind info generation from CONFIG_DEBUG_INFO
PATCH 1/1 x86-64: separate unwind info generation from CONFIG_DEBUG_INFO
As a follow-up to the introduction of CONFIG_UNWIND_INFO, this separates the generation of frame unwind information for x86-64 from that of full debug information.
From: Jan Beulich <[email protected]>
(actual patch attached)
As a follow-up to the introduction of CONFIG_UNWIND_INFO, this separates the generation of frame unwind information for x86-64 from that of full debug information.
From: Jan Beulich <[email protected]>
arch/x86_64/Makefile +3 -1
@@ -38,8 +38,10 @@ CFLAGS += -pipe # actually it makes the kernel smaller too. CFLAGS += -fno-reorder-blocks CFLAGS += -Wno-sign-compare -ifneq ($(CONFIG_DEBUG_INFO),y) +ifneq ($(CONFIG_UNWIND_INFO),y) CFLAGS += -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. #CFLAGS += $(call cc-option,-fweb)
arch/x86_64/kernel/vmlinux.lds.S +1 -1
@@ -189,7 +189,7 @@ SECTIONS /* Sections to be discarded */ /DISCARD/ : { *(.exitcall.exit) -#ifndef CONFIG_DEBUG_INFO +#ifndef CONFIG_UNWIND_INFO *(.eh_frame) #endif }
include/asm-x86_64/dwarf2.h +1 -1
@@ -14,7 +14,7 @@away for older version. */ -#ifdef CONFIG_DEBUG_INFO +#ifdef CONFIG_UNWIND_INFO #define CFI_STARTPROC .cfi_startproc#define CFI_ENDPROC .cfi_endproc
PATCH 1/1 x86-64: fix bound check IDT gate
Other than apparently commonly assumed, the bound instruction does not require the corresponding IDT entry to have DPL 3.
From: Jan Beulich <[email protected]>
(actual patch attached)
Other than apparently commonly assumed, the bound instruction does not require the corresponding IDT entry to have DPL 3.
From: Jan Beulich <[email protected]>
arch/x86_64/kernel/traps.c +2 -2
@@ -917,8 +917,8 @@ void __init trap_init(void)set_intr_gate_ist (1 ,&debug,DEBUG_STACK );set_intr_gate_ist (2 ,&nmi,NMI_STACK );set_system_gate (3 ,&int3); -set_system_gate (4 ,&overflow);/* int4-5 can be called from all */ -set_system_gate (5 ,&bounds); +set_system_gate (4 ,&overflow);/* int4 can be called from all */ +set_intr_gate (5 ,&bounds);set_intr_gate (6 ,&invalid_op);set_intr_gate (7 ,&device_not_available);set_intr_gate_ist (8 ,&double_fault,DOUBLEFAULT_STACK );
PATCH 1/1 x86-64: remove dead die_if_kernel()
In reply to Jan BeulichRemoving unused function die_if_kernel().
From: Jan Beulich <[email protected]>
(actual patch attached)
Removing unused function die_if_kernel().
From: Jan Beulich <[email protected]>
arch/x86_64/kernel/traps.c +0 -5
@@ -399,11 +399,6 @@ void die(const char * str, struct pt_regoops_end (flags);do_exit (SIGSEGV ); } -static inline void die_if_kernel (const char * str,struct pt_regs * regs,long err) -{ -if (!(regs->eflags &VM_MASK ) && (regs->cs == __KERNEL_CS)) -die (str, regs, err); -}void die_nmi (char *str,struct pt_regs *regs) {
PATCH 1/1 x86-64: make trap information available to die notification handlers
In reply to Jan BeulichThis adjusts things so that handlers of the die() notifier will have sufficient information about the trap currently being handled. It also adjusts the notify_die() prototype to (again) match that of i386.
From: Jan Beulich <[email protected]>
(actual patch attached)
This adjusts things so that handlers of the die() notifier will have sufficient information about the trap currently being handled. It also adjusts the notify_die() prototype to (again) match that of i386.
From: Jan Beulich <[email protected]>
arch/x86_64/kernel/traps.c +12 -9
@@ -382,7 +382,7 @@ void __die(const char * str, struct pt_rprintk ("DEBUG_PAGEALLOC" );#endif printk ("\n" ); -notify_die (DIE_OOPS , (char *)str, regs, err,255 ,SIGSEGV ); +notify_die (DIE_OOPS , str, regs, err, current->thread.trap_no,SIGSEGV );show_registers (regs);/* Executive summary in case the oops scrolled away */ printk (KERN_ALERT "RIP " );
@@ -426,6 +426,8 @@ static void __kprobes do_trap(int trapnr struct pt_regs * regs, long error_code, siginfo_t *info) { + struct task_struct *tsk = current; +conditional_sti (regs);#ifdef CONFIG_CHECKING
@@ -441,17 +443,16 @@ static void __kprobes do_trap(int trapnr }#endif -if (user_mode (regs)) { -struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; +if (user_mode (regs)) {if (exception_trace &&unhandled_signal (tsk, signr))printk (KERN_INFO "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n" , tsk->comm, tsk->pid, str, regs->rip,regs->rsp,error_code); - tsk->thread.error_code = error_code; - tsk->thread.trap_no = trapnr;if (info)force_sig_info (signr, info, tsk);else
@@ -511,6 +512,8 @@ DO_ERROR( 8, SIGSEGV, "double fault", do asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,long error_code) { +struct task_struct *tsk = current; +conditional_sti (regs);#ifdef CONFIG_CHECKING
@@ -527,17 +530,16 @@ asmlinkage void __kprobes do_general_pro }#endif -if (user_mode (regs)) { -struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no =13 ; +if (user_mode (regs)) {if (exception_trace &&unhandled_signal (tsk,SIGSEGV ))printk (KERN_INFO "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n" , tsk->comm, tsk->pid, regs->rip,regs->rsp,error_code); - tsk->thread.error_code = error_code; - tsk->thread.trap_no =13 ;force_sig (SIGSEGV , tsk);return ; }
@@ -748,6 +750,7 @@ static int kernel_math_error(struct pt_r }notify_die (DIE_GPF , str, regs,0 ,16 ,SIGFPE );/* Illegal floating point operation in the kernel */ + current->thread.trap_no =16 ;die (str, regs,0 );return 0 ; }
arch/x86_64/mm/fault.c +8 -0
@@ -222,10 +222,15 @@ static noinline void pgtable_bad(unsigne unsigned long error_code) {unsigned long flags =oops_begin (); +struct task_struct *tsk;printk (KERN_ALERT "%s: Corrupted page table at address %lx\n" , current->comm, address);dump_pagetable (address); + tsk = current; + tsk->thread.cr2 = address; + tsk->thread.trap_no =14 ; + tsk->thread.error_code = error_code;__die ("Bad pagetable" , regs, error_code);oops_end (flags);do_exit (SIGKILL );
@@ -533,6 +538,9 @@ no_context:printk_address (regs->rip);printk ("\n" );dump_pagetable (address); + tsk->thread.cr2 = address; + tsk->thread.trap_no =14 ; + tsk->thread.error_code = error_code;__die ("Oops" , regs, error_code);/* Executive summary in case the body of the oops scrolled away */ printk (KERN_EMERG "CR2: %016lx\n" , address);
include/asm-x86_64/kdebug.h +10 -3
@@ -35,9 +35,16 @@ enum die_val { DIE_PAGE_FAULT, }; -static inline int notify_die (enum die_val val,char *str,struct pt_regs *regs,long err,int trap,int sig) -{ -struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig }; +static inline int notify_die (enum die_val val,const char *str, +struct pt_regs *regs,long err,int trap,int sig) +{ +struct die_args args = { + .regs = regs, + .str = str, + .err = err, + .trapnr = trap, + .signr = sig + };return notifier_call_chain (&die_chain, val, &args); }
PATCH 1/1 x86-64: adjust double fault handling
In reply to Jan BeulichSince a double fault always implies that kernel data structures are corrupt, this fault should neither be handed to user mode handling, nor should the handler allow resuming the faulting code stream (since architecturally this isn't a fault, but an abort).
Note that this slightly depends on the previously submitted patch adjusting the prototype of notify_die() (a compiler warning will result
without that other patch).
From: Jan Beulich <[email protected]>
(actual patch attached)
Since a double fault always implies that kernel data structures are corrupt, this fault should neither be handed to user mode handling, nor should the handler allow resuming the faulting code stream (since architecturally this isn't a fault, but an abort).
Note that this slightly depends on the previously submitted patch adjusting the prototype of notify_die() (a compiler warning will result without that other patch).
From: Jan Beulich <[email protected]>
arch/x86_64/kernel/traps.c +29 -1
@@ -506,7 +506,35 @@ DO_ERROR(11, SIGBUS, "segment not prese DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) DO_ERROR(18, SIGSEGV, "reserved", reserved) DO_ERROR(12, SIGBUS, "stack segment", stack_segment) -DO_ERROR( 8, SIGSEGV, "double fault", double_fault) + +asmlinkage void do_double_fault(struct pt_regs * regs, long error_code) +{ +static const char str[] ="double fault" ; +struct task_struct *tsk = current; + +notify_die (DIE_TRAP , str, regs, error_code,8 ,SIGSEGV ); + +#ifdef CONFIG_CHECKING + { +unsigned long gs; +struct x8664_pda *pda = cpu_pda +safe_smp_processor_id (); +rdmsrl (MSR_GS_BASE , gs); +if (gs != (unsigned long )pda) { +wrmsrl (MSR_GS_BASE , pda); +printk ("%s: wrong gs %lx expected %p rip %lx\n" , + str, gs, pda, regs->rip); + } + } +#endif + + tsk->thread.error_code = error_code; + tsk->thread.trap_no =8 ; + +/* This is always a kernel trap and never fixable (and thus must +never return). */ +for (;;) +die (str, regs, error_code); +} asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,long error_code)
PATCH 1/1 x86-64: remove unprotected iret
In reply to Jan BeulichMake sure no iret can fault without attached recovery code.
From: Jan Beulich <[email protected]>
(actual patch attached)
Make sure no iret can fault without attached recovery code.
From: Jan Beulich <[email protected]>
arch/x86_64/kernel/entry.S +1 -1
@@ -751,7 +751,7 @@ error_exit: jnz retint_careful swapgs RESTORE_ARGS 0,8,0 - iretq + jmp iret_label CFI_ENDPROC error_kernelspace:
Re: [discuss] [PATCH] x86-64: remove unprotected iret
Quoted 1 line · Jan Beulich
Make sure no iret can fault without attached recovery code.
The reason it was done this way was that normally iret can only go bad after ptrace and ptrace is handled in the careful path.
But I agree it's safer.
Your patch series looks good. I will try to merge it later
-Andi
PATCH 1/1 x86-64: adjust page fault handling
In reply to Jan BeulichAdjust page fault protection error check before considering it to be a vmalloc synchronization candidate.
From: Jan Beulich <[email protected]>
(actual patch attached)
Adjust page fault protection error check before considering it to be a vmalloc synchronization candidate.
From: Jan Beulich <[email protected]>
arch/x86_64/mm/fault.c +4 -3
@@ -294,7 +294,8 @@ int exception_trace = 1;* bit 0 == 0 means no page found, 1 means protection fault * bit 1 == 0 means read, 1 means write * bit 2 == 0 means kernel, 1 means user-mode -* bit 3 == 1 means fault was an instruction fetch +* bit 3 == 1 means use of reserved bit detected +* bit 4 == 1 means fault was an instruction fetch */ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,unsigned long error_code)
@@ -349,10 +350,10 @@ asmlinkage void __kprobes do_page_fault(* * This verifies that the fault happens in kernel space * (error_code & 4) == 0, and that the fault was not a -* protection error (error_code & 1) == 0. +* protection error (error_code & 9) == 0. */ if (unlikely (address >=TASK_SIZE64 )) { -if (!(error_code &5 ) && +if (!(error_code &0xd ) && ((address >=VMALLOC_START && address <VMALLOC_END ) || (address >=MODULES_VADDR && address <MODULES_END ))) {if (vmalloc_fault (address) <0 )
PATCH 1/1 x86-64: adjust ia32entry.S
IA32 compatibility entry points needlessly played with extended registers. Additionally, frame unwind information was still incorrect for ia32_ptregs_common (sorry, my fault).
From: Jan Beulich <[email protected]>
(actual patch attached)
IA32 compatibility entry points needlessly played with extended registers. Additionally, frame unwind information was still incorrect for ia32_ptregs_common (sorry, my fault).
From: Jan Beulich <[email protected]>
arch/x86_64/ia32/ia32entry.S +56 -28
@@ -26,13 +26,29 @@ movl %edx,%edx /* zero extension */ .endm - /* clobbers %eax */ - .macro CLEAR_RREGS - xorl %eax,%eax - movq %rax,R11(%rsp) - movq %rax,R10(%rsp) - movq %rax,R9(%rsp) - movq %rax,R8(%rsp) + /* clobbers specified register (or %eax) */ + .macro CLEAR_RREGS r=ax + xorl %e\r,%e\r + movq %r\r,R15(%rsp) + movq %r\r,R14(%rsp) + movq %r\r,R13(%rsp) + movq %r\r,R12(%rsp) + movq %r\r,R11(%rsp) + movq %r\r,R10(%rsp) + movq %r\r,R9(%rsp) + movq %r\r,R8(%rsp) + .endm + + .macro CFI_STARTPROC32 simple + CFI_STARTPROC \simple + CFI_UNDEFINED r8 + CFI_UNDEFINED r9 + CFI_UNDEFINED r10 + CFI_UNDEFINED r11 + CFI_UNDEFINED r12 + CFI_UNDEFINED r13 + CFI_UNDEFINED r14 + CFI_UNDEFINED r15 .endm /*
@@ -55,7 +71,7 @@ * with the int 0x80 path. */ ENTRY(ia32_sysenter_target) - CFI_STARTPROC simple + CFI_STARTPROC32 simple CFI_DEF_CFA rsp,0 CFI_REGISTER rsp,rbp swapgs
@@ -107,7 +123,7 @@ sysenter_do_call: jnz int_ret_from_sys_call /* clear IF, that popfq doesn't enable interrupts early */ andl $~0x200,EFLAGS-R11(%rsp) - RESTORE_ARGS 1,24,1,1,1,1 + RESTORE_ARGS 1,24,1,1,1 popfq CFI_ADJUST_CFA_OFFSET -8 /*CFI_RESTORE rflags*/
@@ -123,14 +139,13 @@ sysenter_do_call: sysenter_tracesys: CFI_RESTORE_STATE - SAVE_REST + SAVE_REST 1 CLEAR_RREGS movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ - RESTORE_REST - movl %ebp, %ebp + LOAD_ARGS ARGOFFSET,0,1 /* reload args from stack in case ptrace changed it */ + RESTORE_REST 1 /* no need to do an access_ok check here because rbp has been 32bit zero extended */ 1: movl (%rbp),%r9d
@@ -161,7 +176,7 @@ sysenter_tracesys: * with the int 0x80 path. */ ENTRY(ia32_cstar_target) - CFI_STARTPROC simple + CFI_STARTPROC32 simple CFI_DEF_CFA rsp,0 CFI_REGISTER rip,rcx /*CFI_REGISTER rflags,r11*/
@@ -204,7 +219,7 @@ cstar_do_call: cli testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10) jnz int_ret_from_sys_call - RESTORE_ARGS 1,-ARG_SKIP,1,1,1 + RESTORE_ARGS 1,-ARG_SKIP,1,1 movl RIP-ARGOFFSET(%rsp),%ecx CFI_REGISTER rip,rcx movl EFLAGS-ARGOFFSET(%rsp),%r11d
@@ -216,14 +231,14 @@ cstar_do_call: cstar_tracesys: CFI_RESTORE_STATE - SAVE_REST + SAVE_REST 1 CLEAR_RREGS movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ - RESTORE_REST - movl RSP-ARGOFFSET(%rsp), %r8d + LOAD_ARGS ARGOFFSET,0,1 /* reload args from stack in case ptrace changed it */ + movl RSP(%rsp), %r8d + RESTORE_REST 1 /* no need to do an access_ok check here because r8 has been 32bit zero extended */ 1: movl (%r8),%r9d
@@ -259,7 +274,7 @@ ia32_badarg: */ ENTRY(ia32_syscall) - CFI_STARTPROC simple + CFI_STARTPROC32 simple CFI_DEF_CFA rsp,SS+8-RIP /*CFI_REL_OFFSET ss,SS-RIP*/ CFI_REL_OFFSET rsp,RSP-RIP
@@ -288,12 +303,13 @@ ia32_sysret: jmp int_ret_from_sys_call ia32_tracesys: - SAVE_REST + SAVE_REST 1 + CLEAR_RREGS movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ - RESTORE_REST + LOAD_ARGS ARGOFFSET,0,1 /* reload args from stack in case ptrace changed it */ + RESTORE_REST 1 jmp ia32_do_syscall ia32_badsys:
@@ -318,7 +334,7 @@ quiet_ni_syscall: jmp ia32_ptregs_common .endm - CFI_STARTPROC + CFI_STARTPROC32 PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
@@ -333,11 +349,23 @@ quiet_ni_syscall: ENTRY(ia32_ptregs_common) popq %r11 - CFI_ADJUST_CFA_OFFSET -8 - CFI_REGISTER rip, r11 - SAVE_REST + CFI_ENDPROC + CFI_STARTPROC32 simple + CFI_DEF_CFA rsp,SS+8-ARGOFFSET + CFI_REL_OFFSET rax,RAX-ARGOFFSET + CFI_REL_OFFSET rcx,RCX-ARGOFFSET + CFI_REL_OFFSET rdx,RDX-ARGOFFSET + CFI_REL_OFFSET rsi,RSI-ARGOFFSET + CFI_REL_OFFSET rdi,RDI-ARGOFFSET + CFI_REL_OFFSET rip,RIP-ARGOFFSET +/* CFI_REL_OFFSET cs,CS-ARGOFFSET*/ +/* CFI_REL_OFFSET rflags,EFLAGS-ARGOFFSET*/ + CFI_REL_OFFSET rsp,RSP-ARGOFFSET +/* CFI_REL_OFFSET ss,SS-ARGOFFSET*/ + SAVE_REST 1 + CLEAR_RREGS bx call *%rax - RESTORE_REST + RESTORE_REST 1 jmp ia32_sysret /* misbalances the return cache */ CFI_ENDPROC
include/asm-x86_64/calling.h +51 -10
142 lines not on this page · raw message
include/asm-x86_64/dwarf2.h +2 -0
@@ -28,6 +28,7 @@#define CFI_RESTORE .cfi_restore#define CFI_REMEMBER_STATE .cfi_remember_state#define CFI_RESTORE_STATE .cfi_restore_state +#define CFI_UNDEFINED .cfi_undefined#else
@@ -44,6 +45,7 @@#define CFI_RESTORE ##define CFI_REMEMBER_STATE ##define CFI_RESTORE_STATE # +#define CFI_UNDEFINED ##endif
Re: [PATCH] x86-64: adjust ia32entry.S
Quoted 3 lines · Jan Beulich
IA32 compatibility entry points needlessly played with extended registers. Additionally, frame unwind information was still incorrect for
ia32_ptregs_common(sorry, my fault).
What do you mean with needlessly played? That it didn't initialize all on the stack frame? That was more a feature than a bug. Did it cause you problems?
In general I'm weary of making the asm macros more complex (adding more arguments etc.) Please keep it simple.
-Andi
Re: [PATCH] x86-64: adjust ia32entry.S
Quoted 4 lines
Quoted 1 line
Quoted 1 line
Andi Kleen <[email protected]> 11.11.05 16:34:44 >>>
Quoted 2 lines · Jan Beulich
IA32 compatibility entry points needlessly played with extended registers. Additionally, frame unwind information was still
incorrect
Quoted 5 lines
Quoted 1 line
for
ia32_ptregs_common(sorry, my fault).What do you mean with needlessly played? That it didn't initialize all on the stack frame? That was more a feature than a bug. Did it cause you problems?
It saved and restored R12-R15, even though these registers have no meaning (and are architecturally undefined) when coming from/going to 32-bit mode. Problems? No, except that without the extra loads (stores don't matter that much I believe) performance is better...
Quoted 2 lines
In general I'm weary of making the asm macros more complex (adding more arguments etc.) Please keep it simple.
Then ignore this, perhaps with the exception of the unwind info adjustment.
Jan
Re: [discuss] Re: [PATCH] x86-64: adjust ia32entry.S
Quoted 10 lines · Jan Beulich
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Andi Kleen <[email protected]> 11.11.05 16:34:44 >>>
Quoted 2 lines · Jan Beulich
IA32 compatibility entry points needlessly played with extended registers. Additionally, frame unwind information was still
incorrect
Quoted 2 lines
Quoted 1 line
for
ia32_ptregs_common(sorry, my fault).
Quoted 8 lines
Quoted 3 lines
What do you mean with needlessly played? That it didn't initialize all on the stack frame? That was more a feature than a bug. Did it cause you problems?
It saved and restored R12-R15, even though these registers have no meaning (and are architecturally undefined) when coming from/going to 32-bit mode. Problems? No, except that without the extra loads (stores don't matter that much I believe) performance is better...
int 0x80 can be called from long mode too. We especially kept this option to allow JITs like valgrind to run a 32bit process in a 64bit image. In this case we shouldn't leak kernel registers.
You're right they normally shouldn't be leaked anyways because the C ABI will save/restore it. I will think about it.
Quoted 6 lines
Quoted 3 lines
In general I'm weary of making the asm macros more complex (adding more arguments etc.) Please keep it simple.
Then ignore this, perhaps with the exception of the unwind info adjustment.
Can you please resubmit that as a separate patch?
-Andi