GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: parse.c,v 1.7 2017/09/24 09:14:25 jsg Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* Copyright (c) 2016-2017 Martin Pieuchot |
||
5 |
* Copyright (c) 2016 Jasper Lievisse Adriaanse <jasper@openbsd.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 |
/* |
||
21 |
* DWARF to IT (internal type) representation parser. |
||
22 |
*/ |
||
23 |
|||
24 |
#include <sys/param.h> /* nitems() */ |
||
25 |
#include <sys/queue.h> |
||
26 |
#include <sys/tree.h> |
||
27 |
#include <sys/ctf.h> |
||
28 |
|||
29 |
#include <assert.h> |
||
30 |
#include <limits.h> |
||
31 |
#include <err.h> |
||
32 |
#include <stdlib.h> |
||
33 |
#include <string.h> |
||
34 |
|||
35 |
#include "itype.h" |
||
36 |
#include "xmalloc.h" |
||
37 |
#include "dwarf.h" |
||
38 |
#include "dw.h" |
||
39 |
#include "pool.h" |
||
40 |
|||
41 |
#ifdef DEBUG |
||
42 |
#include <stdio.h> |
||
43 |
#endif |
||
44 |
|||
45 |
#ifndef NOPOOL |
||
46 |
struct pool it_pool, im_pool, ir_pool; |
||
47 |
#endif /* NOPOOL */ |
||
48 |
|||
49 |
#define DPRINTF(x...) do { /*printf(x)*/ } while (0) |
||
50 |
|||
51 |
#define VOID_OFFSET 1 /* Fake offset for generating "void" type. */ |
||
52 |
|||
53 |
/* |
||
54 |
* Tree used to resolve per-CU types based on their offset in |
||
55 |
* the abbrev section. |
||
56 |
*/ |
||
57 |
RB_HEAD(ioff_tree, itype); |
||
58 |
|||
59 |
/* |
||
60 |
* Per-type trees used to merge exsiting types with the ones of |
||
61 |
* a newly parsed CU. |
||
62 |
*/ |
||
63 |
RB_HEAD(itype_tree, itype) itypet[CTF_K_MAX]; |
||
64 |
|||
65 |
/* |
||
66 |
* Tree of symbols used to build a list matching the order of |
||
67 |
* the ELF symbol table. |
||
68 |
*/ |
||
69 |
struct isymb_tree isymbt; |
||
70 |
|||
71 |
struct itype *void_it; |
||
72 |
uint16_t tidx, fidx, oidx; /* type, func & object IDs */ |
||
73 |
uint16_t long_tidx; /* index of "long", for array */ |
||
74 |
|||
75 |
|||
76 |
void cu_stat(void); |
||
77 |
void cu_parse(struct dwcu *, struct itype_queue *, |
||
78 |
struct ioff_tree *); |
||
79 |
void cu_resolve(struct dwcu *, struct itype_queue *, |
||
80 |
struct ioff_tree *); |
||
81 |
void cu_reference(struct dwcu *, struct itype_queue *); |
||
82 |
void cu_merge(struct dwcu *, struct itype_queue *); |
||
83 |
|||
84 |
struct itype *parse_base(struct dwdie *, size_t); |
||
85 |
struct itype *parse_refers(struct dwdie *, size_t, int); |
||
86 |
struct itype *parse_array(struct dwdie *, size_t); |
||
87 |
struct itype *parse_enum(struct dwdie *, size_t); |
||
88 |
struct itype *parse_struct(struct dwdie *, size_t, int, size_t); |
||
89 |
struct itype *parse_function(struct dwdie *, size_t); |
||
90 |
struct itype *parse_funcptr(struct dwdie *, size_t); |
||
91 |
struct itype *parse_variable(struct dwdie *, size_t); |
||
92 |
|||
93 |
void subparse_subrange(struct dwdie *, size_t, struct itype *); |
||
94 |
void subparse_enumerator(struct dwdie *, size_t, struct itype *); |
||
95 |
void subparse_member(struct dwdie *, size_t, struct itype *, size_t); |
||
96 |
void subparse_arguments(struct dwdie *, size_t, struct itype *); |
||
97 |
|||
98 |
size_t dav2val(struct dwaval *, size_t); |
||
99 |
const char *dav2str(struct dwaval *); |
||
100 |
const char *enc2name(unsigned short); |
||
101 |
|||
102 |
struct itype *it_new(uint64_t, size_t, const char *, uint32_t, uint16_t, |
||
103 |
uint64_t, uint16_t, unsigned int); |
||
104 |
void it_reference(struct itype *); |
||
105 |
void it_free(struct itype *); |
||
106 |
int it_cmp(struct itype *, struct itype *); |
||
107 |
int it_name_cmp(struct itype *, struct itype *); |
||
108 |
int it_off_cmp(struct itype *, struct itype *); |
||
109 |
void ir_add(struct itype *, struct itype *); |
||
110 |
void ir_purge(struct itype *); |
||
111 |
struct imember *im_new(const char *, size_t, size_t); |
||
112 |
|||
113 |
✓✓✓✓ ✗✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✓✗✗ ✗✓✗✗ ✗✗✗✓ ✗✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✓ ✓✗✓✓ ✓✓✓✓ ✓✓✗✗ ✗✗✗✗ ✓✓✗✓ ✓✗✓✓ ✓✓✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ |
452 |
RB_GENERATE(itype_tree, itype, it_node, it_cmp); |
114 |
✓✓✓✓ ✓✓✓✓ ✓✗✗✓ ✗✗✗✗ ✗✓✓✗ ✗✓✗✗ ✗✓✗✗ ✗✗✗✓ ✗✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✓ ✓✗✓✓ ✓✓✓✓ ✓✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
814 |
RB_GENERATE(isymb_tree, itype, it_node, it_name_cmp); |
115 |
✓✓✓✓ ✗✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✓ ✗✓✗✗ ✗✗✓✓ ✓✓✓✓ ✓✓✓✓ ✓✗✓✓ ✓✗✓✓ ✓✓✓✓ ✓✓✓✓ ✓✗✗✓ ✗✗✗✗ ✗✗✓✗ ✓✓✗✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✓✓ ✓✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✓✓ ✓✓✓✗ ✓✓✗✓ ✓✗✓✓ ✓✗✓✓ ✓✓✗✗ ✗✗✗✗ ✓✓✗✓ ✓✓✓✗ ✗✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✗ |
2472 |
RB_GENERATE(ioff_tree, itype, it_node, it_off_cmp); |
116 |
|||
117 |
/* |
||
118 |
* Construct a list of internal type and functions based on DWARF |
||
119 |
* INFO and ABBREV sections. |
||
120 |
* |
||
121 |
* Multiple CUs are supported. |
||
122 |
*/ |
||
123 |
void |
||
124 |
dwarf_parse(const char *infobuf, size_t infolen, const char *abbuf, |
||
125 |
size_t ablen) |
||
126 |
{ |
||
127 |
4 |
struct dwbuf info = { .buf = infobuf, .len = infolen }; |
|
128 |
2 |
struct dwbuf abbrev = { .buf = abbuf, .len = ablen }; |
|
129 |
2 |
struct dwcu *dcu = NULL; |
|
130 |
2 |
struct ioff_tree cu_iofft; |
|
131 |
2 |
struct itype_queue cu_itypeq; |
|
132 |
struct itype *it; |
||
133 |
int i; |
||
134 |
|||
135 |
✓✓ | 128 |
for (i = 0; i < CTF_K_MAX; i++) |
136 |
62 |
RB_INIT(&itypet[i]); |
|
137 |
2 |
RB_INIT(&isymbt); |
|
138 |
|||
139 |
2 |
void_it = it_new(++tidx, VOID_OFFSET, "void", 0, |
|
140 |
CTF_INT_SIGNED, 0, CTF_K_INTEGER, 0); |
||
141 |
2 |
TAILQ_INSERT_TAIL(&itypeq, void_it, it_next); |
|
142 |
|||
143 |
✓✓ | 8 |
while (dw_cu_parse(&info, &abbrev, infolen, &dcu) == 0) { |
144 |
2 |
TAILQ_INIT(&cu_itypeq); |
|
145 |
2 |
RB_INIT(&cu_iofft); |
|
146 |
|||
147 |
/* Parse this CU */ |
||
148 |
2 |
cu_parse(dcu, &cu_itypeq, &cu_iofft); |
|
149 |
|||
150 |
/* Resolve its types. */ |
||
151 |
2 |
cu_resolve(dcu, &cu_itypeq, &cu_iofft); |
|
152 |
✗✓ | 2 |
assert(RB_EMPTY(&cu_iofft)); |
153 |
|||
154 |
/* Mark used type as such. */ |
||
155 |
2 |
cu_reference(dcu, &cu_itypeq); |
|
156 |
|||
157 |
#ifdef DEBUG |
||
158 |
/* Dump statistics for current CU. */ |
||
159 |
cu_stat(); |
||
160 |
#endif |
||
161 |
|||
162 |
/* Merge them with the common type list. */ |
||
163 |
2 |
cu_merge(dcu, &cu_itypeq); |
|
164 |
|||
165 |
2 |
dw_dcu_free(dcu); |
|
166 |
} |
||
167 |
|||
168 |
/* We force array's index type to be 'long', for that we need its ID. */ |
||
169 |
✓✓ | 16 |
RB_FOREACH(it, itype_tree, &itypet[CTF_K_INTEGER]) { |
170 |
✓✗✓✓ |
12 |
if (it_name(it) == NULL || it->it_size != (8 * sizeof(long))) |
171 |
continue; |
||
172 |
|||
173 |
✗✓ | 2 |
if (strcmp(it_name(it), "unsigned") == 0) { |
174 |
long_tidx = it->it_idx; |
||
175 |
break; |
||
176 |
} |
||
177 |
} |
||
178 |
2 |
} |
|
179 |
|||
180 |
struct itype * |
||
181 |
it_new(uint64_t index, size_t off, const char *name, uint32_t size, |
||
182 |
uint16_t enc, uint64_t ref, uint16_t type, unsigned int flags) |
||
183 |
{ |
||
184 |
struct itype *it; |
||
185 |
#ifndef NOPOOL |
||
186 |
static int it_pool_inited = 0; |
||
187 |
|||
188 |
✓✓ | 96 |
if (!it_pool_inited) { |
189 |
2 |
pool_init(&it_pool, "it", 512, sizeof(struct itype)); |
|
190 |
2 |
pool_init(&im_pool, "im", 1024, sizeof(struct imember)); |
|
191 |
2 |
pool_init(&ir_pool, "ir", 1024, sizeof(struct itref)); |
|
192 |
2 |
it_pool_inited = 1; |
|
193 |
2 |
} |
|
194 |
#endif |
||
195 |
|||
196 |
✓✓✗✓ |
52 |
assert((name != NULL) || !(flags & (ITF_FUNC|ITF_OBJ))); |
197 |
|||
198 |
48 |
it = pmalloc(&it_pool, sizeof(*it)); |
|
199 |
48 |
SIMPLEQ_INIT(&it->it_refs); |
|
200 |
48 |
TAILQ_INIT(&it->it_members); |
|
201 |
48 |
it->it_off = off; |
|
202 |
48 |
it->it_ref = ref; |
|
203 |
48 |
it->it_refp = NULL; |
|
204 |
48 |
it->it_size = size; |
|
205 |
48 |
it->it_nelems = 0; |
|
206 |
48 |
it->it_enc = enc; |
|
207 |
48 |
it->it_idx = index; |
|
208 |
48 |
it->it_type = type; |
|
209 |
48 |
it->it_flags = flags; |
|
210 |
|||
211 |
✓✓ | 48 |
if (name == NULL) { |
212 |
4 |
it->it_flags |= ITF_ANON; |
|
213 |
4 |
} else { |
|
214 |
size_t n; |
||
215 |
|||
216 |
✗✓ | 44 |
if ((n = strlcpy(it->it_name, name, ITNAME_MAX)) > ITNAME_MAX) |
217 |
warnx("name %s too long %zd > %d", name, n, ITNAME_MAX); |
||
218 |
} |
||
219 |
|||
220 |
48 |
return it; |
|
221 |
} |
||
222 |
|||
223 |
struct itype * |
||
224 |
it_dup(struct itype *it) |
||
225 |
{ |
||
226 |
struct imember *copim, *im; |
||
227 |
struct itype *copit; |
||
228 |
|||
229 |
42 |
copit = it_new(it->it_idx, it->it_off, it_name(it), it->it_size, |
|
230 |
14 |
it->it_enc, it->it_ref, it->it_type, it->it_flags); |
|
231 |
|||
232 |
14 |
copit->it_refp = it->it_refp; |
|
233 |
14 |
copit->it_nelems = it->it_nelems; |
|
234 |
|||
235 |
✗✓ | 28 |
TAILQ_FOREACH(im, &it->it_members, im_next) { |
236 |
copim = im_new(im_name(im), im->im_ref, im->im_off); |
||
237 |
copim->im_refp = im->im_refp; |
||
238 |
TAILQ_INSERT_TAIL(&copit->it_members, copim, im_next); |
||
239 |
} |
||
240 |
|||
241 |
14 |
return copit; |
|
242 |
} |
||
243 |
|||
244 |
const char * |
||
245 |
it_name(struct itype *it) |
||
246 |
{ |
||
247 |
✓✓ | 584 |
if (!(it->it_flags & ITF_ANON)) |
248 |
288 |
return it->it_name; |
|
249 |
|||
250 |
4 |
return NULL; |
|
251 |
292 |
} |
|
252 |
|||
253 |
void |
||
254 |
it_reference(struct itype *it) |
||
255 |
{ |
||
256 |
struct imember *im; |
||
257 |
|||
258 |
✓✓✓✓ |
136 |
if (it == NULL || it->it_flags & ITF_USED) |
259 |
18 |
return; |
|
260 |
|||
261 |
32 |
it->it_flags |= ITF_USED; |
|
262 |
|||
263 |
32 |
it_reference(it->it_refp); |
|
264 |
✓✓ | 72 |
TAILQ_FOREACH(im, &it->it_members, im_next) |
265 |
4 |
it_reference(im->im_refp); |
|
266 |
82 |
} |
|
267 |
|||
268 |
void |
||
269 |
it_free(struct itype *it) |
||
270 |
{ |
||
271 |
struct imember *im; |
||
272 |
|||
273 |
✗✓ | 4 |
if (it == NULL) |
274 |
return; |
||
275 |
|||
276 |
✗✓ | 2 |
while ((im = TAILQ_FIRST(&it->it_members)) != NULL) { |
277 |
TAILQ_REMOVE(&it->it_members, im, im_next); |
||
278 |
pfree(&im_pool, im); |
||
279 |
} |
||
280 |
|||
281 |
2 |
ir_purge(it); |
|
282 |
2 |
pfree(&it_pool, it); |
|
283 |
4 |
} |
|
284 |
|||
285 |
/* |
||
286 |
* Return 0 if ``a'' matches ``b''. |
||
287 |
*/ |
||
288 |
int |
||
289 |
it_cmp(struct itype *a, struct itype *b) |
||
290 |
{ |
||
291 |
int diff; |
||
292 |
|||
293 |
✓✓ | 64 |
if ((diff = (a->it_type - b->it_type)) != 0) |
294 |
4 |
return diff; |
|
295 |
|||
296 |
✓✓ | 28 |
if ((diff = (a->it_size - b->it_size)) != 0) |
297 |
22 |
return diff; |
|
298 |
|||
299 |
✗✓ | 6 |
if ((diff = (a->it_nelems - b->it_nelems)) != 0) |
300 |
return diff; |
||
301 |
|||
302 |
/* Match by name */ |
||
303 |
✓✓✓✗ |
8 |
if (!(a->it_flags & ITF_ANON) && !(b->it_flags & ITF_ANON)) |
304 |
2 |
return strcmp(it_name(a), it_name(b)); |
|
305 |
|||
306 |
/* Only one of them is anonym */ |
||
307 |
✗✓ | 4 |
if ((a->it_flags & ITF_ANON) != (b->it_flags & ITF_ANON)) |
308 |
return (a->it_flags & ITF_ANON) ? -1 : 1; |
||
309 |
|||
310 |
/* Match by reference */ |
||
311 |
✓✗✓✗ |
8 |
if ((a->it_refp != NULL) && (b->it_refp != NULL)) |
312 |
4 |
return it_cmp(a->it_refp, b->it_refp); |
|
313 |
|||
314 |
return 1; |
||
315 |
32 |
} |
|
316 |
|||
317 |
int |
||
318 |
it_name_cmp(struct itype *a, struct itype *b) |
||
319 |
{ |
||
320 |
int diff; |
||
321 |
|||
322 |
✓✓ | 248 |
if ((diff = strcmp(it_name(a), it_name(b))) != 0) |
323 |
110 |
return diff; |
|
324 |
|||
325 |
14 |
return ((a->it_flags|ITF_MASK) - (b->it_flags|ITF_MASK)); |
|
326 |
124 |
} |
|
327 |
|||
328 |
int |
||
329 |
it_off_cmp(struct itype *a, struct itype *b) |
||
330 |
{ |
||
331 |
372 |
return a->it_off - b->it_off; |
|
332 |
} |
||
333 |
|||
334 |
void |
||
335 |
ir_add(struct itype *it, struct itype *tmp) |
||
336 |
{ |
||
337 |
struct itref *ir; |
||
338 |
|||
339 |
✓✓ | 74 |
SIMPLEQ_FOREACH(ir, &tmp->it_refs, ir_next) { |
340 |
✓✓ | 6 |
if (ir->ir_itp == it) |
341 |
2 |
return; |
|
342 |
} |
||
343 |
|||
344 |
20 |
ir = pmalloc(&ir_pool, sizeof(*ir)); |
|
345 |
20 |
ir->ir_itp = it; |
|
346 |
20 |
SIMPLEQ_INSERT_TAIL(&tmp->it_refs, ir, ir_next); |
|
347 |
42 |
} |
|
348 |
|||
349 |
void |
||
350 |
ir_purge(struct itype *it) |
||
351 |
{ |
||
352 |
struct itref *ir; |
||
353 |
|||
354 |
✗✓ | 6 |
while ((ir = SIMPLEQ_FIRST(&it->it_refs)) != NULL) { |
355 |
SIMPLEQ_REMOVE_HEAD(&it->it_refs, ir_next); |
||
356 |
pfree(&ir_pool, ir); |
||
357 |
} |
||
358 |
2 |
} |
|
359 |
|||
360 |
struct imember * |
||
361 |
im_new(const char *name, size_t ref, size_t off) |
||
362 |
{ |
||
363 |
struct imember *im; |
||
364 |
|||
365 |
8 |
im = pmalloc(&im_pool, sizeof(*im)); |
|
366 |
4 |
im->im_ref = ref; |
|
367 |
4 |
im->im_off = off; |
|
368 |
4 |
im->im_refp = NULL; |
|
369 |
✓✗ | 4 |
if (name == NULL) { |
370 |
4 |
im->im_flags = IMF_ANON; |
|
371 |
4 |
} else { |
|
372 |
size_t n; |
||
373 |
|||
374 |
n = strlcpy(im->im_name, name, ITNAME_MAX); |
||
375 |
if (n > ITNAME_MAX) |
||
376 |
warnx("name %s too long %zd > %d", name, n, |
||
377 |
ITNAME_MAX); |
||
378 |
im->im_flags = 0; |
||
379 |
} |
||
380 |
|||
381 |
4 |
return im; |
|
382 |
} |
||
383 |
|||
384 |
const char * |
||
385 |
im_name(struct imember *im) |
||
386 |
{ |
||
387 |
if (!(im->im_flags & IMF_ANON)) |
||
388 |
return im->im_name; |
||
389 |
|||
390 |
return NULL; |
||
391 |
} |
||
392 |
|||
393 |
void |
||
394 |
cu_stat(void) |
||
395 |
{ |
||
396 |
#ifndef NOPOOL |
||
397 |
pool_dump(); |
||
398 |
#endif |
||
399 |
} |
||
400 |
/* |
||
401 |
* Worst case it's a O(n*n) resolution lookup, with ``n'' being the number |
||
402 |
* of elements in ``cutq''. |
||
403 |
*/ |
||
404 |
void |
||
405 |
cu_resolve(struct dwcu *dcu, struct itype_queue *cutq, struct ioff_tree *cuot) |
||
406 |
{ |
||
407 |
4 |
struct itype *it, *ref, tmp; |
|
408 |
struct imember *im; |
||
409 |
unsigned int toresolve; |
||
410 |
2 |
size_t off = dcu->dcu_offset; |
|
411 |
|||
412 |
✓✓ | 68 |
TAILQ_FOREACH(it, cutq, it_next) { |
413 |
✓✓ | 32 |
if (!(it->it_flags & (ITF_UNRES|ITF_UNRES_MEMB))) |
414 |
continue; |
||
415 |
|||
416 |
✓✗ | 18 |
if (it->it_flags & ITF_UNRES) { |
417 |
18 |
tmp.it_off = it->it_ref + off; |
|
418 |
18 |
ref = RB_FIND(ioff_tree, cuot, &tmp); |
|
419 |
✓✗ | 18 |
if (ref != NULL) { |
420 |
18 |
it->it_refp = ref; |
|
421 |
18 |
ir_add(it, ref); |
|
422 |
18 |
it->it_flags &= ~ITF_UNRES; |
|
423 |
18 |
} |
|
424 |
} |
||
425 |
|||
426 |
/* All members need to be resolved. */ |
||
427 |
18 |
toresolve = it->it_nelems; |
|
428 |
✓✓ | 18 |
if ((it->it_flags & ITF_UNRES_MEMB) && toresolve > 0) { |
429 |
✓✓ | 12 |
TAILQ_FOREACH(im, &it->it_members, im_next) { |
430 |
4 |
tmp.it_off = im->im_ref + off; |
|
431 |
4 |
ref = RB_FIND(ioff_tree, cuot, &tmp); |
|
432 |
✓✗ | 4 |
if (ref != NULL) { |
433 |
4 |
im->im_refp = ref; |
|
434 |
4 |
ir_add(it, ref); |
|
435 |
4 |
toresolve--; |
|
436 |
4 |
} |
|
437 |
} |
||
438 |
✓✗ | 2 |
if (toresolve == 0) |
439 |
2 |
it->it_flags &= ~ITF_UNRES_MEMB; |
|
440 |
} |
||
441 |
#if defined(DEBUG) |
||
442 |
if (it->it_flags & (ITF_UNRES|ITF_UNRES_MEMB)) { |
||
443 |
printf("0x%zx: %s type=%d unresolved 0x%llx", |
||
444 |
it->it_off, it_name(it), it->it_type, it->it_ref); |
||
445 |
if (toresolve) |
||
446 |
printf(": %d members", toresolve); |
||
447 |
TAILQ_FOREACH(im, &it->it_members, im_next) { |
||
448 |
if (im->im_refp != NULL) |
||
449 |
continue; |
||
450 |
printf("\n%zu: %s", im->im_ref, im_name(im)); |
||
451 |
} |
||
452 |
printf("\n"); |
||
453 |
} |
||
454 |
#endif /* defined(DEBUG) */ |
||
455 |
} |
||
456 |
|||
457 |
✓✓ | 100 |
RB_FOREACH_SAFE(it, ioff_tree, cuot, ref) |
458 |
32 |
RB_REMOVE(ioff_tree, cuot, it); |
|
459 |
2 |
} |
|
460 |
|||
461 |
void |
||
462 |
cu_reference(struct dwcu *dcu, struct itype_queue *cutq) |
||
463 |
{ |
||
464 |
struct itype *it; |
||
465 |
|||
466 |
✓✓ | 70 |
TAILQ_FOREACH(it, cutq, it_next) { |
467 |
✓✓ | 32 |
if (it->it_flags & (ITF_OBJ|ITF_FUNC)) |
468 |
14 |
it_reference(it); |
|
469 |
} |
||
470 |
2 |
} |
|
471 |
|||
472 |
/* |
||
473 |
* Merge type representation from a CU with already known types. |
||
474 |
*/ |
||
475 |
void |
||
476 |
cu_merge(struct dwcu *dcu, struct itype_queue *cutq) |
||
477 |
{ |
||
478 |
struct itype *it, *nit, *prev, *first; |
||
479 |
int diff; |
||
480 |
|||
481 |
/* First ``it'' that needs a duplicate check. */ |
||
482 |
4 |
first = TAILQ_FIRST(cutq); |
|
483 |
✗✓ | 2 |
if (first == NULL) |
484 |
return; |
||
485 |
|||
486 |
✓✗ | 4 |
TAILQ_CONCAT(&itypeq, cutq, it_next); |
487 |
|||
488 |
/* |
||
489 |
* First pass: merge types |
||
490 |
*/ |
||
491 |
✓✓ | 68 |
for (it = first; it != NULL; it = nit) { |
492 |
32 |
nit = TAILQ_NEXT(it, it_next); |
|
493 |
|||
494 |
/* Move functions & variable to their own list. */ |
||
495 |
✓✓ | 32 |
if (it->it_flags & (ITF_FUNC|ITF_OBJ)) { |
496 |
/* |
||
497 |
* FIXME: allow static variables with the same name |
||
498 |
* to be of different type. |
||
499 |
*/ |
||
500 |
✓✗ | 14 |
if (RB_FIND(isymb_tree, &isymbt, it) == NULL) |
501 |
14 |
RB_INSERT(isymb_tree, &isymbt, it); |
|
502 |
continue; |
||
503 |
} |
||
504 |
|||
505 |
/* Look if we already have this type. */ |
||
506 |
✓✗ | 18 |
if (it->it_flags & ITF_USED) |
507 |
18 |
prev = RB_FIND(itype_tree, &itypet[it->it_type], it); |
|
508 |
else |
||
509 |
prev = NULL; |
||
510 |
|||
511 |
✓✓ | 18 |
if (prev != NULL) { |
512 |
struct itype *old = it; |
||
513 |
struct itref *ir; |
||
514 |
struct imember *im; |
||
515 |
|||
516 |
/* Substitute references */ |
||
517 |
✓✓ | 6 |
while ((ir = SIMPLEQ_FIRST(&old->it_refs)) != NULL) { |
518 |
2 |
it = ir->ir_itp; |
|
519 |
|||
520 |
✓✗ | 4 |
SIMPLEQ_REMOVE_HEAD(&old->it_refs, ir_next); |
521 |
2 |
pfree(&ir_pool, ir); |
|
522 |
|||
523 |
✓✗ | 2 |
if (it->it_refp == old) |
524 |
2 |
it->it_refp = prev; |
|
525 |
|||
526 |
✓✗ | 4 |
TAILQ_FOREACH(im, &it->it_members, im_next) { |
527 |
if (im->im_refp == old) |
||
528 |
im->im_refp = prev; |
||
529 |
} |
||
530 |
} |
||
531 |
|||
532 |
2 |
old->it_flags &= ~ITF_USED; |
|
533 |
✓✗ | 18 |
} else if (it->it_flags & ITF_USED) { |
534 |
16 |
RB_INSERT(itype_tree, &itypet[it->it_type], it); |
|
535 |
16 |
} |
|
536 |
} |
||
537 |
|||
538 |
/* |
||
539 |
* Second pass: update indexes |
||
540 |
*/ |
||
541 |
diff = 0; |
||
542 |
✓✓ | 68 |
for (it = first; it != NULL; it = nit) { |
543 |
32 |
nit = TAILQ_NEXT(it, it_next); |
|
544 |
|||
545 |
✓✓ | 32 |
if (it->it_flags & (ITF_FUNC|ITF_OBJ)) |
546 |
continue; |
||
547 |
|||
548 |
/* Adjust indexes */ |
||
549 |
✓✓ | 18 |
if (it->it_flags & ITF_USED) { |
550 |
16 |
it->it_idx -= diff; |
|
551 |
16 |
continue; |
|
552 |
} |
||
553 |
|||
554 |
/* Remove unused */ |
||
555 |
✓✗ | 6 |
TAILQ_REMOVE(&itypeq, it, it_next); |
556 |
2 |
it_free(it); |
|
557 |
2 |
diff++; |
|
558 |
2 |
} |
|
559 |
|||
560 |
/* Update global index to match removed entries. */ |
||
561 |
2 |
it = TAILQ_LAST(&itypeq, itype_queue); |
|
562 |
✗✓ | 4 |
while (it->it_flags & (ITF_FUNC|ITF_OBJ)) |
563 |
it = TAILQ_PREV(it, itype_queue, it_next); |
||
564 |
|||
565 |
2 |
tidx = it->it_idx; |
|
566 |
4 |
} |
|
567 |
|||
568 |
/* |
||
569 |
* Parse a CU. |
||
570 |
*/ |
||
571 |
void |
||
572 |
cu_parse(struct dwcu *dcu, struct itype_queue *cutq, struct ioff_tree *cuot) |
||
573 |
{ |
||
574 |
struct itype *it = NULL; |
||
575 |
struct dwdie *die; |
||
576 |
4 |
size_t psz = dcu->dcu_psize; |
|
577 |
2 |
size_t off = dcu->dcu_offset; |
|
578 |
|||
579 |
✗✓ | 2 |
assert(RB_EMPTY(cuot)); |
580 |
|||
581 |
✓✓ | 80 |
SIMPLEQ_FOREACH(die, &dcu->dcu_dies, die_next) { |
582 |
38 |
uint64_t tag = die->die_dab->dab_tag; |
|
583 |
|||
584 |
✗✗✓✗ ✗✗✓✗ ✗✗✓✗ ✗✗✓✓ ✗✗✓ |
38 |
switch (tag) { |
585 |
case DW_TAG_array_type: |
||
586 |
it = parse_array(die, dcu->dcu_psize); |
||
587 |
break; |
||
588 |
case DW_TAG_enumeration_type: |
||
589 |
it = parse_enum(die, dcu->dcu_psize); |
||
590 |
break; |
||
591 |
case DW_TAG_pointer_type: |
||
592 |
4 |
it = parse_refers(die, psz, CTF_K_POINTER); |
|
593 |
4 |
break; |
|
594 |
case DW_TAG_structure_type: |
||
595 |
it = parse_struct(die, psz, CTF_K_STRUCT, off); |
||
596 |
if (it == NULL) |
||
597 |
continue; |
||
598 |
break; |
||
599 |
case DW_TAG_typedef: |
||
600 |
it = parse_refers(die, psz, CTF_K_TYPEDEF); |
||
601 |
break; |
||
602 |
case DW_TAG_union_type: |
||
603 |
it = parse_struct(die, psz, CTF_K_UNION, off); |
||
604 |
if (it == NULL) |
||
605 |
continue; |
||
606 |
break; |
||
607 |
case DW_TAG_base_type: |
||
608 |
14 |
it = parse_base(die, psz); |
|
609 |
✗✓ | 14 |
if (it == NULL) |
610 |
continue; |
||
611 |
break; |
||
612 |
case DW_TAG_const_type: |
||
613 |
it = parse_refers(die, psz, CTF_K_CONST); |
||
614 |
break; |
||
615 |
case DW_TAG_volatile_type: |
||
616 |
it = parse_refers(die, psz, CTF_K_VOLATILE); |
||
617 |
break; |
||
618 |
case DW_TAG_restrict_type: |
||
619 |
it = parse_refers(die, psz, CTF_K_RESTRICT); |
||
620 |
break; |
||
621 |
case DW_TAG_subprogram: |
||
622 |
2 |
it = parse_function(die, psz); |
|
623 |
✗✓ | 2 |
if (it == NULL) |
624 |
continue; |
||
625 |
break; |
||
626 |
case DW_TAG_subroutine_type: |
||
627 |
it = parse_funcptr(die, psz); |
||
628 |
break; |
||
629 |
/* |
||
630 |
* Children are assumed to be right after their parent in |
||
631 |
* the list. The parent parsing function takes care of |
||
632 |
* parsing them. |
||
633 |
*/ |
||
634 |
case DW_TAG_member: |
||
635 |
assert(it->it_type == CTF_K_STRUCT || |
||
636 |
it->it_type == CTF_K_UNION || |
||
637 |
it->it_type == CTF_K_ENUM); |
||
638 |
continue; |
||
639 |
case DW_TAG_subrange_type: |
||
640 |
assert(it->it_type == CTF_K_ARRAY); |
||
641 |
continue; |
||
642 |
case DW_TAG_formal_parameter: |
||
643 |
/* |
||
644 |
* If we skipped the second inline definition, |
||
645 |
* skip its arguments. |
||
646 |
*/ |
||
647 |
✗✓ | 4 |
if (it == NULL) |
648 |
continue; |
||
649 |
|||
650 |
/* See comment in subparse_arguments(). */ |
||
651 |
✓✗✗✓ |
8 |
if (it->it_type == CTF_K_STRUCT || |
652 |
✓✗ | 4 |
it->it_type == CTF_K_UNION || |
653 |
✓✗ | 4 |
it->it_type == CTF_K_ENUM || |
654 |
4 |
it->it_type == CTF_K_TYPEDEF) |
|
655 |
continue; |
||
656 |
|||
657 |
✗✓ | 4 |
if (it->it_flags & ITF_OBJ) |
658 |
continue; |
||
659 |
|||
660 |
✗✓ | 4 |
assert(it->it_type == CTF_K_FUNCTION); |
661 |
4 |
continue; |
|
662 |
case DW_TAG_variable: |
||
663 |
12 |
it = parse_variable(die, psz); |
|
664 |
/* Unnamed variables are discarded. */ |
||
665 |
✗✓ | 12 |
if (it == NULL) |
666 |
continue; |
||
667 |
break; |
||
668 |
#if 1 |
||
669 |
case DW_TAG_lexical_block: |
||
670 |
case DW_TAG_inlined_subroutine: |
||
671 |
continue; |
||
672 |
#endif |
||
673 |
case DW_TAG_compile_unit: |
||
674 |
default: |
||
675 |
DPRINTF("%s\n", dw_tag2name(tag)); |
||
676 |
2 |
continue; |
|
677 |
} |
||
678 |
|||
679 |
32 |
TAILQ_INSERT_TAIL(cutq, it, it_next); |
|
680 |
32 |
RB_INSERT(ioff_tree, cuot, it); |
|
681 |
32 |
} |
|
682 |
2 |
} |
|
683 |
|||
684 |
struct itype * |
||
685 |
parse_base(struct dwdie *die, size_t psz) |
||
686 |
{ |
||
687 |
struct itype *it; |
||
688 |
struct dwaval *dav; |
||
689 |
uint16_t encoding, enc = 0, bits = 0; |
||
690 |
int type; |
||
691 |
|||
692 |
✓✓ | 126 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
693 |
✓✓✓ | 70 |
switch (dav->dav_dat->dat_attr) { |
694 |
case DW_AT_encoding: |
||
695 |
14 |
enc = dav2val(dav, psz); |
|
696 |
14 |
break; |
|
697 |
case DW_AT_byte_size: |
||
698 |
14 |
bits = 8 * dav2val(dav, psz); |
|
699 |
14 |
break; |
|
700 |
default: |
||
701 |
DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr)); |
||
702 |
break; |
||
703 |
} |
||
704 |
} |
||
705 |
|||
706 |
✗✗✗✓ ✓✗✓✗ ✗✗ |
14 |
switch (enc) { |
707 |
case DW_ATE_unsigned: |
||
708 |
case DW_ATE_address: |
||
709 |
encoding = 0; |
||
710 |
type = CTF_K_INTEGER; |
||
711 |
break; |
||
712 |
case DW_ATE_unsigned_char: |
||
713 |
encoding = CTF_INT_CHAR; |
||
714 |
type = CTF_K_INTEGER; |
||
715 |
break; |
||
716 |
case DW_ATE_signed: |
||
717 |
encoding = CTF_INT_SIGNED; |
||
718 |
type = CTF_K_INTEGER; |
||
719 |
6 |
break; |
|
720 |
case DW_ATE_signed_char: |
||
721 |
encoding = CTF_INT_SIGNED | CTF_INT_CHAR; |
||
722 |
type = CTF_K_INTEGER; |
||
723 |
2 |
break; |
|
724 |
case DW_ATE_boolean: |
||
725 |
encoding = CTF_INT_SIGNED | CTF_INT_BOOL; |
||
726 |
type = CTF_K_INTEGER; |
||
727 |
break; |
||
728 |
case DW_ATE_float: |
||
729 |
✗✓ | 6 |
if (bits < psz) |
730 |
encoding = CTF_FP_SINGLE; |
||
731 |
✗✓ | 6 |
else if (bits == psz) |
732 |
encoding = CTF_FP_DOUBLE; |
||
733 |
else |
||
734 |
encoding = CTF_FP_LDOUBLE; |
||
735 |
type = CTF_K_FLOAT; |
||
736 |
6 |
break; |
|
737 |
case DW_ATE_complex_float: |
||
738 |
if (bits < psz) |
||
739 |
encoding = CTF_FP_CPLX; |
||
740 |
else if (bits == psz) |
||
741 |
encoding = CTF_FP_DCPLX; |
||
742 |
else |
||
743 |
encoding = CTF_FP_LDCPLX; |
||
744 |
type = CTF_K_FLOAT; |
||
745 |
break; |
||
746 |
case DW_ATE_imaginary_float: |
||
747 |
if (bits < psz) |
||
748 |
encoding = CTF_FP_IMAGRY; |
||
749 |
else if (bits == psz) |
||
750 |
encoding = CTF_FP_DIMAGRY; |
||
751 |
else |
||
752 |
encoding = CTF_FP_LDIMAGRY; |
||
753 |
type = CTF_K_FLOAT; |
||
754 |
break; |
||
755 |
default: |
||
756 |
DPRINTF("unknown encoding: %d\n", enc); |
||
757 |
return (NULL); |
||
758 |
} |
||
759 |
|||
760 |
28 |
it = it_new(++tidx, die->die_offset, enc2name(enc), bits, |
|
761 |
14 |
encoding, 0, type, 0); |
|
762 |
|||
763 |
14 |
return it; |
|
764 |
14 |
} |
|
765 |
|||
766 |
struct itype * |
||
767 |
parse_refers(struct dwdie *die, size_t psz, int type) |
||
768 |
{ |
||
769 |
struct itype *it; |
||
770 |
struct dwaval *dav; |
||
771 |
const char *name = NULL; |
||
772 |
size_t ref = 0, size = 0; |
||
773 |
|||
774 |
✓✓ | 20 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
775 |
✗✓✗✓ |
8 |
switch (dav->dav_dat->dat_attr) { |
776 |
case DW_AT_name: |
||
777 |
name = dav2str(dav); |
||
778 |
break; |
||
779 |
case DW_AT_type: |
||
780 |
4 |
ref = dav2val(dav, psz); |
|
781 |
4 |
break; |
|
782 |
case DW_AT_byte_size: |
||
783 |
size = dav2val(dav, psz); |
||
784 |
assert(size < UINT_MAX); |
||
785 |
break; |
||
786 |
default: |
||
787 |
DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr)); |
||
788 |
break; |
||
789 |
} |
||
790 |
} |
||
791 |
|||
792 |
4 |
it = it_new(++tidx, die->die_offset, name, size, 0, ref, type, |
|
793 |
ITF_UNRES); |
||
794 |
|||
795 |
✗✓✗✗ |
4 |
if (it->it_ref == 0 && (it->it_size == sizeof(void *) || |
796 |
type == CTF_K_CONST || type == CTF_K_VOLATILE || |
||
797 |
type == CTF_K_POINTER)) { |
||
798 |
/* Work around GCC/clang not emiting a type for void */ |
||
799 |
it->it_flags &= ~ITF_UNRES; |
||
800 |
it->it_ref = VOID_OFFSET; |
||
801 |
it->it_refp = void_it; |
||
802 |
} |
||
803 |
|||
804 |
4 |
return it; |
|
805 |
} |
||
806 |
|||
807 |
struct itype * |
||
808 |
parse_array(struct dwdie *die, size_t psz) |
||
809 |
{ |
||
810 |
struct itype *it; |
||
811 |
struct dwaval *dav; |
||
812 |
const char *name = NULL; |
||
813 |
size_t ref = 0; |
||
814 |
|||
815 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
||
816 |
switch (dav->dav_dat->dat_attr) { |
||
817 |
case DW_AT_name: |
||
818 |
name = dav2str(dav); |
||
819 |
break; |
||
820 |
case DW_AT_type: |
||
821 |
ref = dav2val(dav, psz); |
||
822 |
break; |
||
823 |
default: |
||
824 |
DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr)); |
||
825 |
break; |
||
826 |
} |
||
827 |
} |
||
828 |
|||
829 |
it = it_new(++tidx, die->die_offset, name, 0, 0, ref, CTF_K_ARRAY, |
||
830 |
ITF_UNRES); |
||
831 |
|||
832 |
subparse_subrange(die, psz, it); |
||
833 |
|||
834 |
return it; |
||
835 |
} |
||
836 |
|||
837 |
struct itype * |
||
838 |
parse_enum(struct dwdie *die, size_t psz) |
||
839 |
{ |
||
840 |
struct itype *it; |
||
841 |
struct dwaval *dav; |
||
842 |
const char *name = NULL; |
||
843 |
size_t size = 0; |
||
844 |
|||
845 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
||
846 |
switch (dav->dav_dat->dat_attr) { |
||
847 |
case DW_AT_byte_size: |
||
848 |
size = dav2val(dav, psz); |
||
849 |
assert(size < UINT_MAX); |
||
850 |
break; |
||
851 |
case DW_AT_name: |
||
852 |
name = dav2str(dav); |
||
853 |
break; |
||
854 |
default: |
||
855 |
DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr)); |
||
856 |
break; |
||
857 |
} |
||
858 |
} |
||
859 |
|||
860 |
it = it_new(++tidx, die->die_offset, name, size, 0, 0, CTF_K_ENUM, 0); |
||
861 |
|||
862 |
subparse_enumerator(die, psz, it); |
||
863 |
|||
864 |
return it; |
||
865 |
} |
||
866 |
|||
867 |
void |
||
868 |
subparse_subrange(struct dwdie *die, size_t psz, struct itype *it) |
||
869 |
{ |
||
870 |
struct dwaval *dav; |
||
871 |
|||
872 |
assert(it->it_type == CTF_K_ARRAY); |
||
873 |
|||
874 |
if (die->die_dab->dab_children == DW_CHILDREN_no) |
||
875 |
return; |
||
876 |
|||
877 |
/* |
||
878 |
* This loop assumes that the children of a DIE are just |
||
879 |
* after it on the list. |
||
880 |
*/ |
||
881 |
while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) { |
||
882 |
uint64_t tag = die->die_dab->dab_tag; |
||
883 |
size_t nelems = 0; |
||
884 |
|||
885 |
if (tag != DW_TAG_subrange_type) |
||
886 |
break; |
||
887 |
|||
888 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
||
889 |
switch (dav->dav_dat->dat_attr) { |
||
890 |
case DW_AT_count: |
||
891 |
nelems = dav2val(dav, psz); |
||
892 |
break; |
||
893 |
case DW_AT_upper_bound: |
||
894 |
nelems = dav2val(dav, psz) + 1; |
||
895 |
break; |
||
896 |
default: |
||
897 |
DPRINTF("%s\n", |
||
898 |
dw_at2name(dav->dav_dat->dat_attr)); |
||
899 |
break; |
||
900 |
} |
||
901 |
} |
||
902 |
|||
903 |
assert(nelems < UINT_MAX); |
||
904 |
it->it_nelems = nelems; |
||
905 |
} |
||
906 |
} |
||
907 |
|||
908 |
void |
||
909 |
subparse_enumerator(struct dwdie *die, size_t psz, struct itype *it) |
||
910 |
{ |
||
911 |
struct imember *im; |
||
912 |
struct dwaval *dav; |
||
913 |
|||
914 |
assert(it->it_type == CTF_K_ENUM); |
||
915 |
|||
916 |
if (die->die_dab->dab_children == DW_CHILDREN_no) |
||
917 |
return; |
||
918 |
|||
919 |
/* |
||
920 |
* This loop assumes that the children of a DIE are just |
||
921 |
* after it on the list. |
||
922 |
*/ |
||
923 |
while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) { |
||
924 |
uint64_t tag = die->die_dab->dab_tag; |
||
925 |
size_t val = 0; |
||
926 |
const char *name = NULL; |
||
927 |
|||
928 |
if (tag != DW_TAG_enumerator) |
||
929 |
break; |
||
930 |
|||
931 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
||
932 |
switch (dav->dav_dat->dat_attr) { |
||
933 |
case DW_AT_name: |
||
934 |
name = dav2str(dav); |
||
935 |
break; |
||
936 |
case DW_AT_const_value: |
||
937 |
val = dav2val(dav, psz); |
||
938 |
break; |
||
939 |
default: |
||
940 |
DPRINTF("%s\n", |
||
941 |
dw_at2name(dav->dav_dat->dat_attr)); |
||
942 |
break; |
||
943 |
} |
||
944 |
} |
||
945 |
|||
946 |
if (name == NULL) { |
||
947 |
warnx("%s with anon member", it_name(it)); |
||
948 |
continue; |
||
949 |
} |
||
950 |
|||
951 |
im = im_new(name, val, 0); |
||
952 |
assert(it->it_nelems < UINT_MAX); |
||
953 |
it->it_nelems++; |
||
954 |
TAILQ_INSERT_TAIL(&it->it_members, im, im_next); |
||
955 |
} |
||
956 |
} |
||
957 |
|||
958 |
struct itype * |
||
959 |
parse_struct(struct dwdie *die, size_t psz, int type, size_t off) |
||
960 |
{ |
||
961 |
struct itype *it = NULL; |
||
962 |
struct dwaval *dav; |
||
963 |
const char *name = NULL; |
||
964 |
size_t size = 0; |
||
965 |
|||
966 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
||
967 |
switch (dav->dav_dat->dat_attr) { |
||
968 |
case DW_AT_byte_size: |
||
969 |
size = dav2val(dav, psz); |
||
970 |
assert(size < UINT_MAX); |
||
971 |
break; |
||
972 |
case DW_AT_name: |
||
973 |
name = dav2str(dav); |
||
974 |
break; |
||
975 |
default: |
||
976 |
DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr)); |
||
977 |
break; |
||
978 |
} |
||
979 |
} |
||
980 |
|||
981 |
it = it_new(++tidx, die->die_offset, name, size, 0, 0, type, 0); |
||
982 |
|||
983 |
subparse_member(die, psz, it, off); |
||
984 |
|||
985 |
return it; |
||
986 |
} |
||
987 |
|||
988 |
void |
||
989 |
subparse_member(struct dwdie *die, size_t psz, struct itype *it, size_t offset) |
||
990 |
{ |
||
991 |
struct imember *im; |
||
992 |
struct dwaval *dav; |
||
993 |
const char *name; |
||
994 |
size_t off = 0, ref = 0, bits = 0; |
||
995 |
uint8_t lvl = die->die_lvl; |
||
996 |
|||
997 |
assert(it->it_type == CTF_K_STRUCT || it->it_type == CTF_K_UNION); |
||
998 |
|||
999 |
if (die->die_dab->dab_children == DW_CHILDREN_no) |
||
1000 |
return; |
||
1001 |
|||
1002 |
/* |
||
1003 |
* This loop assumes that the children of a DIE are just |
||
1004 |
* after it on the list. |
||
1005 |
*/ |
||
1006 |
while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) { |
||
1007 |
int64_t tag = die->die_dab->dab_tag; |
||
1008 |
|||
1009 |
name = NULL; |
||
1010 |
if (die->die_lvl <= lvl) |
||
1011 |
break; |
||
1012 |
|||
1013 |
/* Skip members of members */ |
||
1014 |
if (die->die_lvl > lvl + 1) |
||
1015 |
continue; |
||
1016 |
/* |
||
1017 |
* Nested declaration. |
||
1018 |
* |
||
1019 |
* This matches the case where a ``struct'', ``union'', |
||
1020 |
* ``enum'' or ``typedef'' is first declared "inside" a |
||
1021 |
* union or struct declaration. |
||
1022 |
*/ |
||
1023 |
if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type || |
||
1024 |
tag == DW_TAG_enumeration_type || tag == DW_TAG_typedef) |
||
1025 |
continue; |
||
1026 |
|||
1027 |
it->it_flags |= ITF_UNRES_MEMB; |
||
1028 |
|||
1029 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
||
1030 |
switch (dav->dav_dat->dat_attr) { |
||
1031 |
case DW_AT_name: |
||
1032 |
name = dav2str(dav); |
||
1033 |
break; |
||
1034 |
case DW_AT_type: |
||
1035 |
ref = dav2val(dav, psz); |
||
1036 |
break; |
||
1037 |
case DW_AT_data_member_location: |
||
1038 |
off = 8 * dav2val(dav, psz); |
||
1039 |
break; |
||
1040 |
case DW_AT_bit_size: |
||
1041 |
bits = dav2val(dav, psz); |
||
1042 |
assert(bits < USHRT_MAX); |
||
1043 |
break; |
||
1044 |
default: |
||
1045 |
DPRINTF("%s\n", |
||
1046 |
dw_at2name(dav->dav_dat->dat_attr)); |
||
1047 |
break; |
||
1048 |
} |
||
1049 |
} |
||
1050 |
|||
1051 |
/* |
||
1052 |
* When a structure is declared inside an union, we |
||
1053 |
* have to generate a reference to make the resolver |
||
1054 |
* happy. |
||
1055 |
*/ |
||
1056 |
if ((ref == 0) && (tag == DW_TAG_structure_type)) |
||
1057 |
ref = die->die_offset - offset; |
||
1058 |
|||
1059 |
im = im_new(name, ref, off); |
||
1060 |
assert(it->it_nelems < UINT_MAX); |
||
1061 |
it->it_nelems++; |
||
1062 |
TAILQ_INSERT_TAIL(&it->it_members, im, im_next); |
||
1063 |
} |
||
1064 |
} |
||
1065 |
|||
1066 |
|||
1067 |
void |
||
1068 |
subparse_arguments(struct dwdie *die, size_t psz, struct itype *it) |
||
1069 |
{ |
||
1070 |
struct imember *im; |
||
1071 |
struct dwaval *dav; |
||
1072 |
size_t ref = 0; |
||
1073 |
|||
1074 |
✗✓ | 4 |
assert(it->it_type == CTF_K_FUNCTION); |
1075 |
|||
1076 |
✗✓ | 2 |
if (die->die_dab->dab_children == DW_CHILDREN_no) |
1077 |
return; |
||
1078 |
|||
1079 |
/* |
||
1080 |
* This loop assumes that the children of a DIE are after it |
||
1081 |
* on the list. |
||
1082 |
*/ |
||
1083 |
✓✗ | 6 |
while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) { |
1084 |
6 |
uint64_t tag = die->die_dab->dab_tag; |
|
1085 |
|||
1086 |
✗✓ | 6 |
if (tag == DW_TAG_unspecified_parameters) { |
1087 |
it->it_flags |= ITF_VARARGS; |
||
1088 |
continue; |
||
1089 |
} |
||
1090 |
|||
1091 |
/* |
||
1092 |
* Nested declaration. |
||
1093 |
* |
||
1094 |
* This matches the case where a ``struct'', ``union'', |
||
1095 |
* ``enum'' or ``typedef'' is first declared "inside" a |
||
1096 |
* function declaration. |
||
1097 |
*/ |
||
1098 |
✗✓ | 18 |
if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type || |
1099 |
12 |
tag == DW_TAG_enumeration_type || tag == DW_TAG_typedef) |
|
1100 |
continue; |
||
1101 |
|||
1102 |
✓✓ | 6 |
if (tag != DW_TAG_formal_parameter) |
1103 |
2 |
break; |
|
1104 |
|||
1105 |
4 |
it->it_flags |= ITF_UNRES_MEMB; |
|
1106 |
|||
1107 |
✓✓ | 48 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
1108 |
✓✓ | 20 |
switch (dav->dav_dat->dat_attr) { |
1109 |
case DW_AT_type: |
||
1110 |
4 |
ref = dav2val(dav, psz); |
|
1111 |
4 |
break; |
|
1112 |
default: |
||
1113 |
DPRINTF("%s\n", |
||
1114 |
dw_at2name(dav->dav_dat->dat_attr)); |
||
1115 |
break; |
||
1116 |
} |
||
1117 |
} |
||
1118 |
|||
1119 |
4 |
im = im_new(NULL, ref, 0); |
|
1120 |
✗✓ | 4 |
assert(it->it_nelems < UINT_MAX); |
1121 |
4 |
it->it_nelems++; |
|
1122 |
4 |
TAILQ_INSERT_TAIL(&it->it_members, im, im_next); |
|
1123 |
✓✓ | 4 |
} |
1124 |
4 |
} |
|
1125 |
|||
1126 |
struct itype * |
||
1127 |
parse_function(struct dwdie *die, size_t psz) |
||
1128 |
{ |
||
1129 |
struct itype *it; |
||
1130 |
struct dwaval *dav; |
||
1131 |
const char *name = NULL; |
||
1132 |
size_t ref = 0; |
||
1133 |
|||
1134 |
✓✓ | 42 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
1135 |
✓✓✗✓ |
22 |
switch (dav->dav_dat->dat_attr) { |
1136 |
case DW_AT_name: |
||
1137 |
2 |
name = dav2str(dav); |
|
1138 |
2 |
break; |
|
1139 |
case DW_AT_type: |
||
1140 |
2 |
ref = dav2val(dav, psz); |
|
1141 |
2 |
break; |
|
1142 |
case DW_AT_abstract_origin: |
||
1143 |
/* |
||
1144 |
* Skip second empty definition for inline |
||
1145 |
* functions. |
||
1146 |
*/ |
||
1147 |
return NULL; |
||
1148 |
default: |
||
1149 |
DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr)); |
||
1150 |
break; |
||
1151 |
} |
||
1152 |
} |
||
1153 |
|||
1154 |
/* |
||
1155 |
* Work around for clang 4.0 generating DW_TAG_subprogram without |
||
1156 |
* any attribute. |
||
1157 |
*/ |
||
1158 |
✗✓ | 2 |
if (name == NULL) |
1159 |
return NULL; |
||
1160 |
|||
1161 |
2 |
it = it_new(++fidx, die->die_offset, name, 0, 0, ref, CTF_K_FUNCTION, |
|
1162 |
ITF_UNRES|ITF_FUNC); |
||
1163 |
|||
1164 |
2 |
subparse_arguments(die, psz, it); |
|
1165 |
|||
1166 |
✗✓ | 2 |
if (it->it_ref == 0) { |
1167 |
/* Work around GCC not emiting a type for void */ |
||
1168 |
it->it_flags &= ~ITF_UNRES; |
||
1169 |
it->it_ref = VOID_OFFSET; |
||
1170 |
it->it_refp = void_it; |
||
1171 |
} |
||
1172 |
|||
1173 |
2 |
return it; |
|
1174 |
2 |
} |
|
1175 |
|||
1176 |
struct itype * |
||
1177 |
parse_funcptr(struct dwdie *die, size_t psz) |
||
1178 |
{ |
||
1179 |
struct itype *it; |
||
1180 |
struct dwaval *dav; |
||
1181 |
const char *name = NULL; |
||
1182 |
size_t ref = 0; |
||
1183 |
|||
1184 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
||
1185 |
switch (dav->dav_dat->dat_attr) { |
||
1186 |
case DW_AT_name: |
||
1187 |
name = dav2str(dav); |
||
1188 |
break; |
||
1189 |
case DW_AT_type: |
||
1190 |
ref = dav2val(dav, psz); |
||
1191 |
break; |
||
1192 |
default: |
||
1193 |
DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr)); |
||
1194 |
break; |
||
1195 |
} |
||
1196 |
} |
||
1197 |
|||
1198 |
it = it_new(++tidx, die->die_offset, name, 0, 0, ref, CTF_K_FUNCTION, |
||
1199 |
ITF_UNRES); |
||
1200 |
|||
1201 |
subparse_arguments(die, psz, it); |
||
1202 |
|||
1203 |
if (it->it_ref == 0) { |
||
1204 |
/* Work around GCC not emiting a type for void */ |
||
1205 |
it->it_flags &= ~ITF_UNRES; |
||
1206 |
it->it_ref = VOID_OFFSET; |
||
1207 |
it->it_refp = void_it; |
||
1208 |
} |
||
1209 |
|||
1210 |
return it; |
||
1211 |
} |
||
1212 |
|||
1213 |
struct itype * |
||
1214 |
parse_variable(struct dwdie *die, size_t psz) |
||
1215 |
{ |
||
1216 |
struct itype *it = NULL; |
||
1217 |
struct dwaval *dav; |
||
1218 |
const char *name = NULL; |
||
1219 |
size_t ref = 0; |
||
1220 |
int declaration = 0; |
||
1221 |
|||
1222 |
✓✓ | 180 |
SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) { |
1223 |
✗✓✓✓ |
96 |
switch (dav->dav_dat->dat_attr) { |
1224 |
case DW_AT_declaration: |
||
1225 |
declaration = dav2val(dav, psz); |
||
1226 |
break; |
||
1227 |
case DW_AT_name: |
||
1228 |
12 |
name = dav2str(dav); |
|
1229 |
12 |
break; |
|
1230 |
case DW_AT_type: |
||
1231 |
12 |
ref = dav2val(dav, psz); |
|
1232 |
12 |
break; |
|
1233 |
default: |
||
1234 |
DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr)); |
||
1235 |
break; |
||
1236 |
} |
||
1237 |
} |
||
1238 |
|||
1239 |
|||
1240 |
✓✗ | 12 |
if (!declaration && name != NULL) { |
1241 |
12 |
it = it_new(++oidx, die->die_offset, name, 0, 0, ref, 0, |
|
1242 |
ITF_UNRES|ITF_OBJ); |
||
1243 |
12 |
} |
|
1244 |
|||
1245 |
12 |
return it; |
|
1246 |
} |
||
1247 |
|||
1248 |
size_t |
||
1249 |
dav2val(struct dwaval *dav, size_t psz) |
||
1250 |
{ |
||
1251 |
150 |
uint64_t val = (uint64_t)-1; |
|
1252 |
|||
1253 |
✗✗✗✗ ✗✗✗✗ ✓✗✗✗ ✓✗✗✗ ✗✗✓ |
100 |
switch (dav->dav_dat->dat_form) { |
1254 |
case DW_FORM_addr: |
||
1255 |
case DW_FORM_ref_addr: |
||
1256 |
if (psz == sizeof(uint32_t)) |
||
1257 |
val = dav->dav_u32; |
||
1258 |
else |
||
1259 |
val = dav->dav_u64; |
||
1260 |
break; |
||
1261 |
case DW_FORM_block1: |
||
1262 |
case DW_FORM_block2: |
||
1263 |
case DW_FORM_block4: |
||
1264 |
case DW_FORM_block: |
||
1265 |
dw_loc_parse(&dav->dav_buf, NULL, &val, NULL); |
||
1266 |
break; |
||
1267 |
case DW_FORM_flag: |
||
1268 |
case DW_FORM_data1: |
||
1269 |
case DW_FORM_ref1: |
||
1270 |
28 |
val = dav->dav_u8; |
|
1271 |
28 |
break; |
|
1272 |
case DW_FORM_data2: |
||
1273 |
case DW_FORM_ref2: |
||
1274 |
val = dav->dav_u16; |
||
1275 |
break; |
||
1276 |
case DW_FORM_data4: |
||
1277 |
case DW_FORM_ref4: |
||
1278 |
22 |
val = dav->dav_u32; |
|
1279 |
22 |
break; |
|
1280 |
case DW_FORM_sdata: |
||
1281 |
case DW_FORM_data8: |
||
1282 |
case DW_FORM_ref8: |
||
1283 |
val = dav->dav_u64; |
||
1284 |
break; |
||
1285 |
case DW_FORM_strp: |
||
1286 |
val = dav->dav_u32; |
||
1287 |
break; |
||
1288 |
case DW_FORM_flag_present: |
||
1289 |
val = 1; |
||
1290 |
break; |
||
1291 |
default: |
||
1292 |
break; |
||
1293 |
} |
||
1294 |
|||
1295 |
100 |
return val; |
|
1296 |
50 |
} |
|
1297 |
|||
1298 |
const char * |
||
1299 |
dav2str(struct dwaval *dav) |
||
1300 |
{ |
||
1301 |
const char *str = NULL; |
||
1302 |
extern const char *dstrbuf; |
||
1303 |
extern size_t dstrlen; |
||
1304 |
|||
1305 |
✗✓✓ | 42 |
switch (dav->dav_dat->dat_form) { |
1306 |
case DW_FORM_string: |
||
1307 |
str = dav->dav_str; |
||
1308 |
break; |
||
1309 |
case DW_FORM_strp: |
||
1310 |
✗✓ | 14 |
if (dav->dav_u32 >= dstrlen) |
1311 |
str = NULL; |
||
1312 |
else |
||
1313 |
14 |
str = dstrbuf + dav->dav_u32; |
|
1314 |
break; |
||
1315 |
default: |
||
1316 |
break; |
||
1317 |
} |
||
1318 |
|||
1319 |
14 |
return str; |
|
1320 |
} |
||
1321 |
|||
1322 |
const char * |
||
1323 |
enc2name(unsigned short enc) |
||
1324 |
{ |
||
1325 |
static const char *enc_name[] = { "address", "boolean", "complex float", |
||
1326 |
"float", "signed", "char", "unsigned", "unsigned char", |
||
1327 |
"imaginary float", "packed decimal", "numeric string", "edited", |
||
1328 |
"signed fixed", "unsigned fixed", "decimal float" }; |
||
1329 |
|||
1330 |
✓✗✓✗ |
42 |
if (enc > 0 && enc <= nitems(enc_name)) |
1331 |
14 |
return enc_name[enc - 1]; |
|
1332 |
|||
1333 |
return "invalid"; |
||
1334 |
14 |
} |
Generated by: GCOVR (Version 3.3) |