1 /* $NetBSD: core_elf32.c,v 1.34 2009/10/21 21:12:06 rmind Exp $ */
4 * Copyright (c) 2001 Wasabi Systems, Inc.
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
39 * core_elf32.c/core_elf64.c: Support for the Elf32/Elf64 core file format.
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.34 2009/10/21 21:12:06 rmind Exp $");
46 #include "opt_coredump.h"
53 #include <sys/param.h>
54 #include <sys/systm.h>
56 #include <sys/vnode.h>
58 #include <sys/exec_elf.h>
59 #include <sys/ptrace.h>
60 #include <sys/malloc.h>
61 #include <sys/kauth.h>
63 #include <machine/reg.h>
65 #include <uvm/uvm_extern.h>
69 struct countsegs_state
{
73 static int ELFNAMEEND(coredump_countsegs
)(struct proc
*, void *,
74 struct uvm_coredump_state
*);
76 struct writesegs_state
{
81 static int ELFNAMEEND(coredump_writeseghdrs
)(struct proc
*, void *,
82 struct uvm_coredump_state
*);
84 static int ELFNAMEEND(coredump_notes
)(struct proc
*, struct lwp
*, void *,
86 static int ELFNAMEEND(coredump_note
)(struct proc
*, struct lwp
*, void *,
89 #define ELFROUNDSIZE 4 /* XXX Should it be sizeof(Elf_Word)? */
90 #define elfround(x) roundup((x), ELFROUNDSIZE)
92 #define elf_process_read_regs CONCAT(process_read_regs, ELFSIZE)
93 #ifdef __HAVE_PROCESS_XFPREGS
94 #define elf_process_read_xfpregs CONCAT(process_read_xfpregs, ELFSIZE)
96 #define elf_process_read_fpregs CONCAT(process_read_fpregs, ELFSIZE)
98 #define elf_reg CONCAT(process_reg, ELFSIZE)
99 #define elf_fpreg CONCAT(process_fpreg, ELFSIZE)
102 ELFNAMEEND(coredump
)(struct lwp
*l
, void *cookie
)
106 Elf_Phdr phdr
, *psections
;
107 struct countsegs_state cs
;
108 struct writesegs_state ws
;
109 off_t notestart
, secstart
, offset
;
116 * We have to make a total of 3 passes across the map:
118 * 1. Count the number of map entries (the number of
121 * 2. Write the P-section headers.
123 * 3. Write the P-sections.
126 /* Pass 1: count the entries. */
128 error
= uvm_coredump_walkmap(p
, NULL
,
129 ELFNAMEEND(coredump_countsegs
), &cs
);
133 /* Count the PT_NOTE section. */
136 /* Get the size of the notes. */
137 error
= ELFNAMEEND(coredump_notes
)(p
, l
, NULL
, ¬esize
);
141 memset(&ehdr
.e_ident
[EI_PAD
], 0, sizeof(ehdr
.e_ident
) - EI_PAD
);
142 memcpy(ehdr
.e_ident
, ELFMAG
, SELFMAG
);
144 ehdr
.e_ident
[EI_CLASS
] = ELFCLASS32
;
146 ehdr
.e_ident
[EI_CLASS
] = ELFCLASS64
;
148 ehdr
.e_ident
[EI_DATA
] = ELFDEFNNAME(MACHDEP_ENDIANNESS
);
149 ehdr
.e_ident
[EI_VERSION
] = EV_CURRENT
;
150 /* XXX Should be the OSABI/ABI version of the executable. */
151 ehdr
.e_ident
[EI_OSABI
] = ELFOSABI_SYSV
;
152 ehdr
.e_ident
[EI_ABIVERSION
] = 0;
154 ehdr
.e_type
= ET_CORE
;
155 /* XXX This should be the e_machine of the executable. */
156 ehdr
.e_machine
= ELFDEFNNAME(MACHDEP_ID
);
157 ehdr
.e_version
= EV_CURRENT
;
159 ehdr
.e_phoff
= sizeof(ehdr
);
162 ehdr
.e_ehsize
= sizeof(ehdr
);
163 ehdr
.e_phentsize
= sizeof(Elf_Phdr
);
164 ehdr
.e_phnum
= cs
.npsections
;
165 ehdr
.e_shentsize
= 0;
169 #ifdef ELF_MD_COREDUMP_SETUP
170 ELF_MD_COREDUMP_SETUP(l
, &ehdr
);
173 /* Write out the ELF header. */
174 error
= coredump_write(cookie
, UIO_SYSSPACE
, &ehdr
, sizeof(ehdr
));
178 offset
= sizeof(ehdr
);
180 notestart
= offset
+ sizeof(phdr
) * cs
.npsections
;
181 secstart
= notestart
+ notesize
;
183 psections
= malloc(cs
.npsections
* sizeof(Elf_Phdr
),
184 M_TEMP
, M_WAITOK
|M_ZERO
);
186 /* Pass 2: now write the P-section headers. */
187 ws
.secoff
= secstart
;
188 ws
.psections
= psections
;
189 error
= uvm_coredump_walkmap(p
, cookie
,
190 ELFNAMEEND(coredump_writeseghdrs
), &ws
);
194 /* Write out the PT_NOTE header. */
195 ws
.psections
->p_type
= PT_NOTE
;
196 ws
.psections
->p_offset
= notestart
;
197 ws
.psections
->p_vaddr
= 0;
198 ws
.psections
->p_paddr
= 0;
199 ws
.psections
->p_filesz
= notesize
;
200 ws
.psections
->p_memsz
= 0;
201 ws
.psections
->p_flags
= PF_R
;
202 ws
.psections
->p_align
= ELFROUNDSIZE
;
204 error
= coredump_write(cookie
, UIO_SYSSPACE
, psections
,
205 cs
.npsections
* sizeof(Elf_Phdr
));
210 offset
+= cs
.npsections
* sizeof(Elf_Phdr
);
211 if (offset
!= notestart
)
212 panic("coredump: offset %lld != notestart %lld",
213 (long long) offset
, (long long) notestart
);
216 /* Write out the notes. */
217 error
= ELFNAMEEND(coredump_notes
)(p
, l
, cookie
, ¬esize
);
223 if (offset
!= secstart
)
224 panic("coredump: offset %lld != secstart %lld",
225 (long long) offset
, (long long) secstart
);
228 /* Pass 3: finally, write the sections themselves. */
229 for (i
= 0; i
< cs
.npsections
- 1; i
++) {
230 if (psections
[i
].p_filesz
== 0)
234 if (offset
!= psections
[i
].p_offset
)
235 panic("coredump: offset %lld != p_offset[%d] %lld",
236 (long long) offset
, i
,
237 (long long) psections
[i
].p_filesz
);
240 error
= coredump_write(cookie
, UIO_USERSPACE
,
241 (void *)(vaddr_t
)psections
[i
].p_vaddr
,
242 psections
[i
].p_filesz
);
247 offset
+= psections
[i
].p_filesz
;
253 free(psections
, M_TEMP
);
258 ELFNAMEEND(coredump_countsegs
)(struct proc
*p
, void *iocookie
,
259 struct uvm_coredump_state
*us
)
261 struct countsegs_state
*cs
= us
->cookie
;
268 ELFNAMEEND(coredump_writeseghdrs
)(struct proc
*p
, void *iocookie
,
269 struct uvm_coredump_state
*us
)
271 struct writesegs_state
*ws
= us
->cookie
;
273 vsize_t size
, realsize
;
277 size
= us
->end
- us
->start
;
278 realsize
= us
->realend
- us
->start
;
281 while (realsize
> 0) {
282 long buf
[1024 / sizeof(long)];
283 size_t slen
= realsize
> sizeof(buf
) ? sizeof(buf
) : realsize
;
288 if ((error
= copyin_proc(p
, (void *)end
, buf
, slen
)) != 0)
291 ep
= (const long *) &buf
[slen
/ sizeof(buf
[0])];
292 for (i
= 0, ep
--; buf
<= ep
; ep
--, i
++) {
296 realsize
-= i
* sizeof(buf
[0]);
297 if (i
* sizeof(buf
[0]) < slen
)
301 phdr
.p_type
= PT_LOAD
;
302 phdr
.p_offset
= ws
->secoff
;
303 phdr
.p_vaddr
= us
->start
;
305 phdr
.p_filesz
= realsize
;
308 if (us
->prot
& VM_PROT_READ
)
309 phdr
.p_flags
|= PF_R
;
310 if (us
->prot
& VM_PROT_WRITE
)
311 phdr
.p_flags
|= PF_W
;
312 if (us
->prot
& VM_PROT_EXECUTE
)
313 phdr
.p_flags
|= PF_X
;
314 phdr
.p_align
= PAGE_SIZE
;
316 ws
->secoff
+= phdr
.p_filesz
;
317 *ws
->psections
++ = phdr
;
323 ELFNAMEEND(coredump_notes
)(struct proc
*p
, struct lwp
*l
,
324 void *iocookie
, size_t *sizep
)
326 struct netbsd_elfcore_procinfo cpi
;
328 size_t size
, notesize
;
335 /* First, write an elfcore_procinfo. */
336 notesize
= sizeof(nhdr
) + elfround(sizeof(ELF_NOTE_NETBSD_CORE_NAME
)) +
337 elfround(sizeof(cpi
));
339 cpi
.cpi_version
= NETBSD_ELFCORE_PROCINFO_VERSION
;
340 cpi
.cpi_cpisize
= sizeof(cpi
);
341 cpi
.cpi_signo
= p
->p_sigctx
.ps_signo
;
342 cpi
.cpi_sigcode
= p
->p_sigctx
.ps_code
;
343 cpi
.cpi_siglwp
= p
->p_sigctx
.ps_lwp
;
346 * XXX This should be per-LWP.
348 ss1
= p
->p_sigpend
.sp_set
;
350 LIST_FOREACH(l0
, &p
->p_lwps
, l_sibling
) {
351 sigplusset(&l0
->l_sigpend
.sp_set
, &ss1
);
352 sigplusset(&l0
->l_sigmask
, &ss2
);
354 memcpy(&cpi
.cpi_sigpend
, &ss1
, sizeof(cpi
.cpi_sigpend
));
355 memcpy(&cpi
.cpi_sigmask
, &ss2
, sizeof(cpi
.cpi_sigmask
));
356 memcpy(&cpi
.cpi_sigignore
, &p
->p_sigctx
.ps_sigignore
,
357 sizeof(cpi
.cpi_sigignore
));
358 memcpy(&cpi
.cpi_sigcatch
, &p
->p_sigctx
.ps_sigcatch
,
359 sizeof(cpi
.cpi_sigcatch
));
361 cpi
.cpi_pid
= p
->p_pid
;
362 mutex_enter(proc_lock
);
363 cpi
.cpi_ppid
= p
->p_pptr
->p_pid
;
364 cpi
.cpi_pgrp
= p
->p_pgid
;
365 cpi
.cpi_sid
= p
->p_session
->s_sid
;
366 mutex_exit(proc_lock
);
368 cpi
.cpi_ruid
= kauth_cred_getuid(l
->l_cred
);
369 cpi
.cpi_euid
= kauth_cred_geteuid(l
->l_cred
);
370 cpi
.cpi_svuid
= kauth_cred_getsvuid(l
->l_cred
);
372 cpi
.cpi_rgid
= kauth_cred_getgid(l
->l_cred
);
373 cpi
.cpi_egid
= kauth_cred_getegid(l
->l_cred
);
374 cpi
.cpi_svgid
= kauth_cred_getsvgid(l
->l_cred
);
376 cpi
.cpi_nlwps
= p
->p_nlwps
;
377 (void)strncpy(cpi
.cpi_name
, p
->p_comm
, sizeof(cpi
.cpi_name
));
378 cpi
.cpi_name
[sizeof(cpi
.cpi_name
) - 1] = '\0';
380 nhdr
.n_namesz
= sizeof(ELF_NOTE_NETBSD_CORE_NAME
);
381 nhdr
.n_descsz
= sizeof(cpi
);
382 nhdr
.n_type
= ELF_NOTE_NETBSD_CORE_PROCINFO
;
384 error
= ELFNAMEEND(coredump_writenote
)(p
, iocookie
, &nhdr
,
385 ELF_NOTE_NETBSD_CORE_NAME
"\0\0\0", &cpi
);
392 /* XXX Add hook for machdep per-proc notes. */
395 * Now write the register info for the thread that caused the
398 error
= ELFNAMEEND(coredump_note
)(p
, l
, iocookie
, ¬esize
);
404 * Now, for each LWP, write the register info and any other
405 * per-LWP notes. Since we're dumping core, we don't bother
408 LIST_FOREACH(l0
, &p
->p_lwps
, l_sibling
) {
409 if (l0
== l
) /* we've taken care of this thread */
411 error
= ELFNAMEEND(coredump_note
)(p
, l0
, iocookie
, ¬esize
);
422 ELFNAMEEND(coredump_note
)(struct proc
*p
, struct lwp
*l
, void *iocookie
,
426 int size
, notesize
, error
;
428 char name
[64+ELFROUNDSIZE
];
436 snprintf(name
, sizeof(name
)-ELFROUNDSIZE
, "%s@%d",
437 ELF_NOTE_NETBSD_CORE_NAME
, l
->l_lid
);
438 namesize
= strlen(name
) + 1;
439 memset(name
+ namesize
, 0, elfround(namesize
) - namesize
);
441 notesize
= sizeof(nhdr
) + elfround(namesize
) + elfround(sizeof(intreg
));
443 error
= elf_process_read_regs(l
, &intreg
);
447 nhdr
.n_namesz
= namesize
;
448 nhdr
.n_descsz
= sizeof(intreg
);
449 nhdr
.n_type
= PT_GETREGS
;
451 error
= ELFNAMEEND(coredump_writenote
)(p
, iocookie
, &nhdr
,
460 notesize
= sizeof(nhdr
) + elfround(namesize
) + elfround(sizeof(freg
));
462 size_t freglen
= sizeof(freg
);
463 #ifdef __HAVE_PROCESS_XFPREGS
464 error
= elf_process_read_xfpregs(l
, &freg
, &freglen
);
466 error
= elf_process_read_fpregs(l
, &freg
);
471 nhdr
.n_namesz
= namesize
;
472 nhdr
.n_descsz
= freglen
;
473 nhdr
.n_type
= PT_GETFPREGS
;
475 error
= ELFNAMEEND(coredump_writenote
)(p
, iocookie
, &nhdr
,
483 /* XXX Add hook for machdep per-LWP notes. */
488 ELFNAMEEND(coredump_writenote
)(struct proc
*p
, void *cookie
, Elf_Nhdr
*nhdr
,
489 const char *name
, void *data
)
493 error
= coredump_write(cookie
, UIO_SYSSPACE
, nhdr
, sizeof(*nhdr
));
497 error
= coredump_write(cookie
, UIO_SYSSPACE
, name
,
498 elfround(nhdr
->n_namesz
));
502 return coredump_write(cookie
, UIO_SYSSPACE
, data
, nhdr
->n_descsz
);
508 ELFNAMEEND(coredump
)(struct lwp
*l
, void *cookie
)
514 #endif /* COREDUMP */