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