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 1006b8b036SSami Tolvanen static bool do_linebreak; 1106b8b036SSami Tolvanen static int indentation_level; 1206b8b036SSami Tolvanen 1306b8b036SSami Tolvanen /* Line breaks and indentation for pretty-printing */ 1406b8b036SSami Tolvanen static void process_linebreak(struct die *cache, int n) 1506b8b036SSami Tolvanen { 1606b8b036SSami Tolvanen indentation_level += n; 1706b8b036SSami Tolvanen do_linebreak = true; 1806b8b036SSami Tolvanen die_map_add_linebreak(cache, n); 1906b8b036SSami Tolvanen } 2006b8b036SSami 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 30*f936c129SSami Tolvanen DEFINE_GET_ATTR(flag, bool) 315b7780e8SSami Tolvanen DEFINE_GET_ATTR(udata, Dwarf_Word) 325b7780e8SSami Tolvanen 33f2856884SSami Tolvanen static bool get_ref_die_attr(Dwarf_Die *die, unsigned int id, Dwarf_Die *value) 34f2856884SSami Tolvanen { 35f2856884SSami Tolvanen Dwarf_Attribute da; 36f2856884SSami Tolvanen 37f2856884SSami Tolvanen /* dwarf_formref_die returns a pointer instead of an error value. */ 38f2856884SSami Tolvanen return dwarf_attr(die, id, &da) && dwarf_formref_die(&da, value); 39f2856884SSami Tolvanen } 40f2856884SSami Tolvanen 41f2856884SSami Tolvanen #define DEFINE_GET_STRING_ATTR(attr) \ 42f2856884SSami Tolvanen static const char *get_##attr##_attr(Dwarf_Die *die) \ 43f2856884SSami Tolvanen { \ 44f2856884SSami Tolvanen Dwarf_Attribute da; \ 45f2856884SSami Tolvanen if (dwarf_attr(die, DW_AT_##attr, &da)) \ 46f2856884SSami Tolvanen return dwarf_formstring(&da); \ 47f2856884SSami Tolvanen return NULL; \ 48f2856884SSami Tolvanen } 49f2856884SSami Tolvanen 50f2856884SSami Tolvanen DEFINE_GET_STRING_ATTR(name) 51f2856884SSami Tolvanen DEFINE_GET_STRING_ATTR(linkage_name) 52f2856884SSami Tolvanen 53f2856884SSami Tolvanen static const char *get_symbol_name(Dwarf_Die *die) 54f2856884SSami Tolvanen { 55f2856884SSami Tolvanen const char *name; 56f2856884SSami Tolvanen 57f2856884SSami Tolvanen /* rustc uses DW_AT_linkage_name for exported symbols */ 58f2856884SSami Tolvanen name = get_linkage_name_attr(die); 59f2856884SSami Tolvanen if (!name) 60f2856884SSami Tolvanen name = get_name_attr(die); 61f2856884SSami Tolvanen 62f2856884SSami Tolvanen return name; 63f2856884SSami Tolvanen } 64f2856884SSami Tolvanen 65f2856884SSami Tolvanen static bool match_export_symbol(struct state *state, Dwarf_Die *die) 66f2856884SSami Tolvanen { 67f2856884SSami Tolvanen Dwarf_Die *source = die; 68f2856884SSami Tolvanen Dwarf_Die origin; 69f2856884SSami Tolvanen 70f2856884SSami Tolvanen /* If the DIE has an abstract origin, use it for type information. */ 71f2856884SSami Tolvanen if (get_ref_die_attr(die, DW_AT_abstract_origin, &origin)) 72f2856884SSami Tolvanen source = &origin; 73f2856884SSami Tolvanen 74f2856884SSami Tolvanen state->sym = symbol_get(get_symbol_name(die)); 75f2856884SSami Tolvanen 76f2856884SSami Tolvanen /* Look up using the origin name if there are no matches. */ 77f2856884SSami Tolvanen if (!state->sym && source != die) 78f2856884SSami Tolvanen state->sym = symbol_get(get_symbol_name(source)); 79f2856884SSami Tolvanen 80f2856884SSami Tolvanen state->die = *source; 81f2856884SSami Tolvanen return !!state->sym; 82f2856884SSami Tolvanen } 83f2856884SSami Tolvanen 84*f936c129SSami Tolvanen /* DW_AT_decl_file -> struct srcfile */ 85*f936c129SSami Tolvanen static struct cache srcfile_cache; 86*f936c129SSami Tolvanen 87*f936c129SSami Tolvanen static bool is_definition_private(Dwarf_Die *die) 88*f936c129SSami Tolvanen { 89*f936c129SSami Tolvanen Dwarf_Word filenum; 90*f936c129SSami Tolvanen Dwarf_Files *files; 91*f936c129SSami Tolvanen Dwarf_Die cudie; 92*f936c129SSami Tolvanen const char *s; 93*f936c129SSami Tolvanen int res; 94*f936c129SSami Tolvanen 95*f936c129SSami Tolvanen /* 96*f936c129SSami Tolvanen * Definitions in .c files cannot change the public ABI, 97*f936c129SSami Tolvanen * so consider them private. 98*f936c129SSami Tolvanen */ 99*f936c129SSami Tolvanen if (!get_udata_attr(die, DW_AT_decl_file, &filenum)) 100*f936c129SSami Tolvanen return false; 101*f936c129SSami Tolvanen 102*f936c129SSami Tolvanen res = cache_get(&srcfile_cache, filenum); 103*f936c129SSami Tolvanen if (res >= 0) 104*f936c129SSami Tolvanen return !!res; 105*f936c129SSami Tolvanen 106*f936c129SSami Tolvanen if (!dwarf_cu_die(die->cu, &cudie, NULL, NULL, NULL, NULL, NULL, NULL)) 107*f936c129SSami Tolvanen error("dwarf_cu_die failed: '%s'", dwarf_errmsg(-1)); 108*f936c129SSami Tolvanen 109*f936c129SSami Tolvanen if (dwarf_getsrcfiles(&cudie, &files, NULL)) 110*f936c129SSami Tolvanen error("dwarf_getsrcfiles failed: '%s'", dwarf_errmsg(-1)); 111*f936c129SSami Tolvanen 112*f936c129SSami Tolvanen s = dwarf_filesrc(files, filenum, NULL, NULL); 113*f936c129SSami Tolvanen if (!s) 114*f936c129SSami Tolvanen error("dwarf_filesrc failed: '%s'", dwarf_errmsg(-1)); 115*f936c129SSami Tolvanen 116*f936c129SSami Tolvanen s = strrchr(s, '.'); 117*f936c129SSami Tolvanen res = s && !strcmp(s, ".c"); 118*f936c129SSami Tolvanen cache_set(&srcfile_cache, filenum, res); 119*f936c129SSami Tolvanen 120*f936c129SSami Tolvanen return !!res; 121*f936c129SSami Tolvanen } 122*f936c129SSami Tolvanen 123*f936c129SSami Tolvanen static bool is_kabi_definition(Dwarf_Die *die) 124*f936c129SSami Tolvanen { 125*f936c129SSami Tolvanen bool value; 126*f936c129SSami Tolvanen 127*f936c129SSami Tolvanen if (get_flag_attr(die, DW_AT_declaration, &value) && value) 128*f936c129SSami Tolvanen return false; 129*f936c129SSami Tolvanen 130*f936c129SSami Tolvanen return !is_definition_private(die); 131*f936c129SSami Tolvanen } 132*f936c129SSami Tolvanen 133f2856884SSami Tolvanen /* 134f2856884SSami Tolvanen * Type string processing 135f2856884SSami Tolvanen */ 1360c1c7627SSami Tolvanen static void process(struct die *cache, const char *s) 137f2856884SSami Tolvanen { 138f2856884SSami Tolvanen s = s ?: "<null>"; 139f2856884SSami Tolvanen 14006b8b036SSami Tolvanen if (dump_dies && do_linebreak) { 14106b8b036SSami Tolvanen fputs("\n", stderr); 14206b8b036SSami Tolvanen for (int i = 0; i < indentation_level; i++) 14306b8b036SSami Tolvanen fputs(" ", stderr); 14406b8b036SSami Tolvanen do_linebreak = false; 14506b8b036SSami Tolvanen } 146f2856884SSami Tolvanen if (dump_dies) 147f2856884SSami Tolvanen fputs(s, stderr); 1480c1c7627SSami Tolvanen 1490c1c7627SSami Tolvanen die_map_add_string(cache, s); 150f2856884SSami Tolvanen } 151f2856884SSami Tolvanen 1525b7780e8SSami Tolvanen #define MAX_FMT_BUFFER_SIZE 128 1535b7780e8SSami Tolvanen 1540c1c7627SSami Tolvanen static void process_fmt(struct die *cache, const char *fmt, ...) 1555b7780e8SSami Tolvanen { 1565b7780e8SSami Tolvanen char buf[MAX_FMT_BUFFER_SIZE]; 1575b7780e8SSami Tolvanen va_list args; 1585b7780e8SSami Tolvanen 1595b7780e8SSami Tolvanen va_start(args, fmt); 1605b7780e8SSami Tolvanen 1615b7780e8SSami Tolvanen if (checkp(vsnprintf(buf, sizeof(buf), fmt, args)) >= sizeof(buf)) 1625b7780e8SSami Tolvanen error("vsnprintf overflow: increase MAX_FMT_BUFFER_SIZE"); 1635b7780e8SSami Tolvanen 1640c1c7627SSami Tolvanen process(cache, buf); 1655b7780e8SSami Tolvanen va_end(args); 1665b7780e8SSami Tolvanen } 1675b7780e8SSami Tolvanen 1685b7780e8SSami Tolvanen #define MAX_FQN_SIZE 64 1695b7780e8SSami Tolvanen 1705b7780e8SSami Tolvanen /* Get a fully qualified name from DWARF scopes */ 1715b7780e8SSami Tolvanen static char *get_fqn(Dwarf_Die *die) 1725b7780e8SSami Tolvanen { 1735b7780e8SSami Tolvanen const char *list[MAX_FQN_SIZE]; 1745b7780e8SSami Tolvanen Dwarf_Die *scopes = NULL; 1755b7780e8SSami Tolvanen bool has_name = false; 1765b7780e8SSami Tolvanen char *fqn = NULL; 1775b7780e8SSami Tolvanen char *p; 1785b7780e8SSami Tolvanen int count = 0; 1795b7780e8SSami Tolvanen int len = 0; 1805b7780e8SSami Tolvanen int res; 1815b7780e8SSami Tolvanen int i; 1825b7780e8SSami Tolvanen 1835b7780e8SSami Tolvanen res = checkp(dwarf_getscopes_die(die, &scopes)); 1845b7780e8SSami Tolvanen if (!res) { 1855b7780e8SSami Tolvanen list[count] = get_name_attr(die); 1865b7780e8SSami Tolvanen 1875b7780e8SSami Tolvanen if (!list[count]) 1885b7780e8SSami Tolvanen return NULL; 1895b7780e8SSami Tolvanen 1905b7780e8SSami Tolvanen len += strlen(list[count]); 1915b7780e8SSami Tolvanen count++; 1925b7780e8SSami Tolvanen 1935b7780e8SSami Tolvanen goto done; 1945b7780e8SSami Tolvanen } 1955b7780e8SSami Tolvanen 1965b7780e8SSami Tolvanen for (i = res - 1; i >= 0 && count < MAX_FQN_SIZE; i--) { 1975b7780e8SSami Tolvanen if (dwarf_tag(&scopes[i]) == DW_TAG_compile_unit) 1985b7780e8SSami Tolvanen continue; 1995b7780e8SSami Tolvanen 2005b7780e8SSami Tolvanen list[count] = get_name_attr(&scopes[i]); 2015b7780e8SSami Tolvanen 2025b7780e8SSami Tolvanen if (list[count]) { 2035b7780e8SSami Tolvanen has_name = true; 2045b7780e8SSami Tolvanen } else { 2055b7780e8SSami Tolvanen list[count] = "<anonymous>"; 2065b7780e8SSami Tolvanen has_name = false; 2075b7780e8SSami Tolvanen } 2085b7780e8SSami Tolvanen 2095b7780e8SSami Tolvanen len += strlen(list[count]); 2105b7780e8SSami Tolvanen count++; 2115b7780e8SSami Tolvanen 2125b7780e8SSami Tolvanen if (i > 0) { 2135b7780e8SSami Tolvanen list[count++] = "::"; 2145b7780e8SSami Tolvanen len += 2; 2155b7780e8SSami Tolvanen } 2165b7780e8SSami Tolvanen } 2175b7780e8SSami Tolvanen 2185b7780e8SSami Tolvanen free(scopes); 2195b7780e8SSami Tolvanen 2205b7780e8SSami Tolvanen if (count == MAX_FQN_SIZE) 2215b7780e8SSami Tolvanen warn("increase MAX_FQN_SIZE: reached the maximum"); 2225b7780e8SSami Tolvanen 2235b7780e8SSami Tolvanen /* Consider the DIE unnamed if the last scope doesn't have a name */ 2245b7780e8SSami Tolvanen if (!has_name) 2255b7780e8SSami Tolvanen return NULL; 2265b7780e8SSami Tolvanen done: 2275b7780e8SSami Tolvanen fqn = xmalloc(len + 1); 2285b7780e8SSami Tolvanen *fqn = '\0'; 2295b7780e8SSami Tolvanen 2305b7780e8SSami Tolvanen p = fqn; 2315b7780e8SSami Tolvanen for (i = 0; i < count; i++) 2325b7780e8SSami Tolvanen p = stpcpy(p, list[i]); 2335b7780e8SSami Tolvanen 2345b7780e8SSami Tolvanen return fqn; 2355b7780e8SSami Tolvanen } 2365b7780e8SSami Tolvanen 2370c1c7627SSami Tolvanen static void update_fqn(struct die *cache, Dwarf_Die *die) 2385b7780e8SSami Tolvanen { 2390c1c7627SSami Tolvanen if (!cache->fqn) 2400c1c7627SSami Tolvanen cache->fqn = get_fqn(die) ?: ""; 2410c1c7627SSami Tolvanen } 2420c1c7627SSami Tolvanen 2430c1c7627SSami Tolvanen static void process_fqn(struct die *cache, Dwarf_Die *die) 2440c1c7627SSami Tolvanen { 2450c1c7627SSami Tolvanen update_fqn(cache, die); 2460c1c7627SSami Tolvanen if (*cache->fqn) 2470c1c7627SSami Tolvanen process(cache, " "); 2480c1c7627SSami Tolvanen process(cache, cache->fqn); 2495b7780e8SSami Tolvanen } 2505b7780e8SSami Tolvanen 2515b7780e8SSami Tolvanen #define DEFINE_PROCESS_UDATA_ATTRIBUTE(attribute) \ 2520c1c7627SSami Tolvanen static void process_##attribute##_attr(struct die *cache, \ 2530c1c7627SSami Tolvanen Dwarf_Die *die) \ 2545b7780e8SSami Tolvanen { \ 2555b7780e8SSami Tolvanen Dwarf_Word value; \ 2565b7780e8SSami Tolvanen if (get_udata_attr(die, DW_AT_##attribute, &value)) \ 2570c1c7627SSami Tolvanen process_fmt(cache, " " #attribute "(%" PRIu64 ")", \ 2580c1c7627SSami Tolvanen value); \ 2595b7780e8SSami Tolvanen } 2605b7780e8SSami Tolvanen 261f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(accessibility) 2625b7780e8SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment) 263f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(bit_size) 2645b7780e8SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size) 2655b7780e8SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding) 266f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(data_bit_offset) 267f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(data_member_location) 268f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(discr_value) 2695b7780e8SSami Tolvanen 270220a0857SSami Tolvanen /* Match functions -- die_match_callback_t */ 271220a0857SSami Tolvanen #define DEFINE_MATCH(type) \ 272220a0857SSami Tolvanen static bool match_##type##_type(Dwarf_Die *die) \ 273220a0857SSami Tolvanen { \ 274220a0857SSami Tolvanen return dwarf_tag(die) == DW_TAG_##type##_type; \ 275220a0857SSami Tolvanen } 276220a0857SSami Tolvanen 277f6bb9245SSami Tolvanen DEFINE_MATCH(enumerator) 278220a0857SSami Tolvanen DEFINE_MATCH(formal_parameter) 279f6bb9245SSami Tolvanen DEFINE_MATCH(member) 280c772f1d1SSami Tolvanen DEFINE_MATCH(subrange) 281220a0857SSami Tolvanen 282f2856884SSami Tolvanen bool match_all(Dwarf_Die *die) 283f2856884SSami Tolvanen { 284f2856884SSami Tolvanen return true; 285f2856884SSami Tolvanen } 286f2856884SSami Tolvanen 2870c1c7627SSami Tolvanen int process_die_container(struct state *state, struct die *cache, 2880c1c7627SSami Tolvanen Dwarf_Die *die, die_callback_t func, 2890c1c7627SSami Tolvanen die_match_callback_t match) 290f2856884SSami Tolvanen { 291f2856884SSami Tolvanen Dwarf_Die current; 292f2856884SSami Tolvanen int res; 293f2856884SSami Tolvanen 294220a0857SSami Tolvanen /* Track the first item in lists. */ 295220a0857SSami Tolvanen if (state) 296220a0857SSami Tolvanen state->first_list_item = true; 297220a0857SSami Tolvanen 298f2856884SSami Tolvanen res = checkp(dwarf_child(die, ¤t)); 299f2856884SSami Tolvanen while (!res) { 300f2856884SSami Tolvanen if (match(¤t)) { 301f2856884SSami Tolvanen /* <0 = error, 0 = continue, >0 = stop */ 3020c1c7627SSami Tolvanen res = checkp(func(state, cache, ¤t)); 303f2856884SSami Tolvanen if (res) 304220a0857SSami Tolvanen goto out; 305f2856884SSami Tolvanen } 306f2856884SSami Tolvanen 307f2856884SSami Tolvanen res = checkp(dwarf_siblingof(¤t, ¤t)); 308f2856884SSami Tolvanen } 309f2856884SSami Tolvanen 310220a0857SSami Tolvanen res = 0; 311220a0857SSami Tolvanen out: 312220a0857SSami Tolvanen if (state) 313220a0857SSami Tolvanen state->first_list_item = false; 314220a0857SSami Tolvanen 315220a0857SSami Tolvanen return res; 316f2856884SSami Tolvanen } 317f2856884SSami Tolvanen 3180c1c7627SSami Tolvanen static int process_type(struct state *state, struct die *parent, 3190c1c7627SSami Tolvanen Dwarf_Die *die); 3205b7780e8SSami Tolvanen 3210c1c7627SSami Tolvanen static void process_type_attr(struct state *state, struct die *cache, 3220c1c7627SSami Tolvanen Dwarf_Die *die) 3235b7780e8SSami Tolvanen { 3245b7780e8SSami Tolvanen Dwarf_Die type; 3255b7780e8SSami Tolvanen 3265b7780e8SSami Tolvanen if (get_ref_die_attr(die, DW_AT_type, &type)) { 3270c1c7627SSami Tolvanen check(process_type(state, cache, &type)); 3285b7780e8SSami Tolvanen return; 3295b7780e8SSami Tolvanen } 3305b7780e8SSami Tolvanen 3315b7780e8SSami Tolvanen /* Compilers can omit DW_AT_type -- print out 'void' to clarify */ 3320c1c7627SSami Tolvanen process(cache, "base_type void"); 3335b7780e8SSami Tolvanen } 3345b7780e8SSami Tolvanen 335220a0857SSami Tolvanen static void process_list_comma(struct state *state, struct die *cache) 336220a0857SSami Tolvanen { 337220a0857SSami Tolvanen if (state->first_list_item) { 338220a0857SSami Tolvanen state->first_list_item = false; 339220a0857SSami Tolvanen } else { 340220a0857SSami Tolvanen process(cache, " ,"); 341220a0857SSami Tolvanen process_linebreak(cache, 0); 342220a0857SSami Tolvanen } 343220a0857SSami Tolvanen } 344220a0857SSami Tolvanen 345220a0857SSami Tolvanen /* Comma-separated with DW_AT_type */ 346220a0857SSami Tolvanen static void __process_list_type(struct state *state, struct die *cache, 347220a0857SSami Tolvanen Dwarf_Die *die, const char *type) 348220a0857SSami Tolvanen { 349220a0857SSami Tolvanen const char *name = get_name_attr(die); 350220a0857SSami Tolvanen 351220a0857SSami Tolvanen process_list_comma(state, cache); 352220a0857SSami Tolvanen process(cache, type); 353220a0857SSami Tolvanen process_type_attr(state, cache, die); 354220a0857SSami Tolvanen if (name) { 355220a0857SSami Tolvanen process(cache, " "); 356220a0857SSami Tolvanen process(cache, name); 357220a0857SSami Tolvanen } 358f6bb9245SSami Tolvanen process_accessibility_attr(cache, die); 359f6bb9245SSami Tolvanen process_bit_size_attr(cache, die); 360f6bb9245SSami Tolvanen process_data_bit_offset_attr(cache, die); 361f6bb9245SSami Tolvanen process_data_member_location_attr(cache, die); 362220a0857SSami Tolvanen } 363220a0857SSami Tolvanen 364220a0857SSami Tolvanen #define DEFINE_PROCESS_LIST_TYPE(type) \ 365220a0857SSami Tolvanen static void process_##type##_type(struct state *state, \ 366220a0857SSami Tolvanen struct die *cache, Dwarf_Die *die) \ 367220a0857SSami Tolvanen { \ 368220a0857SSami Tolvanen __process_list_type(state, cache, die, #type " "); \ 369220a0857SSami Tolvanen } 370220a0857SSami Tolvanen 371220a0857SSami Tolvanen DEFINE_PROCESS_LIST_TYPE(formal_parameter) 372f6bb9245SSami Tolvanen DEFINE_PROCESS_LIST_TYPE(member) 373220a0857SSami Tolvanen 37406b8b036SSami Tolvanen /* Container types with DW_AT_type */ 37506b8b036SSami Tolvanen static void __process_type(struct state *state, struct die *cache, 37606b8b036SSami Tolvanen Dwarf_Die *die, const char *type) 37706b8b036SSami Tolvanen { 37806b8b036SSami Tolvanen process(cache, type); 37906b8b036SSami Tolvanen process_fqn(cache, die); 38006b8b036SSami Tolvanen process(cache, " {"); 38106b8b036SSami Tolvanen process_linebreak(cache, 1); 38206b8b036SSami Tolvanen process_type_attr(state, cache, die); 38306b8b036SSami Tolvanen process_linebreak(cache, -1); 38406b8b036SSami Tolvanen process(cache, "}"); 38506b8b036SSami Tolvanen process_byte_size_attr(cache, die); 38606b8b036SSami Tolvanen process_alignment_attr(cache, die); 38706b8b036SSami Tolvanen } 38806b8b036SSami Tolvanen 38906b8b036SSami Tolvanen #define DEFINE_PROCESS_TYPE(type) \ 39006b8b036SSami Tolvanen static void process_##type##_type(struct state *state, \ 39106b8b036SSami Tolvanen struct die *cache, Dwarf_Die *die) \ 39206b8b036SSami Tolvanen { \ 39306b8b036SSami Tolvanen __process_type(state, cache, die, #type "_type"); \ 39406b8b036SSami Tolvanen } 39506b8b036SSami Tolvanen 39606b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(atomic) 39706b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(const) 39806b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(immutable) 39906b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(packed) 40006b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(pointer) 40106b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(reference) 40206b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(restrict) 40306b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(rvalue_reference) 40406b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(shared) 405f6bb9245SSami Tolvanen DEFINE_PROCESS_TYPE(template_type_parameter) 40606b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(volatile) 40706b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(typedef) 40806b8b036SSami Tolvanen 409c772f1d1SSami Tolvanen static void process_subrange_type(struct state *state, struct die *cache, 410c772f1d1SSami Tolvanen Dwarf_Die *die) 411c772f1d1SSami Tolvanen { 412c772f1d1SSami Tolvanen Dwarf_Word count = 0; 413c772f1d1SSami Tolvanen 414c772f1d1SSami Tolvanen if (get_udata_attr(die, DW_AT_count, &count)) 415c772f1d1SSami Tolvanen process_fmt(cache, "[%" PRIu64 "]", count); 416c772f1d1SSami Tolvanen else if (get_udata_attr(die, DW_AT_upper_bound, &count)) 417c772f1d1SSami Tolvanen process_fmt(cache, "[%" PRIu64 "]", count + 1); 418c772f1d1SSami Tolvanen else 419c772f1d1SSami Tolvanen process(cache, "[]"); 420c772f1d1SSami Tolvanen } 421c772f1d1SSami Tolvanen 422c772f1d1SSami Tolvanen static void process_array_type(struct state *state, struct die *cache, 423c772f1d1SSami Tolvanen Dwarf_Die *die) 424c772f1d1SSami Tolvanen { 425c772f1d1SSami Tolvanen process(cache, "array_type"); 426c772f1d1SSami Tolvanen /* Array size */ 427c772f1d1SSami Tolvanen check(process_die_container(state, cache, die, process_type, 428c772f1d1SSami Tolvanen match_subrange_type)); 429c772f1d1SSami Tolvanen process(cache, " {"); 430c772f1d1SSami Tolvanen process_linebreak(cache, 1); 431c772f1d1SSami Tolvanen process_type_attr(state, cache, die); 432c772f1d1SSami Tolvanen process_linebreak(cache, -1); 433c772f1d1SSami Tolvanen process(cache, "}"); 434c772f1d1SSami Tolvanen } 435c772f1d1SSami Tolvanen 436220a0857SSami Tolvanen static void __process_subroutine_type(struct state *state, struct die *cache, 437220a0857SSami Tolvanen Dwarf_Die *die, const char *type) 438220a0857SSami Tolvanen { 439220a0857SSami Tolvanen process(cache, type); 440220a0857SSami Tolvanen process(cache, " ("); 441220a0857SSami Tolvanen process_linebreak(cache, 1); 442220a0857SSami Tolvanen /* Parameters */ 443220a0857SSami Tolvanen check(process_die_container(state, cache, die, process_type, 444220a0857SSami Tolvanen match_formal_parameter_type)); 445220a0857SSami Tolvanen process_linebreak(cache, -1); 446220a0857SSami Tolvanen process(cache, ")"); 447220a0857SSami Tolvanen process_linebreak(cache, 0); 448220a0857SSami Tolvanen /* Return type */ 449220a0857SSami Tolvanen process(cache, "-> "); 450220a0857SSami Tolvanen process_type_attr(state, cache, die); 451220a0857SSami Tolvanen } 452220a0857SSami Tolvanen 453220a0857SSami Tolvanen static void process_subroutine_type(struct state *state, struct die *cache, 454220a0857SSami Tolvanen Dwarf_Die *die) 455220a0857SSami Tolvanen { 456220a0857SSami Tolvanen __process_subroutine_type(state, cache, die, "subroutine_type"); 457220a0857SSami Tolvanen } 458220a0857SSami Tolvanen 459f6bb9245SSami Tolvanen static void process_variant_type(struct state *state, struct die *cache, 460f6bb9245SSami Tolvanen Dwarf_Die *die) 461f6bb9245SSami Tolvanen { 462f6bb9245SSami Tolvanen process_list_comma(state, cache); 463f6bb9245SSami Tolvanen process(cache, "variant {"); 464f6bb9245SSami Tolvanen process_linebreak(cache, 1); 465f6bb9245SSami Tolvanen check(process_die_container(state, cache, die, process_type, 466f6bb9245SSami Tolvanen match_member_type)); 467f6bb9245SSami Tolvanen process_linebreak(cache, -1); 468f6bb9245SSami Tolvanen process(cache, "}"); 469f6bb9245SSami Tolvanen process_discr_value_attr(cache, die); 470f6bb9245SSami Tolvanen } 471f6bb9245SSami Tolvanen 472f6bb9245SSami Tolvanen static void process_variant_part_type(struct state *state, struct die *cache, 473f6bb9245SSami Tolvanen Dwarf_Die *die) 474f6bb9245SSami Tolvanen { 475f6bb9245SSami Tolvanen process_list_comma(state, cache); 476f6bb9245SSami Tolvanen process(cache, "variant_part {"); 477f6bb9245SSami Tolvanen process_linebreak(cache, 1); 478f6bb9245SSami Tolvanen check(process_die_container(state, cache, die, process_type, 479f6bb9245SSami Tolvanen match_all)); 480f6bb9245SSami Tolvanen process_linebreak(cache, -1); 481f6bb9245SSami Tolvanen process(cache, "}"); 482f6bb9245SSami Tolvanen } 483f6bb9245SSami Tolvanen 484f6bb9245SSami Tolvanen static int ___process_structure_type(struct state *state, struct die *cache, 485f6bb9245SSami Tolvanen Dwarf_Die *die) 486f6bb9245SSami Tolvanen { 487f6bb9245SSami Tolvanen switch (dwarf_tag(die)) { 488f6bb9245SSami Tolvanen case DW_TAG_member: 489f6bb9245SSami Tolvanen case DW_TAG_variant_part: 490f6bb9245SSami Tolvanen return check(process_type(state, cache, die)); 491f6bb9245SSami Tolvanen case DW_TAG_class_type: 492f6bb9245SSami Tolvanen case DW_TAG_enumeration_type: 493f6bb9245SSami Tolvanen case DW_TAG_structure_type: 494f6bb9245SSami Tolvanen case DW_TAG_template_type_parameter: 495f6bb9245SSami Tolvanen case DW_TAG_union_type: 496f6bb9245SSami Tolvanen case DW_TAG_subprogram: 497f6bb9245SSami Tolvanen /* Skip non-member types, including member functions */ 498f6bb9245SSami Tolvanen return 0; 499f6bb9245SSami Tolvanen default: 500f6bb9245SSami Tolvanen error("unexpected structure_type child: %x", dwarf_tag(die)); 501f6bb9245SSami Tolvanen } 502f6bb9245SSami Tolvanen } 503f6bb9245SSami Tolvanen 504f6bb9245SSami Tolvanen static void __process_structure_type(struct state *state, struct die *cache, 505f6bb9245SSami Tolvanen Dwarf_Die *die, const char *type, 506f6bb9245SSami Tolvanen die_callback_t process_func, 507f6bb9245SSami Tolvanen die_match_callback_t match_func) 508f6bb9245SSami Tolvanen { 509*f936c129SSami Tolvanen bool expand; 510*f936c129SSami Tolvanen 511f6bb9245SSami Tolvanen process(cache, type); 512f6bb9245SSami Tolvanen process_fqn(cache, die); 513f6bb9245SSami Tolvanen process(cache, " {"); 514f6bb9245SSami Tolvanen process_linebreak(cache, 1); 515f6bb9245SSami Tolvanen 516*f936c129SSami Tolvanen expand = state->expand.expand && is_kabi_definition(die); 517*f936c129SSami Tolvanen 518*f936c129SSami Tolvanen if (expand) { 519f6bb9245SSami Tolvanen check(process_die_container(state, cache, die, process_func, 520f6bb9245SSami Tolvanen match_func)); 521*f936c129SSami Tolvanen } 522f6bb9245SSami Tolvanen 523f6bb9245SSami Tolvanen process_linebreak(cache, -1); 524f6bb9245SSami Tolvanen process(cache, "}"); 525f6bb9245SSami Tolvanen 526*f936c129SSami Tolvanen if (expand) { 527f6bb9245SSami Tolvanen process_byte_size_attr(cache, die); 528f6bb9245SSami Tolvanen process_alignment_attr(cache, die); 529f6bb9245SSami Tolvanen } 530*f936c129SSami Tolvanen } 531f6bb9245SSami Tolvanen 532f6bb9245SSami Tolvanen #define DEFINE_PROCESS_STRUCTURE_TYPE(structure) \ 533f6bb9245SSami Tolvanen static void process_##structure##_type( \ 534f6bb9245SSami Tolvanen struct state *state, struct die *cache, Dwarf_Die *die) \ 535f6bb9245SSami Tolvanen { \ 536f6bb9245SSami Tolvanen __process_structure_type(state, cache, die, \ 537f6bb9245SSami Tolvanen #structure "_type", \ 538f6bb9245SSami Tolvanen ___process_structure_type, \ 539f6bb9245SSami Tolvanen match_all); \ 540f6bb9245SSami Tolvanen } 541f6bb9245SSami Tolvanen 542f6bb9245SSami Tolvanen DEFINE_PROCESS_STRUCTURE_TYPE(class) 543f6bb9245SSami Tolvanen DEFINE_PROCESS_STRUCTURE_TYPE(structure) 544f6bb9245SSami Tolvanen DEFINE_PROCESS_STRUCTURE_TYPE(union) 545f6bb9245SSami Tolvanen 546f6bb9245SSami Tolvanen static void process_enumerator_type(struct state *state, struct die *cache, 547f6bb9245SSami Tolvanen Dwarf_Die *die) 548f6bb9245SSami Tolvanen { 549f6bb9245SSami Tolvanen Dwarf_Word value; 550f6bb9245SSami Tolvanen 551f6bb9245SSami Tolvanen process_list_comma(state, cache); 552f6bb9245SSami Tolvanen process(cache, "enumerator"); 553f6bb9245SSami Tolvanen process_fqn(cache, die); 554f6bb9245SSami Tolvanen 555f6bb9245SSami Tolvanen if (get_udata_attr(die, DW_AT_const_value, &value)) { 556f6bb9245SSami Tolvanen process(cache, " = "); 557f6bb9245SSami Tolvanen process_fmt(cache, "%" PRIu64, value); 558f6bb9245SSami Tolvanen } 559f6bb9245SSami Tolvanen } 560f6bb9245SSami Tolvanen 561f6bb9245SSami Tolvanen static void process_enumeration_type(struct state *state, struct die *cache, 562f6bb9245SSami Tolvanen Dwarf_Die *die) 563f6bb9245SSami Tolvanen { 564f6bb9245SSami Tolvanen __process_structure_type(state, cache, die, "enumeration_type", 565f6bb9245SSami Tolvanen process_type, match_enumerator_type); 566f6bb9245SSami Tolvanen } 567f6bb9245SSami Tolvanen 5680c1c7627SSami Tolvanen static void process_base_type(struct state *state, struct die *cache, 5690c1c7627SSami Tolvanen Dwarf_Die *die) 5705b7780e8SSami Tolvanen { 5710c1c7627SSami Tolvanen process(cache, "base_type"); 5720c1c7627SSami Tolvanen process_fqn(cache, die); 5730c1c7627SSami Tolvanen process_byte_size_attr(cache, die); 5740c1c7627SSami Tolvanen process_encoding_attr(cache, die); 5750c1c7627SSami Tolvanen process_alignment_attr(cache, die); 5760c1c7627SSami Tolvanen } 5770c1c7627SSami Tolvanen 578f6bb9245SSami Tolvanen static void process_unspecified_type(struct state *state, struct die *cache, 579f6bb9245SSami Tolvanen Dwarf_Die *die) 580f6bb9245SSami Tolvanen { 581f6bb9245SSami Tolvanen /* 582f6bb9245SSami Tolvanen * These can be emitted for stand-alone assembly code, which means we 583f6bb9245SSami Tolvanen * might run into them in vmlinux.o. 584f6bb9245SSami Tolvanen */ 585f6bb9245SSami Tolvanen process(cache, "unspecified_type"); 586f6bb9245SSami Tolvanen } 587f6bb9245SSami Tolvanen 5880c1c7627SSami Tolvanen static void process_cached(struct state *state, struct die *cache, 5890c1c7627SSami Tolvanen Dwarf_Die *die) 5900c1c7627SSami Tolvanen { 5910c1c7627SSami Tolvanen struct die_fragment *df; 5920c1c7627SSami Tolvanen Dwarf_Die child; 5930c1c7627SSami Tolvanen 5940c1c7627SSami Tolvanen list_for_each_entry(df, &cache->fragments, list) { 5950c1c7627SSami Tolvanen switch (df->type) { 5960c1c7627SSami Tolvanen case FRAGMENT_STRING: 5970c1c7627SSami Tolvanen process(NULL, df->data.str); 5980c1c7627SSami Tolvanen break; 59906b8b036SSami Tolvanen case FRAGMENT_LINEBREAK: 60006b8b036SSami Tolvanen process_linebreak(NULL, df->data.linebreak); 60106b8b036SSami Tolvanen break; 6020c1c7627SSami Tolvanen case FRAGMENT_DIE: 6030c1c7627SSami Tolvanen if (!dwarf_die_addr_die(dwarf_cu_getdwarf(die->cu), 6040c1c7627SSami Tolvanen (void *)df->data.addr, &child)) 6050c1c7627SSami Tolvanen error("dwarf_die_addr_die failed"); 6060c1c7627SSami Tolvanen check(process_type(state, NULL, &child)); 6070c1c7627SSami Tolvanen break; 6080c1c7627SSami Tolvanen default: 6090c1c7627SSami Tolvanen error("empty die_fragment"); 6100c1c7627SSami Tolvanen } 6110c1c7627SSami Tolvanen } 6125b7780e8SSami Tolvanen } 6135b7780e8SSami Tolvanen 614*f936c129SSami Tolvanen static void state_init(struct state *state) 615*f936c129SSami Tolvanen { 616*f936c129SSami Tolvanen state->expand.expand = true; 617*f936c129SSami Tolvanen cache_init(&state->expansion_cache); 618*f936c129SSami Tolvanen } 619*f936c129SSami Tolvanen 620*f936c129SSami Tolvanen static void expansion_state_restore(struct expansion_state *state, 621*f936c129SSami Tolvanen struct expansion_state *saved) 622*f936c129SSami Tolvanen { 623*f936c129SSami Tolvanen state->expand = saved->expand; 624*f936c129SSami Tolvanen } 625*f936c129SSami Tolvanen 626*f936c129SSami Tolvanen static void expansion_state_save(struct expansion_state *state, 627*f936c129SSami Tolvanen struct expansion_state *saved) 628*f936c129SSami Tolvanen { 629*f936c129SSami Tolvanen expansion_state_restore(saved, state); 630*f936c129SSami Tolvanen } 631*f936c129SSami Tolvanen 632*f936c129SSami Tolvanen static bool is_expanded_type(int tag) 633*f936c129SSami Tolvanen { 634*f936c129SSami Tolvanen return tag == DW_TAG_class_type || tag == DW_TAG_structure_type || 635*f936c129SSami Tolvanen tag == DW_TAG_union_type || tag == DW_TAG_enumeration_type; 636*f936c129SSami Tolvanen } 637*f936c129SSami Tolvanen 6385b7780e8SSami Tolvanen #define PROCESS_TYPE(type) \ 6395b7780e8SSami Tolvanen case DW_TAG_##type##_type: \ 6400c1c7627SSami Tolvanen process_##type##_type(state, cache, die); \ 6415b7780e8SSami Tolvanen break; 6425b7780e8SSami Tolvanen 6430c1c7627SSami Tolvanen static int process_type(struct state *state, struct die *parent, Dwarf_Die *die) 6445b7780e8SSami Tolvanen { 645*f936c129SSami Tolvanen enum die_state want_state = DIE_COMPLETE; 6460c1c7627SSami Tolvanen struct die *cache; 647*f936c129SSami Tolvanen struct expansion_state saved; 6485b7780e8SSami Tolvanen int tag = dwarf_tag(die); 6495b7780e8SSami Tolvanen 650*f936c129SSami Tolvanen expansion_state_save(&state->expand, &saved); 651*f936c129SSami Tolvanen 6520c1c7627SSami Tolvanen /* 653*f936c129SSami Tolvanen * Structures and enumeration types are expanded only once per 654*f936c129SSami Tolvanen * exported symbol. This is sufficient for detecting ABI changes 655*f936c129SSami Tolvanen * within the structure. 656*f936c129SSami Tolvanen */ 657*f936c129SSami Tolvanen if (is_expanded_type(tag)) { 658*f936c129SSami Tolvanen if (cache_was_expanded(&state->expansion_cache, die->addr)) 659*f936c129SSami Tolvanen state->expand.expand = false; 660*f936c129SSami Tolvanen 661*f936c129SSami Tolvanen if (state->expand.expand) 662*f936c129SSami Tolvanen cache_mark_expanded(&state->expansion_cache, die->addr); 663*f936c129SSami Tolvanen else 664*f936c129SSami Tolvanen want_state = DIE_UNEXPANDED; 665*f936c129SSami Tolvanen } 666*f936c129SSami Tolvanen 667*f936c129SSami Tolvanen /* 668*f936c129SSami Tolvanen * If we have want_state already cached, use it instead of walking 6690c1c7627SSami Tolvanen * through DWARF. 6700c1c7627SSami Tolvanen */ 671*f936c129SSami Tolvanen cache = die_map_get(die, want_state); 6720c1c7627SSami Tolvanen 673*f936c129SSami Tolvanen if (cache->state == want_state) { 6740c1c7627SSami Tolvanen process_cached(state, cache, die); 6750c1c7627SSami Tolvanen die_map_add_die(parent, cache); 676*f936c129SSami Tolvanen 677*f936c129SSami Tolvanen expansion_state_restore(&state->expand, &saved); 6780c1c7627SSami Tolvanen return 0; 6790c1c7627SSami Tolvanen } 6800c1c7627SSami Tolvanen 6815b7780e8SSami Tolvanen switch (tag) { 68206b8b036SSami Tolvanen /* Type modifiers */ 68306b8b036SSami Tolvanen PROCESS_TYPE(atomic) 68406b8b036SSami Tolvanen PROCESS_TYPE(const) 68506b8b036SSami Tolvanen PROCESS_TYPE(immutable) 68606b8b036SSami Tolvanen PROCESS_TYPE(packed) 68706b8b036SSami Tolvanen PROCESS_TYPE(pointer) 68806b8b036SSami Tolvanen PROCESS_TYPE(reference) 68906b8b036SSami Tolvanen PROCESS_TYPE(restrict) 69006b8b036SSami Tolvanen PROCESS_TYPE(rvalue_reference) 69106b8b036SSami Tolvanen PROCESS_TYPE(shared) 69206b8b036SSami Tolvanen PROCESS_TYPE(volatile) 693f6bb9245SSami Tolvanen /* Container types */ 694f6bb9245SSami Tolvanen PROCESS_TYPE(class) 695f6bb9245SSami Tolvanen PROCESS_TYPE(structure) 696f6bb9245SSami Tolvanen PROCESS_TYPE(union) 697f6bb9245SSami Tolvanen PROCESS_TYPE(enumeration) 698220a0857SSami Tolvanen /* Subtypes */ 699f6bb9245SSami Tolvanen PROCESS_TYPE(enumerator) 700220a0857SSami Tolvanen PROCESS_TYPE(formal_parameter) 701f6bb9245SSami Tolvanen PROCESS_TYPE(member) 702c772f1d1SSami Tolvanen PROCESS_TYPE(subrange) 703f6bb9245SSami Tolvanen PROCESS_TYPE(template_type_parameter) 704f6bb9245SSami Tolvanen PROCESS_TYPE(variant) 705f6bb9245SSami Tolvanen PROCESS_TYPE(variant_part) 70606b8b036SSami Tolvanen /* Other types */ 707c772f1d1SSami Tolvanen PROCESS_TYPE(array) 7085b7780e8SSami Tolvanen PROCESS_TYPE(base) 709220a0857SSami Tolvanen PROCESS_TYPE(subroutine) 71006b8b036SSami Tolvanen PROCESS_TYPE(typedef) 711f6bb9245SSami Tolvanen PROCESS_TYPE(unspecified) 7125b7780e8SSami Tolvanen default: 713f6bb9245SSami Tolvanen error("unexpected type: %x", tag); 7145b7780e8SSami Tolvanen } 7155b7780e8SSami Tolvanen 7160c1c7627SSami Tolvanen /* Update cache state and append to the parent (if any) */ 7170c1c7627SSami Tolvanen cache->tag = tag; 718*f936c129SSami Tolvanen cache->state = want_state; 7190c1c7627SSami Tolvanen die_map_add_die(parent, cache); 7200c1c7627SSami Tolvanen 721*f936c129SSami Tolvanen expansion_state_restore(&state->expand, &saved); 7225b7780e8SSami Tolvanen return 0; 7235b7780e8SSami Tolvanen } 7245b7780e8SSami Tolvanen 725f2856884SSami Tolvanen /* 726f2856884SSami Tolvanen * Exported symbol processing 727f2856884SSami Tolvanen */ 728f2856884SSami Tolvanen static void process_symbol(struct state *state, Dwarf_Die *die, 729f2856884SSami Tolvanen die_callback_t process_func) 730f2856884SSami Tolvanen { 731f2856884SSami Tolvanen debug("%s", state->sym->name); 7320c1c7627SSami Tolvanen check(process_func(state, NULL, die)); 733f2856884SSami Tolvanen if (dump_dies) 734f2856884SSami Tolvanen fputs("\n", stderr); 735f2856884SSami Tolvanen } 736f2856884SSami Tolvanen 7370c1c7627SSami Tolvanen static int __process_subprogram(struct state *state, struct die *cache, 7380c1c7627SSami Tolvanen Dwarf_Die *die) 739f2856884SSami Tolvanen { 740220a0857SSami Tolvanen __process_subroutine_type(state, cache, die, "subprogram"); 741f2856884SSami Tolvanen return 0; 742f2856884SSami Tolvanen } 743f2856884SSami Tolvanen 744f2856884SSami Tolvanen static void process_subprogram(struct state *state, Dwarf_Die *die) 745f2856884SSami Tolvanen { 746f2856884SSami Tolvanen process_symbol(state, die, __process_subprogram); 747f2856884SSami Tolvanen } 748f2856884SSami Tolvanen 7490c1c7627SSami Tolvanen static int __process_variable(struct state *state, struct die *cache, 7500c1c7627SSami Tolvanen Dwarf_Die *die) 751f2856884SSami Tolvanen { 7520c1c7627SSami Tolvanen process(cache, "variable "); 7530c1c7627SSami Tolvanen process_type_attr(state, cache, die); 754f2856884SSami Tolvanen return 0; 755f2856884SSami Tolvanen } 756f2856884SSami Tolvanen 757f2856884SSami Tolvanen static void process_variable(struct state *state, Dwarf_Die *die) 758f2856884SSami Tolvanen { 759f2856884SSami Tolvanen process_symbol(state, die, __process_variable); 760f2856884SSami Tolvanen } 761f2856884SSami Tolvanen 7620c1c7627SSami Tolvanen static int process_exported_symbols(struct state *unused, struct die *cache, 7630c1c7627SSami Tolvanen Dwarf_Die *die) 764f2856884SSami Tolvanen { 765f2856884SSami Tolvanen int tag = dwarf_tag(die); 766f2856884SSami Tolvanen 767f2856884SSami Tolvanen switch (tag) { 768f2856884SSami Tolvanen /* Possible containers of exported symbols */ 769f2856884SSami Tolvanen case DW_TAG_namespace: 770f2856884SSami Tolvanen case DW_TAG_class_type: 771f2856884SSami Tolvanen case DW_TAG_structure_type: 772f2856884SSami Tolvanen return check(process_die_container( 7730c1c7627SSami Tolvanen NULL, cache, die, process_exported_symbols, match_all)); 774f2856884SSami Tolvanen 775f2856884SSami Tolvanen /* Possible exported symbols */ 776f2856884SSami Tolvanen case DW_TAG_subprogram: 777f2856884SSami Tolvanen case DW_TAG_variable: { 778f2856884SSami Tolvanen struct state state; 779f2856884SSami Tolvanen 780f2856884SSami Tolvanen if (!match_export_symbol(&state, die)) 781f2856884SSami Tolvanen return 0; 782f2856884SSami Tolvanen 783*f936c129SSami Tolvanen state_init(&state); 784*f936c129SSami Tolvanen 785f2856884SSami Tolvanen if (tag == DW_TAG_subprogram) 786f2856884SSami Tolvanen process_subprogram(&state, &state.die); 787f2856884SSami Tolvanen else 788f2856884SSami Tolvanen process_variable(&state, &state.die); 789f2856884SSami Tolvanen 790*f936c129SSami Tolvanen cache_free(&state.expansion_cache); 791f2856884SSami Tolvanen return 0; 792f2856884SSami Tolvanen } 793f2856884SSami Tolvanen default: 794f2856884SSami Tolvanen return 0; 795f2856884SSami Tolvanen } 796f2856884SSami Tolvanen } 797f2856884SSami Tolvanen 798f2856884SSami Tolvanen void process_cu(Dwarf_Die *cudie) 799f2856884SSami Tolvanen { 8000c1c7627SSami Tolvanen check(process_die_container(NULL, NULL, cudie, process_exported_symbols, 801f2856884SSami Tolvanen match_all)); 802*f936c129SSami Tolvanen 803*f936c129SSami Tolvanen cache_free(&srcfile_cache); 804f2856884SSami Tolvanen } 805