/* $OpenBSD: core.c,v 1.7 2007/08/01 15:43:56 deraadt Exp $ */ /* * Copyright (c) 2002 Jean-Francois Brousseau * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "pmdb.h" #include "symbol.h" int read_core(const char *path, struct pstate *ps) { struct corefile *cf; void *core_map; off_t c_off; int i, cfd; cf = (struct corefile *)malloc(sizeof(*cf)); if (cf == NULL) err(1, "malloc"); cfd = open(path, O_RDONLY, 0600); if (cfd < 0) err(1, "open() failed on core file"); if (fstat(cfd, &(cf->cfstat)) < 0) err(1, "fstat() failed on core"); if (cf->cfstat.st_mtimespec.tv_sec < ps->exec_stat.st_mtimespec.tv_sec) warnx("executable is more recent than core file!"); core_map = mmap(NULL, cf->cfstat.st_size, PROT_READ, MAP_PRIVATE, cfd, 0); if (core_map == MAP_FAILED) err(1, "mmap() failed on core"); close(cfd); cf->chdr = (struct core *)core_map; c_off = cf->chdr->c_hdrsize; if (CORE_GETMAGIC(*(cf->chdr)) != COREMAGIC) errx(1, "hey, that's not a core file"); printf("Core file generated from '%s' by signal %d (SIG%s)\n", cf->chdr->c_name, cf->chdr->c_signo, sys_signame[cf->chdr->c_signo]); #ifdef DEBUG printf("Core: text=0x%lx, data=0x%lx, stack=0x%lx\n", cf->chdr->c_tsize, cf->chdr->c_dsize, cf->chdr->c_ssize); #endif cf->segs = (struct coreseg **)calloc(cf->chdr->c_nseg, sizeof(cf->segs)); if (cf->segs == NULL) err(1, "calloc"); for (i = 0; i < cf->chdr->c_nseg; i++) { cf->segs[i] = (struct coreseg *)(core_map + c_off); if (CORE_GETMAGIC(*(cf->segs[i])) != CORESEGMAGIC) errx(1, "invalid segment hdr for segment %d", i); if (CORE_GETFLAG(*(cf->segs[i])) & CORE_CPU) { cf->regs = (struct reg *) ((long) cf->segs[i] + cf->chdr->c_seghdrsize); } if (CORE_GETFLAG(*(cf->segs[i])) & CORE_STACK) cf->c_stack = cf->segs[i] + cf->chdr->c_seghdrsize; c_off += cf->chdr->c_seghdrsize + cf->segs[i]->c_size; #ifdef DEBUG (void)printf("seg[%d]: midmag=0x%lx addr=0x%lx size=0x%lx\n", i, cf->segs[i]->c_midmag, cf->segs[i]->c_addr, cf->segs[i]->c_size); #endif } cf->path = (char *)path; ps->ps_flags |= PSF_CORE; ps->ps_core = cf; return (0); } void free_core(struct pstate *ps) { struct corefile *cf = ps->ps_core; if (cf == NULL) return; if (cf->segs != NULL) { free(cf->segs); cf->segs = NULL; } } void core_printregs(struct pstate *ps) { struct corefile *cf = ps->ps_core; reg *rg; char buf[256]; int i; rg = (reg *)cf->regs; for (i = 0; i < md_def.nregs; i++) printf("%s:\t0x%.*lx\t%s\n", md_def.md_reg_names[i], (int)(sizeof(reg) * 2), (long) rg[i], sym_print(ps, rg[i], buf, sizeof(buf))); } ssize_t core_read(struct pstate *ps, off_t from, void *to, size_t size) { struct coreseg *cs; size_t read; void *fp; int i; for (i = 0; i < ps->ps_core->chdr->c_nseg; i++) { cs = ps->ps_core->segs[i]; if ((from >= cs->c_addr) && (from < (cs->c_addr + cs->c_size))) { read = size; if ((from + size) > (cs->c_addr + cs->c_size)) read = (cs->c_addr + cs->c_size) - from; fp = (void *)cs + sizeof(*cs) + ((u_long)from - cs->c_addr); memcpy(to, fp, read); return (read); } } return (-1); } ssize_t core_write(struct pstate *ps, off_t to, void *from, size_t size) { struct coreseg *cs; size_t written; void *fp; int i; for (i = 0; i < ps->ps_core->chdr->c_nseg; i++) { cs = ps->ps_core->segs[i]; if ((to > cs->c_addr) && (to < (cs->c_addr + cs->c_size))) { written = size; fp = (void *)cs + sizeof(*cs) + (to - cs->c_addr); memcpy(fp, from, written); return (written); } } return (-1); }