1 /* $NetBSD: core_elf32.c,v 1.23 2006/03/12 20:25:26 cube 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.23 2006/03/12 20:25:26 cube 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 strlcpy(cpi.cpi_name, p->p_comm, sizeof(cpi.cpi_name)); 354 355 nhdr.n_namesz = sizeof(ELF_NOTE_NETBSD_CORE_NAME); 356 nhdr.n_descsz = sizeof(cpi); 357 nhdr.n_type = ELF_NOTE_NETBSD_CORE_PROCINFO; 358 359 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, 360 ELF_NOTE_NETBSD_CORE_NAME "\0\0\0", &cpi); 361 if (error) 362 return (error); 363 } 364 365 size += notesize; 366 367 /* XXX Add hook for machdep per-proc notes. */ 368 369 /* 370 * Now write the register info for the thread that caused the 371 * coredump. 372 */ 373 error = ELFNAMEEND(coredump_note)(p, l, iocookie, ¬esize); 374 if (error) 375 return (error); 376 size += notesize; 377 378 /* 379 * Now, for each LWP, write the register info and any other 380 * per-LWP notes. 381 */ 382 LIST_FOREACH(l0, &p->p_lwps, l_sibling) { 383 if (l0 == l) /* we've taken care of this thread */ 384 continue; 385 error = ELFNAMEEND(coredump_note)(p, l0, iocookie, ¬esize); 386 if (error) 387 return (error); 388 size += notesize; 389 } 390 391 *sizep = size; 392 return (0); 393 } 394 395 static int 396 ELFNAMEEND(coredump_note)(struct proc *p, struct lwp *l, void *iocookie, 397 size_t *sizep) 398 { 399 Elf_Nhdr nhdr; 400 int size, notesize, error; 401 int namesize; 402 char name[64+ELFROUNDSIZE]; 403 elf_reg intreg; 404 #ifdef PT_GETFPREGS 405 elf_fpreg freg; 406 #endif 407 408 size = 0; 409 410 snprintf(name, sizeof(name)-ELFROUNDSIZE, "%s@%d", 411 ELF_NOTE_NETBSD_CORE_NAME, l->l_lid); 412 namesize = strlen(name) + 1; 413 memset(name + namesize, 0, elfround(namesize) - namesize); 414 415 notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(intreg)); 416 if (iocookie) { 417 PHOLD(l); 418 error = elf_process_read_regs(l, &intreg); 419 PRELE(l); 420 if (error) 421 return (error); 422 423 nhdr.n_namesz = namesize; 424 nhdr.n_descsz = sizeof(intreg); 425 nhdr.n_type = PT_GETREGS; 426 427 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, 428 name, &intreg); 429 if (error) 430 return (error); 431 432 } 433 size += notesize; 434 435 #ifdef PT_GETFPREGS 436 notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(freg)); 437 if (iocookie) { 438 PHOLD(l); 439 error = elf_process_read_fpregs(l, &freg); 440 PRELE(l); 441 if (error) 442 return (error); 443 444 nhdr.n_namesz = namesize; 445 nhdr.n_descsz = sizeof(freg); 446 nhdr.n_type = PT_GETFPREGS; 447 448 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr, 449 name, &freg); 450 if (error) 451 return (error); 452 } 453 size += notesize; 454 #endif 455 *sizep = size; 456 /* XXX Add hook for machdep per-LWP notes. */ 457 return (0); 458 } 459 460 int 461 ELFNAMEEND(coredump_writenote)(struct proc *p, void *cookie, Elf_Nhdr *nhdr, 462 const char *name, void *data) 463 { 464 int error; 465 466 error = coredump_write(cookie, UIO_SYSSPACE, nhdr, sizeof(*nhdr)); 467 if (error) 468 return error; 469 470 error = coredump_write(cookie, UIO_SYSSPACE, name, 471 elfround(nhdr->n_namesz)); 472 if (error) 473 return error; 474 475 return coredump_write(cookie, UIO_SYSSPACE, data, nhdr->n_descsz); 476 } 477