GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: dw.c,v 1.4 2017/09/27 08:59:38 mpi Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* Copyright (c) 2016 Martin Pieuchot |
||
5 |
* Copyright (c) 2014 Matthew Dempsky <matthew@dempsky.org> |
||
6 |
* |
||
7 |
* Permission to use, copy, modify, and distribute this software for any |
||
8 |
* purpose with or without fee is hereby granted, provided that the above |
||
9 |
* copyright notice and this permission notice appear in all copies. |
||
10 |
* |
||
11 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||
12 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||
13 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||
14 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||
15 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||
16 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||
17 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||
18 |
*/ |
||
19 |
|||
20 |
#include <sys/queue.h> |
||
21 |
|||
22 |
#include <errno.h> |
||
23 |
#include <stdint.h> |
||
24 |
#include <stdlib.h> |
||
25 |
#include <string.h> |
||
26 |
|||
27 |
#include "dw.h" |
||
28 |
#include "dwarf.h" |
||
29 |
#include "pool.h" |
||
30 |
|||
31 |
#ifndef NOPOOL |
||
32 |
struct pool dcu_pool, die_pool, dav_pool, dab_pool, dat_pool; |
||
33 |
#endif /* NOPOOL */ |
||
34 |
|||
35 |
#ifndef nitems |
||
36 |
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) |
||
37 |
#endif |
||
38 |
|||
39 |
static int dw_read_u8(struct dwbuf *, uint8_t *); |
||
40 |
static int dw_read_u16(struct dwbuf *, uint16_t *); |
||
41 |
static int dw_read_u32(struct dwbuf *, uint32_t *); |
||
42 |
static int dw_read_u64(struct dwbuf *, uint64_t *); |
||
43 |
|||
44 |
static int dw_read_sleb128(struct dwbuf *, int64_t *); |
||
45 |
static int dw_read_uleb128(struct dwbuf *, uint64_t *); |
||
46 |
|||
47 |
static int dw_read_bytes(struct dwbuf *, void *, size_t); |
||
48 |
static int dw_read_string(struct dwbuf *, const char **); |
||
49 |
static int dw_read_buf(struct dwbuf *, struct dwbuf *, size_t); |
||
50 |
|||
51 |
static int dw_skip_bytes(struct dwbuf *, size_t); |
||
52 |
|||
53 |
static int dw_read_filename(struct dwbuf *, const char **, const char **, |
||
54 |
uint8_t, uint64_t); |
||
55 |
|||
56 |
|||
57 |
static int dw_attr_parse(struct dwbuf *, struct dwattr *, uint8_t, |
||
58 |
struct dwaval_queue *); |
||
59 |
static void dw_attr_purge(struct dwaval_queue *); |
||
60 |
static int dw_die_parse(struct dwbuf *, size_t, uint8_t, |
||
61 |
struct dwabbrev_queue *, struct dwdie_queue *); |
||
62 |
static void dw_die_purge(struct dwdie_queue *); |
||
63 |
|||
64 |
static int |
||
65 |
dw_read_bytes(struct dwbuf *d, void *v, size_t n) |
||
66 |
{ |
||
67 |
✗✓ | 812 |
if (d->len < n) |
68 |
return -1; |
||
69 |
406 |
memcpy(v, d->buf, n); |
|
70 |
406 |
d->buf += n; |
|
71 |
406 |
d->len -= n; |
|
72 |
406 |
return 0; |
|
73 |
406 |
} |
|
74 |
|||
75 |
static int |
||
76 |
dw_read_u8(struct dwbuf *d, uint8_t *v) |
||
77 |
{ |
||
78 |
648 |
return dw_read_bytes(d, v, sizeof(*v)); |
|
79 |
} |
||
80 |
|||
81 |
static int |
||
82 |
dw_read_u16(struct dwbuf *d, uint16_t *v) |
||
83 |
{ |
||
84 |
8 |
return dw_read_bytes(d, v, sizeof(*v)); |
|
85 |
} |
||
86 |
|||
87 |
static int |
||
88 |
dw_read_u32(struct dwbuf *d, uint32_t *v) |
||
89 |
{ |
||
90 |
136 |
return dw_read_bytes(d, v, sizeof(*v)); |
|
91 |
} |
||
92 |
|||
93 |
static int |
||
94 |
dw_read_u64(struct dwbuf *d, uint64_t *v) |
||
95 |
{ |
||
96 |
16 |
return dw_read_bytes(d, v, sizeof(*v)); |
|
97 |
} |
||
98 |
|||
99 |
/* Read a DWARF LEB128 (little-endian base-128) value. */ |
||
100 |
static inline int |
||
101 |
dw_read_leb128(struct dwbuf *d, uint64_t *v, int signextend) |
||
102 |
{ |
||
103 |
unsigned int shift = 0; |
||
104 |
uint64_t res = 0; |
||
105 |
432 |
uint8_t x; |
|
106 |
|||
107 |
✓✗✓✗ |
648 |
while (shift < 64 && !dw_read_u8(d, &x)) { |
108 |
216 |
res |= (uint64_t)(x & 0x7f) << shift; |
|
109 |
216 |
shift += 7; |
|
110 |
✗✓ | 216 |
if ((x & 0x80) == 0) { |
111 |
✗✓✗✗ |
216 |
if (signextend && shift < 64 && (x & 0x40) != 0) |
112 |
res |= ~(uint64_t)0 << shift; |
||
113 |
216 |
*v = res; |
|
114 |
216 |
return 0; |
|
115 |
} |
||
116 |
} |
||
117 |
return -1; |
||
118 |
216 |
} |
|
119 |
|||
120 |
static int |
||
121 |
dw_read_sleb128(struct dwbuf *d, int64_t *v) |
||
122 |
{ |
||
123 |
return dw_read_leb128(d, (uint64_t *)v, 1); |
||
124 |
} |
||
125 |
|||
126 |
static int |
||
127 |
dw_read_uleb128(struct dwbuf *d, uint64_t *v) |
||
128 |
{ |
||
129 |
432 |
return dw_read_leb128(d, v, 0); |
|
130 |
} |
||
131 |
|||
132 |
/* Read a NUL terminated string. */ |
||
133 |
static int |
||
134 |
dw_read_string(struct dwbuf *d, const char **s) |
||
135 |
{ |
||
136 |
const char *end = memchr(d->buf, '\0', d->len); |
||
137 |
size_t n; |
||
138 |
|||
139 |
if (end == NULL) |
||
140 |
return -1; |
||
141 |
|||
142 |
n = end - d->buf + 1; |
||
143 |
*s = d->buf; |
||
144 |
d->buf += n; |
||
145 |
d->len -= n; |
||
146 |
return 0; |
||
147 |
} |
||
148 |
|||
149 |
static int |
||
150 |
dw_read_buf(struct dwbuf *d, struct dwbuf *v, size_t n) |
||
151 |
{ |
||
152 |
✗✓ | 32 |
if (d->len < n) |
153 |
return -1; |
||
154 |
16 |
v->buf = d->buf; |
|
155 |
16 |
v->len = n; |
|
156 |
16 |
d->buf += n; |
|
157 |
16 |
d->len -= n; |
|
158 |
16 |
return 0; |
|
159 |
16 |
} |
|
160 |
|||
161 |
static int |
||
162 |
dw_skip_bytes(struct dwbuf *d, size_t n) |
||
163 |
{ |
||
164 |
✗✓ | 4 |
if (d->len < n) |
165 |
return -1; |
||
166 |
2 |
d->buf += n; |
|
167 |
2 |
d->len -= n; |
|
168 |
2 |
return 0; |
|
169 |
2 |
} |
|
170 |
|||
171 |
static int |
||
172 |
dw_read_filename(struct dwbuf *names, const char **outdirname, |
||
173 |
const char **outbasename, uint8_t opcode_base, uint64_t file) |
||
174 |
{ |
||
175 |
struct dwbuf dirnames; |
||
176 |
const char *basename = NULL, *dirname = NULL; |
||
177 |
uint64_t mtime, size, dummy, dir = 0; |
||
178 |
const char *name; |
||
179 |
size_t i; |
||
180 |
|||
181 |
if (file == 0) |
||
182 |
return -1; |
||
183 |
|||
184 |
/* Skip over opcode table. */ |
||
185 |
for (i = 1; i < opcode_base; i++) { |
||
186 |
if (dw_read_uleb128(names, &dummy)) |
||
187 |
return -1; |
||
188 |
} |
||
189 |
|||
190 |
/* Skip over directory name table for now. */ |
||
191 |
dirnames = *names; |
||
192 |
for (;;) { |
||
193 |
if (dw_read_string(names, &name)) |
||
194 |
return -1; |
||
195 |
if (*name == '\0') |
||
196 |
break; |
||
197 |
} |
||
198 |
|||
199 |
/* Locate file entry. */ |
||
200 |
for (i = 0; i < file; i++) { |
||
201 |
if (dw_read_string(names, &basename) || *basename == '\0' || |
||
202 |
dw_read_uleb128(names, &dir) || |
||
203 |
dw_read_uleb128(names, &mtime) || |
||
204 |
dw_read_uleb128(names, &size)) |
||
205 |
return -1; |
||
206 |
} |
||
207 |
|||
208 |
for (i = 0; i < dir; i++) { |
||
209 |
if (!dw_read_string(&dirnames, &dirname) || *dirname == '\0') |
||
210 |
return -1; |
||
211 |
} |
||
212 |
|||
213 |
*outdirname = dirname; |
||
214 |
*outbasename = basename; |
||
215 |
|||
216 |
return 0; |
||
217 |
} |
||
218 |
|||
219 |
|||
220 |
const char * |
||
221 |
dw_tag2name(uint64_t tag) |
||
222 |
{ |
||
223 |
static const char *dw_tags[] = { DW_TAG_NAMES }; |
||
224 |
|||
225 |
if (tag <= nitems(dw_tags)) |
||
226 |
return dw_tags[tag - 1]; |
||
227 |
|||
228 |
if (tag == DW_TAG_lo_user) |
||
229 |
return "DW_TAG_lo_user"; |
||
230 |
if (tag == DW_TAG_hi_user) |
||
231 |
return "DW_TAG_hi_user"; |
||
232 |
|||
233 |
return NULL; |
||
234 |
} |
||
235 |
|||
236 |
const char * |
||
237 |
dw_at2name(uint64_t at) |
||
238 |
{ |
||
239 |
static const char *dw_attrs[] = { DW_AT_NAMES }; |
||
240 |
|||
241 |
if (at <= nitems(dw_attrs)) |
||
242 |
return dw_attrs[at - 1]; |
||
243 |
|||
244 |
if (at == DW_AT_lo_user) |
||
245 |
return "DW_AT_lo_user"; |
||
246 |
if (at == DW_AT_hi_user) |
||
247 |
return "DW_AT_hi_user"; |
||
248 |
|||
249 |
return NULL; |
||
250 |
} |
||
251 |
|||
252 |
const char * |
||
253 |
dw_form2name(uint64_t form) |
||
254 |
{ |
||
255 |
static const char *dw_forms[] = { DW_FORM_NAMES }; |
||
256 |
|||
257 |
if (form <= nitems(dw_forms)) |
||
258 |
return dw_forms[form - 1]; |
||
259 |
|||
260 |
if (form == DW_FORM_GNU_ref_alt) |
||
261 |
return "DW_FORM_GNU_ref_alt"; |
||
262 |
if (form == DW_FORM_GNU_strp_alt) |
||
263 |
return "DW_FORM_GNU_strp_alt"; |
||
264 |
|||
265 |
return NULL; |
||
266 |
} |
||
267 |
|||
268 |
const char * |
||
269 |
dw_op2name(uint8_t op) |
||
270 |
{ |
||
271 |
static const char *dw_ops[] = { DW_OP_NAMES }; |
||
272 |
|||
273 |
if (op <= nitems(dw_ops)) |
||
274 |
return dw_ops[op - 1]; |
||
275 |
|||
276 |
if (op == DW_OP_lo_user) |
||
277 |
return "DW_OP_lo_user"; |
||
278 |
if (op == DW_OP_hi_user) |
||
279 |
return "DW_OP_hi_user"; |
||
280 |
|||
281 |
return NULL; |
||
282 |
} |
||
283 |
|||
284 |
static int |
||
285 |
dw_attr_parse(struct dwbuf *dwbuf, struct dwattr *dat, uint8_t psz, |
||
286 |
struct dwaval_queue *davq) |
||
287 |
{ |
||
288 |
struct dwaval *dav; |
||
289 |
340 |
uint64_t form = dat->dat_form; |
|
290 |
int error = 0, i = 0; |
||
291 |
|||
292 |
✗✓ | 340 |
while (form == DW_FORM_indirect) { |
293 |
/* XXX loop prevention not strict enough? */ |
||
294 |
if (dw_read_uleb128(dwbuf, &form) || (++i > 3)) |
||
295 |
return ELOOP; |
||
296 |
} |
||
297 |
|||
298 |
170 |
dav = pzalloc(&dav_pool, sizeof(*dav)); |
|
299 |
✗✓ | 170 |
if (dav == NULL) |
300 |
return ENOMEM; |
||
301 |
|||
302 |
170 |
dav->dav_dat = dat; |
|
303 |
|||
304 |
✗✓✓✗ ✗✗✗✗ ✓✗✓✗ ✓✗✗✗ ✗✗✗✓ ✗✗ |
170 |
switch (form) { |
305 |
case DW_FORM_addr: |
||
306 |
case DW_FORM_ref_addr: |
||
307 |
✗✓ | 8 |
if (psz == sizeof(uint32_t)) |
308 |
error = dw_read_u32(dwbuf, &dav->dav_u32); |
||
309 |
else |
||
310 |
8 |
error = dw_read_u64(dwbuf, &dav->dav_u64); |
|
311 |
break; |
||
312 |
case DW_FORM_block1: |
||
313 |
14 |
error = dw_read_u8(dwbuf, &dav->dav_u8); |
|
314 |
✓✗ | 14 |
if (error == 0) |
315 |
14 |
error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u8); |
|
316 |
break; |
||
317 |
case DW_FORM_block2: |
||
318 |
error = dw_read_u16(dwbuf, &dav->dav_u16); |
||
319 |
if (error == 0) |
||
320 |
error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u16); |
||
321 |
break; |
||
322 |
case DW_FORM_block4: |
||
323 |
error = dw_read_u32(dwbuf, &dav->dav_u32); |
||
324 |
if (error == 0) |
||
325 |
error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u32); |
||
326 |
break; |
||
327 |
case DW_FORM_block: |
||
328 |
error = dw_read_uleb128(dwbuf, &dav->dav_u64); |
||
329 |
if (error == 0) |
||
330 |
error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u64); |
||
331 |
break; |
||
332 |
case DW_FORM_data1: |
||
333 |
case DW_FORM_flag: |
||
334 |
case DW_FORM_ref1: |
||
335 |
80 |
error = dw_read_u8(dwbuf, &dav->dav_u8); |
|
336 |
80 |
break; |
|
337 |
case DW_FORM_data2: |
||
338 |
case DW_FORM_ref2: |
||
339 |
2 |
error = dw_read_u16(dwbuf, &dav->dav_u16); |
|
340 |
2 |
break; |
|
341 |
case DW_FORM_data4: |
||
342 |
case DW_FORM_ref4: |
||
343 |
28 |
error = dw_read_u32(dwbuf, &dav->dav_u32); |
|
344 |
28 |
break; |
|
345 |
case DW_FORM_data8: |
||
346 |
case DW_FORM_ref8: |
||
347 |
error = dw_read_u64(dwbuf, &dav->dav_u64); |
||
348 |
break; |
||
349 |
case DW_FORM_ref_udata: |
||
350 |
case DW_FORM_udata: |
||
351 |
error = dw_read_uleb128(dwbuf, &dav->dav_u64); |
||
352 |
break; |
||
353 |
case DW_FORM_sdata: |
||
354 |
error = dw_read_sleb128(dwbuf, &dav->dav_s64); |
||
355 |
break; |
||
356 |
case DW_FORM_string: |
||
357 |
error = dw_read_string(dwbuf, &dav->dav_str); |
||
358 |
break; |
||
359 |
case DW_FORM_strp: |
||
360 |
38 |
error = dw_read_u32(dwbuf, &dav->dav_u32); |
|
361 |
38 |
break; |
|
362 |
case DW_FORM_flag_present: |
||
363 |
dav->dav_u8 = 1; |
||
364 |
break; |
||
365 |
default: |
||
366 |
error = ENOENT; |
||
367 |
break; |
||
368 |
} |
||
369 |
|||
370 |
✗✓ | 170 |
if (error) { |
371 |
pfree(&dav_pool, dav); |
||
372 |
return error; |
||
373 |
} |
||
374 |
|||
375 |
170 |
SIMPLEQ_INSERT_TAIL(davq, dav, dav_next); |
|
376 |
170 |
return 0; |
|
377 |
170 |
} |
|
378 |
|||
379 |
static void |
||
380 |
dw_attr_purge(struct dwaval_queue *davq) |
||
381 |
{ |
||
382 |
struct dwaval *dav; |
||
383 |
|||
384 |
✓✓ | 454 |
while ((dav = SIMPLEQ_FIRST(davq)) != NULL) { |
385 |
✓✓ | 208 |
SIMPLEQ_REMOVE_HEAD(davq, dav_next); |
386 |
170 |
pfree(&dav_pool, dav); |
|
387 |
} |
||
388 |
|||
389 |
38 |
SIMPLEQ_INIT(davq); |
|
390 |
38 |
} |
|
391 |
|||
392 |
static int |
||
393 |
dw_die_parse(struct dwbuf *dwbuf, size_t nextoff, uint8_t psz, |
||
394 |
struct dwabbrev_queue *dabq, struct dwdie_queue *dieq) |
||
395 |
{ |
||
396 |
struct dwdie *die; |
||
397 |
struct dwabbrev *dab; |
||
398 |
struct dwattr *dat; |
||
399 |
4 |
uint64_t code; |
|
400 |
size_t doff; |
||
401 |
uint8_t lvl = 0; |
||
402 |
int error; |
||
403 |
|||
404 |
|||
405 |
✓✓ | 84 |
while (dwbuf->len > 0) { |
406 |
42 |
doff = nextoff - dwbuf->len; |
|
407 |
✗✓ | 42 |
if (dw_read_uleb128(dwbuf, &code)) |
408 |
return -1; |
||
409 |
|||
410 |
✓✓ | 42 |
if (code == 0) { |
411 |
4 |
lvl--; |
|
412 |
4 |
continue; |
|
413 |
} |
||
414 |
|||
415 |
✓✗ | 240 |
SIMPLEQ_FOREACH(dab, dabq, dab_next) { |
416 |
✓✓ | 120 |
if (dab->dab_code == code) |
417 |
break; |
||
418 |
} |
||
419 |
✗✓ | 38 |
if (dab == NULL) |
420 |
return ESRCH; |
||
421 |
|||
422 |
38 |
die = pmalloc(&die_pool, sizeof(*die)); |
|
423 |
✗✓ | 38 |
if (die == NULL) |
424 |
return ENOMEM; |
||
425 |
|||
426 |
38 |
die->die_lvl = lvl; |
|
427 |
38 |
die->die_dab = dab; |
|
428 |
38 |
die->die_offset = doff; |
|
429 |
38 |
SIMPLEQ_INIT(&die->die_avals); |
|
430 |
|||
431 |
✓✓ | 416 |
SIMPLEQ_FOREACH(dat, &dab->dab_attrs, dat_next) { |
432 |
170 |
error = dw_attr_parse(dwbuf, dat, psz, &die->die_avals); |
|
433 |
✗✓ | 170 |
if (error != 0) { |
434 |
dw_attr_purge(&die->die_avals); |
||
435 |
return error; |
||
436 |
} |
||
437 |
} |
||
438 |
|||
439 |
✓✓ | 38 |
if (dab->dab_children == DW_CHILDREN_yes) |
440 |
4 |
lvl++; |
|
441 |
|||
442 |
38 |
SIMPLEQ_INSERT_TAIL(dieq, die, die_next); |
|
443 |
} |
||
444 |
|||
445 |
2 |
return 0; |
|
446 |
2 |
} |
|
447 |
|||
448 |
static void |
||
449 |
dw_die_purge(struct dwdie_queue *dieq) |
||
450 |
{ |
||
451 |
struct dwdie *die; |
||
452 |
|||
453 |
✓✓ | 82 |
while ((die = SIMPLEQ_FIRST(dieq)) != NULL) { |
454 |
✓✓ | 40 |
SIMPLEQ_REMOVE_HEAD(dieq, die_next); |
455 |
38 |
dw_attr_purge(&die->die_avals); |
|
456 |
38 |
pfree(&die_pool, die); |
|
457 |
} |
||
458 |
|||
459 |
2 |
SIMPLEQ_INIT(dieq); |
|
460 |
2 |
} |
|
461 |
|||
462 |
int |
||
463 |
dw_ab_parse(struct dwbuf *abseg, struct dwabbrev_queue *dabq) |
||
464 |
{ |
||
465 |
struct dwabbrev *dab; |
||
466 |
4 |
uint64_t code, tag; |
|
467 |
2 |
uint8_t children; |
|
468 |
|||
469 |
✗✓ | 2 |
if (abseg->len == 0) |
470 |
return EINVAL; |
||
471 |
|||
472 |
for (;;) { |
||
473 |
✓✓ | 14 |
if (dw_read_uleb128(abseg, &code) || (code == 0)) |
474 |
break; |
||
475 |
|||
476 |
✓✗✗✓ |
24 |
if (dw_read_uleb128(abseg, &tag) || |
477 |
12 |
dw_read_u8(abseg, &children)) |
|
478 |
return -1; |
||
479 |
|||
480 |
12 |
dab = pmalloc(&dab_pool, sizeof(*dab)); |
|
481 |
✗✓ | 12 |
if (dab == NULL) |
482 |
return ENOMEM; |
||
483 |
|||
484 |
12 |
dab->dab_code = code; |
|
485 |
12 |
dab->dab_tag = tag; |
|
486 |
12 |
dab->dab_children = children; |
|
487 |
12 |
SIMPLEQ_INIT(&dab->dab_attrs); |
|
488 |
|||
489 |
12 |
SIMPLEQ_INSERT_TAIL(dabq, dab, dab_next); |
|
490 |
|||
491 |
12 |
for (;;) { |
|
492 |
struct dwattr *dat; |
||
493 |
74 |
uint64_t attr = 0, form = 0; |
|
494 |
|||
495 |
✓✗✗✓ |
148 |
if (dw_read_uleb128(abseg, &attr) || |
496 |
74 |
dw_read_uleb128(abseg, &form)) |
|
497 |
return -1; |
||
498 |
|||
499 |
✓✓ | 74 |
if ((attr == 0) && (form == 0)) |
500 |
12 |
break; |
|
501 |
|||
502 |
62 |
dat = pmalloc(&dat_pool, sizeof(*dat)); |
|
503 |
✗✓ | 62 |
if (dat == NULL) |
504 |
return ENOMEM; |
||
505 |
|||
506 |
62 |
dat->dat_attr = attr; |
|
507 |
62 |
dat->dat_form = form; |
|
508 |
|||
509 |
62 |
SIMPLEQ_INSERT_TAIL(&dab->dab_attrs, dat, dat_next); |
|
510 |
✓✓✓ | 148 |
} |
511 |
} |
||
512 |
|||
513 |
2 |
return 0; |
|
514 |
2 |
} |
|
515 |
|||
516 |
void |
||
517 |
dw_dabq_purge(struct dwabbrev_queue *dabq) |
||
518 |
{ |
||
519 |
struct dwabbrev *dab; |
||
520 |
|||
521 |
✓✓ | 30 |
while ((dab = SIMPLEQ_FIRST(dabq)) != NULL) { |
522 |
struct dwattr *dat; |
||
523 |
|||
524 |
✓✓ | 14 |
SIMPLEQ_REMOVE_HEAD(dabq, dab_next); |
525 |
✓✓ | 136 |
while ((dat = SIMPLEQ_FIRST(&dab->dab_attrs)) != NULL) { |
526 |
✓✓ | 74 |
SIMPLEQ_REMOVE_HEAD(&dab->dab_attrs, dat_next); |
527 |
62 |
pfree(&dat_pool, dat); |
|
528 |
} |
||
529 |
|||
530 |
12 |
pfree(&dab_pool, dab); |
|
531 |
} |
||
532 |
|||
533 |
2 |
SIMPLEQ_INIT(dabq); |
|
534 |
2 |
} |
|
535 |
|||
536 |
int |
||
537 |
dw_cu_parse(struct dwbuf *info, struct dwbuf *abbrev, size_t seglen, |
||
538 |
struct dwcu **dcup) |
||
539 |
{ |
||
540 |
8 |
struct dwbuf abseg = *abbrev; |
|
541 |
4 |
struct dwbuf dwbuf; |
|
542 |
size_t segoff, nextoff, addrsize; |
||
543 |
struct dwcu *dcu = NULL; |
||
544 |
4 |
uint32_t length = 0, abbroff = 0; |
|
545 |
4 |
uint16_t version; |
|
546 |
4 |
uint8_t psz; |
|
547 |
int error; |
||
548 |
#ifndef NOPOOL |
||
549 |
static int dw_pool_inited = 0; |
||
550 |
|||
551 |
✓✓ | 4 |
if (!dw_pool_inited) { |
552 |
2 |
pool_init(&dcu_pool, "dcu", 1, sizeof(struct dwcu)); |
|
553 |
2 |
pool_init(&dab_pool, "dab", 32, sizeof(struct dwabbrev)); |
|
554 |
2 |
pool_init(&dat_pool, "dat", 32, sizeof(struct dwattr)); |
|
555 |
2 |
pool_init(&die_pool, "die", 512, sizeof(struct dwdie)); |
|
556 |
2 |
pool_init(&dav_pool, "dav", 1024, sizeof(struct dwaval)); |
|
557 |
2 |
dw_pool_inited = 1; |
|
558 |
2 |
} |
|
559 |
#endif /* NOPOOL */ |
||
560 |
|||
561 |
✓✓✗✓ |
6 |
if (info->len == 0 || abbrev->len == 0) |
562 |
2 |
return EINVAL; |
|
563 |
|||
564 |
/* Offset in the segment of the current Compile Unit. */ |
||
565 |
2 |
segoff = seglen - info->len; |
|
566 |
|||
567 |
✗✓ | 2 |
if (dw_read_u32(info, &length)) |
568 |
return -1; |
||
569 |
|||
570 |
✓✗✗✓ |
4 |
if (length >= 0xfffffff0 || length > info->len) |
571 |
return EOVERFLOW; |
||
572 |
|||
573 |
/* Offset of the next Compile Unit. */ |
||
574 |
2 |
nextoff = segoff + length + sizeof(uint32_t); |
|
575 |
|||
576 |
✗✓ | 2 |
if (dw_read_buf(info, &dwbuf, length)) |
577 |
return -1; |
||
578 |
|||
579 |
addrsize = 4; /* XXX */ |
||
580 |
|||
581 |
✓✗✗✓ |
4 |
if (dw_read_u16(&dwbuf, &version) || |
582 |
✓✗ | 2 |
dw_read_bytes(&dwbuf, &abbroff, addrsize) || |
583 |
2 |
dw_read_u8(&dwbuf, &psz)) |
|
584 |
return -1; |
||
585 |
|||
586 |
✗✓ | 2 |
if (dw_skip_bytes(&abseg, abbroff)) |
587 |
return -1; |
||
588 |
|||
589 |
/* Only DWARF2 until extended. */ |
||
590 |
✗✓ | 2 |
if (version != 2) |
591 |
return ENOTSUP; |
||
592 |
|||
593 |
2 |
dcu = pmalloc(&dcu_pool, sizeof(*dcu)); |
|
594 |
✗✓ | 2 |
if (dcu == NULL) |
595 |
return ENOMEM; |
||
596 |
|||
597 |
2 |
dcu->dcu_offset = segoff; |
|
598 |
2 |
dcu->dcu_length = length; |
|
599 |
2 |
dcu->dcu_version = version; |
|
600 |
2 |
dcu->dcu_abbroff = abbroff; |
|
601 |
2 |
dcu->dcu_psize = psz; |
|
602 |
2 |
SIMPLEQ_INIT(&dcu->dcu_abbrevs); |
|
603 |
2 |
SIMPLEQ_INIT(&dcu->dcu_dies); |
|
604 |
|||
605 |
2 |
error = dw_ab_parse(&abseg, &dcu->dcu_abbrevs); |
|
606 |
✗✓ | 2 |
if (error != 0) { |
607 |
dw_dcu_free(dcu); |
||
608 |
return error; |
||
609 |
} |
||
610 |
|||
611 |
2 |
error = dw_die_parse(&dwbuf, nextoff, psz, &dcu->dcu_abbrevs, |
|
612 |
&dcu->dcu_dies); |
||
613 |
✗✓ | 2 |
if (error != 0) { |
614 |
dw_dcu_free(dcu); |
||
615 |
return error; |
||
616 |
} |
||
617 |
|||
618 |
✓✗ | 2 |
if (dcup != NULL) |
619 |
2 |
*dcup = dcu; |
|
620 |
else |
||
621 |
dw_dcu_free(dcu); |
||
622 |
|||
623 |
2 |
return 0; |
|
624 |
4 |
} |
|
625 |
|||
626 |
void |
||
627 |
dw_dcu_free(struct dwcu *dcu) |
||
628 |
{ |
||
629 |
✓✗ | 4 |
if (dcu == NULL) |
630 |
return; |
||
631 |
|||
632 |
2 |
dw_die_purge(&dcu->dcu_dies); |
|
633 |
2 |
dw_dabq_purge(&dcu->dcu_abbrevs); |
|
634 |
2 |
pfree(&dcu_pool, dcu); |
|
635 |
4 |
} |
|
636 |
|||
637 |
int |
||
638 |
dw_loc_parse(struct dwbuf *dwbuf, uint8_t *pop, uint64_t *poper1, |
||
639 |
uint64_t *poper2) |
||
640 |
{ |
||
641 |
uint64_t oper1 = 0, oper2 = 0; |
||
642 |
uint8_t op; |
||
643 |
|||
644 |
if (dw_read_u8(dwbuf, &op)) |
||
645 |
return -1; |
||
646 |
|||
647 |
if (pop != NULL) |
||
648 |
*pop = op; |
||
649 |
|||
650 |
switch (op) { |
||
651 |
case DW_OP_constu: |
||
652 |
case DW_OP_plus_uconst: |
||
653 |
case DW_OP_regx: |
||
654 |
case DW_OP_piece: |
||
655 |
dw_read_uleb128(dwbuf, &oper1); |
||
656 |
break; |
||
657 |
|||
658 |
case DW_OP_consts: |
||
659 |
case DW_OP_breg0 ... DW_OP_breg31: |
||
660 |
case DW_OP_fbreg: |
||
661 |
dw_read_sleb128(dwbuf, &oper1); |
||
662 |
break; |
||
663 |
default: |
||
664 |
return ENOTSUP; |
||
665 |
} |
||
666 |
|||
667 |
if (poper1 != NULL) |
||
668 |
*poper1 = oper1; |
||
669 |
if (poper2 != NULL) |
||
670 |
*poper2 = oper2; |
||
671 |
|||
672 |
return 0; |
||
673 |
} |
Generated by: GCOVR (Version 3.3) |