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