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