Deleted Added
sdiff udiff text old ( 249677 ) new ( 249679 )
full compact
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 $
27 */
28
29#include <sys/param.h>
30#include <sys/elf.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);
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;
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;
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 }
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}