xref: /openbsd-src/usr.bin/ctfconv/parse.c (revision 76af8930adea681ce324d24d9d9d169c274e84b0)
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