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