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