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/malloc.h> 61 #include <sys/kauth.h> 62 63 #include <machine/reg.h> 64 65 #include <uvm/uvm_extern.h> 66 67 #ifdef COREDUMP 68 69 struct countsegs_state { 70 int npsections; 71 }; 72 73 static int ELFNAMEEND(coredump_countsegs)(struct proc *, void *, 74 struct uvm_coredump_state *); 75 76 struct writesegs_state { 77 Elf_Phdr *psections; 78 off_t secoff; 79 }; 80 81 static int ELFNAMEEND(coredump_writeseghdrs)(struct proc *, void *, 82 struct uvm_coredump_state *); 83 84 static int ELFNAMEEND(coredump_notes)(struct proc *, struct lwp *, void *, 85 size_t *); 86 static 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 101 int 102 ELFNAMEEND(coredump)(struct lwp *l, void *cookie) 103 { 104 struct proc *p; 105 Elf_Ehdr ehdr; 106 Elf_Phdr phdr, *psections; 107 struct countsegs_state cs; 108 struct writesegs_state ws; 109 off_t notestart, secstart, offset; 110 size_t notesize; 111 int error, i; 112 113 psections = NULL; 114 p = l->l_proc; 115 /* 116 * We have to make a total of 3 passes across the map: 117 * 118 * 1. Count the number of map entries (the number of 119 * PT_LOAD sections). 120 * 121 * 2. Write the P-section headers. 122 * 123 * 3. Write the P-sections. 124 */ 125 126 /* Pass 1: count the entries. */ 127 cs.npsections = 0; 128 error = uvm_coredump_walkmap(p, NULL, 129 ELFNAMEEND(coredump_countsegs), &cs); 130 if (error) 131 goto out; 132 133 /* Count the PT_NOTE section. */ 134 cs.npsections++; 135 136 /* Get the size of the notes. */ 137 error = ELFNAMEEND(coredump_notes)(p, l, NULL, ¬esize); 138 if (error) 139 goto out; 140 141 memset(&ehdr.e_ident[EI_PAD], 0, sizeof(ehdr.e_ident) - EI_PAD); 142 memcpy(ehdr.e_ident, ELFMAG, SELFMAG); 143 #if ELFSIZE == 32 144 ehdr.e_ident[EI_CLASS] = ELFCLASS32; 145 #elif ELFSIZE == 64 146 ehdr.e_ident[EI_CLASS] = ELFCLASS64; 147 #endif 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; 153 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; 158 ehdr.e_entry = 0; 159 ehdr.e_phoff = sizeof(ehdr); 160 ehdr.e_shoff = 0; 161 ehdr.e_flags = 0; 162 ehdr.e_ehsize = sizeof(ehdr); 163 ehdr.e_phentsize = sizeof(Elf_Phdr); 164 ehdr.e_phnum = cs.npsections; 165 ehdr.e_shentsize = 0; 166 ehdr.e_shnum = 0; 167 ehdr.e_shstrndx = 0; 168 169 #ifdef ELF_MD_COREDUMP_SETUP 170 ELF_MD_COREDUMP_SETUP(l, &ehdr); 171 #endif 172 173 /* Write out the ELF header. */ 174 error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr)); 175 if (error) 176 goto out; 177 178 offset = sizeof(ehdr); 179 180 notestart = offset + sizeof(phdr) * cs.npsections; 181 secstart = notestart + notesize; 182 183 psections = malloc(cs.npsections * sizeof(Elf_Phdr), 184 M_TEMP, M_WAITOK|M_ZERO); 185 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); 191 if (error) 192 goto out; 193 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; 203 204 error = coredump_write(cookie, UIO_SYSSPACE, psections, 205 cs.npsections * sizeof(Elf_Phdr)); 206 if (error) 207 goto out; 208 209 #ifdef DIAGNOSTIC 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); 214 #endif 215 216 /* Write out the notes. */ 217 error = ELFNAMEEND(coredump_notes)(p, l, cookie, ¬esize); 218 if (error) 219 goto out; 220 221 #ifdef DIAGNOSTIC 222 offset += notesize; 223 if (offset != secstart) 224 panic("coredump: offset %lld != secstart %lld", 225 (long long) offset, (long long) secstart); 226 #endif 227 228 /* Pass 3: finally, write the sections themselves. */ 229 for (i = 0; i < cs.npsections - 1; i++) { 230 if (psections[i].p_filesz == 0) 231 continue; 232 233 #ifdef DIAGNOSTIC 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); 238 #endif 239 240 error = coredump_write(cookie, UIO_USERSPACE, 241 (void *)(vaddr_t)psections[i].p_vaddr, 242 psections[i].p_filesz); 243 if (error) 244 goto out; 245 246 #ifdef DIAGNOSTIC 247 offset += psections[i].p_filesz; 248 #endif 249 } 250 251 out: 252 if (psections) 253 free(psections, M_TEMP); 254 return (error); 255 } 256 257 static int 258 ELFNAMEEND(coredump_countsegs)(struct proc *p, void *iocookie, 259 struct uvm_coredump_state *us) 260 { 261 struct countsegs_state *cs = us->cookie; 262 263 cs->npsections++; 264 return (0); 265 } 266 267 static int 268 ELFNAMEEND(coredump_writeseghdrs)(struct proc *p, void *iocookie, 269 struct uvm_coredump_state *us) 270 { 271 struct writesegs_state *ws = us->cookie; 272 Elf_Phdr phdr; 273 vsize_t size, realsize; 274 vaddr_t end; 275 int error; 276 277 size = us->end - us->start; 278 realsize = us->realend - us->start; 279 end = us->realend; 280 281 while (realsize > 0) { 282 long buf[1024 / sizeof(long)]; 283 size_t slen = realsize > sizeof(buf) ? sizeof(buf) : realsize; 284 const long *ep; 285 int i; 286 287 end -= slen; 288 if ((error = copyin_proc(p, (void *)end, buf, slen)) != 0) 289 return error; 290 291 ep = (const long *) &buf[slen / sizeof(buf[0])]; 292 for (i = 0, ep--; buf <= ep; ep--, i++) { 293 if (*ep) 294 break; 295 } 296 realsize -= i * sizeof(buf[0]); 297 if (i * sizeof(buf[0]) < slen) 298 break; 299 } 300 301 phdr.p_type = PT_LOAD; 302 phdr.p_offset = ws->secoff; 303 phdr.p_vaddr = us->start; 304 phdr.p_paddr = 0; 305 phdr.p_filesz = realsize; 306 phdr.p_memsz = size; 307 phdr.p_flags = 0; 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; 315 316 ws->secoff += phdr.p_filesz; 317 *ws->psections++ = phdr; 318 319 return (0); 320 } 321 322 static int 323 ELFNAMEEND(coredump_notes)(struct proc *p, struct lwp *l, 324 void *iocookie, size_t *sizep) 325 { 326 struct netbsd_elfcore_procinfo cpi; 327 Elf_Nhdr nhdr; 328 size_t size, notesize; 329 int error; 330 struct lwp *l0; 331 sigset_t ss1, ss2; 332 333 size = 0; 334 335 /* First, write an elfcore_procinfo. */ 336 notesize = sizeof(nhdr) + elfround(sizeof(ELF_NOTE_NETBSD_CORE_NAME)) + 337 elfround(sizeof(cpi)); 338 if (iocookie) { 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; 344 345 /* 346 * XXX This should be per-LWP. 347 */ 348 ss1 = p->p_sigpend.sp_set; 349 sigemptyset(&ss2); 350 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 351 sigplusset(&l0->l_sigpend.sp_set, &ss1); 352 sigplusset(&l0->l_sigmask, &ss2); 353 } 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)); 360 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); 367 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); 371 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); 375 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'; 379 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; 383 384 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, 385 ELF_NOTE_NETBSD_CORE_NAME "\0\0\0", &cpi); 386 if (error) 387 return (error); 388 } 389 390 size += notesize; 391 392 /* XXX Add hook for machdep per-proc notes. */ 393 394 /* 395 * Now write the register info for the thread that caused the 396 * coredump. 397 */ 398 error = ELFNAMEEND(coredump_note)(p, l, iocookie, ¬esize); 399 if (error) 400 return (error); 401 size += notesize; 402 403 /* 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 406 * locking. 407 */ 408 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 409 if (l0 == l) /* we've taken care of this thread */ 410 continue; 411 error = ELFNAMEEND(coredump_note)(p, l0, iocookie, ¬esize); 412 if (error) 413 return (error); 414 size += notesize; 415 } 416 417 *sizep = size; 418 return (0); 419 } 420 421 static int 422 ELFNAMEEND(coredump_note)(struct proc *p, struct lwp *l, void *iocookie, 423 size_t *sizep) 424 { 425 Elf_Nhdr nhdr; 426 int size, notesize, error; 427 int namesize; 428 char name[64+ELFROUNDSIZE]; 429 elf_reg intreg; 430 #ifdef PT_GETFPREGS 431 elf_fpreg freg; 432 #endif 433 434 size = 0; 435 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); 440 441 notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(intreg)); 442 if (iocookie) { 443 error = elf_process_read_regs(l, &intreg); 444 if (error) 445 return (error); 446 447 nhdr.n_namesz = namesize; 448 nhdr.n_descsz = sizeof(intreg); 449 nhdr.n_type = PT_GETREGS; 450 451 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, 452 name, &intreg); 453 if (error) 454 return (error); 455 456 } 457 size += notesize; 458 459 #ifdef PT_GETFPREGS 460 notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(freg)); 461 if (iocookie) { 462 size_t freglen = sizeof(freg); 463 #ifdef __HAVE_PROCESS_XFPREGS 464 error = elf_process_read_xfpregs(l, &freg, &freglen); 465 #else 466 error = elf_process_read_fpregs(l, &freg); 467 #endif 468 if (error) 469 return (error); 470 471 nhdr.n_namesz = namesize; 472 nhdr.n_descsz = freglen; 473 nhdr.n_type = PT_GETFPREGS; 474 475 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, 476 name, &freg); 477 if (error) 478 return (error); 479 } 480 size += notesize; 481 #endif 482 *sizep = size; 483 /* XXX Add hook for machdep per-LWP notes. */ 484 return (0); 485 } 486 487 int 488 ELFNAMEEND(coredump_writenote)(struct proc *p, void *cookie, Elf_Nhdr *nhdr, 489 const char *name, void *data) 490 { 491 int error; 492 493 error = coredump_write(cookie, UIO_SYSSPACE, nhdr, sizeof(*nhdr)); 494 if (error) 495 return error; 496 497 error = coredump_write(cookie, UIO_SYSSPACE, name, 498 elfround(nhdr->n_namesz)); 499 if (error) 500 return error; 501 502 return coredump_write(cookie, UIO_SYSSPACE, data, nhdr->n_descsz); 503 } 504 505 #else /* COREDUMP */ 506 507 int 508 ELFNAMEEND(coredump)(struct lwp *l, void *cookie) 509 { 510 511 return ENOSYS; 512 } 513 514 #endif /* COREDUMP */ 515