xref: /linux/scripts/gendwarfksyms/dwarf.c (revision 06b8b036ab9c1e70a562705a398bcd271e0b5ebf)
1f2856884SSami Tolvanen // SPDX-License-Identifier: GPL-2.0
2f2856884SSami Tolvanen /*
3f2856884SSami Tolvanen  * Copyright (C) 2024 Google LLC
4f2856884SSami Tolvanen  */
5f2856884SSami Tolvanen 
65b7780e8SSami Tolvanen #include <inttypes.h>
75b7780e8SSami Tolvanen #include <stdarg.h>
8f2856884SSami Tolvanen #include "gendwarfksyms.h"
9f2856884SSami Tolvanen 
10*06b8b036SSami Tolvanen static bool do_linebreak;
11*06b8b036SSami Tolvanen static int indentation_level;
12*06b8b036SSami Tolvanen 
13*06b8b036SSami Tolvanen /* Line breaks and indentation for pretty-printing */
14*06b8b036SSami Tolvanen static void process_linebreak(struct die *cache, int n)
15*06b8b036SSami Tolvanen {
16*06b8b036SSami Tolvanen 	indentation_level += n;
17*06b8b036SSami Tolvanen 	do_linebreak = true;
18*06b8b036SSami Tolvanen 	die_map_add_linebreak(cache, n);
19*06b8b036SSami Tolvanen }
20*06b8b036SSami Tolvanen 
215b7780e8SSami Tolvanen #define DEFINE_GET_ATTR(attr, type)                                    \
225b7780e8SSami Tolvanen 	static bool get_##attr##_attr(Dwarf_Die *die, unsigned int id, \
235b7780e8SSami Tolvanen 				      type *value)                     \
245b7780e8SSami Tolvanen 	{                                                              \
255b7780e8SSami Tolvanen 		Dwarf_Attribute da;                                    \
265b7780e8SSami Tolvanen 		return dwarf_attr(die, id, &da) &&                     \
275b7780e8SSami Tolvanen 		       !dwarf_form##attr(&da, value);                  \
285b7780e8SSami Tolvanen 	}
295b7780e8SSami Tolvanen 
305b7780e8SSami Tolvanen DEFINE_GET_ATTR(udata, Dwarf_Word)
315b7780e8SSami Tolvanen 
32f2856884SSami Tolvanen static bool get_ref_die_attr(Dwarf_Die *die, unsigned int id, Dwarf_Die *value)
33f2856884SSami Tolvanen {
34f2856884SSami Tolvanen 	Dwarf_Attribute da;
35f2856884SSami Tolvanen 
36f2856884SSami Tolvanen 	/* dwarf_formref_die returns a pointer instead of an error value. */
37f2856884SSami Tolvanen 	return dwarf_attr(die, id, &da) && dwarf_formref_die(&da, value);
38f2856884SSami Tolvanen }
39f2856884SSami Tolvanen 
40f2856884SSami Tolvanen #define DEFINE_GET_STRING_ATTR(attr)                         \
41f2856884SSami Tolvanen 	static const char *get_##attr##_attr(Dwarf_Die *die) \
42f2856884SSami Tolvanen 	{                                                    \
43f2856884SSami Tolvanen 		Dwarf_Attribute da;                          \
44f2856884SSami Tolvanen 		if (dwarf_attr(die, DW_AT_##attr, &da))      \
45f2856884SSami Tolvanen 			return dwarf_formstring(&da);        \
46f2856884SSami Tolvanen 		return NULL;                                 \
47f2856884SSami Tolvanen 	}
48f2856884SSami Tolvanen 
49f2856884SSami Tolvanen DEFINE_GET_STRING_ATTR(name)
50f2856884SSami Tolvanen DEFINE_GET_STRING_ATTR(linkage_name)
51f2856884SSami Tolvanen 
52f2856884SSami Tolvanen static const char *get_symbol_name(Dwarf_Die *die)
53f2856884SSami Tolvanen {
54f2856884SSami Tolvanen 	const char *name;
55f2856884SSami Tolvanen 
56f2856884SSami Tolvanen 	/* rustc uses DW_AT_linkage_name for exported symbols */
57f2856884SSami Tolvanen 	name = get_linkage_name_attr(die);
58f2856884SSami Tolvanen 	if (!name)
59f2856884SSami Tolvanen 		name = get_name_attr(die);
60f2856884SSami Tolvanen 
61f2856884SSami Tolvanen 	return name;
62f2856884SSami Tolvanen }
63f2856884SSami Tolvanen 
64f2856884SSami Tolvanen static bool match_export_symbol(struct state *state, Dwarf_Die *die)
65f2856884SSami Tolvanen {
66f2856884SSami Tolvanen 	Dwarf_Die *source = die;
67f2856884SSami Tolvanen 	Dwarf_Die origin;
68f2856884SSami Tolvanen 
69f2856884SSami Tolvanen 	/* If the DIE has an abstract origin, use it for type information. */
70f2856884SSami Tolvanen 	if (get_ref_die_attr(die, DW_AT_abstract_origin, &origin))
71f2856884SSami Tolvanen 		source = &origin;
72f2856884SSami Tolvanen 
73f2856884SSami Tolvanen 	state->sym = symbol_get(get_symbol_name(die));
74f2856884SSami Tolvanen 
75f2856884SSami Tolvanen 	/* Look up using the origin name if there are no matches. */
76f2856884SSami Tolvanen 	if (!state->sym && source != die)
77f2856884SSami Tolvanen 		state->sym = symbol_get(get_symbol_name(source));
78f2856884SSami Tolvanen 
79f2856884SSami Tolvanen 	state->die = *source;
80f2856884SSami Tolvanen 	return !!state->sym;
81f2856884SSami Tolvanen }
82f2856884SSami Tolvanen 
83f2856884SSami Tolvanen /*
84f2856884SSami Tolvanen  * Type string processing
85f2856884SSami Tolvanen  */
860c1c7627SSami Tolvanen static void process(struct die *cache, const char *s)
87f2856884SSami Tolvanen {
88f2856884SSami Tolvanen 	s = s ?: "<null>";
89f2856884SSami Tolvanen 
90*06b8b036SSami Tolvanen 	if (dump_dies && do_linebreak) {
91*06b8b036SSami Tolvanen 		fputs("\n", stderr);
92*06b8b036SSami Tolvanen 		for (int i = 0; i < indentation_level; i++)
93*06b8b036SSami Tolvanen 			fputs("  ", stderr);
94*06b8b036SSami Tolvanen 		do_linebreak = false;
95*06b8b036SSami Tolvanen 	}
96f2856884SSami Tolvanen 	if (dump_dies)
97f2856884SSami Tolvanen 		fputs(s, stderr);
980c1c7627SSami Tolvanen 
990c1c7627SSami Tolvanen 	die_map_add_string(cache, s);
100f2856884SSami Tolvanen }
101f2856884SSami Tolvanen 
1025b7780e8SSami Tolvanen #define MAX_FMT_BUFFER_SIZE 128
1035b7780e8SSami Tolvanen 
1040c1c7627SSami Tolvanen static void process_fmt(struct die *cache, const char *fmt, ...)
1055b7780e8SSami Tolvanen {
1065b7780e8SSami Tolvanen 	char buf[MAX_FMT_BUFFER_SIZE];
1075b7780e8SSami Tolvanen 	va_list args;
1085b7780e8SSami Tolvanen 
1095b7780e8SSami Tolvanen 	va_start(args, fmt);
1105b7780e8SSami Tolvanen 
1115b7780e8SSami Tolvanen 	if (checkp(vsnprintf(buf, sizeof(buf), fmt, args)) >= sizeof(buf))
1125b7780e8SSami Tolvanen 		error("vsnprintf overflow: increase MAX_FMT_BUFFER_SIZE");
1135b7780e8SSami Tolvanen 
1140c1c7627SSami Tolvanen 	process(cache, buf);
1155b7780e8SSami Tolvanen 	va_end(args);
1165b7780e8SSami Tolvanen }
1175b7780e8SSami Tolvanen 
1185b7780e8SSami Tolvanen #define MAX_FQN_SIZE 64
1195b7780e8SSami Tolvanen 
1205b7780e8SSami Tolvanen /* Get a fully qualified name from DWARF scopes */
1215b7780e8SSami Tolvanen static char *get_fqn(Dwarf_Die *die)
1225b7780e8SSami Tolvanen {
1235b7780e8SSami Tolvanen 	const char *list[MAX_FQN_SIZE];
1245b7780e8SSami Tolvanen 	Dwarf_Die *scopes = NULL;
1255b7780e8SSami Tolvanen 	bool has_name = false;
1265b7780e8SSami Tolvanen 	char *fqn = NULL;
1275b7780e8SSami Tolvanen 	char *p;
1285b7780e8SSami Tolvanen 	int count = 0;
1295b7780e8SSami Tolvanen 	int len = 0;
1305b7780e8SSami Tolvanen 	int res;
1315b7780e8SSami Tolvanen 	int i;
1325b7780e8SSami Tolvanen 
1335b7780e8SSami Tolvanen 	res = checkp(dwarf_getscopes_die(die, &scopes));
1345b7780e8SSami Tolvanen 	if (!res) {
1355b7780e8SSami Tolvanen 		list[count] = get_name_attr(die);
1365b7780e8SSami Tolvanen 
1375b7780e8SSami Tolvanen 		if (!list[count])
1385b7780e8SSami Tolvanen 			return NULL;
1395b7780e8SSami Tolvanen 
1405b7780e8SSami Tolvanen 		len += strlen(list[count]);
1415b7780e8SSami Tolvanen 		count++;
1425b7780e8SSami Tolvanen 
1435b7780e8SSami Tolvanen 		goto done;
1445b7780e8SSami Tolvanen 	}
1455b7780e8SSami Tolvanen 
1465b7780e8SSami Tolvanen 	for (i = res - 1; i >= 0 && count < MAX_FQN_SIZE; i--) {
1475b7780e8SSami Tolvanen 		if (dwarf_tag(&scopes[i]) == DW_TAG_compile_unit)
1485b7780e8SSami Tolvanen 			continue;
1495b7780e8SSami Tolvanen 
1505b7780e8SSami Tolvanen 		list[count] = get_name_attr(&scopes[i]);
1515b7780e8SSami Tolvanen 
1525b7780e8SSami Tolvanen 		if (list[count]) {
1535b7780e8SSami Tolvanen 			has_name = true;
1545b7780e8SSami Tolvanen 		} else {
1555b7780e8SSami Tolvanen 			list[count] = "<anonymous>";
1565b7780e8SSami Tolvanen 			has_name = false;
1575b7780e8SSami Tolvanen 		}
1585b7780e8SSami Tolvanen 
1595b7780e8SSami Tolvanen 		len += strlen(list[count]);
1605b7780e8SSami Tolvanen 		count++;
1615b7780e8SSami Tolvanen 
1625b7780e8SSami Tolvanen 		if (i > 0) {
1635b7780e8SSami Tolvanen 			list[count++] = "::";
1645b7780e8SSami Tolvanen 			len += 2;
1655b7780e8SSami Tolvanen 		}
1665b7780e8SSami Tolvanen 	}
1675b7780e8SSami Tolvanen 
1685b7780e8SSami Tolvanen 	free(scopes);
1695b7780e8SSami Tolvanen 
1705b7780e8SSami Tolvanen 	if (count == MAX_FQN_SIZE)
1715b7780e8SSami Tolvanen 		warn("increase MAX_FQN_SIZE: reached the maximum");
1725b7780e8SSami Tolvanen 
1735b7780e8SSami Tolvanen 	/* Consider the DIE unnamed if the last scope doesn't have a name */
1745b7780e8SSami Tolvanen 	if (!has_name)
1755b7780e8SSami Tolvanen 		return NULL;
1765b7780e8SSami Tolvanen done:
1775b7780e8SSami Tolvanen 	fqn = xmalloc(len + 1);
1785b7780e8SSami Tolvanen 	*fqn = '\0';
1795b7780e8SSami Tolvanen 
1805b7780e8SSami Tolvanen 	p = fqn;
1815b7780e8SSami Tolvanen 	for (i = 0; i < count; i++)
1825b7780e8SSami Tolvanen 		p = stpcpy(p, list[i]);
1835b7780e8SSami Tolvanen 
1845b7780e8SSami Tolvanen 	return fqn;
1855b7780e8SSami Tolvanen }
1865b7780e8SSami Tolvanen 
1870c1c7627SSami Tolvanen static void update_fqn(struct die *cache, Dwarf_Die *die)
1885b7780e8SSami Tolvanen {
1890c1c7627SSami Tolvanen 	if (!cache->fqn)
1900c1c7627SSami Tolvanen 		cache->fqn = get_fqn(die) ?: "";
1910c1c7627SSami Tolvanen }
1920c1c7627SSami Tolvanen 
1930c1c7627SSami Tolvanen static void process_fqn(struct die *cache, Dwarf_Die *die)
1940c1c7627SSami Tolvanen {
1950c1c7627SSami Tolvanen 	update_fqn(cache, die);
1960c1c7627SSami Tolvanen 	if (*cache->fqn)
1970c1c7627SSami Tolvanen 		process(cache, " ");
1980c1c7627SSami Tolvanen 	process(cache, cache->fqn);
1995b7780e8SSami Tolvanen }
2005b7780e8SSami Tolvanen 
2015b7780e8SSami Tolvanen #define DEFINE_PROCESS_UDATA_ATTRIBUTE(attribute)                          \
2020c1c7627SSami Tolvanen 	static void process_##attribute##_attr(struct die *cache,          \
2030c1c7627SSami Tolvanen 					       Dwarf_Die *die)             \
2045b7780e8SSami Tolvanen 	{                                                                  \
2055b7780e8SSami Tolvanen 		Dwarf_Word value;                                          \
2065b7780e8SSami Tolvanen 		if (get_udata_attr(die, DW_AT_##attribute, &value))        \
2070c1c7627SSami Tolvanen 			process_fmt(cache, " " #attribute "(%" PRIu64 ")", \
2080c1c7627SSami Tolvanen 				    value);                                \
2095b7780e8SSami Tolvanen 	}
2105b7780e8SSami Tolvanen 
2115b7780e8SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment)
2125b7780e8SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size)
2135b7780e8SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding)
2145b7780e8SSami Tolvanen 
215f2856884SSami Tolvanen bool match_all(Dwarf_Die *die)
216f2856884SSami Tolvanen {
217f2856884SSami Tolvanen 	return true;
218f2856884SSami Tolvanen }
219f2856884SSami Tolvanen 
2200c1c7627SSami Tolvanen int process_die_container(struct state *state, struct die *cache,
2210c1c7627SSami Tolvanen 			  Dwarf_Die *die, die_callback_t func,
2220c1c7627SSami Tolvanen 			  die_match_callback_t match)
223f2856884SSami Tolvanen {
224f2856884SSami Tolvanen 	Dwarf_Die current;
225f2856884SSami Tolvanen 	int res;
226f2856884SSami Tolvanen 
227f2856884SSami Tolvanen 	res = checkp(dwarf_child(die, &current));
228f2856884SSami Tolvanen 	while (!res) {
229f2856884SSami Tolvanen 		if (match(&current)) {
230f2856884SSami Tolvanen 			/* <0 = error, 0 = continue, >0 = stop */
2310c1c7627SSami Tolvanen 			res = checkp(func(state, cache, &current));
232f2856884SSami Tolvanen 			if (res)
233f2856884SSami Tolvanen 				return res;
234f2856884SSami Tolvanen 		}
235f2856884SSami Tolvanen 
236f2856884SSami Tolvanen 		res = checkp(dwarf_siblingof(&current, &current));
237f2856884SSami Tolvanen 	}
238f2856884SSami Tolvanen 
239f2856884SSami Tolvanen 	return 0;
240f2856884SSami Tolvanen }
241f2856884SSami Tolvanen 
2420c1c7627SSami Tolvanen static int process_type(struct state *state, struct die *parent,
2430c1c7627SSami Tolvanen 			Dwarf_Die *die);
2445b7780e8SSami Tolvanen 
2450c1c7627SSami Tolvanen static void process_type_attr(struct state *state, struct die *cache,
2460c1c7627SSami Tolvanen 			      Dwarf_Die *die)
2475b7780e8SSami Tolvanen {
2485b7780e8SSami Tolvanen 	Dwarf_Die type;
2495b7780e8SSami Tolvanen 
2505b7780e8SSami Tolvanen 	if (get_ref_die_attr(die, DW_AT_type, &type)) {
2510c1c7627SSami Tolvanen 		check(process_type(state, cache, &type));
2525b7780e8SSami Tolvanen 		return;
2535b7780e8SSami Tolvanen 	}
2545b7780e8SSami Tolvanen 
2555b7780e8SSami Tolvanen 	/* Compilers can omit DW_AT_type -- print out 'void' to clarify */
2560c1c7627SSami Tolvanen 	process(cache, "base_type void");
2575b7780e8SSami Tolvanen }
2585b7780e8SSami Tolvanen 
259*06b8b036SSami Tolvanen /* Container types with DW_AT_type */
260*06b8b036SSami Tolvanen static void __process_type(struct state *state, struct die *cache,
261*06b8b036SSami Tolvanen 			   Dwarf_Die *die, const char *type)
262*06b8b036SSami Tolvanen {
263*06b8b036SSami Tolvanen 	process(cache, type);
264*06b8b036SSami Tolvanen 	process_fqn(cache, die);
265*06b8b036SSami Tolvanen 	process(cache, " {");
266*06b8b036SSami Tolvanen 	process_linebreak(cache, 1);
267*06b8b036SSami Tolvanen 	process_type_attr(state, cache, die);
268*06b8b036SSami Tolvanen 	process_linebreak(cache, -1);
269*06b8b036SSami Tolvanen 	process(cache, "}");
270*06b8b036SSami Tolvanen 	process_byte_size_attr(cache, die);
271*06b8b036SSami Tolvanen 	process_alignment_attr(cache, die);
272*06b8b036SSami Tolvanen }
273*06b8b036SSami Tolvanen 
274*06b8b036SSami Tolvanen #define DEFINE_PROCESS_TYPE(type)                                            \
275*06b8b036SSami Tolvanen 	static void process_##type##_type(struct state *state,               \
276*06b8b036SSami Tolvanen 					  struct die *cache, Dwarf_Die *die) \
277*06b8b036SSami Tolvanen 	{                                                                    \
278*06b8b036SSami Tolvanen 		__process_type(state, cache, die, #type "_type");            \
279*06b8b036SSami Tolvanen 	}
280*06b8b036SSami Tolvanen 
281*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(atomic)
282*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(const)
283*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(immutable)
284*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(packed)
285*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(pointer)
286*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(reference)
287*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(restrict)
288*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(rvalue_reference)
289*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(shared)
290*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(volatile)
291*06b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(typedef)
292*06b8b036SSami Tolvanen 
2930c1c7627SSami Tolvanen static void process_base_type(struct state *state, struct die *cache,
2940c1c7627SSami Tolvanen 			      Dwarf_Die *die)
2955b7780e8SSami Tolvanen {
2960c1c7627SSami Tolvanen 	process(cache, "base_type");
2970c1c7627SSami Tolvanen 	process_fqn(cache, die);
2980c1c7627SSami Tolvanen 	process_byte_size_attr(cache, die);
2990c1c7627SSami Tolvanen 	process_encoding_attr(cache, die);
3000c1c7627SSami Tolvanen 	process_alignment_attr(cache, die);
3010c1c7627SSami Tolvanen }
3020c1c7627SSami Tolvanen 
3030c1c7627SSami Tolvanen static void process_cached(struct state *state, struct die *cache,
3040c1c7627SSami Tolvanen 			   Dwarf_Die *die)
3050c1c7627SSami Tolvanen {
3060c1c7627SSami Tolvanen 	struct die_fragment *df;
3070c1c7627SSami Tolvanen 	Dwarf_Die child;
3080c1c7627SSami Tolvanen 
3090c1c7627SSami Tolvanen 	list_for_each_entry(df, &cache->fragments, list) {
3100c1c7627SSami Tolvanen 		switch (df->type) {
3110c1c7627SSami Tolvanen 		case FRAGMENT_STRING:
3120c1c7627SSami Tolvanen 			process(NULL, df->data.str);
3130c1c7627SSami Tolvanen 			break;
314*06b8b036SSami Tolvanen 		case FRAGMENT_LINEBREAK:
315*06b8b036SSami Tolvanen 			process_linebreak(NULL, df->data.linebreak);
316*06b8b036SSami Tolvanen 			break;
3170c1c7627SSami Tolvanen 		case FRAGMENT_DIE:
3180c1c7627SSami Tolvanen 			if (!dwarf_die_addr_die(dwarf_cu_getdwarf(die->cu),
3190c1c7627SSami Tolvanen 						(void *)df->data.addr, &child))
3200c1c7627SSami Tolvanen 				error("dwarf_die_addr_die failed");
3210c1c7627SSami Tolvanen 			check(process_type(state, NULL, &child));
3220c1c7627SSami Tolvanen 			break;
3230c1c7627SSami Tolvanen 		default:
3240c1c7627SSami Tolvanen 			error("empty die_fragment");
3250c1c7627SSami Tolvanen 		}
3260c1c7627SSami Tolvanen 	}
3275b7780e8SSami Tolvanen }
3285b7780e8SSami Tolvanen 
3295b7780e8SSami Tolvanen #define PROCESS_TYPE(type)                                \
3305b7780e8SSami Tolvanen 	case DW_TAG_##type##_type:                        \
3310c1c7627SSami Tolvanen 		process_##type##_type(state, cache, die); \
3325b7780e8SSami Tolvanen 		break;
3335b7780e8SSami Tolvanen 
3340c1c7627SSami Tolvanen static int process_type(struct state *state, struct die *parent, Dwarf_Die *die)
3355b7780e8SSami Tolvanen {
3360c1c7627SSami Tolvanen 	struct die *cache;
3375b7780e8SSami Tolvanen 	int tag = dwarf_tag(die);
3385b7780e8SSami Tolvanen 
3390c1c7627SSami Tolvanen 	/*
3400c1c7627SSami Tolvanen 	 * If we have the DIE already cached, use it instead of walking
3410c1c7627SSami Tolvanen 	 * through DWARF.
3420c1c7627SSami Tolvanen 	 */
3430c1c7627SSami Tolvanen 	cache = die_map_get(die, DIE_COMPLETE);
3440c1c7627SSami Tolvanen 
3450c1c7627SSami Tolvanen 	if (cache->state == DIE_COMPLETE) {
3460c1c7627SSami Tolvanen 		process_cached(state, cache, die);
3470c1c7627SSami Tolvanen 		die_map_add_die(parent, cache);
3480c1c7627SSami Tolvanen 		return 0;
3490c1c7627SSami Tolvanen 	}
3500c1c7627SSami Tolvanen 
3515b7780e8SSami Tolvanen 	switch (tag) {
352*06b8b036SSami Tolvanen 	/* Type modifiers */
353*06b8b036SSami Tolvanen 	PROCESS_TYPE(atomic)
354*06b8b036SSami Tolvanen 	PROCESS_TYPE(const)
355*06b8b036SSami Tolvanen 	PROCESS_TYPE(immutable)
356*06b8b036SSami Tolvanen 	PROCESS_TYPE(packed)
357*06b8b036SSami Tolvanen 	PROCESS_TYPE(pointer)
358*06b8b036SSami Tolvanen 	PROCESS_TYPE(reference)
359*06b8b036SSami Tolvanen 	PROCESS_TYPE(restrict)
360*06b8b036SSami Tolvanen 	PROCESS_TYPE(rvalue_reference)
361*06b8b036SSami Tolvanen 	PROCESS_TYPE(shared)
362*06b8b036SSami Tolvanen 	PROCESS_TYPE(volatile)
363*06b8b036SSami Tolvanen 	/* Other types */
3645b7780e8SSami Tolvanen 	PROCESS_TYPE(base)
365*06b8b036SSami Tolvanen 	PROCESS_TYPE(typedef)
3665b7780e8SSami Tolvanen 	default:
3675b7780e8SSami Tolvanen 		debug("unimplemented type: %x", tag);
3685b7780e8SSami Tolvanen 		break;
3695b7780e8SSami Tolvanen 	}
3705b7780e8SSami Tolvanen 
3710c1c7627SSami Tolvanen 	/* Update cache state and append to the parent (if any) */
3720c1c7627SSami Tolvanen 	cache->tag = tag;
3730c1c7627SSami Tolvanen 	cache->state = DIE_COMPLETE;
3740c1c7627SSami Tolvanen 	die_map_add_die(parent, cache);
3750c1c7627SSami Tolvanen 
3765b7780e8SSami Tolvanen 	return 0;
3775b7780e8SSami Tolvanen }
3785b7780e8SSami Tolvanen 
379f2856884SSami Tolvanen /*
380f2856884SSami Tolvanen  * Exported symbol processing
381f2856884SSami Tolvanen  */
382f2856884SSami Tolvanen static void process_symbol(struct state *state, Dwarf_Die *die,
383f2856884SSami Tolvanen 			   die_callback_t process_func)
384f2856884SSami Tolvanen {
385f2856884SSami Tolvanen 	debug("%s", state->sym->name);
3860c1c7627SSami Tolvanen 	check(process_func(state, NULL, die));
387f2856884SSami Tolvanen 	if (dump_dies)
388f2856884SSami Tolvanen 		fputs("\n", stderr);
389f2856884SSami Tolvanen }
390f2856884SSami Tolvanen 
3910c1c7627SSami Tolvanen static int __process_subprogram(struct state *state, struct die *cache,
3920c1c7627SSami Tolvanen 				Dwarf_Die *die)
393f2856884SSami Tolvanen {
3940c1c7627SSami Tolvanen 	process(cache, "subprogram");
395f2856884SSami Tolvanen 	return 0;
396f2856884SSami Tolvanen }
397f2856884SSami Tolvanen 
398f2856884SSami Tolvanen static void process_subprogram(struct state *state, Dwarf_Die *die)
399f2856884SSami Tolvanen {
400f2856884SSami Tolvanen 	process_symbol(state, die, __process_subprogram);
401f2856884SSami Tolvanen }
402f2856884SSami Tolvanen 
4030c1c7627SSami Tolvanen static int __process_variable(struct state *state, struct die *cache,
4040c1c7627SSami Tolvanen 			      Dwarf_Die *die)
405f2856884SSami Tolvanen {
4060c1c7627SSami Tolvanen 	process(cache, "variable ");
4070c1c7627SSami Tolvanen 	process_type_attr(state, cache, die);
408f2856884SSami Tolvanen 	return 0;
409f2856884SSami Tolvanen }
410f2856884SSami Tolvanen 
411f2856884SSami Tolvanen static void process_variable(struct state *state, Dwarf_Die *die)
412f2856884SSami Tolvanen {
413f2856884SSami Tolvanen 	process_symbol(state, die, __process_variable);
414f2856884SSami Tolvanen }
415f2856884SSami Tolvanen 
4160c1c7627SSami Tolvanen static int process_exported_symbols(struct state *unused, struct die *cache,
4170c1c7627SSami Tolvanen 				    Dwarf_Die *die)
418f2856884SSami Tolvanen {
419f2856884SSami Tolvanen 	int tag = dwarf_tag(die);
420f2856884SSami Tolvanen 
421f2856884SSami Tolvanen 	switch (tag) {
422f2856884SSami Tolvanen 	/* Possible containers of exported symbols */
423f2856884SSami Tolvanen 	case DW_TAG_namespace:
424f2856884SSami Tolvanen 	case DW_TAG_class_type:
425f2856884SSami Tolvanen 	case DW_TAG_structure_type:
426f2856884SSami Tolvanen 		return check(process_die_container(
4270c1c7627SSami Tolvanen 			NULL, cache, die, process_exported_symbols, match_all));
428f2856884SSami Tolvanen 
429f2856884SSami Tolvanen 	/* Possible exported symbols */
430f2856884SSami Tolvanen 	case DW_TAG_subprogram:
431f2856884SSami Tolvanen 	case DW_TAG_variable: {
432f2856884SSami Tolvanen 		struct state state;
433f2856884SSami Tolvanen 
434f2856884SSami Tolvanen 		if (!match_export_symbol(&state, die))
435f2856884SSami Tolvanen 			return 0;
436f2856884SSami Tolvanen 
437f2856884SSami Tolvanen 		if (tag == DW_TAG_subprogram)
438f2856884SSami Tolvanen 			process_subprogram(&state, &state.die);
439f2856884SSami Tolvanen 		else
440f2856884SSami Tolvanen 			process_variable(&state, &state.die);
441f2856884SSami Tolvanen 
442f2856884SSami Tolvanen 		return 0;
443f2856884SSami Tolvanen 	}
444f2856884SSami Tolvanen 	default:
445f2856884SSami Tolvanen 		return 0;
446f2856884SSami Tolvanen 	}
447f2856884SSami Tolvanen }
448f2856884SSami Tolvanen 
449f2856884SSami Tolvanen void process_cu(Dwarf_Die *cudie)
450f2856884SSami Tolvanen {
4510c1c7627SSami Tolvanen 	check(process_die_container(NULL, NULL, cudie, process_exported_symbols,
452f2856884SSami Tolvanen 				    match_all));
453f2856884SSami Tolvanen }
454