1/* $NetBSD: core_elf32.c,v 1.35 2009/12/14 00:48:35 matt Exp $ */ 2 3/* 4 * Copyright (c) 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 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 23 * written permission. 24 * 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. 36 */ 37 38/* 39 * core_elf32.c/core_elf64.c: Support for the Elf32/Elf64 core file format. 40 */ 41 42#include <sys/cdefs.h> 43__KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.35 2009/12/14 00:48:35 matt Exp $"); 44 45#ifdef _KERNEL_OPT 46#include "opt_coredump.h" 47#endif 48 49#ifndef ELFSIZE 50#define ELFSIZE 32 51#endif 52 53#include <sys/param.h> 54#include <sys/systm.h> 55#include <sys/proc.h> 56#include <sys/vnode.h> 57#include <sys/exec.h> 58#include <sys/exec_elf.h> 59#include <sys/ptrace.h> 60#include <sys/kmem.h> 61#include <sys/kauth.h> 62 63#include <machine/reg.h> 64 65#include <uvm/uvm_extern.h> 66 67#ifdef COREDUMP 68 69struct countsegs_state { 70 int npsections; 71}; 72 73static int ELFNAMEEND(coredump_countsegs)(struct proc *, void *, 74 struct uvm_coredump_state *); 75 76struct writesegs_state { 77 Elf_Phdr *psections; 78 off_t secoff; 79}; 80 81static int ELFNAMEEND(coredump_writeseghdrs)(struct proc *, void *, 82 struct uvm_coredump_state *); 83 84static int ELFNAMEEND(coredump_notes)(struct proc *, struct lwp *, void *, 85 size_t *); 86static int ELFNAMEEND(coredump_note)(struct proc *, struct lwp *, void *, 87 size_t *); 88 89#define ELFROUNDSIZE 4 /* XXX Should it be sizeof(Elf_Word)? */ 90#define elfround(x) roundup((x), ELFROUNDSIZE) 91 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) 95#else 96#define elf_process_read_fpregs CONCAT(process_read_fpregs, ELFSIZE) 97#endif 98#define elf_reg CONCAT(process_reg, ELFSIZE) 99#define elf_fpreg CONCAT(process_fpreg, ELFSIZE) 100 101int 102ELFNAMEEND(coredump)(struct lwp *l, void *cookie) 103{ 104 struct proc *p; 105 Elf_Ehdr ehdr; 106 Elf_Phdr phdr, *psections; 107 size_t psectionssize; 108 struct countsegs_state cs; 109 struct writesegs_state ws; 110 off_t notestart, secstart, offset; 111 size_t notesize; 112 int error, i; 113 114 psections = NULL; 115 p = l->l_proc; 116 /* 117 * We have to make a total of 3 passes across the map: 118 * 119 * 1. Count the number of map entries (the number of 120 * PT_LOAD sections). 121 * 122 * 2. Write the P-section headers. 123 * 124 * 3. Write the P-sections. 125 */ 126 127 /* Pass 1: count the entries. */ 128 cs.npsections = 0; 129 error = uvm_coredump_walkmap(p, NULL, 130 ELFNAMEEND(coredump_countsegs), &cs); 131 if (error) 132 goto out; 133 134 /* Count the PT_NOTE section. */ 135 cs.npsections++; 136 137 /* Get the size of the notes. */ 138 error = ELFNAMEEND(coredump_notes)(p, l, NULL, ¬esize); 139 if (error) 140 goto out; 141 142 memset(&ehdr.e_ident[EI_PAD], 0, sizeof(ehdr.e_ident) - EI_PAD); 143 memcpy(ehdr.e_ident, ELFMAG, SELFMAG); 144#if ELFSIZE == 32 145 ehdr.e_ident[EI_CLASS] = ELFCLASS32; 146#elif ELFSIZE == 64 147 ehdr.e_ident[EI_CLASS] = ELFCLASS64; 148#endif 149 ehdr.e_ident[EI_DATA] = ELFDEFNNAME(MACHDEP_ENDIANNESS); 150 ehdr.e_ident[EI_VERSION] = EV_CURRENT; 151 /* XXX Should be the OSABI/ABI version of the executable. */ 152 ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV; 153 ehdr.e_ident[EI_ABIVERSION] = 0; 154 155 ehdr.e_type = ET_CORE; 156 /* XXX This should be the e_machine of the executable. */ 157 ehdr.e_machine = ELFDEFNNAME(MACHDEP_ID); 158 ehdr.e_version = EV_CURRENT; 159 ehdr.e_entry = 0; 160 ehdr.e_phoff = sizeof(ehdr); 161 ehdr.e_shoff = 0; 162 ehdr.e_flags = 0; 163 ehdr.e_ehsize = sizeof(ehdr); 164 ehdr.e_phentsize = sizeof(Elf_Phdr); 165 ehdr.e_phnum = cs.npsections; 166 ehdr.e_shentsize = 0; 167 ehdr.e_shnum = 0; 168 ehdr.e_shstrndx = 0; 169 170#ifdef ELF_MD_COREDUMP_SETUP 171 ELF_MD_COREDUMP_SETUP(l, &ehdr); 172#endif 173 174 /* Write out the ELF header. */ 175 error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr)); 176 if (error) 177 goto out; 178 179 offset = sizeof(ehdr); 180 181 notestart = offset + sizeof(phdr) * cs.npsections; 182 secstart = notestart + notesize; 183 184 psectionssize = cs.npsections * sizeof(Elf_Phdr); 185 psections = kmem_zalloc(psectionssize, KM_SLEEP); 186 187 /* Pass 2: now write the P-section headers. */ 188 ws.secoff = secstart; 189 ws.psections = psections; 190 error = uvm_coredump_walkmap(p, cookie, 191 ELFNAMEEND(coredump_writeseghdrs), &ws); 192 if (error) 193 goto out; 194 195 /* Write out the PT_NOTE header. */ 196 ws.psections->p_type = PT_NOTE; 197 ws.psections->p_offset = notestart; 198 ws.psections->p_vaddr = 0; 199 ws.psections->p_paddr = 0; 200 ws.psections->p_filesz = notesize; 201 ws.psections->p_memsz = 0; 202 ws.psections->p_flags = PF_R; 203 ws.psections->p_align = ELFROUNDSIZE; 204 205 error = coredump_write(cookie, UIO_SYSSPACE, psections, 206 cs.npsections * sizeof(Elf_Phdr)); 207 if (error) 208 goto out; 209 210#ifdef DIAGNOSTIC 211 offset += cs.npsections * sizeof(Elf_Phdr); 212 if (offset != notestart) 213 panic("coredump: offset %lld != notestart %lld", 214 (long long) offset, (long long) notestart); 215#endif 216 217 /* Write out the notes. */ 218 error = ELFNAMEEND(coredump_notes)(p, l, cookie, ¬esize); 219 if (error) 220 goto out; 221 222#ifdef DIAGNOSTIC 223 offset += notesize; 224 if (offset != secstart) 225 panic("coredump: offset %lld != secstart %lld", 226 (long long) offset, (long long) secstart); 227#endif 228 229 /* Pass 3: finally, write the sections themselves. */ 230 for (i = 0; i < cs.npsections - 1; i++) { 231 if (psections[i].p_filesz == 0) 232 continue; 233 234#ifdef DIAGNOSTIC 235 if (offset != psections[i].p_offset) 236 panic("coredump: offset %lld != p_offset[%d] %lld", 237 (long long) offset, i, 238 (long long) psections[i].p_filesz); 239#endif 240 241 error = coredump_write(cookie, UIO_USERSPACE, 242 (void *)(vaddr_t)psections[i].p_vaddr, 243 psections[i].p_filesz); 244 if (error) 245 goto out; 246 247#ifdef DIAGNOSTIC 248 offset += psections[i].p_filesz; 249#endif 250 } 251 252 out: 253 if (psections) 254 kmem_free(psections, psectionssize); 255 return (error); 256} 257 258static int 259ELFNAMEEND(coredump_countsegs)(struct proc *p, void *iocookie, 260 struct uvm_coredump_state *us) 261{ 262 struct countsegs_state *cs = us->cookie; 263 264 cs->npsections++; 265 return (0); 266} 267 268static int 269ELFNAMEEND(coredump_writeseghdrs)(struct proc *p, void *iocookie, 270 struct uvm_coredump_state *us) 271{ 272 struct writesegs_state *ws = us->cookie; 273 Elf_Phdr phdr; 274 vsize_t size, realsize; 275 vaddr_t end; 276 int error; 277 278 size = us->end - us->start; 279 realsize = us->realend - us->start; 280 end = us->realend; 281 282 while (realsize > 0) { 283 long buf[1024 / sizeof(long)]; 284 size_t slen = realsize > sizeof(buf) ? sizeof(buf) : realsize; 285 const long *ep; 286 int i; 287 288 end -= slen; 289 if ((error = copyin_proc(p, (void *)end, buf, slen)) != 0) 290 return error; 291 292 ep = (const long *) &buf[slen / sizeof(buf[0])]; 293 for (i = 0, ep--; buf <= ep; ep--, i++) { 294 if (*ep) 295 break; 296 } 297 realsize -= i * sizeof(buf[0]); 298 if (i * sizeof(buf[0]) < slen) 299 break; 300 } 301 302 phdr.p_type = PT_LOAD; 303 phdr.p_offset = ws->secoff; 304 phdr.p_vaddr = us->start; 305 phdr.p_paddr = 0; 306 phdr.p_filesz = realsize; 307 phdr.p_memsz = size; 308 phdr.p_flags = 0; 309 if (us->prot & VM_PROT_READ) 310 phdr.p_flags |= PF_R; 311 if (us->prot & VM_PROT_WRITE) 312 phdr.p_flags |= PF_W; 313 if (us->prot & VM_PROT_EXECUTE) 314 phdr.p_flags |= PF_X; 315 phdr.p_align = PAGE_SIZE; 316 317 ws->secoff += phdr.p_filesz; 318 *ws->psections++ = phdr; 319 320 return (0); 321} 322 323static int 324ELFNAMEEND(coredump_notes)(struct proc *p, struct lwp *l, 325 void *iocookie, size_t *sizep) 326{ 327 struct netbsd_elfcore_procinfo cpi; 328 Elf_Nhdr nhdr; 329 size_t size, notesize; 330 int error; 331 struct lwp *l0; 332 sigset_t ss1, ss2; 333 334 size = 0; 335 336 /* First, write an elfcore_procinfo. */ 337 notesize = sizeof(nhdr) + elfround(sizeof(ELF_NOTE_NETBSD_CORE_NAME)) + 338 elfround(sizeof(cpi)); 339 if (iocookie) { 340 cpi.cpi_version = NETBSD_ELFCORE_PROCINFO_VERSION; 341 cpi.cpi_cpisize = sizeof(cpi); 342 cpi.cpi_signo = p->p_sigctx.ps_signo; 343 cpi.cpi_sigcode = p->p_sigctx.ps_code; 344 cpi.cpi_siglwp = p->p_sigctx.ps_lwp; 345 346 /* 347 * XXX This should be per-LWP. 348 */ 349 ss1 = p->p_sigpend.sp_set; 350 sigemptyset(&ss2); 351 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 352 sigplusset(&l0->l_sigpend.sp_set, &ss1); 353 sigplusset(&l0->l_sigmask, &ss2); 354 } 355 memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend)); 356 memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask)); 357 memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore, 358 sizeof(cpi.cpi_sigignore)); 359 memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch, 360 sizeof(cpi.cpi_sigcatch)); 361 362 cpi.cpi_pid = p->p_pid; 363 mutex_enter(proc_lock); 364 cpi.cpi_ppid = p->p_pptr->p_pid; 365 cpi.cpi_pgrp = p->p_pgid; 366 cpi.cpi_sid = p->p_session->s_sid; 367 mutex_exit(proc_lock); 368 369 cpi.cpi_ruid = kauth_cred_getuid(l->l_cred); 370 cpi.cpi_euid = kauth_cred_geteuid(l->l_cred); 371 cpi.cpi_svuid = kauth_cred_getsvuid(l->l_cred); 372 373 cpi.cpi_rgid = kauth_cred_getgid(l->l_cred); 374 cpi.cpi_egid = kauth_cred_getegid(l->l_cred); 375 cpi.cpi_svgid = kauth_cred_getsvgid(l->l_cred); 376 377 cpi.cpi_nlwps = p->p_nlwps; 378 (void)strncpy(cpi.cpi_name, p->p_comm, sizeof(cpi.cpi_name)); 379 cpi.cpi_name[sizeof(cpi.cpi_name) - 1] = '\0'; 380 381 nhdr.n_namesz = sizeof(ELF_NOTE_NETBSD_CORE_NAME); 382 nhdr.n_descsz = sizeof(cpi); 383 nhdr.n_type = ELF_NOTE_NETBSD_CORE_PROCINFO; 384 385 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, 386 ELF_NOTE_NETBSD_CORE_NAME "\0\0\0", &cpi); 387 if (error) 388 return (error); 389 } 390 391 size += notesize; 392 393 /* XXX Add hook for machdep per-proc notes. */ 394 395 /* 396 * Now write the register info for the thread that caused the 397 * coredump. 398 */ 399 error = ELFNAMEEND(coredump_note)(p, l, iocookie, ¬esize); 400 if (error) 401 return (error); 402 size += notesize; 403 404 /* 405 * Now, for each LWP, write the register info and any other 406 * per-LWP notes. Since we're dumping core, we don't bother 407 * locking. 408 */ 409 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 410 if (l0 == l) /* we've taken care of this thread */ 411 continue; 412 error = ELFNAMEEND(coredump_note)(p, l0, iocookie, ¬esize); 413 if (error) 414 return (error); 415 size += notesize; 416 } 417 418 *sizep = size; 419 return (0); 420} 421 422static int 423ELFNAMEEND(coredump_note)(struct proc *p, struct lwp *l, void *iocookie, 424 size_t *sizep) 425{ 426 Elf_Nhdr nhdr; 427 int size, notesize, error; 428 int namesize; 429 char name[64+ELFROUNDSIZE]; 430 elf_reg intreg; 431#ifdef PT_GETFPREGS 432 elf_fpreg freg; 433#endif 434 435 size = 0; 436 437 snprintf(name, sizeof(name)-ELFROUNDSIZE, "%s@%d", 438 ELF_NOTE_NETBSD_CORE_NAME, l->l_lid); 439 namesize = strlen(name) + 1; 440 memset(name + namesize, 0, elfround(namesize) - namesize); 441 442 notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(intreg)); 443 if (iocookie) { 444 error = elf_process_read_regs(l, &intreg); 445 if (error) 446 return (error); 447 448 nhdr.n_namesz = namesize; 449 nhdr.n_descsz = sizeof(intreg); 450 nhdr.n_type = PT_GETREGS; 451 452 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, 453 name, &intreg); 454 if (error) 455 return (error); 456 457 } 458 size += notesize; 459 460#ifdef PT_GETFPREGS 461 notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(freg)); 462 if (iocookie) { 463 size_t freglen = sizeof(freg); 464#ifdef __HAVE_PROCESS_XFPREGS 465 error = elf_process_read_xfpregs(l, &freg, &freglen); 466#else 467 error = elf_process_read_fpregs(l, &freg); 468#endif 469 if (error) 470 return (error); 471 472 nhdr.n_namesz = namesize; 473 nhdr.n_descsz = freglen; 474 nhdr.n_type = PT_GETFPREGS; 475 476 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, 477 name, &freg); 478 if (error) 479 return (error); 480 } 481 size += notesize; 482#endif 483 *sizep = size; 484 /* XXX Add hook for machdep per-LWP notes. */ 485 return (0); 486} 487 488int 489ELFNAMEEND(coredump_writenote)(struct proc *p, void *cookie, Elf_Nhdr *nhdr, 490 const char *name, void *data) 491{ 492 int error; 493 494 error = coredump_write(cookie, UIO_SYSSPACE, nhdr, sizeof(*nhdr)); 495 if (error) 496 return error; 497 498 error = coredump_write(cookie, UIO_SYSSPACE, name, 499 elfround(nhdr->n_namesz)); 500 if (error) 501 return error; 502 503 return coredump_write(cookie, UIO_SYSSPACE, data, nhdr->n_descsz); 504} 505 506#else /* COREDUMP */ 507 508int 509ELFNAMEEND(coredump)(struct lwp *l, void *cookie) 510{ 511 512 return ENOSYS; 513} 514 515#endif /* COREDUMP */ 516