1 /*- 2 * Copyright (c) 1998 John D. Polstra 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <sys/param.h> 30 #include <sys/procfs.h> 31 #include <machine/elf.h> 32 #include <vm/vm_param.h> 33 #include <vm/vm.h> 34 #include <vm/pmap.h> 35 #include <vm/vm_map.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include "extern.h" 45 46 /* 47 * Code for generating ELF core dumps. 48 */ 49 50 typedef void (*segment_callback)(vm_map_entry_t, void *); 51 52 /* Closure for cb_put_phdr(). */ 53 struct phdr_closure { 54 Elf_Phdr *phdr; /* Program header to fill in */ 55 Elf_Off offset; /* Offset of segment in core file */ 56 }; 57 58 /* Closure for cb_size_segment(). */ 59 struct sseg_closure { 60 int count; /* Count of writable segments. */ 61 size_t size; /* Total size of all writable segments. */ 62 }; 63 64 static void cb_put_phdr(vm_map_entry_t, void *); 65 static void cb_size_segment(vm_map_entry_t, void *); 66 static void each_writable_segment(vm_map_entry_t, segment_callback, 67 void *closure); 68 static void elf_corehdr(int fd, pid_t, vm_map_entry_t, int numsegs, 69 void *hdr, size_t hdrsize); 70 static void elf_puthdr(vm_map_entry_t, void *, size_t *, 71 const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int numsegs); 72 static void elf_putnote(void *dst, size_t *off, const char *name, int type, 73 const void *desc, size_t descsz); 74 static void freemap(vm_map_entry_t); 75 static void readhdrinfo(pid_t, prstatus_t *, prfpregset_t *, prpsinfo_t *); 76 static vm_map_entry_t readmap(pid_t); 77 78 /* 79 * Write an ELF coredump for the given pid to the given fd. 80 */ 81 void 82 elf_coredump(int fd, pid_t pid) 83 { 84 vm_map_entry_t map; 85 struct sseg_closure seginfo; 86 void *hdr; 87 size_t hdrsize; 88 char memname[64]; 89 int memfd; 90 Elf_Phdr *php; 91 int i; 92 93 /* Get the program's memory map. */ 94 map = readmap(pid); 95 96 /* Size the program segments. */ 97 seginfo.count = 0; 98 seginfo.size = 0; 99 each_writable_segment(map, cb_size_segment, &seginfo); 100 101 /* 102 * Calculate the size of the core file header area by making 103 * a dry run of generating it. Nothing is written, but the 104 * size is calculated. 105 */ 106 hdrsize = 0; 107 elf_puthdr(map, (void *)NULL, &hdrsize, 108 (const prstatus_t *)NULL, (const prfpregset_t *)NULL, 109 (const prpsinfo_t *)NULL, seginfo.count); 110 111 /* 112 * Allocate memory for building the header, fill it up, 113 * and write it out. 114 */ 115 hdr = malloc(hdrsize); 116 if ((hdr = malloc(hdrsize)) == NULL) 117 errx(1, "out of memory"); 118 elf_corehdr(fd, pid, map, seginfo.count, hdr, hdrsize); 119 120 /* Write the contents of all of the writable segments. */ 121 snprintf(memname, sizeof memname, "/proc/%d/mem", pid); 122 if ((memfd = open(memname, O_RDONLY)) == -1) 123 err(1, "cannot open %s", memname); 124 125 php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 126 for (i = 0; i < seginfo.count; i++) { 127 int nleft = php->p_filesz; 128 129 lseek(memfd, (off_t)php->p_vaddr, SEEK_SET); 130 while (nleft > 0) { 131 char buf[8*1024]; 132 int nwant; 133 int ngot; 134 135 nwant = nleft; 136 if (nwant > sizeof buf) 137 nwant = sizeof buf; 138 ngot = read(memfd, buf, nwant); 139 if (ngot == -1) 140 err(1, "read from %s", memname); 141 if (ngot < nwant) 142 errx(1, "short read from %s:" 143 " wanted %d, got %d\n", memname, 144 nwant, ngot); 145 ngot = write(fd, buf, nwant); 146 if (ngot == -1) 147 err(1, "write of segment %d failed", i); 148 if (ngot != nwant) 149 errx(1, "short write"); 150 nleft -= nwant; 151 } 152 php++; 153 } 154 close(memfd); 155 free(hdr); 156 freemap(map); 157 } 158 159 /* 160 * A callback for each_writable_segment() to write out the segment's 161 * program header entry. 162 */ 163 static void 164 cb_put_phdr(vm_map_entry_t entry, void *closure) 165 { 166 struct phdr_closure *phc = (struct phdr_closure *)closure; 167 Elf_Phdr *phdr = phc->phdr; 168 169 phc->offset = round_page(phc->offset); 170 171 phdr->p_type = PT_LOAD; 172 phdr->p_offset = phc->offset; 173 phdr->p_vaddr = entry->start; 174 phdr->p_paddr = 0; 175 phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 176 phdr->p_align = PAGE_SIZE; 177 phdr->p_flags = 0; 178 if (entry->protection & VM_PROT_READ) 179 phdr->p_flags |= PF_R; 180 if (entry->protection & VM_PROT_WRITE) 181 phdr->p_flags |= PF_W; 182 if (entry->protection & VM_PROT_EXECUTE) 183 phdr->p_flags |= PF_X; 184 185 phc->offset += phdr->p_filesz; 186 phc->phdr++; 187 } 188 189 /* 190 * A callback for each_writable_segment() to gather information about 191 * the number of segments and their total size. 192 */ 193 static void 194 cb_size_segment(vm_map_entry_t entry, void *closure) 195 { 196 struct sseg_closure *ssc = (struct sseg_closure *)closure; 197 198 ssc->count++; 199 ssc->size += entry->end - entry->start; 200 } 201 202 /* 203 * For each segment in the given memory map, call the given function 204 * with a pointer to the map entry and some arbitrary caller-supplied 205 * data. 206 */ 207 static void 208 each_writable_segment(vm_map_entry_t map, segment_callback func, void *closure) 209 { 210 vm_map_entry_t entry; 211 212 for (entry = map; entry != NULL; entry = entry->next) 213 (*func)(entry, closure); 214 } 215 216 /* 217 * Write the core file header to the file, including padding up to 218 * the page boundary. 219 */ 220 static void 221 elf_corehdr(int fd, pid_t pid, vm_map_entry_t map, int numsegs, void *hdr, 222 size_t hdrsize) 223 { 224 size_t off; 225 prstatus_t status; 226 prfpregset_t fpregset; 227 prpsinfo_t psinfo; 228 229 /* Gather the information for the header. */ 230 readhdrinfo(pid, &status, &fpregset, &psinfo); 231 232 /* Fill in the header. */ 233 memset(hdr, 0, hdrsize); 234 off = 0; 235 elf_puthdr(map, hdr, &off, &status, &fpregset, &psinfo, numsegs); 236 237 /* Write it to the core file. */ 238 if (write(fd, hdr, hdrsize) == -1) 239 err(1, "write"); 240 } 241 242 /* 243 * Generate the ELF coredump header into the buffer at "dst". "dst" may 244 * be NULL, in which case the header is sized but not actually generated. 245 */ 246 static void 247 elf_puthdr(vm_map_entry_t map, void *dst, size_t *off, const prstatus_t *status, 248 const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) 249 { 250 size_t ehoff; 251 size_t phoff; 252 size_t noteoff; 253 size_t notesz; 254 255 ehoff = *off; 256 *off += sizeof(Elf_Ehdr); 257 258 phoff = *off; 259 *off += (numsegs + 1) * sizeof(Elf_Phdr); 260 261 noteoff = *off; 262 elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, 263 sizeof *status); 264 elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, 265 sizeof *fpregset); 266 elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, 267 sizeof *psinfo); 268 notesz = *off - noteoff; 269 270 /* Align up to a page boundary for the program segments. */ 271 *off = round_page(*off); 272 273 if (dst != NULL) { 274 Elf_Ehdr *ehdr; 275 Elf_Phdr *phdr; 276 struct phdr_closure phc; 277 278 /* 279 * Fill in the ELF header. 280 */ 281 ehdr = (Elf_Ehdr *)((char *)dst + ehoff); 282 ehdr->e_ident[EI_MAG0] = ELFMAG0; 283 ehdr->e_ident[EI_MAG1] = ELFMAG1; 284 ehdr->e_ident[EI_MAG2] = ELFMAG2; 285 ehdr->e_ident[EI_MAG3] = ELFMAG3; 286 ehdr->e_ident[EI_CLASS] = ELF_CLASS; 287 ehdr->e_ident[EI_DATA] = ELF_DATA; 288 ehdr->e_ident[EI_VERSION] = EV_CURRENT; 289 ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 290 ehdr->e_ident[EI_ABIVERSION] = 0; 291 ehdr->e_ident[EI_PAD] = 0; 292 ehdr->e_type = ET_CORE; 293 ehdr->e_machine = ELF_ARCH; 294 ehdr->e_version = EV_CURRENT; 295 ehdr->e_entry = 0; 296 ehdr->e_phoff = phoff; 297 ehdr->e_flags = 0; 298 ehdr->e_ehsize = sizeof(Elf_Ehdr); 299 ehdr->e_phentsize = sizeof(Elf_Phdr); 300 ehdr->e_phnum = numsegs + 1; 301 ehdr->e_shentsize = sizeof(Elf_Shdr); 302 ehdr->e_shnum = 0; 303 ehdr->e_shstrndx = SHN_UNDEF; 304 305 /* 306 * Fill in the program header entries. 307 */ 308 phdr = (Elf_Phdr *)((char *)dst + phoff); 309 310 /* The note segement. */ 311 phdr->p_type = PT_NOTE; 312 phdr->p_offset = noteoff; 313 phdr->p_vaddr = 0; 314 phdr->p_paddr = 0; 315 phdr->p_filesz = notesz; 316 phdr->p_memsz = 0; 317 phdr->p_flags = 0; 318 phdr->p_align = 0; 319 phdr++; 320 321 /* All the writable segments from the program. */ 322 phc.phdr = phdr; 323 phc.offset = *off; 324 each_writable_segment(map, cb_put_phdr, &phc); 325 } 326 } 327 328 /* 329 * Emit one note section to "dst", or just size it if "dst" is NULL. 330 */ 331 static void 332 elf_putnote(void *dst, size_t *off, const char *name, int type, 333 const void *desc, size_t descsz) 334 { 335 Elf_Note note; 336 337 note.n_namesz = strlen(name) + 1; 338 note.n_descsz = descsz; 339 note.n_type = type; 340 if (dst != NULL) 341 bcopy(¬e, (char *)dst + *off, sizeof note); 342 *off += sizeof note; 343 if (dst != NULL) 344 bcopy(name, (char *)dst + *off, note.n_namesz); 345 *off += roundup2(note.n_namesz, sizeof(Elf_Size)); 346 if (dst != NULL) 347 bcopy(desc, (char *)dst + *off, note.n_descsz); 348 *off += roundup2(note.n_descsz, sizeof(Elf_Size)); 349 } 350 351 /* 352 * Free the memory map. 353 */ 354 static void 355 freemap(vm_map_entry_t map) 356 { 357 while (map != NULL) { 358 vm_map_entry_t next = map->next; 359 free(map); 360 map = next; 361 } 362 } 363 364 /* 365 * Read the process information necessary to fill in the core file's header. 366 */ 367 static void 368 readhdrinfo(pid_t pid, prstatus_t *status, prfpregset_t *fpregset, 369 prpsinfo_t *psinfo) 370 { 371 char name[64]; 372 char line[256]; 373 int fd; 374 int i; 375 int n; 376 377 memset(status, 0, sizeof *status); 378 status->pr_version = PRSTATUS_VERSION; 379 status->pr_statussz = sizeof(prstatus_t); 380 status->pr_gregsetsz = sizeof(gregset_t); 381 status->pr_fpregsetsz = sizeof(fpregset_t); 382 status->pr_osreldate = __FreeBSD_version; 383 status->pr_pid = pid; 384 385 memset(fpregset, 0, sizeof *fpregset); 386 387 memset(psinfo, 0, sizeof *psinfo); 388 psinfo->pr_version = PRPSINFO_VERSION; 389 psinfo->pr_psinfosz = sizeof(prpsinfo_t); 390 391 /* Read the general registers. */ 392 snprintf(name, sizeof name, "/proc/%d/regs", pid); 393 if ((fd = open(name, O_RDONLY)) == -1) 394 err(1, "cannot open %s", name); 395 if ((n = read(fd, &status->pr_reg, sizeof status->pr_reg)) == -1) 396 err(1, "read error from %s", name); 397 if (n < sizeof status->pr_reg) 398 errx(1, "short read from %s: wanted %u, got %d", name, 399 sizeof status->pr_reg, n); 400 close(fd); 401 402 /* Read the floating point registers. */ 403 snprintf(name, sizeof name, "/proc/%d/fpregs", pid); 404 if ((fd = open(name, O_RDONLY)) == -1) 405 err(1, "cannot open %s", name); 406 if ((n = read(fd, fpregset, sizeof *fpregset)) == -1) 407 err(1, "read error from %s", name); 408 if (n < sizeof *fpregset) 409 errx(1, "short read from %s: wanted %u, got %d", name, 410 sizeof *fpregset, n); 411 close(fd); 412 413 /* Read and parse the process status. */ 414 snprintf(name, sizeof name, "/proc/%d/status", pid); 415 if ((fd = open(name, O_RDONLY)) == -1) 416 err(1, "cannot open %s", name); 417 if ((n = read(fd, line, sizeof line - 1)) == -1) 418 err(1, "read error from %s", name); 419 if (n > MAXCOMLEN) 420 n = MAXCOMLEN; 421 for (i = 0; i < n && line[i] != ' '; i++) 422 psinfo->pr_fname[i] = line[i]; 423 strncpy(psinfo->pr_psargs, psinfo->pr_fname, PRARGSZ); 424 close(fd); 425 } 426 427 /* 428 * Read the process's memory map using procfs, and return a list of 429 * VM map entries. Only the non-device read/writable segments are 430 * returned. The map entries in the list aren't fully filled in; only 431 * the items we need are present. 432 */ 433 static vm_map_entry_t 434 readmap(pid_t pid) 435 { 436 char mapname[64]; 437 int mapfd; 438 ssize_t mapsize; 439 size_t bufsize; 440 char *mapbuf; 441 int pos; 442 vm_map_entry_t map; 443 vm_map_entry_t *linkp; 444 445 snprintf(mapname, sizeof mapname, "/proc/%d/map", pid); 446 if ((mapfd = open(mapname, O_RDONLY)) == -1) 447 err(1, "cannot open %s", mapname); 448 449 /* 450 * Procfs requires (for consistency) that the entire memory map 451 * be read with a single read() call. Start with a reasonbly sized 452 * buffer, and double it until it is big enough. 453 */ 454 bufsize = 8 * 1024; 455 mapbuf = NULL; 456 for ( ; ; ) { 457 if ((mapbuf = realloc(mapbuf, bufsize + 1)) == NULL) 458 errx(1, "out of memory"); 459 mapsize = read(mapfd, mapbuf, bufsize); 460 if (mapsize != -1 || errno != EFBIG) 461 break; 462 bufsize *= 2; 463 /* This lseek shouldn't be necessary, but it is. */ 464 lseek(mapfd, (off_t)0, SEEK_SET); 465 } 466 if (mapsize == -1) 467 err(1, "read error from %s", mapname); 468 if (mapsize == 0) 469 errx(1, "empty map file %s", mapname); 470 mapbuf[mapsize] = 0; 471 close(mapfd); 472 473 pos = 0; 474 map = NULL; 475 linkp = ↦ 476 while (pos < mapsize) { 477 vm_map_entry_t ent; 478 vm_offset_t start; 479 vm_offset_t end; 480 char prot[4]; 481 char type[16]; 482 int n; 483 int len; 484 485 len = 0; 486 n = sscanf(mapbuf + pos, "%x %x %*d %*d %*x %3[-rwx]" 487 " %*d %*d %*x %*s %*s %16s%*[\n]%n", 488 &start, &end, prot, type, &len); 489 if (n != 4) 490 errx(1, "ill-formed line in %s", mapname); 491 pos += len; 492 493 /* Ignore segments of the wrong kind, and unwritable ones */ 494 if (strncmp(prot, "rw", 2) != 0 || 495 (strcmp(type, "default") != 0 && 496 strcmp(type, "vnode") != 0 && 497 strcmp(type, "swap") != 0)) 498 continue; 499 500 if ((ent = (vm_map_entry_t)calloc(1, sizeof *ent)) == NULL) 501 errx(1, "out of memory"); 502 ent->start = start; 503 ent->end = end; 504 ent->protection = VM_PROT_READ | VM_PROT_WRITE; 505 if (prot[2] == 'x') 506 ent->protection |= VM_PROT_EXECUTE; 507 508 *linkp = ent; 509 linkp = &ent->next; 510 } 511 free(mapbuf); 512 return map; 513 } 514