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