1/*- 2 * Copyright (c) 2013 Mikolaj Golub <trociny@FreeBSD.org> 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 REGENTS 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 REGENTS 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 *
| 1/*- 2 * Copyright (c) 2013 Mikolaj Golub <trociny@FreeBSD.org> 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 REGENTS 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 REGENTS 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: head/lib/libprocstat/core.c 249677 2013-04-20 08:03:56Z trociny $
| 26 * $FreeBSD: head/lib/libprocstat/core.c 249679 2013-04-20 08:07:04Z trociny $
|
27 */ 28 29#include <sys/param.h> 30#include <sys/elf.h>
| 27 */ 28 29#include <sys/param.h> 30#include <sys/elf.h>
|
| 31#include <sys/exec.h>
|
31#include <sys/user.h> 32 33#include <assert.h> 34#include <err.h> 35#include <fcntl.h> 36#include <gelf.h> 37#include <libelf.h> 38#include <stdbool.h> 39#include <stdint.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <unistd.h> 44 45#include "core.h" 46 47#define PROCSTAT_CORE_MAGIC 0x012DADB8 48struct procstat_core 49{ 50 int pc_magic; 51 int pc_fd; 52 Elf *pc_elf; 53 GElf_Ehdr pc_ehdr; 54 GElf_Phdr pc_phdr; 55}; 56 57static bool core_offset(struct procstat_core *core, off_t offset); 58static bool core_read(struct procstat_core *core, void *buf, size_t len);
| 32#include <sys/user.h> 33 34#include <assert.h> 35#include <err.h> 36#include <fcntl.h> 37#include <gelf.h> 38#include <libelf.h> 39#include <stdbool.h> 40#include <stdint.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <unistd.h> 45 46#include "core.h" 47 48#define PROCSTAT_CORE_MAGIC 0x012DADB8 49struct procstat_core 50{ 51 int pc_magic; 52 int pc_fd; 53 Elf *pc_elf; 54 GElf_Ehdr pc_ehdr; 55 GElf_Phdr pc_phdr; 56}; 57 58static bool core_offset(struct procstat_core *core, off_t offset); 59static bool core_read(struct procstat_core *core, void *buf, size_t len);
|
| 60static ssize_t core_read_mem(struct procstat_core *core, void *buf, 61 size_t len, vm_offset_t addr, bool readall); 62static void *get_args(struct procstat_core *core, vm_offset_t psstrings, 63 enum psc_type type, void *buf, size_t *lenp);
|
59 60struct procstat_core * 61procstat_core_open(const char *filename) 62{ 63 struct procstat_core *core; 64 Elf *e; 65 GElf_Ehdr ehdr; 66 GElf_Phdr phdr; 67 size_t nph; 68 int fd, i; 69 70 if (elf_version(EV_CURRENT) == EV_NONE) { 71 warnx("ELF library too old"); 72 return (NULL); 73 } 74 fd = open(filename, O_RDONLY, 0); 75 if (fd == -1) { 76 warn("open(%s)", filename); 77 return (NULL); 78 } 79 e = elf_begin(fd, ELF_C_READ, NULL); 80 if (e == NULL) { 81 warnx("elf_begin: %s", elf_errmsg(-1)); 82 goto fail; 83 } 84 if (elf_kind(e) != ELF_K_ELF) { 85 warnx("%s is not an ELF object", filename); 86 goto fail; 87 } 88 if (gelf_getehdr(e, &ehdr) == NULL) { 89 warnx("gelf_getehdr: %s", elf_errmsg(-1)); 90 goto fail; 91 } 92 if (ehdr.e_type != ET_CORE) { 93 warnx("%s is not a CORE file", filename); 94 goto fail; 95 } 96 if (elf_getphnum(e, &nph) == 0) { 97 warnx("program headers not found"); 98 goto fail; 99 } 100 for (i = 0; i < ehdr.e_phnum; i++) { 101 if (gelf_getphdr(e, i, &phdr) != &phdr) { 102 warnx("gelf_getphdr: %s", elf_errmsg(-1)); 103 goto fail; 104 } 105 if (phdr.p_type == PT_NOTE) 106 break; 107 } 108 if (i == ehdr.e_phnum) { 109 warnx("NOTE program header not found"); 110 goto fail; 111 } 112 core = malloc(sizeof(struct procstat_core)); 113 if (core == NULL) { 114 warn("malloc(%zu)", sizeof(struct procstat_core)); 115 goto fail; 116 } 117 core->pc_magic = PROCSTAT_CORE_MAGIC; 118 core->pc_fd = fd; 119 core->pc_elf = e; 120 core->pc_ehdr = ehdr; 121 core->pc_phdr = phdr; 122 123 return (core); 124fail: 125 if (e != NULL) 126 elf_end(e); 127 close(fd); 128 129 return (NULL); 130} 131 132void 133procstat_core_close(struct procstat_core *core) 134{ 135 136 assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 137 138 elf_end(core->pc_elf); 139 close(core->pc_fd); 140 free(core); 141} 142 143void * 144procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, 145 size_t *lenp) 146{ 147 Elf_Note nhdr; 148 off_t offset, eoffset;
| 64 65struct procstat_core * 66procstat_core_open(const char *filename) 67{ 68 struct procstat_core *core; 69 Elf *e; 70 GElf_Ehdr ehdr; 71 GElf_Phdr phdr; 72 size_t nph; 73 int fd, i; 74 75 if (elf_version(EV_CURRENT) == EV_NONE) { 76 warnx("ELF library too old"); 77 return (NULL); 78 } 79 fd = open(filename, O_RDONLY, 0); 80 if (fd == -1) { 81 warn("open(%s)", filename); 82 return (NULL); 83 } 84 e = elf_begin(fd, ELF_C_READ, NULL); 85 if (e == NULL) { 86 warnx("elf_begin: %s", elf_errmsg(-1)); 87 goto fail; 88 } 89 if (elf_kind(e) != ELF_K_ELF) { 90 warnx("%s is not an ELF object", filename); 91 goto fail; 92 } 93 if (gelf_getehdr(e, &ehdr) == NULL) { 94 warnx("gelf_getehdr: %s", elf_errmsg(-1)); 95 goto fail; 96 } 97 if (ehdr.e_type != ET_CORE) { 98 warnx("%s is not a CORE file", filename); 99 goto fail; 100 } 101 if (elf_getphnum(e, &nph) == 0) { 102 warnx("program headers not found"); 103 goto fail; 104 } 105 for (i = 0; i < ehdr.e_phnum; i++) { 106 if (gelf_getphdr(e, i, &phdr) != &phdr) { 107 warnx("gelf_getphdr: %s", elf_errmsg(-1)); 108 goto fail; 109 } 110 if (phdr.p_type == PT_NOTE) 111 break; 112 } 113 if (i == ehdr.e_phnum) { 114 warnx("NOTE program header not found"); 115 goto fail; 116 } 117 core = malloc(sizeof(struct procstat_core)); 118 if (core == NULL) { 119 warn("malloc(%zu)", sizeof(struct procstat_core)); 120 goto fail; 121 } 122 core->pc_magic = PROCSTAT_CORE_MAGIC; 123 core->pc_fd = fd; 124 core->pc_elf = e; 125 core->pc_ehdr = ehdr; 126 core->pc_phdr = phdr; 127 128 return (core); 129fail: 130 if (e != NULL) 131 elf_end(e); 132 close(fd); 133 134 return (NULL); 135} 136 137void 138procstat_core_close(struct procstat_core *core) 139{ 140 141 assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 142 143 elf_end(core->pc_elf); 144 close(core->pc_fd); 145 free(core); 146} 147 148void * 149procstat_core_get(struct procstat_core *core, enum psc_type type, void *buf, 150 size_t *lenp) 151{ 152 Elf_Note nhdr; 153 off_t offset, eoffset;
|
| 154 vm_offset_t psstrings;
|
149 void *freebuf; 150 size_t len; 151 u_int32_t n_type; 152 int cstructsize, structsize; 153 char nbuf[8]; 154 155 assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 156 157 switch(type) { 158 case PSC_TYPE_PROC: 159 n_type = NT_PROCSTAT_PROC; 160 structsize = sizeof(struct kinfo_proc); 161 break; 162 case PSC_TYPE_FILES: 163 n_type = NT_PROCSTAT_FILES; 164 structsize = sizeof(struct kinfo_file); 165 break; 166 case PSC_TYPE_VMMAP: 167 n_type = NT_PROCSTAT_VMMAP; 168 structsize = sizeof(struct kinfo_vmentry); 169 break; 170 case PSC_TYPE_GROUPS: 171 n_type = NT_PROCSTAT_GROUPS; 172 structsize = sizeof(gid_t); 173 break; 174 case PSC_TYPE_UMASK: 175 n_type = NT_PROCSTAT_UMASK; 176 structsize = sizeof(u_short); 177 break; 178 case PSC_TYPE_RLIMIT: 179 n_type = NT_PROCSTAT_RLIMIT; 180 structsize = sizeof(struct rlimit) * RLIM_NLIMITS; 181 break; 182 case PSC_TYPE_OSREL: 183 n_type = NT_PROCSTAT_OSREL; 184 structsize = sizeof(int); 185 break;
| 155 void *freebuf; 156 size_t len; 157 u_int32_t n_type; 158 int cstructsize, structsize; 159 char nbuf[8]; 160 161 assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 162 163 switch(type) { 164 case PSC_TYPE_PROC: 165 n_type = NT_PROCSTAT_PROC; 166 structsize = sizeof(struct kinfo_proc); 167 break; 168 case PSC_TYPE_FILES: 169 n_type = NT_PROCSTAT_FILES; 170 structsize = sizeof(struct kinfo_file); 171 break; 172 case PSC_TYPE_VMMAP: 173 n_type = NT_PROCSTAT_VMMAP; 174 structsize = sizeof(struct kinfo_vmentry); 175 break; 176 case PSC_TYPE_GROUPS: 177 n_type = NT_PROCSTAT_GROUPS; 178 structsize = sizeof(gid_t); 179 break; 180 case PSC_TYPE_UMASK: 181 n_type = NT_PROCSTAT_UMASK; 182 structsize = sizeof(u_short); 183 break; 184 case PSC_TYPE_RLIMIT: 185 n_type = NT_PROCSTAT_RLIMIT; 186 structsize = sizeof(struct rlimit) * RLIM_NLIMITS; 187 break; 188 case PSC_TYPE_OSREL: 189 n_type = NT_PROCSTAT_OSREL; 190 structsize = sizeof(int); 191 break;
|
| 192 case PSC_TYPE_PSSTRINGS: 193 case PSC_TYPE_ARGV: 194 case PSC_TYPE_ENVV: 195 n_type = NT_PROCSTAT_PSSTRINGS; 196 structsize = sizeof(vm_offset_t); 197 break;
|
186 default: 187 warnx("unknown core stat type: %d", type); 188 return (NULL); 189 } 190 191 offset = core->pc_phdr.p_offset; 192 eoffset = offset + core->pc_phdr.p_filesz; 193 194 while (offset < eoffset) { 195 if (!core_offset(core, offset)) 196 return (NULL); 197 if (!core_read(core, &nhdr, sizeof(nhdr))) 198 return (NULL); 199 200 offset += sizeof(nhdr) + 201 roundup2(nhdr.n_namesz, sizeof(Elf32_Size)) + 202 roundup2(nhdr.n_descsz, sizeof(Elf32_Size)); 203 204 if (nhdr.n_namesz == 0 && nhdr.n_descsz == 0) 205 break; 206 if (nhdr.n_type != n_type) 207 continue; 208 if (nhdr.n_namesz != 8) 209 continue; 210 if (!core_read(core, nbuf, sizeof(nbuf))) 211 return (NULL); 212 if (strcmp(nbuf, "FreeBSD") != 0) 213 continue; 214 if (nhdr.n_descsz < sizeof(cstructsize)) { 215 warnx("corrupted core file"); 216 return (NULL); 217 } 218 if (!core_read(core, &cstructsize, sizeof(cstructsize))) 219 return (NULL); 220 if (cstructsize != structsize) { 221 warnx("version mismatch"); 222 return (NULL); 223 } 224 len = nhdr.n_descsz - sizeof(cstructsize); 225 if (len == 0) 226 return (NULL); 227 if (buf != NULL) { 228 len = MIN(len, *lenp); 229 freebuf = NULL; 230 } else { 231 freebuf = buf = malloc(len); 232 if (buf == NULL) { 233 warn("malloc(%zu)", len); 234 return (NULL); 235 } 236 } 237 if (!core_read(core, buf, len)) { 238 free(freebuf); 239 return (NULL); 240 }
| 198 default: 199 warnx("unknown core stat type: %d", type); 200 return (NULL); 201 } 202 203 offset = core->pc_phdr.p_offset; 204 eoffset = offset + core->pc_phdr.p_filesz; 205 206 while (offset < eoffset) { 207 if (!core_offset(core, offset)) 208 return (NULL); 209 if (!core_read(core, &nhdr, sizeof(nhdr))) 210 return (NULL); 211 212 offset += sizeof(nhdr) + 213 roundup2(nhdr.n_namesz, sizeof(Elf32_Size)) + 214 roundup2(nhdr.n_descsz, sizeof(Elf32_Size)); 215 216 if (nhdr.n_namesz == 0 && nhdr.n_descsz == 0) 217 break; 218 if (nhdr.n_type != n_type) 219 continue; 220 if (nhdr.n_namesz != 8) 221 continue; 222 if (!core_read(core, nbuf, sizeof(nbuf))) 223 return (NULL); 224 if (strcmp(nbuf, "FreeBSD") != 0) 225 continue; 226 if (nhdr.n_descsz < sizeof(cstructsize)) { 227 warnx("corrupted core file"); 228 return (NULL); 229 } 230 if (!core_read(core, &cstructsize, sizeof(cstructsize))) 231 return (NULL); 232 if (cstructsize != structsize) { 233 warnx("version mismatch"); 234 return (NULL); 235 } 236 len = nhdr.n_descsz - sizeof(cstructsize); 237 if (len == 0) 238 return (NULL); 239 if (buf != NULL) { 240 len = MIN(len, *lenp); 241 freebuf = NULL; 242 } else { 243 freebuf = buf = malloc(len); 244 if (buf == NULL) { 245 warn("malloc(%zu)", len); 246 return (NULL); 247 } 248 } 249 if (!core_read(core, buf, len)) { 250 free(freebuf); 251 return (NULL); 252 }
|
| 253 if (type == PSC_TYPE_ARGV || type == PSC_TYPE_ENVV) { 254 if (len < sizeof(psstrings)) { 255 free(freebuf); 256 return (NULL); 257 } 258 psstrings = *(vm_offset_t *)buf; 259 if (freebuf == NULL) 260 len = *lenp; 261 else 262 buf = NULL; 263 free(freebuf); 264 buf = get_args(core, psstrings, type, buf, &len); 265 }
|
241 *lenp = len; 242 return (buf); 243 } 244 245 return (NULL); 246} 247 248static bool 249core_offset(struct procstat_core *core, off_t offset) 250{ 251 252 assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 253 254 if (lseek(core->pc_fd, offset, SEEK_SET) == -1) { 255 warn("core: lseek(%jd)", (intmax_t)offset); 256 return (false); 257 } 258 return (true); 259} 260 261static bool 262core_read(struct procstat_core *core, void *buf, size_t len) 263{ 264 ssize_t n; 265 266 assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 267 268 n = read(core->pc_fd, buf, len); 269 if (n == -1) { 270 warn("core: read"); 271 return (false); 272 } 273 if (n < (ssize_t)len) { 274 warnx("core: short read"); 275 return (false); 276 } 277 return (true); 278}
| 266 *lenp = len; 267 return (buf); 268 } 269 270 return (NULL); 271} 272 273static bool 274core_offset(struct procstat_core *core, off_t offset) 275{ 276 277 assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 278 279 if (lseek(core->pc_fd, offset, SEEK_SET) == -1) { 280 warn("core: lseek(%jd)", (intmax_t)offset); 281 return (false); 282 } 283 return (true); 284} 285 286static bool 287core_read(struct procstat_core *core, void *buf, size_t len) 288{ 289 ssize_t n; 290 291 assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 292 293 n = read(core->pc_fd, buf, len); 294 if (n == -1) { 295 warn("core: read"); 296 return (false); 297 } 298 if (n < (ssize_t)len) { 299 warnx("core: short read"); 300 return (false); 301 } 302 return (true); 303}
|
| 304 305static ssize_t 306core_read_mem(struct procstat_core *core, void *buf, size_t len, 307 vm_offset_t addr, bool readall) 308{ 309 GElf_Phdr phdr; 310 off_t offset; 311 int i; 312 313 assert(core->pc_magic == PROCSTAT_CORE_MAGIC); 314 315 for (i = 0; i < core->pc_ehdr.e_phnum; i++) { 316 if (gelf_getphdr(core->pc_elf, i, &phdr) != &phdr) { 317 warnx("gelf_getphdr: %s", elf_errmsg(-1)); 318 return (-1); 319 } 320 if (phdr.p_type != PT_LOAD) 321 continue; 322 if (addr < phdr.p_vaddr || addr > phdr.p_vaddr + phdr.p_memsz) 323 continue; 324 offset = phdr.p_offset + (addr - phdr.p_vaddr); 325 if ((phdr.p_vaddr + phdr.p_memsz) - addr < len) { 326 if (readall) { 327 warnx("format error: " 328 "attempt to read out of segment"); 329 return (-1); 330 } 331 len = (phdr.p_vaddr + phdr.p_memsz) - addr; 332 } 333 if (!core_offset(core, offset)) 334 return (-1); 335 if (!core_read(core, buf, len)) 336 return (-1); 337 return (len); 338 } 339 warnx("format error: address %ju not found", (uintmax_t)addr); 340 return (-1); 341} 342 343#define ARGS_CHUNK_SZ 256 /* Chunk size (bytes) for get_args operations. */ 344 345static void * 346get_args(struct procstat_core *core, vm_offset_t psstrings, enum psc_type type, 347 void *args, size_t *lenp) 348{ 349 struct ps_strings pss; 350 void *freeargs; 351 vm_offset_t addr; 352 char **argv, *p; 353 size_t chunksz, done, len, nchr, size; 354 ssize_t n; 355 u_int i, nstr; 356 357 assert(type == PSC_TYPE_ARGV || type == PSC_TYPE_ENVV); 358 359 if (core_read_mem(core, &pss, sizeof(pss), psstrings, true) == -1) 360 return (NULL); 361 if (type == PSC_TYPE_ARGV) { 362 addr = (vm_offset_t)pss.ps_argvstr; 363 nstr = pss.ps_nargvstr; 364 } else /* type == PSC_TYPE_ENVV */ { 365 addr = (vm_offset_t)pss.ps_envstr; 366 nstr = pss.ps_nenvstr; 367 } 368 if (addr == 0 || nstr == 0) 369 return (NULL); 370 if (nstr > ARG_MAX) { 371 warnx("format error"); 372 return (NULL); 373 } 374 size = nstr * sizeof(char *); 375 argv = malloc(size); 376 if (argv == NULL) { 377 warn("malloc(%zu)", size); 378 return (NULL); 379 } 380 done = 0; 381 freeargs = NULL; 382 if (core_read_mem(core, argv, size, addr, true) == -1) 383 goto fail; 384 if (args != NULL) { 385 nchr = MIN(ARG_MAX, *lenp); 386 } else { 387 nchr = ARG_MAX; 388 freeargs = args = malloc(nchr); 389 if (args == NULL) { 390 warn("malloc(%zu)", nchr); 391 goto fail; 392 } 393 } 394 p = args; 395 for (i = 0; ; i++) { 396 if (i == nstr) 397 goto done; 398 /* 399 * The program may have scribbled into its argv array, e.g. to 400 * remove some arguments. If that has happened, break out 401 * before trying to read from NULL. 402 */ 403 if (argv[i] == NULL) 404 goto done; 405 for (addr = (vm_offset_t)argv[i]; ; addr += chunksz) { 406 chunksz = MIN(ARGS_CHUNK_SZ, nchr - 1 - done); 407 if (chunksz <= 0) 408 goto done; 409 n = core_read_mem(core, p, chunksz, addr, false); 410 if (n == -1) 411 goto fail; 412 len = strnlen(p, chunksz); 413 p += len; 414 done += len; 415 if (len != chunksz) 416 break; 417 } 418 *p++ = '\0'; 419 done++; 420 } 421fail: 422 free(freeargs); 423 args = NULL; 424done: 425 *lenp = done; 426 free(argv); 427 return (args); 428}
|
| |