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