2005-12-14 18:17:04

by Dave

[permalink] [raw]
Subject: x86_64 segfault error codes

For segfault error codes on x86_64, bits 0-3 are documented in
arch/x86_64/mm/fault.c. However, I am getting error 0x14 and 0x15 with this
particular user app when it segfaults. Is bit 4 valid and what does that
imply?

xxx-001[2085]: segfault at 0000007f960ea86b rip 0000007f960ea86b rsp
0000007fbfffe968 error 14
xxx-001[2091]: segfault at 0000007fbfffe670 rip 0000007fbfffe670 rsp
0000007fbfffe668 error 15

--
-= Dave =-


2005-12-14 18:31:11

by Andi Kleen

[permalink] [raw]
Subject: Re: x86_64 segfault error codes

Dave <[email protected]> writes:

> For segfault error codes on x86_64, bits 0-3 are documented in
> arch/x86_64/mm/fault.c. However, I am getting error 0x14 and 0x15 with this
> particular user app when it segfaults. Is bit 4 valid and what does that
> imply?

bit 4 is documented too in 2.6. It means it was an instruction fetch.
The error code is just the architectural error code for page faults
BTW, see the Intel and AMD manuals for details.

-Andi

2005-12-14 19:24:44

by Dave

[permalink] [raw]
Subject: Re: x86_64 segfault error codes

Ah ok, thx! Looks like the comment in mm/fault.c is wrong then.... It
says bit 3 is instruction fetch and no mention of bit 4.

On 14 Dec 2005 19:31:07 +0100, Andi Kleen <[email protected]> wrote:
> Dave <[email protected]> writes:
>
> > For segfault error codes on x86_64, bits 0-3 are documented in
> > arch/x86_64/mm/fault.c. However, I am getting error 0x14 and 0x15 with this
> > particular user app when it segfaults. Is bit 4 valid and what does that
> > imply?
>
> bit 4 is documented too in 2.6. It means it was an instruction fetch.
> The error code is just the architectural error code for page faults
> BTW, see the Intel and AMD manuals for details.
>
> -Andi
>


--
-= Dave =-

2005-12-14 19:58:50

by Andi Kleen

[permalink] [raw]
Subject: Re: x86_64 segfault error codes

On Wed, Dec 14, 2005 at 12:24:42PM -0700, Dave wrote:
> Ah ok, thx! Looks like the comment in mm/fault.c is wrong then.... It
> says bit 3 is instruction fetch and no mention of bit 4.

Don't know what kernel you're looking at, but 2.6.15rc5 has

* 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



-Andi

2005-12-14 20:09:40

by Dave

[permalink] [raw]
Subject: Re: x86_64 segfault error codes

On 12/14/05, Andi Kleen <[email protected]> wrote:
> On Wed, Dec 14, 2005 at 12:24:42PM -0700, Dave wrote:
> > Ah ok, thx! Looks like the comment in mm/fault.c is wrong then.... It
> > says bit 3 is instruction fetch and no mention of bit 4.
>
> Don't know what kernel you're looking at, but 2.6.15rc5 has
>
> * 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

Ah sorry. Was looking at 2.6.14.

--
-= Dave =-

2005-12-15 09:56:04

by Hugh Dickins

[permalink] [raw]
Subject: Re: x86_64 segfault error codes

On Wed, 14 Dec 2005, Andi Kleen wrote:
>
> Don't know what kernel you're looking at, but 2.6.15rc5 has
>
> * 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

I can't see it there in 2.6.15-rc5 or 2.6.15-rc5-git; but it is there
in 2.6.15-rc5-mm3: which seems to contains a lot of x86_64 patches,
perhaps some of which you're expecting already to be in 2.6.15?

Hugh

2005-12-15 09:59:57

by Andi Kleen

[permalink] [raw]
Subject: Re: x86_64 segfault error codes

On Thu, Dec 15, 2005 at 09:55:40AM +0000, Hugh Dickins wrote:
> On Wed, 14 Dec 2005, Andi Kleen wrote:
> >
> > Don't know what kernel you're looking at, but 2.6.15rc5 has
> >
> > * 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
>
> I can't see it there in 2.6.15-rc5 or 2.6.15-rc5-git; but it is there
> in 2.6.15-rc5-mm3: which seems to contains a lot of x86_64 patches,
> perhaps some of which you're expecting already to be in 2.6.15?

Yah it's only in the 2.6.16 queue. Sorry for the confusion.

Anyways nobody should rely on these comments. If you want the details
look at the architecture manuals.

-Andi

2005-12-15 14:49:46

by Andi Kleen

[permalink] [raw]
Subject: Re: x86_64 segfault error codes


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;