core.c revision 249672
1249666Strociny/*- 2249666Strociny * Copyright (c) 2013 Mikolaj Golub <trociny@FreeBSD.org> 3249666Strociny * All rights reserved. 4249666Strociny * 5249666Strociny * Redistribution and use in source and binary forms, with or without 6249666Strociny * modification, are permitted provided that the following conditions 7249666Strociny * are met: 8249666Strociny * 1. Redistributions of source code must retain the above copyright 9249666Strociny * notice, this list of conditions and the following disclaimer. 10249666Strociny * 2. Redistributions in binary form must reproduce the above copyright 11249666Strociny * notice, this list of conditions and the following disclaimer in the 12249666Strociny * documentation and/or other materials provided with the distribution. 13249666Strociny * 14249666Strociny * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 15249666Strociny * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16249666Strociny * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17249666Strociny * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 18249666Strociny * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19249666Strociny * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20249666Strociny * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21249666Strociny * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22249666Strociny * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23249666Strociny * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24249666Strociny * SUCH DAMAGE. 25249666Strociny * 26249666Strociny * $FreeBSD: head/lib/libprocstat/core.c 249672 2013-04-20 07:57:08Z trociny $ 27249666Strociny */ 28249666Strociny 29249666Strociny#include <sys/param.h> 30249666Strociny#include <sys/elf.h> 31249666Strociny#include <sys/user.h> 32249666Strociny 33249666Strociny#include <assert.h> 34249666Strociny#include <err.h> 35249666Strociny#include <fcntl.h> 36249666Strociny#include <gelf.h> 37249666Strociny#include <libelf.h> 38249666Strociny#include <stdbool.h> 39249666Strociny#include <stdint.h> 40249666Strociny#include <stdio.h> 41249666Strociny#include <stdlib.h> 42249666Strociny#include <string.h> 43249666Strociny#include <unistd.h> 44249666Strociny 45249666Strociny#include "core.h" 46249666Strociny 47249666Strociny#define PROCSTAT_CORE_MAGIC 0x012DADB8 48249666Strocinystruct procstat_core 49249666Strociny{ 50249666Strociny int pc_magic; 51249666Strociny int pc_fd; 52249666Strociny Elf *pc_elf; 53249666Strociny GElf_Ehdr pc_ehdr; 54249666Strociny GElf_Phdr pc_phdr; 55249666Strociny}; 56249666Strociny 57249666Strocinystatic bool core_offset(struct procstat_core *core, off_t offset); 58249666Strocinystatic bool core_read(struct procstat_core *core, void *buf, size_t len); 59249666Strociny 60249666Strocinystruct procstat_core * 61249666Strocinyprocstat_core_open(const char *filename) 62249666Strociny{ 63249666Strociny struct procstat_core *core; 64249666Strociny Elf *e; 65249666Strociny GElf_Ehdr ehdr; 66249666Strociny GElf_Phdr phdr; 67249666Strociny size_t nph; 68249666Strociny int fd, i; 69249666Strociny 70249666Strociny if (elf_version(EV_CURRENT) == EV_NONE) { 71249666Strociny warnx("ELF library too old"); 72249666Strociny return (NULL); 73249666Strociny } 74249666Strociny fd = open(filename, O_RDONLY, 0); 75249666Strociny if (fd == -1) { 76249666Strociny warn("open(%s)", filename); 77249666Strociny return (NULL); 78249666Strociny } 79249666Strociny e = elf_begin(fd, ELF_C_READ, NULL); 80249666Strociny if (e == NULL) { 81249666Strociny warnx("elf_begin: %s", elf_errmsg(-1)); 82249666Strociny goto fail; 83249666Strociny } 84249666Strociny if (elf_kind(e) != ELF_K_ELF) { 85249666Strociny warnx("%s is not an ELF object", filename); 86249666Strociny goto fail; 87249666Strociny } 88249666Strociny if (gelf_getehdr(e, &ehdr) == NULL) { 89249666Strociny warnx("gelf_getehdr: %s", elf_errmsg(-1)); 90249666Strociny goto fail; 91249666Strociny } 92249666Strociny if (ehdr.e_type != ET_CORE) { 93249666Strociny warnx("%s is not a CORE file", filename); 94249666Strociny goto fail; 95249666Strociny } 96249666Strociny if (elf_getphnum(e, &nph) == 0) { 97249666Strociny warnx("program headers not found"); 98249666Strociny goto fail; 99249666Strociny } 100249666Strociny for (i = 0; i < ehdr.e_phnum; i++) { 101249666Strociny if (gelf_getphdr(e, i, &phdr) != &phdr) { 102249666Strociny warnx("gelf_getphdr: %s", elf_errmsg(-1)); 103249666Strociny goto fail; 104249666Strociny } 105249666Strociny if (phdr.p_type == PT_NOTE) 106249666Strociny break; 107249666Strociny } 108249666Strociny if (i == ehdr.e_phnum) { 109249666Strociny warnx("NOTE program header not found"); 110249666Strociny goto fail; 111249666Strociny } 112249666Strociny core = malloc(sizeof(struct procstat_core)); 113249666Strociny if (core == NULL) { 114249666Strociny warn("malloc(%zu)", sizeof(struct procstat_core)); 115249666Strociny goto fail; 116249666Strociny } 117249666Strociny core->pc_magic = PROCSTAT_CORE_MAGIC; 118249666Strociny core->pc_fd = fd; 119249666Strociny core->pc_elf = e; 120249666Strociny core->pc_ehdr = ehdr; 121249666Strociny core->pc_phdr = phdr; 122249666Strociny 123249666Strociny return (core); 124249666Strocinyfail: 125249666Strociny if (e != NULL) 126249666Strociny elf_end(e); 127249666Strociny close(fd); 128249666Strociny 129249666Strociny return (NULL); 130249666Strociny} 131249666Strociny 132249666Strocinyvoid 133249666Strocinyprocstat_core_close(struct procstat_core *core) 134249666Strociny{ 135249666Strociny 136249666Strociny assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 137249666Strociny 138249666Strociny elf_end(core->pc_elf); 139249666Strociny close(core->pc_fd); 140249666Strociny free(core); 141249666Strociny} 142249666Strociny 143249666Strocinyvoid * 144249666Strocinyprocstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, 145249666Strociny size_t *lenp) 146249666Strociny{ 147249666Strociny Elf_Note nhdr; 148249666Strociny off_t offset, eoffset; 149249666Strociny void *freebuf; 150249666Strociny size_t len; 151249666Strociny u_int32_t n_type; 152249666Strociny int cstructsize, structsize; 153249666Strociny char nbuf[8]; 154249666Strociny 155249666Strociny assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 156249666Strociny 157249666Strociny switch(type) { 158249666Strociny case PSC_TYPE_PROC: 159249666Strociny n_type = NT_PROCSTAT_PROC; 160249666Strociny structsize = sizeof(struct kinfo_proc); 161249666Strociny break; 162249666Strociny case PSC_TYPE_FILES: 163249666Strociny n_type = NT_PROCSTAT_FILES; 164249666Strociny structsize = sizeof(struct kinfo_file); 165249666Strociny break; 166249666Strociny case PSC_TYPE_VMMAP: 167249666Strociny n_type = NT_PROCSTAT_VMMAP; 168249666Strociny structsize = sizeof(struct kinfo_vmentry); 169249666Strociny break; 170249670Strociny case PSC_TYPE_GROUPS: 171249670Strociny n_type = NT_PROCSTAT_GROUPS; 172249670Strociny structsize = sizeof(gid_t); 173249670Strociny break; 174249672Strociny case PSC_TYPE_UMASK: 175249672Strociny n_type = NT_PROCSTAT_UMASK; 176249672Strociny structsize = sizeof(u_short); 177249672Strociny break; 178249666Strociny default: 179249666Strociny warnx("unknown core stat type: %d", type); 180249666Strociny return (NULL); 181249666Strociny } 182249666Strociny 183249666Strociny offset = core->pc_phdr.p_offset; 184249666Strociny eoffset = offset + core->pc_phdr.p_filesz; 185249666Strociny 186249666Strociny while (offset < eoffset) { 187249666Strociny if (!core_offset(core, offset)) 188249666Strociny return (NULL); 189249666Strociny if (!core_read(core, &nhdr, sizeof(nhdr))) 190249666Strociny return (NULL); 191249666Strociny 192249666Strociny offset += sizeof(nhdr) + 193249666Strociny roundup2(nhdr.n_namesz, sizeof(Elf32_Size)) + 194249666Strociny roundup2(nhdr.n_descsz, sizeof(Elf32_Size)); 195249666Strociny 196249666Strociny if (nhdr.n_namesz == 0 && nhdr.n_descsz == 0) 197249666Strociny break; 198249666Strociny if (nhdr.n_type != n_type) 199249666Strociny continue; 200249666Strociny if (nhdr.n_namesz != 8) 201249666Strociny continue; 202249666Strociny if (!core_read(core, nbuf, sizeof(nbuf))) 203249666Strociny return (NULL); 204249666Strociny if (strcmp(nbuf, "FreeBSD") != 0) 205249666Strociny continue; 206249666Strociny if (nhdr.n_descsz < sizeof(cstructsize)) { 207249666Strociny warnx("corrupted core file"); 208249666Strociny return (NULL); 209249666Strociny } 210249666Strociny if (!core_read(core, &cstructsize, sizeof(cstructsize))) 211249666Strociny return (NULL); 212249666Strociny if (cstructsize != structsize) { 213249666Strociny warnx("version mismatch"); 214249666Strociny return (NULL); 215249666Strociny } 216249666Strociny len = nhdr.n_descsz - sizeof(cstructsize); 217249666Strociny if (len == 0) 218249666Strociny return (NULL); 219249666Strociny if (buf != NULL) { 220249666Strociny len = MIN(len, *lenp); 221249666Strociny freebuf = NULL; 222249666Strociny } else { 223249666Strociny freebuf = buf = malloc(len); 224249666Strociny if (buf == NULL) { 225249666Strociny warn("malloc(%zu)", len); 226249666Strociny return (NULL); 227249666Strociny } 228249666Strociny } 229249666Strociny if (!core_read(core, buf, len)) { 230249666Strociny free(freebuf); 231249666Strociny return (NULL); 232249666Strociny } 233249666Strociny *lenp = len; 234249666Strociny return (buf); 235249666Strociny } 236249666Strociny 237249666Strociny return (NULL); 238249666Strociny} 239249666Strociny 240249666Strocinystatic bool 241249666Strocinycore_offset(struct procstat_core *core, off_t offset) 242249666Strociny{ 243249666Strociny 244249666Strociny assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 245249666Strociny 246249666Strociny if (lseek(core->pc_fd, offset, SEEK_SET) == -1) { 247249666Strociny warn("core: lseek(%jd)", (intmax_t)offset); 248249666Strociny return (false); 249249666Strociny } 250249666Strociny return (true); 251249666Strociny} 252249666Strociny 253249666Strocinystatic bool 254249666Strocinycore_read(struct procstat_core *core, void *buf, size_t len) 255249666Strociny{ 256249666Strociny ssize_t n; 257249666Strociny 258249666Strociny assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 259249666Strociny 260249666Strociny n = read(core->pc_fd, buf, len); 261249666Strociny if (n == -1) { 262249666Strociny warn("core: read"); 263249666Strociny return (false); 264249666Strociny } 265249666Strociny if (n < (ssize_t)len) { 266249666Strociny warnx("core: short read"); 267249666Strociny return (false); 268249666Strociny } 269249666Strociny return (true); 270249666Strociny} 271