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