Re: x86_64 segfault error codes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



FWIW I converted the magic numbers now to defines in the source
and deleted the comment (since kernel source is no replacement
for an architecture manual) 

-Andi

Review welcome. I think I didn't do any mistakes though
and the result at least boots.


Convert page fault error codes to symbolic constants.

Much better to deal with these than with the magic numbers.

And remove the comment describing the bits - kernel source
is no replacement for an architecture manual.

Signed-off-by: Andi Kleen <[email protected]>

Index: linux/arch/x86_64/mm/fault.c
===================================================================
--- linux.orig/arch/x86_64/mm/fault.c
+++ linux/arch/x86_64/mm/fault.c
@@ -35,6 +35,13 @@
 #include <asm-generic/sections.h>
 #include <asm/kdebug.h>
 
+/* Page fault error code bits */
+#define PF_PROT	(1<<0)		/* or no page found */
+#define PF_WRITE	(1<<1)
+#define PF_USER	(1<<2)
+#define PF_RSVD	(1<<3)
+#define PF_INSTR	(1<<4)
+
 void bust_spinlocks(int yes)
 {
 	int loglevel_save = console_loglevel;
@@ -68,7 +75,7 @@ static noinline int is_prefetch(struct p
 	unsigned char *max_instr;
 
 	/* If it was a exec fault ignore */
-	if (error_code & (1<<4))
+	if (error_code & PF_INSTR)
 		return 0;
 	
 	instr = (unsigned char *)convert_rip_to_linear(current, regs);
@@ -293,13 +300,6 @@ int exception_trace = 1;
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
- *
- * error_code:
- *	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 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)
@@ -350,7 +350,7 @@ asmlinkage void __kprobes do_page_fault(
 		 * is always initialized because it's shared with the main
 		 * kernel text. Only vmalloc may need PML4 syncups.
 		 */
-		if (!(error_code & 0xd) &&
+		if (!(error_code & (PF_RSVD|PF_KERNEL|PF_PROT)) &&
 		      ((address >= VMALLOC_START && address < VMALLOC_END))) {
 			if (vmalloc_fault(address) < 0)
 				goto bad_area_nosemaphore;
@@ -363,7 +363,7 @@ asmlinkage void __kprobes do_page_fault(
 		goto bad_area_nosemaphore;
 	}
 
-	if (unlikely(error_code & (1 << 3)))
+	if (unlikely(error_code & PF_RSVD))
 		pgtable_bad(address, regs, error_code);
 
 	/*
@@ -390,7 +390,7 @@ asmlinkage void __kprobes do_page_fault(
 	 * thus avoiding the deadlock.
 	 */
 	if (!down_read_trylock(&mm->mmap_sem)) {
-		if ((error_code & 4) == 0 &&
+		if ((error_code & PF_KERNEL) == 0 &&
 		    !search_exception_tables(regs->rip))
 			goto bad_area_nosemaphore;
 		down_read(&mm->mmap_sem);
@@ -417,17 +417,17 @@ asmlinkage void __kprobes do_page_fault(
 good_area:
 	info.si_code = SEGV_ACCERR;
 	write = 0;
-	switch (error_code & 3) {
+	switch (error_code & (PF_PROT|PF_READ) {
 		default:	/* 3: write, present */
 			/* fall through */
-		case 2:		/* write, not present */
+		case PF_WRITE:		/* write, not present */
 			if (!(vma->vm_flags & VM_WRITE))
 				goto bad_area;
 			write++;
 			break;
-		case 1:		/* read, present */
+		case PF_PROT:		/* read, present */
 			goto bad_area;
-		case 0:		/* read, not present */
+		case 0:			/* read, not present */
 			if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 				goto bad_area;
 	}
@@ -462,7 +462,7 @@ bad_area:
 
 bad_area_nosemaphore:
 	/* User mode accesses just cause a SIGSEGV */
-	if (error_code & 4) {
+	if (error_code & PF_USER) {
 		if (is_prefetch(regs, address, error_code))
 			return;
 
@@ -478,7 +478,7 @@ bad_area_nosemaphore:
 
 		if (exception_trace && unhandled_signal(tsk, SIGSEGV)) {
 			printk(
-		       "%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
+		       "%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %x\n",
 					tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
 					tsk->comm, tsk->pid, address, regs->rip,
 					regs->rsp, error_code);
@@ -558,7 +558,7 @@ do_sigbus:
 	up_read(&mm->mmap_sem);
 
 	/* Kernel mode? Handle exceptions or die */
-	if (!(error_code & 4))
+	if (!(error_code & PF_USER))
 		goto no_context;
 
 	tsk->thread.cr2 = address;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux