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