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