1*76af8930Sclaudio /* $OpenBSD: parse.c,v 1.20 2024/02/22 13:17:18 claudio Exp $ */
20687c322Sjasper
3192095f7Smpi /*
4192095f7Smpi * Copyright (c) 2016-2017 Martin Pieuchot
5192095f7Smpi * Copyright (c) 2016 Jasper Lievisse Adriaanse <jasper@openbsd.org>
6192095f7Smpi *
7192095f7Smpi * Permission to use, copy, modify, and distribute this software for any
8192095f7Smpi * purpose with or without fee is hereby granted, provided that the above
9192095f7Smpi * copyright notice and this permission notice appear in all copies.
10192095f7Smpi *
11192095f7Smpi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12192095f7Smpi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13192095f7Smpi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14192095f7Smpi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15192095f7Smpi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16192095f7Smpi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17192095f7Smpi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18192095f7Smpi */
19192095f7Smpi
20192095f7Smpi /*
21192095f7Smpi * DWARF to IT (internal type) representation parser.
22192095f7Smpi */
23192095f7Smpi
24192095f7Smpi #include <sys/queue.h>
25192095f7Smpi #include <sys/tree.h>
26a9ec4c35Smpi #include <sys/types.h>
27192095f7Smpi #include <sys/ctf.h>
28192095f7Smpi
29192095f7Smpi #include <assert.h>
302c999465Sderaadt #include <limits.h>
31192095f7Smpi #include <err.h>
32192095f7Smpi #include <stdlib.h>
33192095f7Smpi #include <string.h>
34192095f7Smpi
35192095f7Smpi #include "itype.h"
36192095f7Smpi #include "xmalloc.h"
37192095f7Smpi #include "dwarf.h"
38192095f7Smpi #include "dw.h"
39192095f7Smpi #include "pool.h"
40192095f7Smpi
41192095f7Smpi #ifdef DEBUG
42192095f7Smpi #include <stdio.h>
43192095f7Smpi #endif
44192095f7Smpi
45192095f7Smpi #ifndef NOPOOL
46192095f7Smpi struct pool it_pool, im_pool, ir_pool;
47192095f7Smpi #endif /* NOPOOL */
48192095f7Smpi
49a9ec4c35Smpi #ifndef nitems
50a9ec4c35Smpi #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
51a9ec4c35Smpi #endif
52a9ec4c35Smpi
5378f4e5a0Sclaudio #ifdef DEBUG
5478f4e5a0Sclaudio #define DPRINTF(x...) do { printf(x); } while (0)
5578f4e5a0Sclaudio #else
5678f4e5a0Sclaudio #define DPRINTF(x...) do { ; } while (0)
5778f4e5a0Sclaudio #endif
58192095f7Smpi
59192095f7Smpi #define VOID_OFFSET 1 /* Fake offset for generating "void" type. */
60192095f7Smpi
61192095f7Smpi /*
62192095f7Smpi * Tree used to resolve per-CU types based on their offset in
63192095f7Smpi * the abbrev section.
64192095f7Smpi */
65192095f7Smpi RB_HEAD(ioff_tree, itype);
66192095f7Smpi
67192095f7Smpi /*
68c02203f9Smpi * Per-type trees used to merge existing types with the ones of
69192095f7Smpi * a newly parsed CU.
70192095f7Smpi */
71192095f7Smpi RB_HEAD(itype_tree, itype) itypet[CTF_K_MAX];
72192095f7Smpi
73192095f7Smpi /*
74192095f7Smpi * Tree of symbols used to build a list matching the order of
75192095f7Smpi * the ELF symbol table.
76192095f7Smpi */
77192095f7Smpi struct isymb_tree isymbt;
78192095f7Smpi
795c036317Sjmc struct itype *void_it; /* no type is emited for void */
80192095f7Smpi uint16_t tidx, fidx, oidx; /* type, func & object IDs */
81192095f7Smpi uint16_t long_tidx; /* index of "long", for array */
82192095f7Smpi
83192095f7Smpi
84192095f7Smpi void cu_stat(void);
85192095f7Smpi void cu_parse(struct dwcu *, struct itype_queue *,
86192095f7Smpi struct ioff_tree *);
87192095f7Smpi void cu_resolve(struct dwcu *, struct itype_queue *,
88192095f7Smpi struct ioff_tree *);
89192095f7Smpi void cu_reference(struct dwcu *, struct itype_queue *);
90192095f7Smpi void cu_merge(struct dwcu *, struct itype_queue *);
91192095f7Smpi
92192095f7Smpi struct itype *parse_base(struct dwdie *, size_t);
93192095f7Smpi struct itype *parse_refers(struct dwdie *, size_t, int);
94192095f7Smpi struct itype *parse_array(struct dwdie *, size_t);
95192095f7Smpi struct itype *parse_enum(struct dwdie *, size_t);
96192095f7Smpi struct itype *parse_struct(struct dwdie *, size_t, int, size_t);
97192095f7Smpi struct itype *parse_function(struct dwdie *, size_t);
98192095f7Smpi struct itype *parse_funcptr(struct dwdie *, size_t);
99192095f7Smpi struct itype *parse_variable(struct dwdie *, size_t);
100192095f7Smpi
101192095f7Smpi void subparse_subrange(struct dwdie *, size_t, struct itype *);
102192095f7Smpi void subparse_enumerator(struct dwdie *, size_t, struct itype *);
103192095f7Smpi void subparse_member(struct dwdie *, size_t, struct itype *, size_t);
104192095f7Smpi void subparse_arguments(struct dwdie *, size_t, struct itype *);
105192095f7Smpi
106192095f7Smpi size_t dav2val(struct dwaval *, size_t);
107192095f7Smpi const char *dav2str(struct dwaval *);
108192095f7Smpi const char *enc2name(unsigned short);
109192095f7Smpi
110192095f7Smpi struct itype *it_new(uint64_t, size_t, const char *, uint32_t, uint16_t,
111192095f7Smpi uint64_t, uint16_t, unsigned int);
1121657e891Smpi void it_merge(struct itype *, struct itype *);
113192095f7Smpi void it_reference(struct itype *);
114192095f7Smpi void it_free(struct itype *);
115192095f7Smpi int it_cmp(struct itype *, struct itype *);
116192095f7Smpi int it_name_cmp(struct itype *, struct itype *);
117192095f7Smpi int it_off_cmp(struct itype *, struct itype *);
118192095f7Smpi void ir_add(struct itype *, struct itype *);
119192095f7Smpi void ir_purge(struct itype *);
120192095f7Smpi struct imember *im_new(const char *, size_t, size_t);
121192095f7Smpi
122192095f7Smpi RB_GENERATE(itype_tree, itype, it_node, it_cmp);
123192095f7Smpi RB_GENERATE(isymb_tree, itype, it_node, it_name_cmp);
124192095f7Smpi RB_GENERATE(ioff_tree, itype, it_node, it_off_cmp);
125192095f7Smpi
126192095f7Smpi /*
127192095f7Smpi * Construct a list of internal type and functions based on DWARF
128192095f7Smpi * INFO and ABBREV sections.
129192095f7Smpi *
130192095f7Smpi * Multiple CUs are supported.
131192095f7Smpi */
132192095f7Smpi void
dwarf_parse(const char * infobuf,size_t infolen,const char * abbuf,size_t ablen)133192095f7Smpi dwarf_parse(const char *infobuf, size_t infolen, const char *abbuf,
134192095f7Smpi size_t ablen)
135192095f7Smpi {
136192095f7Smpi struct dwbuf info = { .buf = infobuf, .len = infolen };
137192095f7Smpi struct dwbuf abbrev = { .buf = abbuf, .len = ablen };
138192095f7Smpi struct dwcu *dcu = NULL;
139192095f7Smpi struct ioff_tree cu_iofft;
140192095f7Smpi struct itype_queue cu_itypeq;
141192095f7Smpi struct itype *it;
142192095f7Smpi int i;
143192095f7Smpi
144192095f7Smpi for (i = 0; i < CTF_K_MAX; i++)
145192095f7Smpi RB_INIT(&itypet[i]);
146192095f7Smpi RB_INIT(&isymbt);
147192095f7Smpi
148192095f7Smpi void_it = it_new(++tidx, VOID_OFFSET, "void", 0,
149192095f7Smpi CTF_INT_SIGNED, 0, CTF_K_INTEGER, 0);
150192095f7Smpi TAILQ_INSERT_TAIL(&itypeq, void_it, it_next);
151192095f7Smpi
152192095f7Smpi while (dw_cu_parse(&info, &abbrev, infolen, &dcu) == 0) {
153192095f7Smpi TAILQ_INIT(&cu_itypeq);
154c02203f9Smpi
155c02203f9Smpi /* We use a tree to speed-up type resolution. */
156192095f7Smpi RB_INIT(&cu_iofft);
157192095f7Smpi
158192095f7Smpi /* Parse this CU */
159192095f7Smpi cu_parse(dcu, &cu_itypeq, &cu_iofft);
160192095f7Smpi
161192095f7Smpi /* Resolve its types. */
162192095f7Smpi cu_resolve(dcu, &cu_itypeq, &cu_iofft);
163192095f7Smpi assert(RB_EMPTY(&cu_iofft));
164192095f7Smpi
165192095f7Smpi /* Mark used type as such. */
166192095f7Smpi cu_reference(dcu, &cu_itypeq);
167192095f7Smpi
168192095f7Smpi #ifdef DEBUG
169192095f7Smpi /* Dump statistics for current CU. */
170192095f7Smpi cu_stat();
171192095f7Smpi #endif
172192095f7Smpi
173192095f7Smpi /* Merge them with the common type list. */
174192095f7Smpi cu_merge(dcu, &cu_itypeq);
175192095f7Smpi
176192095f7Smpi dw_dcu_free(dcu);
177192095f7Smpi }
178192095f7Smpi
179192095f7Smpi /* We force array's index type to be 'long', for that we need its ID. */
180192095f7Smpi RB_FOREACH(it, itype_tree, &itypet[CTF_K_INTEGER]) {
181192095f7Smpi if (it_name(it) == NULL || it->it_size != (8 * sizeof(long)))
182192095f7Smpi continue;
183192095f7Smpi
184192095f7Smpi if (strcmp(it_name(it), "unsigned") == 0) {
185192095f7Smpi long_tidx = it->it_idx;
186192095f7Smpi break;
187192095f7Smpi }
188192095f7Smpi }
189192095f7Smpi }
190192095f7Smpi
191192095f7Smpi struct itype *
it_new(uint64_t index,size_t off,const char * name,uint32_t size,uint16_t enc,uint64_t ref,uint16_t type,unsigned int flags)192192095f7Smpi it_new(uint64_t index, size_t off, const char *name, uint32_t size,
193192095f7Smpi uint16_t enc, uint64_t ref, uint16_t type, unsigned int flags)
194192095f7Smpi {
195192095f7Smpi struct itype *it;
196192095f7Smpi #ifndef NOPOOL
197192095f7Smpi static int it_pool_inited = 0;
198192095f7Smpi
199192095f7Smpi if (!it_pool_inited) {
200192095f7Smpi pool_init(&it_pool, "it", 512, sizeof(struct itype));
201192095f7Smpi pool_init(&im_pool, "im", 1024, sizeof(struct imember));
202192095f7Smpi pool_init(&ir_pool, "ir", 1024, sizeof(struct itref));
203192095f7Smpi it_pool_inited = 1;
204192095f7Smpi }
205192095f7Smpi #endif
206192095f7Smpi
207192095f7Smpi assert((name != NULL) || !(flags & (ITF_FUNC|ITF_OBJ)));
208192095f7Smpi
209192095f7Smpi it = pmalloc(&it_pool, sizeof(*it));
210192095f7Smpi SIMPLEQ_INIT(&it->it_refs);
211192095f7Smpi TAILQ_INIT(&it->it_members);
212192095f7Smpi it->it_off = off;
213192095f7Smpi it->it_ref = ref;
214192095f7Smpi it->it_refp = NULL;
215192095f7Smpi it->it_size = size;
216192095f7Smpi it->it_nelems = 0;
217192095f7Smpi it->it_enc = enc;
218192095f7Smpi it->it_idx = index;
219192095f7Smpi it->it_type = type;
220192095f7Smpi it->it_flags = flags;
221192095f7Smpi
222192095f7Smpi if (name == NULL) {
223192095f7Smpi it->it_flags |= ITF_ANON;
224192095f7Smpi } else {
225192095f7Smpi size_t n;
226192095f7Smpi
227192095f7Smpi if ((n = strlcpy(it->it_name, name, ITNAME_MAX)) > ITNAME_MAX)
228192095f7Smpi warnx("name %s too long %zd > %d", name, n, ITNAME_MAX);
229192095f7Smpi }
230192095f7Smpi
231192095f7Smpi return it;
232192095f7Smpi }
233192095f7Smpi
234192095f7Smpi struct itype *
it_dup(struct itype * it)235192095f7Smpi it_dup(struct itype *it)
236192095f7Smpi {
237192095f7Smpi struct imember *copim, *im;
238192095f7Smpi struct itype *copit;
239192095f7Smpi
240192095f7Smpi copit = it_new(it->it_idx, it->it_off, it_name(it), it->it_size,
241192095f7Smpi it->it_enc, it->it_ref, it->it_type, it->it_flags);
242192095f7Smpi
243192095f7Smpi copit->it_refp = it->it_refp;
244192095f7Smpi copit->it_nelems = it->it_nelems;
245192095f7Smpi
246192095f7Smpi TAILQ_FOREACH(im, &it->it_members, im_next) {
24772c906afSmpi copim = im_new(im_name(im), im->im_ref, im->im_off);
248192095f7Smpi copim->im_refp = im->im_refp;
249192095f7Smpi TAILQ_INSERT_TAIL(&copit->it_members, copim, im_next);
250192095f7Smpi }
251192095f7Smpi
252192095f7Smpi return copit;
253192095f7Smpi }
254192095f7Smpi
2551657e891Smpi /*
2561657e891Smpi * Merge the content of ``it'', the full type declaration into the
2571657e891Smpi * forwarding representation ``fwd''.
2581657e891Smpi */
2591657e891Smpi void
it_merge(struct itype * fwd,struct itype * it)2601657e891Smpi it_merge(struct itype *fwd, struct itype *it)
2611657e891Smpi {
2621657e891Smpi assert(fwd->it_flags & ITF_FORWARD);
2631657e891Smpi assert(fwd->it_type == it->it_type);
2641657e891Smpi assert(TAILQ_EMPTY(&fwd->it_members));
2651657e891Smpi assert(SIMPLEQ_EMPTY(&it->it_refs));
2661657e891Smpi
2671657e891Smpi fwd->it_off = it->it_off;
2681657e891Smpi fwd->it_ref = it->it_ref;
2691657e891Smpi fwd->it_refp = it->it_refp;
2701657e891Smpi fwd->it_size = it->it_size;
2711657e891Smpi fwd->it_nelems = it->it_nelems;
2721657e891Smpi fwd->it_enc = it->it_enc;
2731657e891Smpi fwd->it_flags = it->it_flags;
2741657e891Smpi
2751657e891Smpi TAILQ_CONCAT(&fwd->it_members, &it->it_members, im_next);
2761657e891Smpi assert(TAILQ_EMPTY(&it->it_members));
2771657e891Smpi }
2781657e891Smpi
279192095f7Smpi const char *
it_name(struct itype * it)280192095f7Smpi it_name(struct itype *it)
281192095f7Smpi {
282192095f7Smpi if (!(it->it_flags & ITF_ANON))
283192095f7Smpi return it->it_name;
284192095f7Smpi
285192095f7Smpi return NULL;
286192095f7Smpi }
287192095f7Smpi
288192095f7Smpi void
it_reference(struct itype * it)289192095f7Smpi it_reference(struct itype *it)
290192095f7Smpi {
291192095f7Smpi struct imember *im;
292192095f7Smpi
293192095f7Smpi if (it == NULL || it->it_flags & ITF_USED)
294192095f7Smpi return;
295192095f7Smpi
296192095f7Smpi it->it_flags |= ITF_USED;
297192095f7Smpi
298192095f7Smpi it_reference(it->it_refp);
299192095f7Smpi TAILQ_FOREACH(im, &it->it_members, im_next)
300192095f7Smpi it_reference(im->im_refp);
301192095f7Smpi }
302192095f7Smpi
303192095f7Smpi void
it_free(struct itype * it)304192095f7Smpi it_free(struct itype *it)
305192095f7Smpi {
306192095f7Smpi struct imember *im;
307192095f7Smpi
308192095f7Smpi if (it == NULL)
309192095f7Smpi return;
310192095f7Smpi
311192095f7Smpi while ((im = TAILQ_FIRST(&it->it_members)) != NULL) {
312192095f7Smpi TAILQ_REMOVE(&it->it_members, im, im_next);
313192095f7Smpi pfree(&im_pool, im);
314192095f7Smpi }
315192095f7Smpi
316192095f7Smpi ir_purge(it);
317192095f7Smpi pfree(&it_pool, it);
318192095f7Smpi }
319192095f7Smpi
320192095f7Smpi /*
321192095f7Smpi * Return 0 if ``a'' matches ``b''.
322192095f7Smpi */
323192095f7Smpi int
it_cmp(struct itype * a,struct itype * b)324192095f7Smpi it_cmp(struct itype *a, struct itype *b)
325192095f7Smpi {
326*76af8930Sclaudio if (a->it_type > b->it_type)
327*76af8930Sclaudio return 1;
328*76af8930Sclaudio if (a->it_type < b->it_type)
329*76af8930Sclaudio return -1;
330192095f7Smpi
331*76af8930Sclaudio /* Basic types need to have the same encoding and size. */
332*76af8930Sclaudio if ((a->it_type == CTF_K_INTEGER || a->it_type == CTF_K_FLOAT)) {
333*76af8930Sclaudio if (a->it_enc > b->it_enc)
334*76af8930Sclaudio return 1;
335*76af8930Sclaudio if (a->it_enc < b->it_enc)
336*76af8930Sclaudio return -1;
337*76af8930Sclaudio if (a->it_size > b->it_size)
338*76af8930Sclaudio return 1;
339*76af8930Sclaudio if (a->it_size < b->it_size)
340*76af8930Sclaudio return -1;
341*76af8930Sclaudio }
3420ed49adfSmpi
3438a1eddeaSclaudio /* Arrays need to have same number of elements */
344*76af8930Sclaudio if (a->it_type == CTF_K_ARRAY) {
345*76af8930Sclaudio if (a->it_nelems > b->it_nelems)
346*76af8930Sclaudio return 1;
347*76af8930Sclaudio if (a->it_nelems < b->it_nelems)
348*76af8930Sclaudio return -1;
349*76af8930Sclaudio }
3508a1eddeaSclaudio
351192095f7Smpi /* Match by name */
352192095f7Smpi if (!(a->it_flags & ITF_ANON) && !(b->it_flags & ITF_ANON))
353192095f7Smpi return strcmp(it_name(a), it_name(b));
354192095f7Smpi
355192095f7Smpi /* Only one of them is anonym */
356192095f7Smpi if ((a->it_flags & ITF_ANON) != (b->it_flags & ITF_ANON))
357192095f7Smpi return (a->it_flags & ITF_ANON) ? -1 : 1;
358192095f7Smpi
359192095f7Smpi /* Match by reference */
360192095f7Smpi if ((a->it_refp != NULL) && (b->it_refp != NULL))
361192095f7Smpi return it_cmp(a->it_refp, b->it_refp);
362*76af8930Sclaudio if (a->it_refp == NULL)
363*76af8930Sclaudio return -1;
364*76af8930Sclaudio if (b->it_refp == NULL)
365*76af8930Sclaudio return 1;
366192095f7Smpi
3678a1eddeaSclaudio return 0;
368192095f7Smpi }
369192095f7Smpi
370192095f7Smpi int
it_name_cmp(struct itype * a,struct itype * b)371192095f7Smpi it_name_cmp(struct itype *a, struct itype *b)
372192095f7Smpi {
373192095f7Smpi int diff;
374192095f7Smpi
375192095f7Smpi if ((diff = strcmp(it_name(a), it_name(b))) != 0)
376192095f7Smpi return diff;
377192095f7Smpi
378192095f7Smpi return ((a->it_flags|ITF_MASK) - (b->it_flags|ITF_MASK));
379192095f7Smpi }
380192095f7Smpi
381192095f7Smpi int
it_off_cmp(struct itype * a,struct itype * b)382192095f7Smpi it_off_cmp(struct itype *a, struct itype *b)
383192095f7Smpi {
384192095f7Smpi return a->it_off - b->it_off;
385192095f7Smpi }
386192095f7Smpi
387192095f7Smpi void
ir_add(struct itype * it,struct itype * tmp)388192095f7Smpi ir_add(struct itype *it, struct itype *tmp)
389192095f7Smpi {
390192095f7Smpi struct itref *ir;
391192095f7Smpi
392192095f7Smpi SIMPLEQ_FOREACH(ir, &tmp->it_refs, ir_next) {
393192095f7Smpi if (ir->ir_itp == it)
394192095f7Smpi return;
395192095f7Smpi }
396192095f7Smpi
397192095f7Smpi ir = pmalloc(&ir_pool, sizeof(*ir));
398192095f7Smpi ir->ir_itp = it;
399192095f7Smpi SIMPLEQ_INSERT_TAIL(&tmp->it_refs, ir, ir_next);
400192095f7Smpi }
401192095f7Smpi
402192095f7Smpi void
ir_purge(struct itype * it)403192095f7Smpi ir_purge(struct itype *it)
404192095f7Smpi {
405192095f7Smpi struct itref *ir;
406192095f7Smpi
407192095f7Smpi while ((ir = SIMPLEQ_FIRST(&it->it_refs)) != NULL) {
408192095f7Smpi SIMPLEQ_REMOVE_HEAD(&it->it_refs, ir_next);
409192095f7Smpi pfree(&ir_pool, ir);
410192095f7Smpi }
411192095f7Smpi }
412192095f7Smpi
413192095f7Smpi struct imember *
im_new(const char * name,size_t ref,size_t off)414192095f7Smpi im_new(const char *name, size_t ref, size_t off)
415192095f7Smpi {
416192095f7Smpi struct imember *im;
417192095f7Smpi
418192095f7Smpi im = pmalloc(&im_pool, sizeof(*im));
419192095f7Smpi im->im_ref = ref;
420192095f7Smpi im->im_off = off;
421192095f7Smpi im->im_refp = NULL;
422192095f7Smpi if (name == NULL) {
42372c906afSmpi im->im_flags = IMF_ANON;
424192095f7Smpi } else {
425192095f7Smpi size_t n;
426192095f7Smpi
427192095f7Smpi n = strlcpy(im->im_name, name, ITNAME_MAX);
428192095f7Smpi if (n > ITNAME_MAX)
429192095f7Smpi warnx("name %s too long %zd > %d", name, n,
430192095f7Smpi ITNAME_MAX);
431192095f7Smpi im->im_flags = 0;
432192095f7Smpi }
433192095f7Smpi
434192095f7Smpi return im;
435192095f7Smpi }
436192095f7Smpi
43772c906afSmpi const char *
im_name(struct imember * im)43872c906afSmpi im_name(struct imember *im)
43972c906afSmpi {
44072c906afSmpi if (!(im->im_flags & IMF_ANON))
44172c906afSmpi return im->im_name;
44272c906afSmpi
44372c906afSmpi return NULL;
44472c906afSmpi }
44572c906afSmpi
446192095f7Smpi void
cu_stat(void)447192095f7Smpi cu_stat(void)
448192095f7Smpi {
449192095f7Smpi #ifndef NOPOOL
450192095f7Smpi pool_dump();
451192095f7Smpi #endif
452192095f7Smpi }
453c02203f9Smpi
454192095f7Smpi /*
455c02203f9Smpi * Iterate over all types found in a given CU. For all non-resolved types
456c02203f9Smpi * use their DWARF relative offset to find the relative type they are pointing
457c02203f9Smpi * to. The CU offset tree, `cuot', is used to speedup relative type lookup.
458192095f7Smpi */
459192095f7Smpi void
cu_resolve(struct dwcu * dcu,struct itype_queue * cutq,struct ioff_tree * cuot)460192095f7Smpi cu_resolve(struct dwcu *dcu, struct itype_queue *cutq, struct ioff_tree *cuot)
461192095f7Smpi {
462192095f7Smpi struct itype *it, *ref, tmp;
463192095f7Smpi struct imember *im;
464192095f7Smpi unsigned int toresolve;
465192095f7Smpi size_t off = dcu->dcu_offset;
466192095f7Smpi
467192095f7Smpi TAILQ_FOREACH(it, cutq, it_next) {
468192095f7Smpi if (!(it->it_flags & (ITF_UNRES|ITF_UNRES_MEMB)))
469192095f7Smpi continue;
470192095f7Smpi
471c02203f9Smpi /* If this type references another one, try to find it. */
472192095f7Smpi if (it->it_flags & ITF_UNRES) {
473192095f7Smpi tmp.it_off = it->it_ref + off;
474192095f7Smpi ref = RB_FIND(ioff_tree, cuot, &tmp);
475192095f7Smpi if (ref != NULL) {
476192095f7Smpi it->it_refp = ref;
477192095f7Smpi ir_add(it, ref);
478192095f7Smpi it->it_flags &= ~ITF_UNRES;
479192095f7Smpi }
480192095f7Smpi }
481192095f7Smpi
482c02203f9Smpi /* If this type has members, resolve all of them. */
483192095f7Smpi toresolve = it->it_nelems;
484192095f7Smpi if ((it->it_flags & ITF_UNRES_MEMB) && toresolve > 0) {
485192095f7Smpi TAILQ_FOREACH(im, &it->it_members, im_next) {
486192095f7Smpi tmp.it_off = im->im_ref + off;
487192095f7Smpi ref = RB_FIND(ioff_tree, cuot, &tmp);
488192095f7Smpi if (ref != NULL) {
489192095f7Smpi im->im_refp = ref;
490192095f7Smpi ir_add(it, ref);
491192095f7Smpi toresolve--;
492192095f7Smpi }
493192095f7Smpi }
494192095f7Smpi if (toresolve == 0)
495192095f7Smpi it->it_flags &= ~ITF_UNRES_MEMB;
496192095f7Smpi }
497192095f7Smpi #if defined(DEBUG)
498192095f7Smpi if (it->it_flags & (ITF_UNRES|ITF_UNRES_MEMB)) {
499192095f7Smpi printf("0x%zx: %s type=%d unresolved 0x%llx",
500192095f7Smpi it->it_off, it_name(it), it->it_type, it->it_ref);
501192095f7Smpi if (toresolve)
502192095f7Smpi printf(": %d members", toresolve);
503192095f7Smpi TAILQ_FOREACH(im, &it->it_members, im_next) {
50472c906afSmpi if (im->im_refp != NULL)
50572c906afSmpi continue;
50672c906afSmpi printf("\n%zu: %s", im->im_ref, im_name(im));
507192095f7Smpi }
508192095f7Smpi printf("\n");
509192095f7Smpi }
510192095f7Smpi #endif /* defined(DEBUG) */
511192095f7Smpi }
512192095f7Smpi
513c02203f9Smpi /* We'll reuse the tree for the next CU, so empty it. */
514192095f7Smpi RB_FOREACH_SAFE(it, ioff_tree, cuot, ref)
515192095f7Smpi RB_REMOVE(ioff_tree, cuot, it);
516192095f7Smpi }
517192095f7Smpi
518192095f7Smpi void
cu_reference(struct dwcu * dcu,struct itype_queue * cutq)519192095f7Smpi cu_reference(struct dwcu *dcu, struct itype_queue *cutq)
520192095f7Smpi {
521192095f7Smpi struct itype *it;
522192095f7Smpi
523192095f7Smpi TAILQ_FOREACH(it, cutq, it_next) {
524192095f7Smpi if (it->it_flags & (ITF_OBJ|ITF_FUNC))
525192095f7Smpi it_reference(it);
526192095f7Smpi }
527192095f7Smpi }
528192095f7Smpi
529192095f7Smpi /*
530192095f7Smpi * Merge type representation from a CU with already known types.
531192095f7Smpi */
532192095f7Smpi void
cu_merge(struct dwcu * dcu,struct itype_queue * cutq)533192095f7Smpi cu_merge(struct dwcu *dcu, struct itype_queue *cutq)
534192095f7Smpi {
535192095f7Smpi struct itype *it, *nit, *prev, *first;
536192095f7Smpi int diff;
537192095f7Smpi
538192095f7Smpi /* First ``it'' that needs a duplicate check. */
539192095f7Smpi first = TAILQ_FIRST(cutq);
540192095f7Smpi if (first == NULL)
541192095f7Smpi return;
542192095f7Smpi
543192095f7Smpi TAILQ_CONCAT(&itypeq, cutq, it_next);
544192095f7Smpi
545192095f7Smpi /*
546192095f7Smpi * First pass: merge types
547192095f7Smpi */
548192095f7Smpi for (it = first; it != NULL; it = nit) {
549192095f7Smpi nit = TAILQ_NEXT(it, it_next);
550192095f7Smpi
551192095f7Smpi /* Move functions & variable to their own list. */
552192095f7Smpi if (it->it_flags & (ITF_FUNC|ITF_OBJ)) {
553192095f7Smpi /*
554192095f7Smpi * FIXME: allow static variables with the same name
555192095f7Smpi * to be of different type.
556192095f7Smpi */
557192095f7Smpi if (RB_FIND(isymb_tree, &isymbt, it) == NULL)
558192095f7Smpi RB_INSERT(isymb_tree, &isymbt, it);
559192095f7Smpi continue;
560192095f7Smpi }
561192095f7Smpi
562192095f7Smpi /* Look if we already have this type. */
563192095f7Smpi if (it->it_flags & ITF_USED)
564192095f7Smpi prev = RB_FIND(itype_tree, &itypet[it->it_type], it);
565192095f7Smpi else
566192095f7Smpi prev = NULL;
567192095f7Smpi
568192095f7Smpi if (prev != NULL) {
569192095f7Smpi struct itype *old = it;
570192095f7Smpi struct itref *ir;
571192095f7Smpi struct imember *im;
572192095f7Smpi
573192095f7Smpi /* Substitute references */
574192095f7Smpi while ((ir = SIMPLEQ_FIRST(&old->it_refs)) != NULL) {
575192095f7Smpi it = ir->ir_itp;
576192095f7Smpi
577192095f7Smpi SIMPLEQ_REMOVE_HEAD(&old->it_refs, ir_next);
578192095f7Smpi pfree(&ir_pool, ir);
579192095f7Smpi
580192095f7Smpi if (it->it_refp == old)
581192095f7Smpi it->it_refp = prev;
582192095f7Smpi
583192095f7Smpi TAILQ_FOREACH(im, &it->it_members, im_next) {
584192095f7Smpi if (im->im_refp == old)
585192095f7Smpi im->im_refp = prev;
586192095f7Smpi }
587192095f7Smpi }
588192095f7Smpi
5891657e891Smpi /* If we first got a forward reference, complete it. */
5901657e891Smpi if ((prev->it_flags & ITF_FORWARD) &&
5911657e891Smpi (old->it_flags & ITF_FORWARD) == 0)
5921657e891Smpi it_merge(prev, old);
5931657e891Smpi
594192095f7Smpi old->it_flags &= ~ITF_USED;
595192095f7Smpi } else if (it->it_flags & ITF_USED) {
596192095f7Smpi RB_INSERT(itype_tree, &itypet[it->it_type], it);
597192095f7Smpi }
598192095f7Smpi }
599192095f7Smpi
600192095f7Smpi /*
601192095f7Smpi * Second pass: update indexes
602192095f7Smpi */
603192095f7Smpi diff = 0;
604192095f7Smpi for (it = first; it != NULL; it = nit) {
605192095f7Smpi nit = TAILQ_NEXT(it, it_next);
606192095f7Smpi
607192095f7Smpi if (it->it_flags & (ITF_FUNC|ITF_OBJ))
608192095f7Smpi continue;
609192095f7Smpi
610192095f7Smpi /* Adjust indexes */
611192095f7Smpi if (it->it_flags & ITF_USED) {
612192095f7Smpi it->it_idx -= diff;
613192095f7Smpi continue;
614192095f7Smpi }
615192095f7Smpi
616192095f7Smpi /* Remove unused */
617192095f7Smpi TAILQ_REMOVE(&itypeq, it, it_next);
618192095f7Smpi it_free(it);
619192095f7Smpi diff++;
620192095f7Smpi }
621192095f7Smpi
622192095f7Smpi /* Update global index to match removed entries. */
623192095f7Smpi it = TAILQ_LAST(&itypeq, itype_queue);
624192095f7Smpi while (it->it_flags & (ITF_FUNC|ITF_OBJ))
625192095f7Smpi it = TAILQ_PREV(it, itype_queue, it_next);
626192095f7Smpi
627192095f7Smpi tidx = it->it_idx;
628192095f7Smpi }
629192095f7Smpi
630192095f7Smpi /*
631192095f7Smpi * Parse a CU.
632192095f7Smpi */
633192095f7Smpi void
cu_parse(struct dwcu * dcu,struct itype_queue * cutq,struct ioff_tree * cuot)634192095f7Smpi cu_parse(struct dwcu *dcu, struct itype_queue *cutq, struct ioff_tree *cuot)
635192095f7Smpi {
636192095f7Smpi struct itype *it = NULL;
637192095f7Smpi struct dwdie *die;
638192095f7Smpi size_t psz = dcu->dcu_psize;
639192095f7Smpi size_t off = dcu->dcu_offset;
640192095f7Smpi
641192095f7Smpi assert(RB_EMPTY(cuot));
642192095f7Smpi
643192095f7Smpi SIMPLEQ_FOREACH(die, &dcu->dcu_dies, die_next) {
644192095f7Smpi uint64_t tag = die->die_dab->dab_tag;
645192095f7Smpi
646192095f7Smpi switch (tag) {
647192095f7Smpi case DW_TAG_array_type:
648192095f7Smpi it = parse_array(die, dcu->dcu_psize);
649192095f7Smpi break;
650192095f7Smpi case DW_TAG_enumeration_type:
651192095f7Smpi it = parse_enum(die, dcu->dcu_psize);
652192095f7Smpi break;
653192095f7Smpi case DW_TAG_pointer_type:
654192095f7Smpi it = parse_refers(die, psz, CTF_K_POINTER);
655192095f7Smpi break;
656192095f7Smpi case DW_TAG_structure_type:
657192095f7Smpi it = parse_struct(die, psz, CTF_K_STRUCT, off);
658192095f7Smpi if (it == NULL)
659192095f7Smpi continue;
660192095f7Smpi break;
661192095f7Smpi case DW_TAG_typedef:
662192095f7Smpi it = parse_refers(die, psz, CTF_K_TYPEDEF);
663192095f7Smpi break;
664192095f7Smpi case DW_TAG_union_type:
665192095f7Smpi it = parse_struct(die, psz, CTF_K_UNION, off);
666192095f7Smpi if (it == NULL)
667192095f7Smpi continue;
668192095f7Smpi break;
669192095f7Smpi case DW_TAG_base_type:
670192095f7Smpi it = parse_base(die, psz);
671b62fc310Sjsg if (it == NULL)
672b62fc310Sjsg continue;
673192095f7Smpi break;
674192095f7Smpi case DW_TAG_const_type:
675192095f7Smpi it = parse_refers(die, psz, CTF_K_CONST);
676192095f7Smpi break;
677192095f7Smpi case DW_TAG_volatile_type:
678192095f7Smpi it = parse_refers(die, psz, CTF_K_VOLATILE);
679192095f7Smpi break;
680192095f7Smpi case DW_TAG_restrict_type:
681192095f7Smpi it = parse_refers(die, psz, CTF_K_RESTRICT);
682192095f7Smpi break;
683192095f7Smpi case DW_TAG_subprogram:
684192095f7Smpi it = parse_function(die, psz);
685192095f7Smpi if (it == NULL)
686192095f7Smpi continue;
687192095f7Smpi break;
688192095f7Smpi case DW_TAG_subroutine_type:
689192095f7Smpi it = parse_funcptr(die, psz);
690192095f7Smpi break;
691192095f7Smpi /*
692192095f7Smpi * Children are assumed to be right after their parent in
693192095f7Smpi * the list. The parent parsing function takes care of
694192095f7Smpi * parsing them.
695192095f7Smpi */
696192095f7Smpi case DW_TAG_member:
697192095f7Smpi assert(it->it_type == CTF_K_STRUCT ||
698192095f7Smpi it->it_type == CTF_K_UNION ||
699192095f7Smpi it->it_type == CTF_K_ENUM);
700192095f7Smpi continue;
701192095f7Smpi case DW_TAG_subrange_type:
702192095f7Smpi assert(it->it_type == CTF_K_ARRAY);
703192095f7Smpi continue;
704192095f7Smpi case DW_TAG_formal_parameter:
705192095f7Smpi /*
706192095f7Smpi * If we skipped the second inline definition,
707192095f7Smpi * skip its arguments.
708192095f7Smpi */
709192095f7Smpi if (it == NULL)
710192095f7Smpi continue;
711192095f7Smpi
712192095f7Smpi /* See comment in subparse_arguments(). */
713192095f7Smpi if (it->it_type == CTF_K_STRUCT ||
714192095f7Smpi it->it_type == CTF_K_UNION ||
715192095f7Smpi it->it_type == CTF_K_ENUM ||
716192095f7Smpi it->it_type == CTF_K_TYPEDEF)
717192095f7Smpi continue;
718192095f7Smpi
719192095f7Smpi if (it->it_flags & ITF_OBJ)
720192095f7Smpi continue;
721192095f7Smpi
722192095f7Smpi assert(it->it_type == CTF_K_FUNCTION);
723192095f7Smpi continue;
724192095f7Smpi case DW_TAG_variable:
725192095f7Smpi it = parse_variable(die, psz);
726192095f7Smpi /* Unnamed variables are discarded. */
727192095f7Smpi if (it == NULL)
728192095f7Smpi continue;
729192095f7Smpi break;
730192095f7Smpi #if 1
731192095f7Smpi case DW_TAG_lexical_block:
732192095f7Smpi case DW_TAG_inlined_subroutine:
733192095f7Smpi continue;
734192095f7Smpi #endif
735192095f7Smpi case DW_TAG_compile_unit:
736192095f7Smpi default:
737192095f7Smpi DPRINTF("%s\n", dw_tag2name(tag));
738192095f7Smpi continue;
739192095f7Smpi }
740192095f7Smpi
741192095f7Smpi TAILQ_INSERT_TAIL(cutq, it, it_next);
742192095f7Smpi RB_INSERT(ioff_tree, cuot, it);
743192095f7Smpi }
744192095f7Smpi }
745192095f7Smpi
746192095f7Smpi struct itype *
parse_base(struct dwdie * die,size_t psz)747192095f7Smpi parse_base(struct dwdie *die, size_t psz)
748192095f7Smpi {
749192095f7Smpi struct itype *it;
750192095f7Smpi struct dwaval *dav;
751192095f7Smpi uint16_t encoding, enc = 0, bits = 0;
752192095f7Smpi int type;
753192095f7Smpi
754192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
755192095f7Smpi switch (dav->dav_dat->dat_attr) {
756192095f7Smpi case DW_AT_encoding:
757192095f7Smpi enc = dav2val(dav, psz);
758192095f7Smpi break;
759192095f7Smpi case DW_AT_byte_size:
760192095f7Smpi bits = 8 * dav2val(dav, psz);
761192095f7Smpi break;
762192095f7Smpi default:
763192095f7Smpi DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
764192095f7Smpi break;
765192095f7Smpi }
766192095f7Smpi }
767192095f7Smpi
768192095f7Smpi switch (enc) {
769192095f7Smpi case DW_ATE_unsigned:
770192095f7Smpi case DW_ATE_address:
771192095f7Smpi encoding = 0;
772192095f7Smpi type = CTF_K_INTEGER;
773192095f7Smpi break;
774192095f7Smpi case DW_ATE_unsigned_char:
775192095f7Smpi encoding = CTF_INT_CHAR;
776192095f7Smpi type = CTF_K_INTEGER;
777192095f7Smpi break;
778192095f7Smpi case DW_ATE_signed:
779192095f7Smpi encoding = CTF_INT_SIGNED;
780192095f7Smpi type = CTF_K_INTEGER;
781192095f7Smpi break;
782192095f7Smpi case DW_ATE_signed_char:
783192095f7Smpi encoding = CTF_INT_SIGNED | CTF_INT_CHAR;
784192095f7Smpi type = CTF_K_INTEGER;
785192095f7Smpi break;
786192095f7Smpi case DW_ATE_boolean:
787192095f7Smpi encoding = CTF_INT_SIGNED | CTF_INT_BOOL;
788192095f7Smpi type = CTF_K_INTEGER;
789192095f7Smpi break;
790192095f7Smpi case DW_ATE_float:
791192095f7Smpi if (bits < psz)
792192095f7Smpi encoding = CTF_FP_SINGLE;
793192095f7Smpi else if (bits == psz)
794192095f7Smpi encoding = CTF_FP_DOUBLE;
795192095f7Smpi else
796192095f7Smpi encoding = CTF_FP_LDOUBLE;
797192095f7Smpi type = CTF_K_FLOAT;
798192095f7Smpi break;
799192095f7Smpi case DW_ATE_complex_float:
800192095f7Smpi if (bits < psz)
801192095f7Smpi encoding = CTF_FP_CPLX;
802192095f7Smpi else if (bits == psz)
803192095f7Smpi encoding = CTF_FP_DCPLX;
804192095f7Smpi else
805192095f7Smpi encoding = CTF_FP_LDCPLX;
806192095f7Smpi type = CTF_K_FLOAT;
807192095f7Smpi break;
808192095f7Smpi case DW_ATE_imaginary_float:
809192095f7Smpi if (bits < psz)
810192095f7Smpi encoding = CTF_FP_IMAGRY;
811192095f7Smpi else if (bits == psz)
812192095f7Smpi encoding = CTF_FP_DIMAGRY;
813192095f7Smpi else
814192095f7Smpi encoding = CTF_FP_LDIMAGRY;
815192095f7Smpi type = CTF_K_FLOAT;
816192095f7Smpi break;
817192095f7Smpi default:
818192095f7Smpi DPRINTF("unknown encoding: %d\n", enc);
819192095f7Smpi return (NULL);
820192095f7Smpi }
821192095f7Smpi
822192095f7Smpi it = it_new(++tidx, die->die_offset, enc2name(enc), bits,
823192095f7Smpi encoding, 0, type, 0);
824192095f7Smpi
825192095f7Smpi return it;
826192095f7Smpi }
827192095f7Smpi
828192095f7Smpi struct itype *
parse_refers(struct dwdie * die,size_t psz,int type)829192095f7Smpi parse_refers(struct dwdie *die, size_t psz, int type)
830192095f7Smpi {
831192095f7Smpi struct itype *it;
832192095f7Smpi struct dwaval *dav;
833192095f7Smpi const char *name = NULL;
834192095f7Smpi size_t ref = 0, size = 0;
835192095f7Smpi
836192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
837192095f7Smpi switch (dav->dav_dat->dat_attr) {
838192095f7Smpi case DW_AT_name:
839192095f7Smpi name = dav2str(dav);
840192095f7Smpi break;
841192095f7Smpi case DW_AT_type:
842192095f7Smpi ref = dav2val(dav, psz);
843192095f7Smpi break;
844192095f7Smpi case DW_AT_byte_size:
845192095f7Smpi size = dav2val(dav, psz);
846192095f7Smpi assert(size < UINT_MAX);
847192095f7Smpi break;
848192095f7Smpi default:
849192095f7Smpi DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
850192095f7Smpi break;
851192095f7Smpi }
852192095f7Smpi }
853192095f7Smpi
854192095f7Smpi it = it_new(++tidx, die->die_offset, name, size, 0, ref, type,
855192095f7Smpi ITF_UNRES);
856192095f7Smpi
857192095f7Smpi if (it->it_ref == 0 && (it->it_size == sizeof(void *) ||
858192095f7Smpi type == CTF_K_CONST || type == CTF_K_VOLATILE ||
8592cad1d4bSclaudio type == CTF_K_POINTER || type == CTF_K_TYPEDEF)) {
860192095f7Smpi /* Work around GCC/clang not emiting a type for void */
861192095f7Smpi it->it_flags &= ~ITF_UNRES;
862192095f7Smpi it->it_ref = VOID_OFFSET;
863192095f7Smpi it->it_refp = void_it;
864192095f7Smpi }
865192095f7Smpi
866192095f7Smpi return it;
867192095f7Smpi }
868192095f7Smpi
869192095f7Smpi struct itype *
parse_array(struct dwdie * die,size_t psz)870192095f7Smpi parse_array(struct dwdie *die, size_t psz)
871192095f7Smpi {
872192095f7Smpi struct itype *it;
873192095f7Smpi struct dwaval *dav;
874192095f7Smpi const char *name = NULL;
875192095f7Smpi size_t ref = 0;
876192095f7Smpi
877192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
878192095f7Smpi switch (dav->dav_dat->dat_attr) {
879192095f7Smpi case DW_AT_name:
880192095f7Smpi name = dav2str(dav);
881192095f7Smpi break;
882192095f7Smpi case DW_AT_type:
883192095f7Smpi ref = dav2val(dav, psz);
884192095f7Smpi break;
885192095f7Smpi default:
886192095f7Smpi DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
887192095f7Smpi break;
888192095f7Smpi }
889192095f7Smpi }
890192095f7Smpi
891192095f7Smpi it = it_new(++tidx, die->die_offset, name, 0, 0, ref, CTF_K_ARRAY,
892192095f7Smpi ITF_UNRES);
893192095f7Smpi
894192095f7Smpi subparse_subrange(die, psz, it);
895192095f7Smpi
896192095f7Smpi return it;
897192095f7Smpi }
898192095f7Smpi
899192095f7Smpi struct itype *
parse_enum(struct dwdie * die,size_t psz)900192095f7Smpi parse_enum(struct dwdie *die, size_t psz)
901192095f7Smpi {
902192095f7Smpi struct itype *it;
903192095f7Smpi struct dwaval *dav;
904192095f7Smpi const char *name = NULL;
905192095f7Smpi size_t size = 0;
906192095f7Smpi
907192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
908192095f7Smpi switch (dav->dav_dat->dat_attr) {
909192095f7Smpi case DW_AT_byte_size:
910192095f7Smpi size = dav2val(dav, psz);
911192095f7Smpi assert(size < UINT_MAX);
912192095f7Smpi break;
913192095f7Smpi case DW_AT_name:
914192095f7Smpi name = dav2str(dav);
915192095f7Smpi break;
916192095f7Smpi default:
917192095f7Smpi DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
918192095f7Smpi break;
919192095f7Smpi }
920192095f7Smpi }
921192095f7Smpi
922192095f7Smpi it = it_new(++tidx, die->die_offset, name, size, 0, 0, CTF_K_ENUM, 0);
923192095f7Smpi
924192095f7Smpi subparse_enumerator(die, psz, it);
925192095f7Smpi
926192095f7Smpi return it;
927192095f7Smpi }
928192095f7Smpi
929192095f7Smpi void
subparse_subrange(struct dwdie * die,size_t psz,struct itype * it)930192095f7Smpi subparse_subrange(struct dwdie *die, size_t psz, struct itype *it)
931192095f7Smpi {
932192095f7Smpi struct dwaval *dav;
933192095f7Smpi
934192095f7Smpi assert(it->it_type == CTF_K_ARRAY);
935192095f7Smpi
936192095f7Smpi if (die->die_dab->dab_children == DW_CHILDREN_no)
937192095f7Smpi return;
938192095f7Smpi
939192095f7Smpi /*
940192095f7Smpi * This loop assumes that the children of a DIE are just
941192095f7Smpi * after it on the list.
942192095f7Smpi */
943192095f7Smpi while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) {
944192095f7Smpi uint64_t tag = die->die_dab->dab_tag;
945192095f7Smpi size_t nelems = 0;
946192095f7Smpi
947192095f7Smpi if (tag != DW_TAG_subrange_type)
948192095f7Smpi break;
949192095f7Smpi
950192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
951192095f7Smpi switch (dav->dav_dat->dat_attr) {
952192095f7Smpi case DW_AT_count:
953192095f7Smpi nelems = dav2val(dav, psz);
954192095f7Smpi break;
955192095f7Smpi case DW_AT_upper_bound:
956192095f7Smpi nelems = dav2val(dav, psz) + 1;
957192095f7Smpi break;
958192095f7Smpi default:
959192095f7Smpi DPRINTF("%s\n",
960192095f7Smpi dw_at2name(dav->dav_dat->dat_attr));
961192095f7Smpi break;
962192095f7Smpi }
963192095f7Smpi }
964192095f7Smpi
965192095f7Smpi assert(nelems < UINT_MAX);
966192095f7Smpi it->it_nelems = nelems;
967192095f7Smpi }
968192095f7Smpi }
969192095f7Smpi
970192095f7Smpi void
subparse_enumerator(struct dwdie * die,size_t psz,struct itype * it)971192095f7Smpi subparse_enumerator(struct dwdie *die, size_t psz, struct itype *it)
972192095f7Smpi {
973192095f7Smpi struct imember *im;
974192095f7Smpi struct dwaval *dav;
975192095f7Smpi
976192095f7Smpi assert(it->it_type == CTF_K_ENUM);
977192095f7Smpi
978192095f7Smpi if (die->die_dab->dab_children == DW_CHILDREN_no)
979192095f7Smpi return;
980192095f7Smpi
981192095f7Smpi /*
982192095f7Smpi * This loop assumes that the children of a DIE are just
983192095f7Smpi * after it on the list.
984192095f7Smpi */
985192095f7Smpi while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) {
986192095f7Smpi uint64_t tag = die->die_dab->dab_tag;
987192095f7Smpi size_t val = 0;
988192095f7Smpi const char *name = NULL;
989192095f7Smpi
990192095f7Smpi if (tag != DW_TAG_enumerator)
991192095f7Smpi break;
992192095f7Smpi
993192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
994192095f7Smpi switch (dav->dav_dat->dat_attr) {
995192095f7Smpi case DW_AT_name:
996192095f7Smpi name = dav2str(dav);
997192095f7Smpi break;
998192095f7Smpi case DW_AT_const_value:
999192095f7Smpi val = dav2val(dav, psz);
1000192095f7Smpi break;
1001192095f7Smpi default:
1002192095f7Smpi DPRINTF("%s\n",
1003192095f7Smpi dw_at2name(dav->dav_dat->dat_attr));
1004192095f7Smpi break;
1005192095f7Smpi }
1006192095f7Smpi }
1007192095f7Smpi
1008192095f7Smpi if (name == NULL) {
1009192095f7Smpi warnx("%s with anon member", it_name(it));
1010192095f7Smpi continue;
1011192095f7Smpi }
1012192095f7Smpi
1013192095f7Smpi im = im_new(name, val, 0);
1014192095f7Smpi assert(it->it_nelems < UINT_MAX);
1015192095f7Smpi it->it_nelems++;
1016192095f7Smpi TAILQ_INSERT_TAIL(&it->it_members, im, im_next);
1017192095f7Smpi }
1018192095f7Smpi }
1019192095f7Smpi
1020192095f7Smpi struct itype *
parse_struct(struct dwdie * die,size_t psz,int type,size_t off)1021192095f7Smpi parse_struct(struct dwdie *die, size_t psz, int type, size_t off)
1022192095f7Smpi {
1023192095f7Smpi struct itype *it = NULL;
1024192095f7Smpi struct dwaval *dav;
1025192095f7Smpi const char *name = NULL;
10261657e891Smpi unsigned int flags = 0;
1027192095f7Smpi size_t size = 0;
10281657e891Smpi int forward = 0;
1029192095f7Smpi
1030192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
1031192095f7Smpi switch (dav->dav_dat->dat_attr) {
10321657e891Smpi case DW_AT_declaration:
10331657e891Smpi forward = dav2val(dav, psz);
10341657e891Smpi break;
1035192095f7Smpi case DW_AT_byte_size:
1036192095f7Smpi size = dav2val(dav, psz);
1037192095f7Smpi assert(size < UINT_MAX);
1038192095f7Smpi break;
1039192095f7Smpi case DW_AT_name:
1040192095f7Smpi name = dav2str(dav);
1041192095f7Smpi break;
1042192095f7Smpi default:
1043192095f7Smpi DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
1044192095f7Smpi break;
1045192095f7Smpi }
1046192095f7Smpi }
1047192095f7Smpi
1048192095f7Smpi
10491657e891Smpi if (forward)
10501657e891Smpi flags = ITF_FORWARD;
10511657e891Smpi it = it_new(++tidx, die->die_offset, name, size, 0, 0, type, flags);
1052192095f7Smpi subparse_member(die, psz, it, off);
1053192095f7Smpi
1054192095f7Smpi return it;
1055192095f7Smpi }
1056192095f7Smpi
1057192095f7Smpi void
subparse_member(struct dwdie * die,size_t psz,struct itype * it,size_t offset)1058192095f7Smpi subparse_member(struct dwdie *die, size_t psz, struct itype *it, size_t offset)
1059192095f7Smpi {
1060192095f7Smpi struct imember *im;
1061192095f7Smpi struct dwaval *dav;
1062192095f7Smpi const char *name;
1063192095f7Smpi size_t off = 0, ref = 0, bits = 0;
1064192095f7Smpi uint8_t lvl = die->die_lvl;
1065192095f7Smpi
1066192095f7Smpi assert(it->it_type == CTF_K_STRUCT || it->it_type == CTF_K_UNION);
1067192095f7Smpi
1068192095f7Smpi if (die->die_dab->dab_children == DW_CHILDREN_no)
1069192095f7Smpi return;
1070192095f7Smpi
1071192095f7Smpi /*
1072192095f7Smpi * This loop assumes that the children of a DIE are just
1073192095f7Smpi * after it on the list.
1074192095f7Smpi */
1075192095f7Smpi while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) {
1076192095f7Smpi int64_t tag = die->die_dab->dab_tag;
1077192095f7Smpi
1078192095f7Smpi name = NULL;
1079192095f7Smpi if (die->die_lvl <= lvl)
1080192095f7Smpi break;
1081192095f7Smpi
1082192095f7Smpi /* Skip members of members */
1083192095f7Smpi if (die->die_lvl > lvl + 1)
1084192095f7Smpi continue;
1085d84376f1Smpi /*
1086d84376f1Smpi * Nested declaration.
1087d84376f1Smpi *
1088d84376f1Smpi * This matches the case where a ``struct'', ``union'',
1089d84376f1Smpi * ``enum'' or ``typedef'' is first declared "inside" a
1090d84376f1Smpi * union or struct declaration.
1091d84376f1Smpi */
1092d84376f1Smpi if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type ||
1093d84376f1Smpi tag == DW_TAG_enumeration_type || tag == DW_TAG_typedef)
1094d84376f1Smpi continue;
1095192095f7Smpi
1096192095f7Smpi it->it_flags |= ITF_UNRES_MEMB;
1097192095f7Smpi
1098192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
1099192095f7Smpi switch (dav->dav_dat->dat_attr) {
1100192095f7Smpi case DW_AT_name:
1101192095f7Smpi name = dav2str(dav);
1102192095f7Smpi break;
1103192095f7Smpi case DW_AT_type:
1104192095f7Smpi ref = dav2val(dav, psz);
1105192095f7Smpi break;
1106192095f7Smpi case DW_AT_data_member_location:
1107192095f7Smpi off = 8 * dav2val(dav, psz);
1108192095f7Smpi break;
1109192095f7Smpi case DW_AT_bit_size:
1110192095f7Smpi bits = dav2val(dav, psz);
1111192095f7Smpi assert(bits < USHRT_MAX);
1112192095f7Smpi break;
1113192095f7Smpi default:
1114192095f7Smpi DPRINTF("%s\n",
1115192095f7Smpi dw_at2name(dav->dav_dat->dat_attr));
1116192095f7Smpi break;
1117192095f7Smpi }
1118192095f7Smpi }
1119192095f7Smpi
1120192095f7Smpi /*
1121192095f7Smpi * When a structure is declared inside an union, we
1122192095f7Smpi * have to generate a reference to make the resolver
1123192095f7Smpi * happy.
1124192095f7Smpi */
1125192095f7Smpi if ((ref == 0) && (tag == DW_TAG_structure_type))
1126192095f7Smpi ref = die->die_offset - offset;
1127192095f7Smpi
1128192095f7Smpi im = im_new(name, ref, off);
1129192095f7Smpi assert(it->it_nelems < UINT_MAX);
1130192095f7Smpi it->it_nelems++;
1131192095f7Smpi TAILQ_INSERT_TAIL(&it->it_members, im, im_next);
1132192095f7Smpi }
1133192095f7Smpi }
1134192095f7Smpi
1135192095f7Smpi
1136192095f7Smpi void
subparse_arguments(struct dwdie * die,size_t psz,struct itype * it)1137192095f7Smpi subparse_arguments(struct dwdie *die, size_t psz, struct itype *it)
1138192095f7Smpi {
1139192095f7Smpi struct imember *im;
1140192095f7Smpi struct dwaval *dav;
1141192095f7Smpi size_t ref = 0;
1142192095f7Smpi
1143192095f7Smpi assert(it->it_type == CTF_K_FUNCTION);
1144192095f7Smpi
1145192095f7Smpi if (die->die_dab->dab_children == DW_CHILDREN_no)
1146192095f7Smpi return;
1147192095f7Smpi
1148192095f7Smpi /*
1149192095f7Smpi * This loop assumes that the children of a DIE are after it
1150192095f7Smpi * on the list.
1151192095f7Smpi */
1152192095f7Smpi while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) {
1153192095f7Smpi uint64_t tag = die->die_dab->dab_tag;
1154192095f7Smpi
1155192095f7Smpi if (tag == DW_TAG_unspecified_parameters) {
11561657e891Smpi /* TODO */
1157192095f7Smpi continue;
1158192095f7Smpi }
1159192095f7Smpi
1160192095f7Smpi /*
1161192095f7Smpi * Nested declaration.
1162192095f7Smpi *
1163192095f7Smpi * This matches the case where a ``struct'', ``union'',
1164b1151f87Smpi * ``enum'', ``typedef'' or ``static'' variable is first
1165b1151f87Smpi * declared inside a function declaration.
1166192095f7Smpi */
1167b1151f87Smpi switch (tag) {
1168b1151f87Smpi case DW_TAG_structure_type:
1169b1151f87Smpi case DW_TAG_union_type:
1170b1151f87Smpi case DW_TAG_enumeration_type:
1171b1151f87Smpi case DW_TAG_typedef:
1172b1151f87Smpi case DW_TAG_variable:
1173192095f7Smpi continue;
1174b1151f87Smpi default:
1175b1151f87Smpi break;
1176b1151f87Smpi }
1177192095f7Smpi
1178192095f7Smpi if (tag != DW_TAG_formal_parameter)
1179192095f7Smpi break;
1180192095f7Smpi
1181192095f7Smpi it->it_flags |= ITF_UNRES_MEMB;
1182192095f7Smpi
1183192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
1184192095f7Smpi switch (dav->dav_dat->dat_attr) {
1185192095f7Smpi case DW_AT_type:
1186192095f7Smpi ref = dav2val(dav, psz);
1187192095f7Smpi break;
1188192095f7Smpi default:
1189192095f7Smpi DPRINTF("%s\n",
1190192095f7Smpi dw_at2name(dav->dav_dat->dat_attr));
1191192095f7Smpi break;
1192192095f7Smpi }
1193192095f7Smpi }
1194192095f7Smpi
1195192095f7Smpi im = im_new(NULL, ref, 0);
1196192095f7Smpi assert(it->it_nelems < UINT_MAX);
1197192095f7Smpi it->it_nelems++;
1198192095f7Smpi TAILQ_INSERT_TAIL(&it->it_members, im, im_next);
1199192095f7Smpi }
1200192095f7Smpi }
1201192095f7Smpi
1202192095f7Smpi struct itype *
parse_function(struct dwdie * die,size_t psz)1203192095f7Smpi parse_function(struct dwdie *die, size_t psz)
1204192095f7Smpi {
1205192095f7Smpi struct itype *it;
1206192095f7Smpi struct dwaval *dav;
1207192095f7Smpi const char *name = NULL;
1208192095f7Smpi size_t ref = 0;
1209192095f7Smpi
1210192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
1211192095f7Smpi switch (dav->dav_dat->dat_attr) {
1212192095f7Smpi case DW_AT_name:
1213192095f7Smpi name = dav2str(dav);
1214192095f7Smpi break;
1215192095f7Smpi case DW_AT_type:
1216192095f7Smpi ref = dav2val(dav, psz);
1217192095f7Smpi break;
1218192095f7Smpi case DW_AT_abstract_origin:
1219192095f7Smpi /*
1220192095f7Smpi * Skip second empty definition for inline
1221192095f7Smpi * functions.
1222192095f7Smpi */
1223192095f7Smpi return NULL;
1224192095f7Smpi default:
1225192095f7Smpi DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
1226192095f7Smpi break;
1227192095f7Smpi }
1228192095f7Smpi }
1229192095f7Smpi
1230192095f7Smpi /*
1231192095f7Smpi * Work around for clang 4.0 generating DW_TAG_subprogram without
1232192095f7Smpi * any attribute.
1233192095f7Smpi */
1234192095f7Smpi if (name == NULL)
1235192095f7Smpi return NULL;
1236192095f7Smpi
1237192095f7Smpi it = it_new(++fidx, die->die_offset, name, 0, 0, ref, CTF_K_FUNCTION,
1238192095f7Smpi ITF_UNRES|ITF_FUNC);
1239192095f7Smpi
1240192095f7Smpi subparse_arguments(die, psz, it);
1241192095f7Smpi
1242192095f7Smpi if (it->it_ref == 0) {
1243192095f7Smpi /* Work around GCC not emiting a type for void */
1244192095f7Smpi it->it_flags &= ~ITF_UNRES;
1245192095f7Smpi it->it_ref = VOID_OFFSET;
1246192095f7Smpi it->it_refp = void_it;
1247192095f7Smpi }
1248192095f7Smpi
1249192095f7Smpi return it;
1250192095f7Smpi }
1251192095f7Smpi
1252192095f7Smpi struct itype *
parse_funcptr(struct dwdie * die,size_t psz)1253192095f7Smpi parse_funcptr(struct dwdie *die, size_t psz)
1254192095f7Smpi {
1255192095f7Smpi struct itype *it;
1256192095f7Smpi struct dwaval *dav;
1257192095f7Smpi const char *name = NULL;
1258192095f7Smpi size_t ref = 0;
1259192095f7Smpi
1260192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
1261192095f7Smpi switch (dav->dav_dat->dat_attr) {
1262192095f7Smpi case DW_AT_name:
1263192095f7Smpi name = dav2str(dav);
1264192095f7Smpi break;
1265192095f7Smpi case DW_AT_type:
1266192095f7Smpi ref = dav2val(dav, psz);
1267192095f7Smpi break;
1268192095f7Smpi default:
1269192095f7Smpi DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
1270192095f7Smpi break;
1271192095f7Smpi }
1272192095f7Smpi }
1273192095f7Smpi
1274192095f7Smpi it = it_new(++tidx, die->die_offset, name, 0, 0, ref, CTF_K_FUNCTION,
1275192095f7Smpi ITF_UNRES);
1276192095f7Smpi
1277192095f7Smpi subparse_arguments(die, psz, it);
1278192095f7Smpi
1279192095f7Smpi if (it->it_ref == 0) {
1280192095f7Smpi /* Work around GCC not emiting a type for void */
1281192095f7Smpi it->it_flags &= ~ITF_UNRES;
1282192095f7Smpi it->it_ref = VOID_OFFSET;
1283192095f7Smpi it->it_refp = void_it;
1284192095f7Smpi }
1285192095f7Smpi
1286192095f7Smpi return it;
1287192095f7Smpi }
1288192095f7Smpi
1289192095f7Smpi struct itype *
parse_variable(struct dwdie * die,size_t psz)1290192095f7Smpi parse_variable(struct dwdie *die, size_t psz)
1291192095f7Smpi {
1292192095f7Smpi struct itype *it = NULL;
1293192095f7Smpi struct dwaval *dav;
1294192095f7Smpi const char *name = NULL;
1295192095f7Smpi size_t ref = 0;
1296518f4dcdSmpi int forward = 0, global = 0;
1297192095f7Smpi
1298192095f7Smpi SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
1299192095f7Smpi switch (dav->dav_dat->dat_attr) {
1300192095f7Smpi case DW_AT_declaration:
13011657e891Smpi forward = dav2val(dav, psz);
1302192095f7Smpi break;
1303192095f7Smpi case DW_AT_name:
1304192095f7Smpi name = dav2str(dav);
1305192095f7Smpi break;
1306192095f7Smpi case DW_AT_type:
1307192095f7Smpi ref = dav2val(dav, psz);
1308192095f7Smpi break;
1309518f4dcdSmpi case DW_AT_location:
1310518f4dcdSmpi switch (dav->dav_dat->dat_form) {
1311518f4dcdSmpi case DW_FORM_block:
1312518f4dcdSmpi case DW_FORM_block1:
1313518f4dcdSmpi case DW_FORM_block2:
1314518f4dcdSmpi case DW_FORM_block4:
1315518f4dcdSmpi global = 1;
1316518f4dcdSmpi break;
1317518f4dcdSmpi default:
1318518f4dcdSmpi break;
1319518f4dcdSmpi }
1320518f4dcdSmpi break;
1321192095f7Smpi default:
1322192095f7Smpi DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
1323192095f7Smpi break;
1324192095f7Smpi }
1325192095f7Smpi }
1326192095f7Smpi
1327192095f7Smpi
1328518f4dcdSmpi if (global && !forward && name != NULL) {
1329192095f7Smpi it = it_new(++oidx, die->die_offset, name, 0, 0, ref, 0,
1330192095f7Smpi ITF_UNRES|ITF_OBJ);
1331192095f7Smpi }
1332192095f7Smpi
1333192095f7Smpi return it;
1334192095f7Smpi }
1335192095f7Smpi
1336192095f7Smpi size_t
dav2val(struct dwaval * dav,size_t psz)1337192095f7Smpi dav2val(struct dwaval *dav, size_t psz)
1338192095f7Smpi {
1339192095f7Smpi uint64_t val = (uint64_t)-1;
1340192095f7Smpi
1341192095f7Smpi switch (dav->dav_dat->dat_form) {
1342192095f7Smpi case DW_FORM_addr:
1343192095f7Smpi case DW_FORM_ref_addr:
1344192095f7Smpi if (psz == sizeof(uint32_t))
1345192095f7Smpi val = dav->dav_u32;
1346192095f7Smpi else
1347192095f7Smpi val = dav->dav_u64;
1348192095f7Smpi break;
1349192095f7Smpi case DW_FORM_block1:
1350192095f7Smpi case DW_FORM_block2:
1351192095f7Smpi case DW_FORM_block4:
1352192095f7Smpi case DW_FORM_block:
1353192095f7Smpi dw_loc_parse(&dav->dav_buf, NULL, &val, NULL);
1354192095f7Smpi break;
1355192095f7Smpi case DW_FORM_flag:
1356192095f7Smpi case DW_FORM_data1:
1357192095f7Smpi case DW_FORM_ref1:
1358192095f7Smpi val = dav->dav_u8;
1359192095f7Smpi break;
1360192095f7Smpi case DW_FORM_data2:
1361192095f7Smpi case DW_FORM_ref2:
1362192095f7Smpi val = dav->dav_u16;
1363192095f7Smpi break;
1364192095f7Smpi case DW_FORM_data4:
1365192095f7Smpi case DW_FORM_ref4:
1366192095f7Smpi val = dav->dav_u32;
1367192095f7Smpi break;
1368192095f7Smpi case DW_FORM_sdata:
1369192095f7Smpi case DW_FORM_data8:
1370192095f7Smpi case DW_FORM_ref8:
137144cd804eSclaudio case DW_FORM_udata:
137244cd804eSclaudio case DW_FORM_ref_udata:
1373192095f7Smpi val = dav->dav_u64;
1374192095f7Smpi break;
1375192095f7Smpi case DW_FORM_strp:
1376192095f7Smpi val = dav->dav_u32;
1377192095f7Smpi break;
1378192095f7Smpi case DW_FORM_flag_present:
1379192095f7Smpi val = 1;
1380192095f7Smpi break;
1381192095f7Smpi default:
1382192095f7Smpi break;
1383192095f7Smpi }
1384192095f7Smpi
1385192095f7Smpi return val;
1386192095f7Smpi }
1387192095f7Smpi
1388192095f7Smpi const char *
dav2str(struct dwaval * dav)1389192095f7Smpi dav2str(struct dwaval *dav)
1390192095f7Smpi {
1391192095f7Smpi const char *str = NULL;
1392192095f7Smpi extern const char *dstrbuf;
1393d1d0000fSjsg extern size_t dstrlen;
1394192095f7Smpi
1395192095f7Smpi switch (dav->dav_dat->dat_form) {
1396192095f7Smpi case DW_FORM_string:
1397192095f7Smpi str = dav->dav_str;
1398192095f7Smpi break;
1399192095f7Smpi case DW_FORM_strp:
1400d1d0000fSjsg if (dav->dav_u32 >= dstrlen)
1401d1d0000fSjsg str = NULL;
1402d1d0000fSjsg else
1403192095f7Smpi str = dstrbuf + dav->dav_u32;
1404192095f7Smpi break;
1405192095f7Smpi default:
1406192095f7Smpi break;
1407192095f7Smpi }
1408192095f7Smpi
1409192095f7Smpi return str;
1410192095f7Smpi }
1411192095f7Smpi
1412192095f7Smpi const char *
enc2name(unsigned short enc)1413192095f7Smpi enc2name(unsigned short enc)
1414192095f7Smpi {
1415192095f7Smpi static const char *enc_name[] = { "address", "boolean", "complex float",
1416192095f7Smpi "float", "signed", "char", "unsigned", "unsigned char",
1417192095f7Smpi "imaginary float", "packed decimal", "numeric string", "edited",
1418192095f7Smpi "signed fixed", "unsigned fixed", "decimal float" };
1419192095f7Smpi
1420192095f7Smpi if (enc > 0 && enc <= nitems(enc_name))
1421192095f7Smpi return enc_name[enc - 1];
1422192095f7Smpi
1423192095f7Smpi return "invalid";
1424192095f7Smpi }
1425