coredump of firefox(76129), write failed: errno 14

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

coredump of firefox(76129), write failed: errno 14

Sebastien Marie-3
Hi,

I report this error as it is the first time I saw it when a coredump is
generated.

It occurs reproductibly with my current profile (but not with a fresh
profile) when firefox crashs (currently when I visit
https://locka99.gitbooks.io/a-guide-to-porting-c-to-rust with JS
activated).

Please note that my point isn't the firefox crash, but the kernel error
message.

(launch firefox and visit url above)
$ firefox

(firefox:76129): Gdk-ERROR **: The program 'firefox' received an X Window System error.
This probably reflects a bug in the program.
The error was 'RenderBadPicture (invalid Picture parameter)'.
  (Details: serial 59593 error_code 143 request_code 139 (RENDER) minor_code 7)
  (Note to programmers: normally, X errors are reported asynchronously;
   that is, you will receive the error a while after causing it.
   To debug your program, run it with the GDK_SYNCHRONIZE environment
   variable to change this behavior. You can then get a meaningful
   backtrace from your debugger if you break on the gdk_x_error() function.)
[Child 4704] ###!!! ABORT: Aborting on channel error.: file /usr/obj/ports/firefox-51.0/firefox-51.0/ipc/glue/MessageChannel.cpp, line 2056
[Child 4704] ###!!! ABORT: Aborting on channel error.: file /usr/obj/ports/firefox-51.0/firefox-51.0/ipc/glue/MessageChannel.cpp, line 2056
Trace/BPT trap


When it occurs, I have these errors messages in dmesg buffer:

coredump of firefox(76129), write failed: errno 14
coredump of firefox(4704), write failed: errno 14



A firefox.core is generated, and gdb is able to open it:

$ gdb firefox firefox.core      
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "amd64-unknown-openbsd6.0"...(no debugging symbols found)

Core was generated by `firefox'.
Program terminated with signal 4, Illegal instruction.
Cannot access memory at address 0x9f1bbf0bf08
#0  0x0000000000000000 in ?? ()
(gdb)


The kernel error message comes from coredump_write() function inside
sys/kern/kern_sig.c:1619.

Errno 14 is the error code from vn_rdwr(9). It is EFAULT, and occurs
when a bad address is encountered.

As I don't expect the kernel trying to do something at bad address (even
with a bad program), I prefer to report the error message.


My firefox profile has electrolysis enabled (multiprocesses). Here the
two processes (pid 76129 and 4704) have crashed at same time. Maybe it
is a race somewhere ? I dunno.

I also quickly deep inside the generated coredump to see if all content
belong to firefox and it seems ok.

Thanks.
--
Sebastien Marie

Reply | Threaded
Open this post in threaded view
|

Re: coredump of firefox(76129), write failed: errno 14

Philip Guenther
On Sun, 29 Jan 2017, Sebastien Marie wrote:
> I report this error as it is the first time I saw it when a coredump is
> generated.
>
> It occurs reproductibly with my current profile (but not with a fresh
> profile) when firefox crashs (currently when I visit <...> with JS
> activated).
>
> Please note that my point isn't the firefox crash, but the kernel error
> message.
...
> When it occurs, I have these errors messages in dmesg buffer:
>
> coredump of firefox(76129), write failed: errno 14
> coredump of firefox(4704), write failed: errno 14
...
> The kernel error message comes from coredump_write() function inside
> sys/kern/kern_sig.c:1619.
>
> Errno 14 is the error code from vn_rdwr(9). It is EFAULT, and occurs
> when a bad address is encountered.
>
> As I don't expect the kernel trying to do something at bad address (even
> with a bad program), I prefer to report the error message.

My recall from when I last looked at this is that this generally means
that while trying to write out the memory from an anonymous mapping, the
kernel hits a range which isn't currently backed *and* the process is at
or over its memory limit, so it can't be filled in.

I would argue that uvm_coredump_walkmap() should detect unbacked pages in
anons and indicate this to the callback, possibly invoking the calling
multiple times to walk it across the backed-vs-unbacked ranges of a single
umv_map_entry.  ELFNAMEEND(coredump_writeseghdrs)() would then generate
segments with p_filesz < p_memsz to reflect that, so the unbacked pages
wouldn't be part of the segment's memory size, but not its file size, and
thus wouldn't be written out.

(e.g., if pagesize == 0x1000 and the VA range 0x1234000 - 0x124ffff was an
anon mapping but only the pages 0x1235000, 0x1236000, and 0x1240000
through 0x124f000 had been faulted into actual existence, then I would
have uvm_coredump_walkmap() invoke the callback three times:
        start realend end
        0x1234000 0x1234000 0x1235000
        0x1235000 0x1237000 0x1240000
        0x1240000 0x1250000 0x1250000


Indeed, the exec_elf.c side of that is already there, though currently
it's only in play for the stack on hppa: check out the
MACHINE_STACK_GROWS_UP section of uvm_coredump_walkmap() in
uvm/uvm_unix.c.  <pause>  Actually, that code looks broken, as it's moving
down state.end to a value less than state.realend, but exec_elf.c expects
state.realend to always be >= state.end!  Dang it, now I have to fire up
the hppa again...


Philip Guenther

Reply | Threaded
Open this post in threaded view
|

Re: coredump of firefox(76129), write failed: errno 14

Philip Guenther
Sun, 29 Jan 2017, Philip Guenther wrote:
...
> Indeed, the exec_elf.c side of that is already there, though currently
> it's only in play for the stack on hppa: check out the
> MACHINE_STACK_GROWS_UP section of uvm_coredump_walkmap() in
> uvm/uvm_unix.c.  <pause>  Actually, that code looks broken, as it's moving
> down state.end to a value less than state.realend, but exec_elf.c expects
> state.realend to always be >= state.end!  Dang it, now I have to fire up
> the hppa again...

[[TYPO: exec_elf.c expects state.realend to always be *less than* or equal
to state.end, as realend is the source for p_filesiz while end is the
source for p_memsz, and ELF requires that p_filesz <= p_memsz for PT_LOAD
segments.]]

Yes, this code currently is broken on hppa: if the stack rlimit is beyond
that last page actually used by the program at the time of the coredump,
then an invalid ELF core file is generated that has a segment with
p_filesz > p_memsz:

: jackal; uname -a
OpenBSD jackal.my.domain 6.0 LOCAL#0 hppa
: jackal; ulimit -s 32768
: jackal; vis
^\Quit (core dumped)

: jackal; readelf -l vis.core  | awk '!/LOAD/ || $5 > $6'

Elf file type is CORE (Core file)
Entry point 0x0
There are 42 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x047840 0x7801b000 0x00000000 0x05000 0x03000 RW  0x1000
  NOTE           0x000574 0x00000000 0x00000000 0x002cc 0x00000 R   0x4
: jackal;


The stack handling code in uvm_coredump_walkmap() is, AFAICT, just trying
to skip pages that aren't actually backed.  If we do that all on amaps
then the jockeying (and #ifdef) there can go away.  The diff below appear
to work for me, tested on macppc so far.

It delegates the dumping of uvm_map_entries for amaps to a new function
uvm_coredump_walk_amap() that uses amap_lookups() calls to see which pages
are actually backed and generates calls to the callback for ranges of N
present pages followed by M absent pages, where N + M > 0 but either N or
M may be zero.

To confirm the results, I started a perl process and twice had it fork
with the child killing itself with SIGQUIT to generate a core, with this
new functionality enabled for one child+core but not the other.  Diffing
the output of "readelf -l" on the two core files (with the
offset-in-the-core-file column removed) shows these differences:


< There are 820 program headers, starting at offset 52
---
> There are 826 program headers, starting at offset 52
37c37
<   LOAD           0xbb7fd000 0x00000000 0x04000 0x04000 RW  0x1000
---
>   LOAD           0xbb7fd000 0x00000000 0x01000 0x04000 RW  0x1000
182c182
<   LOAD           0xbebb6000 0x00000000 0x04000 0x04000 RW  0x1000
---
>   LOAD           0xbebb6000 0x00000000 0x01000 0x04000 RW  0x1000
184c184,185
<   LOAD           0xbebbb000 0x00000000 0x09000 0x09000 RW  0x1000
---
>   LOAD           0xbebbb000 0x00000000 0x01000 0x05000 RW  0x1000
>   LOAD           0xbebc0000 0x00000000 0x02000 0x04000 RW  0x1000
334c335,336
<   LOAD           0xc1c86000 0x00000000 0x04000 0x04000 RW  0x1000
---
>   LOAD           0xc1c86000 0x00000000 0x01000 0x03000 RW  0x1000
>   LOAD           0xc1c89000 0x00000000 0x01000 0x01000 RW  0x1000
344c346,347
<   LOAD           0xc1e26000 0x00000000 0x04000 0x04000 RW  0x1000
---
>   LOAD           0xc1e26000 0x00000000 0x01000 0x03000 RW  0x1000
>   LOAD           0xc1e29000 0x00000000 0x01000 0x01000 RW  0x1000
397c400,401
<   LOAD           0xc2f39000 0x00000000 0x03000 0x03000 RW  0x1000
---
>   LOAD           0xc2f39000 0x00000000 0x01000 0x02000 RW  0x1000
>   LOAD           0xc2f3b000 0x00000000 0x01000 0x01000 RW  0x1000
571c575,576
<   LOAD           0xc61b2000 0x00000000 0x03000 0x03000 RW  0x1000
---
>   LOAD           0xc61b2000 0x00000000 0x00000 0x01000 RW  0x1000
>   LOAD           0xc61b3000 0x00000000 0x02000 0x02000 RW  0x1000
826c831,832
<   LOAD           0xfffe0000 0x00000000 0x0f000 0x0f000 RW  0x1000
---
>   LOAD           0xfffe0000 0x00000000 0x00000 0x09000 RW  0x1000
>   LOAD           0xfffe9000 0x00000000 0x06000 0x06000 RW  0x1000

That last chunk, for example, shows that where it previously would have
dumped 15 pages [0xfffe0000, 0xfffef000), it instead shows 9 unbacked
pages [0xfffe0000, 0xfffe9000) and then actually dumps only 6 pages
[0xfffe9000, 0xfffef000).  This means the kernel no longer had to fault in
and create empty backing for those 9 pages, just to write them to the core
file.

I see one thing that need to be checked and fixed in this and one thing
that might need pondering.  The important question is if I create a
*shared* anonymous mapping, can I have process A force another page to be
faulted in and backed while process B is trying to dump the mapping?  If
so, I can trigger an kernel assert by requiring a range to be split, which
will increase the number of segments needed to dump that range in the
core.  Lock all the map entries in the uvmspace across the two walks?  
Yuck...

The minor thought is about how the kernel's coredump code allocates memory
to hold all the segment headers with mallocarray().  An amd64 process can
have MAXDSIZ / PAGE_SIZE == 8 million pages.  If you allocate every other
page, it would require 4 million segments in the core file, which would
take 224MB.  Is that malloc w/M_WAITOK possibly excessive?  Will the
increase in segment count from this diff make whatever limit there is for
this easier to hit?


semarie@, you can consistently trigger that kernel log message, perhaps
you can try reproducing it with this patch and see if it goes away?


Thoughts/comments on the diff?

Philip


Index: uvm/uvm_extern.h
===================================================================
RCS file: /data/src/openbsd/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.139
diff -u -p -r1.139 uvm_extern.h
--- uvm/uvm_extern.h 5 Jun 2016 08:35:57 -0000 1.139
+++ uvm/uvm_extern.h 31 Jan 2017 07:26:48 -0000
@@ -245,14 +245,11 @@ extern struct pool *uvm_aiobuf_pool;
 struct uvm_coredump_state {
  void *cookie; /* opaque for the caller */
  vaddr_t start; /* start of region */
- vaddr_t realend; /* real end of region */
+ vaddr_t realend; /* real end of region (<= end) */
  vaddr_t end; /* virtual end of region */
  vm_prot_t prot; /* protection of region */
- int flags; /* flags; see below */
 };
 
-#define UVM_COREDUMP_STACK 0x01 /* region is user stack */
-
 /*
  * the various kernel maps, owned by MD code
  */
@@ -460,7 +457,7 @@ void uvm_pmr_use_inc(paddr_t, paddr_t)
 void uvm_swap_init(void);
 int uvm_coredump_walkmap(struct proc *,
     void *, int (*)(struct proc *, void *,
-    struct uvm_coredump_state *), void *);
+    const struct uvm_coredump_state *), void *);
 void uvm_grow(struct proc *, vaddr_t);
 void uvm_deallocate(vm_map_t, vaddr_t, vsize_t);
 struct uvm_object *uvn_attach(struct vnode *, vm_prot_t);
Index: uvm/uvm_unix.c
===================================================================
RCS file: /data/src/openbsd/src/sys/uvm/uvm_unix.c,v
retrieving revision 1.60
diff -u -p -r1.60 uvm_unix.c
--- uvm/uvm_unix.c 16 Sep 2016 01:09:53 -0000 1.60
+++ uvm/uvm_unix.c 31 Jan 2017 07:27:22 -0000
@@ -134,26 +134,77 @@ uvm_grow(struct proc *p, vaddr_t sp)
 
 #ifndef SMALL_KERNEL
 
+#define WALK_CHUNK 32
+int
+uvm_coredump_walk_amap(struct proc *p, struct vm_map_entry *entry,
+    void *iocookie,
+    int (*func)(struct proc *, void *, const struct uvm_coredump_state *),
+    struct uvm_coredump_state *state)
+{
+ struct vm_anon *anons[WALK_CHUNK];
+ vaddr_t start, end;
+ int absent = 0;
+ int npages, i, error;
+
+ state->start = start = entry->start;
+ end = MIN(entry->end, VM_MAXUSER_ADDRESS);
+
+ for (; start < end; start += npages << PAGE_SHIFT) {
+ npages = (end - start) >> PAGE_SHIFT;
+ if (npages > WALK_CHUNK)
+ npages = WALK_CHUNK;
+ amap_lookups(&entry->aref, start - entry->start, anons, npages);
+ for (i = 0; i < npages; i++) {
+ if ((anons[i] == NULL) == absent)
+ continue;
+ if (!absent) {
+ /* going from present -> absent: set realend */
+ state->realend = start + (i << PAGE_SHIFT);
+ absent = 1;
+ continue;
+ }
+
+ /* going from absent to present: invoke callback */
+ state->end = start + (i << PAGE_SHIFT);
+ if (state->start != state->end) {
+ error = (*func)(p, iocookie, state);
+ if (error)
+ return error;
+ }
+ state->start = state->realend = state->end;
+ absent = 0;
+ }
+ }
+
+ if (!absent)
+ state->realend = end;
+ state->end = end;
+ return (*func)(p, iocookie, state);
+}
+
+
 /*
  * Walk the VA space for a process, invoking 'func' on each present range
  * that should be included in a coredump.
  */
+
+int sparse = 1;
+
 int
 uvm_coredump_walkmap(struct proc *p, void *iocookie,
-    int (*func)(struct proc *, void *, struct uvm_coredump_state *),
+    int (*func)(struct proc *, void *, const struct uvm_coredump_state *),
     void *cookie)
 {
  struct uvm_coredump_state state;
  struct vmspace *vm = p->p_vmspace;
  struct vm_map *map = &vm->vm_map;
  struct vm_map_entry *entry;
- vaddr_t top;
  int error;
 
+ state.cookie = cookie;
+
  RBT_FOREACH(entry, uvm_map_addr, &map->addr) {
- state.cookie = cookie;
  state.prot = entry->protection;
- state.flags = 0;
 
  /* should never happen for a user process */
  if (UVM_ET_ISSUBMAP(entry)) {
@@ -170,40 +221,23 @@ uvm_coredump_walkmap(struct proc *p, voi
     UVM_OBJ_IS_DEVICE(entry->object.uvm_obj))
  continue;
 
- state.start = entry->start;
- state.realend = entry->end;
- state.end = entry->end;
-
- if (state.start >= VM_MAXUSER_ADDRESS)
+ if (entry->start >= VM_MAXUSER_ADDRESS)
  continue;
 
- if (state.end > VM_MAXUSER_ADDRESS)
- state.end = VM_MAXUSER_ADDRESS;
-
-#ifdef MACHINE_STACK_GROWS_UP
- if ((vaddr_t)vm->vm_maxsaddr <= state.start &&
-    state.start < ((vaddr_t)vm->vm_maxsaddr + MAXSSIZ)) {
- top = round_page((vaddr_t)vm->vm_maxsaddr +
-    ptoa(vm->vm_ssize));
- if (state.end > top)
- state.end = top;
+ if (sparse && entry->aref.ar_amap != NULL) {
+ error = uvm_coredump_walk_amap(p, entry, iocookie,
+    func, &state);
+ } else {
+ state.start = entry->start;
+ state.realend = entry->end;
+ state.end = entry->end;
 
- if (state.start >= state.end)
- continue;
-#else
- if (state.start >= (vaddr_t)vm->vm_maxsaddr) {
- top = trunc_page((vaddr_t)vm->vm_minsaddr -
-    ptoa(vm->vm_ssize));
- if (state.start < top)
- state.start = top;
+ if (state.end > VM_MAXUSER_ADDRESS)
+ state.end = VM_MAXUSER_ADDRESS;
 
- if (state.start >= state.end)
- continue;
-#endif
- state.flags |= UVM_COREDUMP_STACK;
+ error = (*func)(p, iocookie, &state);
  }
 
- error = (*func)(p, iocookie, &state);
  if (error)
  return (error);
  }
Index: kern/exec_elf.c
===================================================================
RCS file: /data/src/openbsd/src/sys/kern/exec_elf.c,v
retrieving revision 1.130
diff -u -p -r1.130 exec_elf.c
--- kern/exec_elf.c 21 Jan 2017 05:42:03 -0000 1.130
+++ kern/exec_elf.c 31 Jan 2017 04:08:17 -0000
@@ -955,7 +955,7 @@ struct countsegs_state {
 };
 
 int ELFNAMEEND(coredump_countsegs)(struct proc *, void *,
-    struct uvm_coredump_state *);
+    const struct uvm_coredump_state *);
 
 struct writesegs_state {
  Elf_Phdr *psections;
@@ -963,7 +963,7 @@ struct writesegs_state {
 };
 
 int ELFNAMEEND(coredump_writeseghdrs)(struct proc *, void *,
-    struct uvm_coredump_state *);
+    const struct uvm_coredump_state *);
 
 int ELFNAMEEND(coredump_notes)(struct proc *, void *, size_t *);
 int ELFNAMEEND(coredump_note)(struct proc *, void *, size_t *);
@@ -1124,7 +1124,7 @@ out:
 
 int
 ELFNAMEEND(coredump_countsegs)(struct proc *p, void *iocookie,
-    struct uvm_coredump_state *us)
+    const struct uvm_coredump_state *us)
 {
 #ifndef SMALL_KERNEL
  struct countsegs_state *cs = us->cookie;
@@ -1136,7 +1136,7 @@ ELFNAMEEND(coredump_countsegs)(struct pr
 
 int
 ELFNAMEEND(coredump_writeseghdrs)(struct proc *p, void *iocookie,
-    struct uvm_coredump_state *us)
+    const struct uvm_coredump_state *us)
 {
 #ifndef SMALL_KERNEL
  struct writesegs_state *ws = us->cookie;

Reply | Threaded
Open this post in threaded view
|

Re: coredump of firefox(76129), write failed: errno 14

Sebastien Marie-3
On Tue, Jan 31, 2017 at 12:07:48AM -0800, Philip Guenther wrote:
> Sun, 29 Jan 2017, Philip Guenther wrote:
> ...
>
> semarie@, you can consistently trigger that kernel log message, perhaps
> you can try reproducing it with this patch and see if it goes away?

it is a bit better now: I have only one error message instead of two.

from the two firefox processes:
  - 90712 parent
  - 97188 contentproc (child)

(firefox:90712): Gdk-ERROR **: The program 'firefox' received an X Window System error.
This probably reflects a bug in the program.
The error was 'RenderBadPicture (invalid Picture parameter)'.
  (Details: serial 3130 error_code 143 request_code 139 (RENDER) minor_code 7)
  (Note to programmers: normally, X errors are reported asynchronously;
   that is, you will receive the error a while after causing it.
   To debug your program, run it with the GDK_SYNCHRONIZE environment
   variable to change this behavior. You can then get a meaningful
   backtrace from your debugger if you break on the gdk_x_error() function.)
[Child 97188] ###!!! ABORT: Aborting on channel error.: file /usr/obj/ports/firefox-51.0/firefox-51.0/ipc/glue/MessageChannel.cpp, line 2056
[Child 97188] ###!!! ABORT: Aborting on channel error.: file /usr/obj/ports/firefox-51.0/firefox-51.0/ipc/glue/MessageChannel.cpp, line 2056
Trace/BPT trap

dmesg has:
coredump of firefox(90712), write failed: errno 14

before, I had two lines (one for each processes).

I use this script for reproduce: https://p.iotek.org/d74 (but landry@
told me he didn't reproduce the Gdk-ERROR, so some elements in my
environment should be missing).

thanks.
--
Sebastien Marie

Reply | Threaded
Open this post in threaded view
|

Re: coredump of firefox(76129), write failed: errno 14

Philip Guenther
On Tue, 31 Jan 2017, Sebastien Marie wrote:
> On Tue, Jan 31, 2017 at 12:07:48AM -0800, Philip Guenther wrote:
> > Sun, 29 Jan 2017, Philip Guenther wrote:
> > ...
> >
> > semarie@, you can consistently trigger that kernel log message, perhaps
> > you can try reproducing it with this patch and see if it goes away?
>
> it is a bit better now: I have only one error message instead of two.

After some investigation with Sebastien off-list, we identified that the
other failure is from mappings that are not readable.  That's a fix that's
easily separable.

oks?

Philip


Index: uvm_unix.c
===================================================================
RCS file: /data/src/openbsd/src/sys/uvm/uvm_unix.c,v
retrieving revision 1.60
diff -u -p -r1.60 uvm_unix.c
--- uvm_unix.c 16 Sep 2016 01:09:53 -0000 1.60
+++ uvm_unix.c 31 Jan 2017 16:59:35 -0000
@@ -165,6 +165,16 @@ uvm_coredump_walkmap(struct proc *p, voi
     entry->start != p->p_p->ps_sigcode)
  continue;
 
+ /*
+ * Skip pages marked as unreadable, as uiomove(UIO_USERSPACE)
+ * will fail on them.  Maybe this really should be a test of
+ * entry->max_protection, but doing
+ * uvm_map_extract(UVM_EXTRACT_FIXPROT)
+ * when dumping such a mapping would suck.
+ */
+ if ((entry->protection & PROT_READ) == 0)
+ continue;
+
  /* Don't dump mmaped devices. */
  if (entry->object.uvm_obj != NULL &&
     UVM_OBJ_IS_DEVICE(entry->object.uvm_obj))

Reply | Threaded
Open this post in threaded view
|

Re: coredump of firefox(76129), write failed: errno 14

Philip Guenther

And here's a rewrite of the coredump bits that does the sparse amap
handling on all amaps that aren't shared at the time of the coredump, so
it'll get consistent data and not panic the kernel.  Doing this without
locking the shared amaps while doing the walks or writing to disk requires
redoing the API between UVM and the ELF bits, but nothing horrendous IMO.

Tested on macppc, including verification that whether a process is sharing
maps changes the break down into the core file.

Philip


Index: uvm/uvm_extern.h
===================================================================
RCS file: /data/src/openbsd/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.139
diff -u -p -r1.139 uvm_extern.h
--- uvm/uvm_extern.h 5 Jun 2016 08:35:57 -0000 1.139
+++ uvm/uvm_extern.h 1 Feb 2017 07:20:06 -0000
@@ -243,16 +243,16 @@ extern struct pool *uvm_aiobuf_pool;
  * used to keep state while iterating over the map for a core dump.
  */
 struct uvm_coredump_state {
- void *cookie; /* opaque for the caller */
- vaddr_t start; /* start of region */
- vaddr_t realend; /* real end of region */
- vaddr_t end; /* virtual end of region */
- vm_prot_t prot; /* protection of region */
- int flags; /* flags; see below */
+ struct proc *us_p; /* the thread doing the dumping */
+ void *us_iocookie; /* opaque for the caller */
+ void *us_cookie; /* opaque for the caller */
+ vaddr_t us_start; /* start of region */
+ vaddr_t us_realend; /* real end of region (<= end) */
+ vaddr_t us_end; /* virtual end of region */
+ vm_prot_t us_prot; /* protection of region */
+ int us_nsegment; /* index of current segment */
 };
 
-#define UVM_COREDUMP_STACK 0x01 /* region is user stack */
-
 /*
  * the various kernel maps, owned by MD code
  */
@@ -458,9 +458,10 @@ int uvm_pglistalloc(psize_t, paddr_t,
 void uvm_pglistfree(struct pglist *);
 void uvm_pmr_use_inc(paddr_t, paddr_t);
 void uvm_swap_init(void);
-int uvm_coredump_walkmap(struct proc *,
-    void *, int (*)(struct proc *, void *,
-    struct uvm_coredump_state *), void *);
+int uvm_coredump_walkmap(struct proc *_p, void *_iocookie,
+        int (*_setup)(const struct uvm_coredump_state *),
+    int (*_walk)(const struct uvm_coredump_state *),
+    void *_cookie);
 void uvm_grow(struct proc *, vaddr_t);
 void uvm_deallocate(vm_map_t, vaddr_t, vsize_t);
 struct uvm_object *uvn_attach(struct vnode *, vm_prot_t);
Index: uvm/uvm_unix.c
===================================================================
RCS file: /data/src/openbsd/src/sys/uvm/uvm_unix.c,v
retrieving revision 1.60
diff -u -p -r1.60 uvm_unix.c
--- uvm/uvm_unix.c 16 Sep 2016 01:09:53 -0000 1.60
+++ uvm/uvm_unix.c 1 Feb 2017 09:02:41 -0000
@@ -134,81 +134,225 @@ uvm_grow(struct proc *p, vaddr_t sp)
 
 #ifndef SMALL_KERNEL
 
+#define WALK_CHUNK 32
+int
+uvm_coredump_walk_amap(struct vm_map_entry *entry,
+    int (*walk)(const struct uvm_coredump_state *),
+    struct uvm_coredump_state *state)
+{
+ struct vm_anon *anons[WALK_CHUNK];
+ vaddr_t start, end;
+ int absent = 0;
+ int npages, i, error;
+
+ state->us_start = start = entry->start;
+ end = MIN(entry->end, VM_MAXUSER_ADDRESS);
+
+ for (; start < end; start += npages << PAGE_SHIFT) {
+ npages = (end - start) >> PAGE_SHIFT;
+ if (npages > WALK_CHUNK)
+ npages = WALK_CHUNK;
+ amap_lookups(&entry->aref, start - entry->start, anons, npages);
+ for (i = 0; i < npages; i++) {
+ if ((anons[i] == NULL) == absent)
+ continue;
+ if (!absent) {
+ /* going from present -> absent: set realend */
+ state->us_realend = start + (i << PAGE_SHIFT);
+ absent = 1;
+ continue;
+ }
+
+ /* going from absent to present: invoke callback */
+ state->us_end = start + (i << PAGE_SHIFT);
+ if (state->us_start != state->us_end) {
+ error = (*walk)(state);
+ if (error)
+ return error;
+ state->us_nsegment++;
+ }
+ state->us_start = state->us_realend = state->us_end;
+ absent = 0;
+ }
+ }
+
+ if (!absent)
+ state->us_realend = end;
+ state->us_end = end;
+ error = (*walk)(state);
+ state->us_nsegment++;
+ return error;
+}
+
 /*
- * Walk the VA space for a process, invoking 'func' on each present range
- * that should be included in a coredump.
+ * Common logic for whether a map entry should be included in a coredump
  */
+static inline int
+uvm_should_coredump(struct proc *p, struct vm_map_entry *entry)
+{
+ if (!(entry->protection & PROT_WRITE) &&
+    entry->aref.ar_amap == NULL &&
+    entry->start != p->p_p->ps_sigcode)
+ return 0;
+
+ /*
+ * Skip ranges marked as unreadable, as uiomove(UIO_USERSPACE)
+ * will fail on them.  Maybe this really should be a test of
+ * entry->max_protection, but doing
+ * uvm_map_extract(UVM_EXTRACT_FIXPROT)
+ * on each such page would suck.
+ */
+ if ((entry->protection & PROT_READ) == 0)
+ return 0;
+
+ /* Don't dump mmaped devices. */
+ if (entry->object.uvm_obj != NULL &&
+    UVM_OBJ_IS_DEVICE(entry->object.uvm_obj))
+ return 0;
+
+ if (entry->start >= VM_MAXUSER_ADDRESS)
+ return 0;
+
+ return 1;
+}
+
+
+/* do nothing callback for uvm_coredump_walk_amap() */
+static int
+noop(const struct uvm_coredump_state *state)
+{
+ return 0;
+}
+
+/*
+ * Walk the VA space for a process twice for ranges that should be
+ * included in a coredump, invoking func1 on each present range in
+ * the first pass, then invoking func2 once between passes, then
+ * invoking func3 on each present range in the second pass.  The
+ * ranges seen by func1 and func3 are guaranteed to be the same.
+ */
+
+int sparse = 1;
+
 int
 uvm_coredump_walkmap(struct proc *p, void *iocookie,
-    int (*func)(struct proc *, void *, struct uvm_coredump_state *),
-    void *cookie)
+    int (*setup)(const struct uvm_coredump_state *),
+    int (*walk)(const struct uvm_coredump_state *), void *cookie)
 {
  struct uvm_coredump_state state;
  struct vmspace *vm = p->p_vmspace;
  struct vm_map *map = &vm->vm_map;
  struct vm_map_entry *entry;
- vaddr_t top;
- int error;
+ int refed_amaps = 0;
+ int error = 0;
 
+ state.us_p = p;
+ state.us_iocookie = iocookie;
+ state.us_cookie = cookie;
+
+ /*
+ * Walk the map once to count the segments.  If an amap is
+ * referenced more than once than take *another* reference
+ * and treat the amap as exactly one segment instead of
+ * checking page presence inside it.  On the second pass
+ * we'll recognize which amaps we did that for by the ref
+ * count being >1...and decrement it then.
+ */
+ state.us_nsegment = 0;
  RBT_FOREACH(entry, uvm_map_addr, &map->addr) {
- state.cookie = cookie;
- state.prot = entry->protection;
- state.flags = 0;
-
  /* should never happen for a user process */
  if (UVM_ET_ISSUBMAP(entry)) {
  panic("%s: user process with submap?", __func__);
  }
 
- if (!(entry->protection & PROT_WRITE) &&
-    entry->aref.ar_amap == NULL &&
-    entry->start != p->p_p->ps_sigcode)
+ if (! uvm_should_coredump(p, entry))
  continue;
 
- /* Don't dump mmaped devices. */
- if (entry->object.uvm_obj != NULL &&
-    UVM_OBJ_IS_DEVICE(entry->object.uvm_obj))
+ if (sparse && entry->aref.ar_amap != NULL) {
+ if (entry->aref.ar_amap->am_ref == 1) {
+ uvm_coredump_walk_amap(entry, &noop, &state);
+ continue;
+ }
+
+ /*
+ * Multiple refs currently, so take another and
+ * treat it as a single segment
+ */
+ entry->aref.ar_amap->am_ref++;
+ refed_amaps++;
+ }
+
+ state.us_nsegment++;
+ }
+
+ /*
+ * Okay, we have a count in state.us_nsegment.  Prepare to
+ * walk it again, then invoke the setup callback.
+ */
+ entry = RBT_MIN(uvm_map_addr, &map->addr);
+ error = (*setup)(&state);
+ if (error)
+ goto cleanup;
+
+ /*
+ * Setup went okay, so do the second walk, invoking the walk
+ * callback on the counted segments and cleaning up references
+ * as we go.
+ */
+ state.us_nsegment = 0;
+ for (; entry != NULL; entry = RBT_NEXT(uvm_map_addr, entry)) {
+ if (! uvm_should_coredump(p, entry))
  continue;
 
- state.start = entry->start;
- state.realend = entry->end;
- state.end = entry->end;
+ state.us_prot = entry->protection;
 
- if (state.start >= VM_MAXUSER_ADDRESS)
+ if (sparse && entry->aref.ar_amap != NULL &&
+    entry->aref.ar_amap->am_ref == 1) {
+ error = uvm_coredump_walk_amap(entry, walk, &state);
+ if (error)
+ break;
  continue;
+ }
 
- if (state.end > VM_MAXUSER_ADDRESS)
- state.end = VM_MAXUSER_ADDRESS;
+ state.us_start = entry->start;
+ state.us_realend = entry->end;
+ state.us_end = entry->end;
 
-#ifdef MACHINE_STACK_GROWS_UP
- if ((vaddr_t)vm->vm_maxsaddr <= state.start &&
-    state.start < ((vaddr_t)vm->vm_maxsaddr + MAXSSIZ)) {
- top = round_page((vaddr_t)vm->vm_maxsaddr +
-    ptoa(vm->vm_ssize));
- if (state.end > top)
- state.end = top;
+ if (state.us_end > VM_MAXUSER_ADDRESS)
+ state.us_end = VM_MAXUSER_ADDRESS;
 
- if (state.start >= state.end)
- continue;
-#else
- if (state.start >= (vaddr_t)vm->vm_maxsaddr) {
- top = trunc_page((vaddr_t)vm->vm_minsaddr -
-    ptoa(vm->vm_ssize));
- if (state.start < top)
- state.start = top;
+ error = (*walk)(&state);
+ if (error)
+ break;
+ state.us_nsegment++;
 
- if (state.start >= state.end)
- continue;
-#endif
- state.flags |= UVM_COREDUMP_STACK;
+ if (sparse && entry->aref.ar_amap != NULL &&
+    entry->aref.ar_amap->am_ref > 1) {
+ /* multiple refs, so we need to drop one */
+ entry->aref.ar_amap->am_ref--;
+ refed_amaps--;
  }
+ }
 
- error = (*func)(p, iocookie, &state);
- if (error)
- return (error);
+ if (error) {
+cleanup:
+ /* clean up the extra references from where we left off */
+ if (refed_amaps > 0) {
+ for (; entry != NULL;
+    entry = RBT_NEXT(uvm_map_addr, entry)) {
+ if (entry->aref.ar_amap == NULL ||
+    entry->aref.ar_amap->am_ref == 1)
+ continue;
+ if (! uvm_should_coredump(p, entry))
+ continue;
+ entry->aref.ar_amap->am_ref--;
+ if (refed_amaps-- == 0)
+ break;
+ }
+ }
  }
 
- return (0);
+ return (error);
 }
 
 #endif /* !SMALL_KERNEL */
Index: kern/exec_elf.c
===================================================================
RCS file: /data/src/openbsd/src/sys/kern/exec_elf.c,v
retrieving revision 1.130
diff -u -p -r1.130 exec_elf.c
--- kern/exec_elf.c 21 Jan 2017 05:42:03 -0000 1.130
+++ kern/exec_elf.c 1 Feb 2017 07:54:14 -0000
@@ -950,21 +950,28 @@ out1:
  return error;
 }
 
-struct countsegs_state {
- int npsections;
-};
+#ifdef SMALL_KERNEL
+
+int
+ELFNAMEEND(coredump)(struct proc *p, void *cookie)
+{
+ return EPERM;
+}
 
-int ELFNAMEEND(coredump_countsegs)(struct proc *, void *,
-    struct uvm_coredump_state *);
+#else
 
 struct writesegs_state {
- Elf_Phdr *psections;
+ off_t notestart;
+ off_t secstart;
  off_t secoff;
+ Elf_Phdr *psections;
+ size_t psectionslen;
+ size_t notesize;
+ int npsections;
 };
 
-int ELFNAMEEND(coredump_writeseghdrs)(struct proc *, void *,
-    struct uvm_coredump_state *);
-
+int ELFNAMEEND(coredump_setup)(const struct uvm_coredump_state *state);
+int ELFNAMEEND(coredump_walk)(const struct uvm_coredump_state *state);
 int ELFNAMEEND(coredump_notes)(struct proc *, void *, size_t *);
 int ELFNAMEEND(coredump_note)(struct proc *, void *, size_t *);
 int ELFNAMEEND(coredump_writenote)(struct proc *, void *, Elf_Note *,
@@ -976,194 +983,175 @@ int ELFNAMEEND(coredump_writenote)(struc
 int
 ELFNAMEEND(coredump)(struct proc *p, void *cookie)
 {
-#ifdef SMALL_KERNEL
- return EPERM;
-#else
- Elf_Ehdr ehdr;
- Elf_Phdr *psections = NULL;
- struct countsegs_state cs;
+#ifdef DIAGNOSTIC
+ off_t offset;
+#endif
  struct writesegs_state ws;
- off_t notestart, secstart, offset;
- size_t notesize, psectionslen;
+ size_t notesize;
  int error, i;
 
+ ws.psections = NULL;
+
  /*
- * We have to make a total of 3 passes across the map:
- *
- * 1. Count the number of map entries (the number of
- *   PT_LOAD sections).
- *
- * 2. Write the P-section headers.
- *
- * 3. Write the P-sections.
+ * Walk the map to get all the segment offsets and lengths,
+ * write out the ELF header.
  */
-
- /* Pass 1: count the entries. */
- cs.npsections = 0;
- error = uvm_coredump_walkmap(p, NULL,
-    ELFNAMEEND(coredump_countsegs), &cs);
- if (error)
- goto out;
-
- /* Count the PT_NOTE section. */
- cs.npsections++;
-
- /* Get the size of the notes. */
- error = ELFNAMEEND(coredump_notes)(p, NULL, &notesize);
- if (error)
- goto out;
-
- memset(&ehdr, 0, sizeof(ehdr));
- memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
- ehdr.e_ident[EI_CLASS] = ELF_TARG_CLASS;
- ehdr.e_ident[EI_DATA] = ELF_TARG_DATA;
- ehdr.e_ident[EI_VERSION] = EV_CURRENT;
- /* XXX Should be the OSABI/ABI version of the executable. */
- ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV;
- ehdr.e_ident[EI_ABIVERSION] = 0;
- ehdr.e_type = ET_CORE;
- /* XXX This should be the e_machine of the executable. */
- ehdr.e_machine = ELF_TARG_MACH;
- ehdr.e_version = EV_CURRENT;
- ehdr.e_entry = 0;
- ehdr.e_phoff = sizeof(ehdr);
- ehdr.e_shoff = 0;
- ehdr.e_flags = 0;
- ehdr.e_ehsize = sizeof(ehdr);
- ehdr.e_phentsize = sizeof(Elf_Phdr);
- ehdr.e_phnum = cs.npsections;
- ehdr.e_shentsize = 0;
- ehdr.e_shnum = 0;
- ehdr.e_shstrndx = 0;
-
- /* Write out the ELF header. */
- error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr));
- if (error)
- goto out;
-
- psections = mallocarray(cs.npsections, sizeof(Elf_Phdr),
-    M_TEMP, M_WAITOK|M_ZERO);
- psectionslen = cs.npsections * sizeof(Elf_Phdr);
-
- offset = sizeof(ehdr);
- notestart = offset + psectionslen;
- secstart = notestart + notesize;
-
- /* Pass 2: now write the P-section headers. */
- ws.secoff = secstart;
- ws.psections = psections;
- error = uvm_coredump_walkmap(p, cookie,
-    ELFNAMEEND(coredump_writeseghdrs), &ws);
+ error = uvm_coredump_walkmap(p, cookie, ELFNAMEEND(coredump_setup),
+    ELFNAMEEND(coredump_walk), &ws);
  if (error)
  goto out;
 
- /* Write out the PT_NOTE header. */
- ws.psections->p_type = PT_NOTE;
- ws.psections->p_offset = notestart;
- ws.psections->p_vaddr = 0;
- ws.psections->p_paddr = 0;
- ws.psections->p_filesz = notesize;
- ws.psections->p_memsz = 0;
- ws.psections->p_flags = PF_R;
- ws.psections->p_align = ELFROUNDSIZE;
-
- error = coredump_write(cookie, UIO_SYSSPACE, psections, psectionslen);
+ error = coredump_write(cookie, UIO_SYSSPACE, ws.psections,
+    ws.psectionslen);
  if (error)
  goto out;
 
-#ifdef DIAGNOSTIC
- offset += psectionslen;
- if (offset != notestart)
- panic("coredump: offset %lld != notestart %lld",
-    (long long) offset, (long long) notestart);
-#endif
-
  /* Write out the notes. */
  error = ELFNAMEEND(coredump_notes)(p, cookie, &notesize);
  if (error)
  goto out;
 
 #ifdef DIAGNOSTIC
- offset += notesize;
- if (offset != secstart)
+ if (notesize != ws.notesize)
+ panic("coredump: notesize changed: %zu != %zu",
+    ws.notesize, notesize);
+ offset = ws.notestart + notesize;
+ if (offset != ws.secstart)
  panic("coredump: offset %lld != secstart %lld",
-    (long long) offset, (long long) secstart);
+    (long long) offset, (long long) ws.secstart);
 #endif
 
  /* Pass 3: finally, write the sections themselves. */
- for (i = 0; i < cs.npsections - 1; i++) {
- if (psections[i].p_filesz == 0)
+ for (i = 0; i < ws.npsections - 1; i++) {
+ Elf_Phdr *pent = &ws.psections[i];
+ if (pent->p_filesz == 0)
  continue;
 
 #ifdef DIAGNOSTIC
- if (offset != psections[i].p_offset)
+ if (offset != pent->p_offset)
  panic("coredump: offset %lld != p_offset[%d] %lld",
     (long long) offset, i,
-    (long long) psections[i].p_filesz);
+    (long long) pent->p_filesz);
 #endif
 
  error = coredump_write(cookie, UIO_USERSPACE,
-    (void *)(vaddr_t)psections[i].p_vaddr,
-    psections[i].p_filesz);
+    (void *)(vaddr_t)pent->p_vaddr, pent->p_filesz);
  if (error)
  goto out;
 
- coredump_unmap(cookie, (vaddr_t)psections[i].p_vaddr,
-    (vaddr_t)psections[i].p_vaddr + psections[i].p_filesz);
+ coredump_unmap(cookie, (vaddr_t)pent->p_vaddr,
+    (vaddr_t)pent->p_vaddr + pent->p_filesz);
 
 #ifdef DIAGNOSTIC
- offset += psections[i].p_filesz;
+ offset += ws.psections[i].p_filesz;
 #endif
  }
 
 out:
- free(psections, M_TEMP, psectionslen);
+ free(ws.psections, M_TEMP, ws.psectionslen);
  return (error);
-#endif
 }
 
+
 int
-ELFNAMEEND(coredump_countsegs)(struct proc *p, void *iocookie,
-    struct uvm_coredump_state *us)
+ELFNAMEEND(coredump_setup)(const struct uvm_coredump_state *us)
 {
-#ifndef SMALL_KERNEL
- struct countsegs_state *cs = us->cookie;
+ Elf_Ehdr ehdr;
+ struct writesegs_state *ws = us->us_cookie;
+ Elf_Phdr *note;
+ int error;
 
- cs->npsections++;
-#endif
- return (0);
+ /* Get the count of segments, plus one for the PT_NOTE */
+ ws->npsections = us->us_nsegment + 1;
+
+ /* Get the size of the notes. */
+ error = ELFNAMEEND(coredump_notes)(us->us_p, NULL, &ws->notesize);
+ if (error)
+ return error;
+
+ /* Setup the ELF header */
+ memset(&ehdr, 0, sizeof(ehdr));
+ memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
+ ehdr.e_ident[EI_CLASS] = ELF_TARG_CLASS;
+ ehdr.e_ident[EI_DATA] = ELF_TARG_DATA;
+ ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ /* XXX Should be the OSABI/ABI version of the executable. */
+ ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV;
+ ehdr.e_ident[EI_ABIVERSION] = 0;
+ ehdr.e_type = ET_CORE;
+ /* XXX This should be the e_machine of the executable. */
+ ehdr.e_machine = ELF_TARG_MACH;
+ ehdr.e_version = EV_CURRENT;
+ ehdr.e_entry = 0;
+ ehdr.e_phoff = sizeof(ehdr);
+ ehdr.e_shoff = 0;
+ ehdr.e_flags = 0;
+ ehdr.e_ehsize = sizeof(ehdr);
+ ehdr.e_phentsize = sizeof(Elf_Phdr);
+ ehdr.e_phnum = ws->npsections;
+ ehdr.e_shentsize = 0;
+ ehdr.e_shnum = 0;
+ ehdr.e_shstrndx = 0;
+
+ /* Write out the ELF header. */
+ error = coredump_write(us->us_iocookie, UIO_SYSSPACE,
+    &ehdr, sizeof(ehdr));
+ if (error)
+ return error;
+
+ /*
+ * Allocate the segment header array and setup to collect
+ * the section sizes and offsets
+ */
+ ws->psections = mallocarray(ws->npsections, sizeof(Elf_Phdr),
+    M_TEMP, M_WAITOK|M_ZERO);
+ ws->psectionslen = ws->npsections * sizeof(Elf_Phdr);
+
+ ws->notestart = sizeof(ehdr) + ws->psectionslen;
+ ws->secstart = ws->notestart + ws->notesize;
+ ws->secoff = ws->secstart;
+
+ /* Fill in the PT_NOTE segment header in the last slot */
+ note = &ws->psections[ws->npsections - 1];
+ note->p_type = PT_NOTE;
+ note->p_offset = ws->notestart;
+ note->p_vaddr = 0;
+ note->p_paddr = 0;
+ note->p_filesz = ws->notesize;
+ note->p_memsz = 0;
+ note->p_flags = PF_R;
+ note->p_align = ELFROUNDSIZE;
+
+ return 0;
 }
 
 int
-ELFNAMEEND(coredump_writeseghdrs)(struct proc *p, void *iocookie,
-    struct uvm_coredump_state *us)
+ELFNAMEEND(coredump_walk)(const struct uvm_coredump_state *us)
 {
-#ifndef SMALL_KERNEL
- struct writesegs_state *ws = us->cookie;
+ struct writesegs_state *ws = us->us_cookie;
  Elf_Phdr phdr;
  vsize_t size, realsize;
 
- size = us->end - us->start;
- realsize = us->realend - us->start;
+ size = us->us_end - us->us_start;
+ realsize = us->us_realend - us->us_start;
 
  phdr.p_type = PT_LOAD;
  phdr.p_offset = ws->secoff;
- phdr.p_vaddr = us->start;
+ phdr.p_vaddr = us->us_start;
  phdr.p_paddr = 0;
  phdr.p_filesz = realsize;
  phdr.p_memsz = size;
  phdr.p_flags = 0;
- if (us->prot & PROT_READ)
+ if (us->us_prot & PROT_READ)
  phdr.p_flags |= PF_R;
- if (us->prot & PROT_WRITE)
+ if (us->us_prot & PROT_WRITE)
  phdr.p_flags |= PF_W;
- if (us->prot & PROT_EXEC)
+ if (us->us_prot & PROT_EXEC)
  phdr.p_flags |= PF_X;
  phdr.p_align = PAGE_SIZE;
 
  ws->secoff += phdr.p_filesz;
- *ws->psections++ = phdr;
-#endif
+ ws->psections[us->us_nsegment] = phdr;
 
  return (0);
 }
@@ -1171,7 +1159,6 @@ ELFNAMEEND(coredump_writeseghdrs)(struct
 int
 ELFNAMEEND(coredump_notes)(struct proc *p, void *iocookie, size_t *sizep)
 {
-#ifndef SMALL_KERNEL
  struct ps_strings pss;
  struct iovec iov;
  struct uio uio;
@@ -1315,14 +1302,12 @@ ELFNAMEEND(coredump_notes)(struct proc *
  }
 
  *sizep = size;
-#endif
  return (0);
 }
 
 int
 ELFNAMEEND(coredump_note)(struct proc *p, void *iocookie, size_t *sizep)
 {
-#ifndef SMALL_KERNEL
  Elf_Note nhdr;
  int size, notesize, error;
  int namesize;
@@ -1378,7 +1363,6 @@ ELFNAMEEND(coredump_note)(struct proc *p
 
  *sizep = size;
  /* XXX Add hook for machdep per-LWP notes. */
-#endif
  return (0);
 }
 
@@ -1386,9 +1370,6 @@ int
 ELFNAMEEND(coredump_writenote)(struct proc *p, void *cookie, Elf_Note *nhdr,
     const char *name, void *data)
 {
-#ifdef SMALL_KERNEL
- return EPERM;
-#else
  int error;
 
  error = coredump_write(cookie, UIO_SYSSPACE, nhdr, sizeof(*nhdr));
@@ -1401,5 +1382,6 @@ ELFNAMEEND(coredump_writenote)(struct pr
  return error;
 
  return coredump_write(cookie, UIO_SYSSPACE, data, nhdr->descsz);
-#endif
 }
+
+#endif /* !SMALL_KERNEL */

Reply | Threaded
Open this post in threaded view
|

Re: coredump of firefox(76129), write failed: errno 14

Landry Breuil-5
In reply to this post by Sebastien Marie-3
On Sun, Jan 29, 2017 at 12:41:20PM +0100, Sebastien Marie wrote:

> Hi,
>
> I report this error as it is the first time I saw it when a coredump is
> generated.
>
> It occurs reproductibly with my current profile (but not with a fresh
> profile) when firefox crashs (currently when I visit
> https://locka99.gitbooks.io/a-guide-to-porting-c-to-rust with JS
> activated).
>
> Please note that my point isn't the firefox crash, but the kernel error
> message.
>
> (launch firefox and visit url above)
> $ firefox
>
> (firefox:76129): Gdk-ERROR **: The program 'firefox' received an X Window System error.
> This probably reflects a bug in the program.
> The error was 'RenderBadPicture (invalid Picture parameter)'.
>   (Details: serial 59593 error_code 143 request_code 139 (RENDER) minor_code 7)
>   (Note to programmers: normally, X errors are reported asynchronously;
>    that is, you will receive the error a while after causing it.
>    To debug your program, run it with the GDK_SYNCHRONIZE environment
>    variable to change this behavior. You can then get a meaningful
>    backtrace from your debugger if you break on the gdk_x_error() function.)
> [Child 4704] ###!!! ABORT: Aborting on channel error.: file /usr/obj/ports/firefox-51.0/firefox-51.0/ipc/glue/MessageChannel.cpp, line 2056
> [Child 4704] ###!!! ABORT: Aborting on channel error.: file /usr/obj/ports/firefox-51.0/firefox-51.0/ipc/glue/MessageChannel.cpp, line 2056

As for this particular crash, looking for RenderBadPicture in bugzilla
yields https://bugzilla.mozilla.org/show_bug.cgi?id=1335827 - testing a
fix.