1 /* $NetBSD: core_elf32.c,v 1.45 2014/04/02 17:19:49 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.45 2014/04/02 17:19:49 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 69 struct writesegs_state { 70 Elf_Phdr *psections; 71 proc_t *p; 72 off_t secoff; 73 size_t npsections; 74 }; 75 76 /* 77 * We need to know how big the 'notes' are before we write the main header. 78 * To avoid problems with double-processing we save the data. 79 */ 80 struct note_buf { 81 struct note_buf *nb_next; 82 unsigned char nb_data[4096 - sizeof (void *)]; 83 }; 84 85 struct note_state { 86 struct note_buf *ns_first; 87 struct note_buf *ns_last; 88 unsigned int ns_count; /* Of full buffers */ 89 unsigned int ns_offset; /* Write point in last buffer */ 90 }; 91 92 static int ELFNAMEEND(coredump_getseghdrs)(struct uvm_coredump_state *); 93 94 static int ELFNAMEEND(coredump_notes)(struct lwp *, struct note_state *); 95 static int ELFNAMEEND(coredump_note)(struct lwp *, struct note_state *); 96 97 /* The 'note' section names and data are always 4-byte aligned. */ 98 #define ELFROUNDSIZE 4 /* XXX Should it be sizeof(Elf_Word)? */ 99 100 #define elf_process_read_regs CONCAT(process_read_regs, ELFSIZE) 101 #define elf_process_read_fpregs CONCAT(process_read_fpregs, ELFSIZE) 102 #define elf_reg CONCAT(process_reg, ELFSIZE) 103 #define elf_fpreg CONCAT(process_fpreg, ELFSIZE) 104 105 int 106 ELFNAMEEND(coredump)(struct lwp *l, struct coredump_iostate *cookie) 107 { 108 Elf_Ehdr ehdr; 109 Elf_Shdr shdr; 110 Elf_Phdr *psections; 111 size_t psectionssize; 112 int npsections; 113 struct writesegs_state ws; 114 off_t notestart; 115 size_t notesize; 116 int error, i; 117 118 struct note_state ns; 119 struct note_buf *nb; 120 121 psections = NULL; 122 123 /* Get all of the notes (mostly all the registers). */ 124 ns.ns_first = kmem_alloc(sizeof *ns.ns_first, KM_SLEEP); 125 ns.ns_last = ns.ns_first; 126 ns.ns_count = 0; 127 ns.ns_offset = 0; 128 error = ELFNAMEEND(coredump_notes)(l, &ns); 129 ns.ns_last->nb_next = NULL; 130 if (error) 131 goto out; 132 notesize = ns.ns_count * sizeof nb->nb_data + ns.ns_offset; 133 134 /* 135 * We have to make a total of 3 passes across the map: 136 * 137 * 1. Count the number of map entries (the number of 138 * PT_LOAD sections in the dump). 139 * 140 * 2. Write the P-section headers. 141 * 142 * 3. Write the P-sections. 143 */ 144 145 /* Pass 1: count the entries. */ 146 npsections = uvm_coredump_count_segs(l->l_proc); 147 /* Allow for the PT_NOTE section. */ 148 npsections++; 149 150 /* Build the main elf header */ 151 memset(&ehdr.e_ident[EI_PAD], 0, sizeof(ehdr.e_ident) - EI_PAD); 152 memcpy(ehdr.e_ident, ELFMAG, SELFMAG); 153 #if ELFSIZE == 32 154 ehdr.e_ident[EI_CLASS] = ELFCLASS32; 155 #elif ELFSIZE == 64 156 ehdr.e_ident[EI_CLASS] = ELFCLASS64; 157 #endif 158 ehdr.e_ident[EI_DATA] = ELFDEFNNAME(MACHDEP_ENDIANNESS); 159 ehdr.e_ident[EI_VERSION] = EV_CURRENT; 160 /* XXX Should be the OSABI/ABI version of the executable. */ 161 ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV; 162 ehdr.e_ident[EI_ABIVERSION] = 0; 163 164 ehdr.e_type = ET_CORE; 165 /* XXX This should be the e_machine of the executable. */ 166 ehdr.e_machine = ELFDEFNNAME(MACHDEP_ID); 167 ehdr.e_version = EV_CURRENT; 168 ehdr.e_entry = 0; 169 ehdr.e_flags = 0; 170 ehdr.e_ehsize = sizeof(ehdr); 171 ehdr.e_phentsize = sizeof(Elf_Phdr); 172 if (npsections < PN_XNUM) { 173 ehdr.e_phnum = npsections; 174 ehdr.e_shentsize = 0; 175 ehdr.e_shnum = 0; 176 ehdr.e_shoff = 0; 177 ehdr.e_phoff = sizeof(ehdr); 178 } else { 179 ehdr.e_phnum = PN_XNUM; 180 ehdr.e_shentsize = sizeof(Elf_Shdr); 181 ehdr.e_shnum = 1; 182 ehdr.e_shoff = sizeof(ehdr); 183 ehdr.e_phoff = sizeof(ehdr) + sizeof(shdr); 184 } 185 ehdr.e_shstrndx = 0; 186 187 #ifdef ELF_MD_COREDUMP_SETUP 188 ELF_MD_COREDUMP_SETUP(l, &ehdr); 189 #endif 190 191 /* Write out the ELF header. */ 192 error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr)); 193 if (error) 194 goto out; 195 196 /* Write out sections, if needed */ 197 if (npsections >= PN_XNUM) { 198 memset(&shdr, 0, sizeof(shdr)); 199 shdr.sh_type = SHT_NULL; 200 shdr.sh_info = npsections; 201 error = coredump_write(cookie, UIO_SYSSPACE, &shdr, 202 sizeof(shdr)); 203 if (error) 204 goto out; 205 } 206 207 psectionssize = npsections * sizeof(*psections); 208 notestart = ehdr.e_phoff + psectionssize; 209 210 psections = kmem_zalloc(psectionssize, KM_SLEEP); 211 212 /* Pass 2: now find the P-section headers. */ 213 ws.secoff = notestart + notesize; 214 ws.psections = psections; 215 ws.npsections = npsections - 1; 216 ws.p = l->l_proc; 217 error = uvm_coredump_walkmap(l->l_proc, ELFNAMEEND(coredump_getseghdrs), 218 &ws); 219 if (error) 220 goto out; 221 if (ws.npsections != 0) { 222 /* A section went away */ 223 error = ENOMEM; 224 goto out; 225 } 226 227 /* Add the PT_NOTE header after the P-section headers. */ 228 ws.psections->p_type = PT_NOTE; 229 ws.psections->p_offset = notestart; 230 ws.psections->p_vaddr = 0; 231 ws.psections->p_paddr = 0; 232 ws.psections->p_filesz = notesize; 233 ws.psections->p_memsz = 0; 234 ws.psections->p_flags = PF_R; 235 ws.psections->p_align = ELFROUNDSIZE; 236 237 /* Write the P-section headers followed by the PT_NOTE header */ 238 error = coredump_write(cookie, UIO_SYSSPACE, psections, psectionssize); 239 if (error) 240 goto out; 241 242 #ifdef DIAGNOSTIC 243 if (coredump_offset(cookie) != notestart) 244 panic("coredump: offset %lld != notestart %lld", 245 (long long) coredump_offset(cookie), 246 (long long) notestart); 247 #endif 248 249 /* Write out the notes. */ 250 for (nb = ns.ns_first; nb != NULL; nb = nb->nb_next) { 251 error = coredump_write(cookie, UIO_SYSSPACE, nb->nb_data, 252 nb->nb_next == NULL ? ns.ns_offset : sizeof nb->nb_data); 253 if (error) 254 goto out; 255 } 256 257 /* Finally, write the sections themselves. */ 258 for (i = 0; i < npsections - 1; i++) { 259 if (psections[i].p_filesz == 0) 260 continue; 261 262 #ifdef DIAGNOSTIC 263 if (coredump_offset(cookie) != psections[i].p_offset) 264 panic("coredump: offset %lld != p_offset[%d] %lld", 265 (long long) coredump_offset(cookie), i, 266 (long long) psections[i].p_filesz); 267 #endif 268 269 error = coredump_write(cookie, UIO_USERSPACE, 270 (void *)(vaddr_t)psections[i].p_vaddr, 271 psections[i].p_filesz); 272 if (error) 273 goto out; 274 } 275 276 out: 277 if (psections) 278 kmem_free(psections, psectionssize); 279 while ((nb = ns.ns_first) != NULL) { 280 ns.ns_first = nb->nb_next; 281 kmem_free(nb, sizeof *nb); 282 } 283 return (error); 284 } 285 286 static int 287 ELFNAMEEND(coredump_getseghdrs)(struct uvm_coredump_state *us) 288 { 289 struct writesegs_state *ws = us->cookie; 290 Elf_Phdr phdr; 291 vsize_t size, realsize; 292 vaddr_t end; 293 int error; 294 295 /* Don't overrun if there are more sections */ 296 if (ws->npsections == 0) 297 return ENOMEM; 298 ws->npsections--; 299 300 size = us->end - us->start; 301 realsize = us->realend - us->start; 302 end = us->realend; 303 304 /* Don't bother writing out trailing zeros */ 305 while (realsize > 0) { 306 long buf[1024 / sizeof(long)]; 307 size_t slen = realsize > sizeof(buf) ? sizeof(buf) : realsize; 308 const long *ep; 309 int i; 310 311 end -= slen; 312 if ((error = copyin_proc(ws->p, (void *)end, buf, slen)) != 0) 313 return error; 314 315 ep = (const long *) &buf[slen / sizeof(buf[0])]; 316 for (i = 0, ep--; buf <= ep; ep--, i++) { 317 if (*ep) 318 break; 319 } 320 realsize -= i * sizeof(buf[0]); 321 if (i * sizeof(buf[0]) < slen) 322 break; 323 } 324 325 phdr.p_type = PT_LOAD; 326 phdr.p_offset = ws->secoff; 327 phdr.p_vaddr = us->start; 328 phdr.p_paddr = 0; 329 phdr.p_filesz = realsize; 330 phdr.p_memsz = size; 331 phdr.p_flags = 0; 332 if (us->prot & VM_PROT_READ) 333 phdr.p_flags |= PF_R; 334 if (us->prot & VM_PROT_WRITE) 335 phdr.p_flags |= PF_W; 336 if (us->prot & VM_PROT_EXECUTE) 337 phdr.p_flags |= PF_X; 338 phdr.p_align = PAGE_SIZE; 339 340 ws->secoff += phdr.p_filesz; 341 *ws->psections++ = phdr; 342 343 return (0); 344 } 345 346 static int 347 ELFNAMEEND(coredump_notes)(struct lwp *l, struct note_state *ns) 348 { 349 struct proc *p; 350 struct netbsd_elfcore_procinfo cpi; 351 int error; 352 struct lwp *l0; 353 sigset_t ss1, ss2; 354 355 p = l->l_proc; 356 357 /* First, write an elfcore_procinfo. */ 358 cpi.cpi_version = NETBSD_ELFCORE_PROCINFO_VERSION; 359 cpi.cpi_cpisize = sizeof(cpi); 360 cpi.cpi_signo = p->p_sigctx.ps_signo; 361 cpi.cpi_sigcode = p->p_sigctx.ps_code; 362 cpi.cpi_siglwp = p->p_sigctx.ps_lwp; 363 364 /* 365 * XXX This should be per-LWP. 366 */ 367 ss1 = p->p_sigpend.sp_set; 368 sigemptyset(&ss2); 369 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 370 sigplusset(&l0->l_sigpend.sp_set, &ss1); 371 sigplusset(&l0->l_sigmask, &ss2); 372 } 373 memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend)); 374 memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask)); 375 memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore, 376 sizeof(cpi.cpi_sigignore)); 377 memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch, 378 sizeof(cpi.cpi_sigcatch)); 379 380 cpi.cpi_pid = p->p_pid; 381 mutex_enter(proc_lock); 382 cpi.cpi_ppid = p->p_pptr->p_pid; 383 cpi.cpi_pgrp = p->p_pgid; 384 cpi.cpi_sid = p->p_session->s_sid; 385 mutex_exit(proc_lock); 386 387 cpi.cpi_ruid = kauth_cred_getuid(l->l_cred); 388 cpi.cpi_euid = kauth_cred_geteuid(l->l_cred); 389 cpi.cpi_svuid = kauth_cred_getsvuid(l->l_cred); 390 391 cpi.cpi_rgid = kauth_cred_getgid(l->l_cred); 392 cpi.cpi_egid = kauth_cred_getegid(l->l_cred); 393 cpi.cpi_svgid = kauth_cred_getsvgid(l->l_cred); 394 395 cpi.cpi_nlwps = p->p_nlwps; 396 (void)strncpy(cpi.cpi_name, p->p_comm, sizeof(cpi.cpi_name)); 397 cpi.cpi_name[sizeof(cpi.cpi_name) - 1] = '\0'; 398 399 ELFNAMEEND(coredump_savenote)(ns, ELF_NOTE_NETBSD_CORE_PROCINFO, 400 ELF_NOTE_NETBSD_CORE_NAME, &cpi, sizeof(cpi)); 401 402 /* XXX Add hook for machdep per-proc notes. */ 403 404 /* 405 * Now write the register info for the thread that caused the 406 * coredump. 407 */ 408 error = ELFNAMEEND(coredump_note)(l, ns); 409 if (error) 410 return (error); 411 412 /* 413 * Now, for each LWP, write the register info and any other 414 * per-LWP notes. 415 * Lock in case this is a gcore requested dump. 416 */ 417 mutex_enter(p->p_lock); 418 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 419 if (l0 == l) /* we've taken care of this thread */ 420 continue; 421 error = ELFNAMEEND(coredump_note)(l0, ns); 422 if (error) 423 break; 424 } 425 mutex_exit(p->p_lock); 426 427 return error; 428 } 429 430 static int 431 ELFNAMEEND(coredump_note)(struct lwp *l, struct note_state *ns) 432 { 433 int error; 434 char name[64]; 435 elf_reg intreg; 436 #ifdef PT_GETFPREGS 437 elf_fpreg freg; 438 size_t freglen; 439 #endif 440 441 snprintf(name, sizeof(name), "%s@%d", 442 ELF_NOTE_NETBSD_CORE_NAME, l->l_lid); 443 444 error = elf_process_read_regs(l, &intreg); 445 if (error) 446 return (error); 447 448 ELFNAMEEND(coredump_savenote)(ns, PT_GETREGS, name, &intreg, 449 sizeof(intreg)); 450 451 #ifdef PT_GETFPREGS 452 freglen = sizeof(freg); 453 error = elf_process_read_fpregs(l, &freg, &freglen); 454 if (error) 455 return (error); 456 457 ELFNAMEEND(coredump_savenote)(ns, PT_GETFPREGS, name, &freg, freglen); 458 #endif 459 /* XXX Add hook for machdep per-LWP notes. */ 460 return (0); 461 } 462 463 static void 464 save_note_bytes(struct note_state *ns, const void *data, size_t len) 465 { 466 struct note_buf *nb = ns->ns_last; 467 size_t copylen; 468 unsigned char *wp; 469 470 /* 471 * Just copy the data into a buffer list. 472 * All but the last buffer is full. 473 */ 474 for (;;) { 475 copylen = min(len, sizeof nb->nb_data - ns->ns_offset); 476 wp = nb->nb_data + ns->ns_offset; 477 memcpy(wp, data, copylen); 478 if (copylen == len) 479 break; 480 nb->nb_next = kmem_alloc(sizeof *nb->nb_next, KM_SLEEP); 481 nb = nb->nb_next; 482 ns->ns_last = nb; 483 ns->ns_count++; 484 ns->ns_offset = 0; 485 len -= copylen; 486 data = (const unsigned char *)data + copylen; 487 } 488 489 while (copylen & (ELFROUNDSIZE - 1)) 490 wp[copylen++] = 0; 491 492 ns->ns_offset += copylen; 493 } 494 495 void 496 ELFNAMEEND(coredump_savenote)(struct note_state *ns, unsigned int type, 497 const char *name, void *data, size_t data_len) 498 { 499 Elf_Nhdr nhdr; 500 501 nhdr.n_namesz = strlen(name) + 1; 502 nhdr.n_descsz = data_len; 503 nhdr.n_type = type; 504 505 save_note_bytes(ns, &nhdr, sizeof (nhdr)); 506 save_note_bytes(ns, name, nhdr.n_namesz); 507 save_note_bytes(ns, data, data_len); 508 } 509 510 #else /* COREDUMP */ 511 512 int 513 ELFNAMEEND(coredump)(struct lwp *l, void *cookie) 514 { 515 516 return ENOSYS; 517 } 518 519 #endif /* COREDUMP */ 520