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 30f936c129SSami 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 84f936c129SSami Tolvanen /* DW_AT_decl_file -> struct srcfile */ 85f936c129SSami Tolvanen static struct cache srcfile_cache; 86f936c129SSami Tolvanen 87f936c129SSami Tolvanen static bool is_definition_private(Dwarf_Die *die) 88f936c129SSami Tolvanen { 89f936c129SSami Tolvanen Dwarf_Word filenum; 90f936c129SSami Tolvanen Dwarf_Files *files; 91f936c129SSami Tolvanen Dwarf_Die cudie; 92f936c129SSami Tolvanen const char *s; 93f936c129SSami Tolvanen int res; 94f936c129SSami Tolvanen 95f936c129SSami Tolvanen /* 96f936c129SSami Tolvanen * Definitions in .c files cannot change the public ABI, 97f936c129SSami Tolvanen * so consider them private. 98f936c129SSami Tolvanen */ 99f936c129SSami Tolvanen if (!get_udata_attr(die, DW_AT_decl_file, &filenum)) 100f936c129SSami Tolvanen return false; 101f936c129SSami Tolvanen 102f936c129SSami Tolvanen res = cache_get(&srcfile_cache, filenum); 103f936c129SSami Tolvanen if (res >= 0) 104f936c129SSami Tolvanen return !!res; 105f936c129SSami Tolvanen 106f936c129SSami Tolvanen if (!dwarf_cu_die(die->cu, &cudie, NULL, NULL, NULL, NULL, NULL, NULL)) 107f936c129SSami Tolvanen error("dwarf_cu_die failed: '%s'", dwarf_errmsg(-1)); 108f936c129SSami Tolvanen 109f936c129SSami Tolvanen if (dwarf_getsrcfiles(&cudie, &files, NULL)) 110f936c129SSami Tolvanen error("dwarf_getsrcfiles failed: '%s'", dwarf_errmsg(-1)); 111f936c129SSami Tolvanen 112f936c129SSami Tolvanen s = dwarf_filesrc(files, filenum, NULL, NULL); 113f936c129SSami Tolvanen if (!s) 114f936c129SSami Tolvanen error("dwarf_filesrc failed: '%s'", dwarf_errmsg(-1)); 115f936c129SSami Tolvanen 116f936c129SSami Tolvanen s = strrchr(s, '.'); 117f936c129SSami Tolvanen res = s && !strcmp(s, ".c"); 118f936c129SSami Tolvanen cache_set(&srcfile_cache, filenum, res); 119f936c129SSami Tolvanen 120f936c129SSami Tolvanen return !!res; 121f936c129SSami Tolvanen } 122f936c129SSami Tolvanen 123*936cf61cSSami Tolvanen static bool is_kabi_definition(struct die *cache, Dwarf_Die *die) 124f936c129SSami Tolvanen { 125f936c129SSami Tolvanen bool value; 126f936c129SSami Tolvanen 127f936c129SSami Tolvanen if (get_flag_attr(die, DW_AT_declaration, &value) && value) 128f936c129SSami Tolvanen return false; 129f936c129SSami Tolvanen 130*936cf61cSSami Tolvanen if (kabi_is_declonly(cache->fqn)) 131*936cf61cSSami Tolvanen return false; 132*936cf61cSSami Tolvanen 133f936c129SSami Tolvanen return !is_definition_private(die); 134f936c129SSami Tolvanen } 135f936c129SSami Tolvanen 136f2856884SSami Tolvanen /* 137f2856884SSami Tolvanen * Type string processing 138f2856884SSami Tolvanen */ 1390c1c7627SSami Tolvanen static void process(struct die *cache, const char *s) 140f2856884SSami Tolvanen { 141f2856884SSami Tolvanen s = s ?: "<null>"; 142f2856884SSami Tolvanen 14306b8b036SSami Tolvanen if (dump_dies && do_linebreak) { 14406b8b036SSami Tolvanen fputs("\n", stderr); 14506b8b036SSami Tolvanen for (int i = 0; i < indentation_level; i++) 14606b8b036SSami Tolvanen fputs(" ", stderr); 14706b8b036SSami Tolvanen do_linebreak = false; 14806b8b036SSami Tolvanen } 149f2856884SSami Tolvanen if (dump_dies) 150f2856884SSami Tolvanen fputs(s, stderr); 1510c1c7627SSami Tolvanen 152d2ffdc1cSSami Tolvanen if (cache) 153d2ffdc1cSSami Tolvanen die_debug_r("cache %p string '%s'", cache, s); 1540c1c7627SSami Tolvanen die_map_add_string(cache, s); 155f2856884SSami Tolvanen } 156f2856884SSami Tolvanen 1575b7780e8SSami Tolvanen #define MAX_FMT_BUFFER_SIZE 128 1585b7780e8SSami Tolvanen 1590c1c7627SSami Tolvanen static void process_fmt(struct die *cache, const char *fmt, ...) 1605b7780e8SSami Tolvanen { 1615b7780e8SSami Tolvanen char buf[MAX_FMT_BUFFER_SIZE]; 1625b7780e8SSami Tolvanen va_list args; 1635b7780e8SSami Tolvanen 1645b7780e8SSami Tolvanen va_start(args, fmt); 1655b7780e8SSami Tolvanen 1665b7780e8SSami Tolvanen if (checkp(vsnprintf(buf, sizeof(buf), fmt, args)) >= sizeof(buf)) 1675b7780e8SSami Tolvanen error("vsnprintf overflow: increase MAX_FMT_BUFFER_SIZE"); 1685b7780e8SSami Tolvanen 1690c1c7627SSami Tolvanen process(cache, buf); 1705b7780e8SSami Tolvanen va_end(args); 1715b7780e8SSami Tolvanen } 1725b7780e8SSami Tolvanen 1735b7780e8SSami Tolvanen #define MAX_FQN_SIZE 64 1745b7780e8SSami Tolvanen 1755b7780e8SSami Tolvanen /* Get a fully qualified name from DWARF scopes */ 1765b7780e8SSami Tolvanen static char *get_fqn(Dwarf_Die *die) 1775b7780e8SSami Tolvanen { 1785b7780e8SSami Tolvanen const char *list[MAX_FQN_SIZE]; 1795b7780e8SSami Tolvanen Dwarf_Die *scopes = NULL; 1805b7780e8SSami Tolvanen bool has_name = false; 1815b7780e8SSami Tolvanen char *fqn = NULL; 1825b7780e8SSami Tolvanen char *p; 1835b7780e8SSami Tolvanen int count = 0; 1845b7780e8SSami Tolvanen int len = 0; 1855b7780e8SSami Tolvanen int res; 1865b7780e8SSami Tolvanen int i; 1875b7780e8SSami Tolvanen 1885b7780e8SSami Tolvanen res = checkp(dwarf_getscopes_die(die, &scopes)); 1895b7780e8SSami Tolvanen if (!res) { 1905b7780e8SSami Tolvanen list[count] = get_name_attr(die); 1915b7780e8SSami Tolvanen 1925b7780e8SSami Tolvanen if (!list[count]) 1935b7780e8SSami Tolvanen return NULL; 1945b7780e8SSami Tolvanen 1955b7780e8SSami Tolvanen len += strlen(list[count]); 1965b7780e8SSami Tolvanen count++; 1975b7780e8SSami Tolvanen 1985b7780e8SSami Tolvanen goto done; 1995b7780e8SSami Tolvanen } 2005b7780e8SSami Tolvanen 2015b7780e8SSami Tolvanen for (i = res - 1; i >= 0 && count < MAX_FQN_SIZE; i--) { 2025b7780e8SSami Tolvanen if (dwarf_tag(&scopes[i]) == DW_TAG_compile_unit) 2035b7780e8SSami Tolvanen continue; 2045b7780e8SSami Tolvanen 2055b7780e8SSami Tolvanen list[count] = get_name_attr(&scopes[i]); 2065b7780e8SSami Tolvanen 2075b7780e8SSami Tolvanen if (list[count]) { 2085b7780e8SSami Tolvanen has_name = true; 2095b7780e8SSami Tolvanen } else { 2105b7780e8SSami Tolvanen list[count] = "<anonymous>"; 2115b7780e8SSami Tolvanen has_name = false; 2125b7780e8SSami Tolvanen } 2135b7780e8SSami Tolvanen 2145b7780e8SSami Tolvanen len += strlen(list[count]); 2155b7780e8SSami Tolvanen count++; 2165b7780e8SSami Tolvanen 2175b7780e8SSami Tolvanen if (i > 0) { 2185b7780e8SSami Tolvanen list[count++] = "::"; 2195b7780e8SSami Tolvanen len += 2; 2205b7780e8SSami Tolvanen } 2215b7780e8SSami Tolvanen } 2225b7780e8SSami Tolvanen 2235b7780e8SSami Tolvanen free(scopes); 2245b7780e8SSami Tolvanen 2255b7780e8SSami Tolvanen if (count == MAX_FQN_SIZE) 2265b7780e8SSami Tolvanen warn("increase MAX_FQN_SIZE: reached the maximum"); 2275b7780e8SSami Tolvanen 2285b7780e8SSami Tolvanen /* Consider the DIE unnamed if the last scope doesn't have a name */ 2295b7780e8SSami Tolvanen if (!has_name) 2305b7780e8SSami Tolvanen return NULL; 2315b7780e8SSami Tolvanen done: 2325b7780e8SSami Tolvanen fqn = xmalloc(len + 1); 2335b7780e8SSami Tolvanen *fqn = '\0'; 2345b7780e8SSami Tolvanen 2355b7780e8SSami Tolvanen p = fqn; 2365b7780e8SSami Tolvanen for (i = 0; i < count; i++) 2375b7780e8SSami Tolvanen p = stpcpy(p, list[i]); 2385b7780e8SSami Tolvanen 2395b7780e8SSami Tolvanen return fqn; 2405b7780e8SSami Tolvanen } 2415b7780e8SSami Tolvanen 2420c1c7627SSami Tolvanen static void update_fqn(struct die *cache, Dwarf_Die *die) 2435b7780e8SSami Tolvanen { 2440c1c7627SSami Tolvanen if (!cache->fqn) 2450c1c7627SSami Tolvanen cache->fqn = get_fqn(die) ?: ""; 2460c1c7627SSami Tolvanen } 2470c1c7627SSami Tolvanen 2480c1c7627SSami Tolvanen static void process_fqn(struct die *cache, Dwarf_Die *die) 2490c1c7627SSami Tolvanen { 2500c1c7627SSami Tolvanen update_fqn(cache, die); 2510c1c7627SSami Tolvanen if (*cache->fqn) 2520c1c7627SSami Tolvanen process(cache, " "); 2530c1c7627SSami Tolvanen process(cache, cache->fqn); 2545b7780e8SSami Tolvanen } 2555b7780e8SSami Tolvanen 2565b7780e8SSami Tolvanen #define DEFINE_PROCESS_UDATA_ATTRIBUTE(attribute) \ 2570c1c7627SSami Tolvanen static void process_##attribute##_attr(struct die *cache, \ 2580c1c7627SSami Tolvanen Dwarf_Die *die) \ 2595b7780e8SSami Tolvanen { \ 2605b7780e8SSami Tolvanen Dwarf_Word value; \ 2615b7780e8SSami Tolvanen if (get_udata_attr(die, DW_AT_##attribute, &value)) \ 2620c1c7627SSami Tolvanen process_fmt(cache, " " #attribute "(%" PRIu64 ")", \ 2630c1c7627SSami Tolvanen value); \ 2645b7780e8SSami Tolvanen } 2655b7780e8SSami Tolvanen 266f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(accessibility) 2675b7780e8SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment) 268f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(bit_size) 2695b7780e8SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size) 2705b7780e8SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding) 271f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(data_bit_offset) 272f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(data_member_location) 273f6bb9245SSami Tolvanen DEFINE_PROCESS_UDATA_ATTRIBUTE(discr_value) 2745b7780e8SSami Tolvanen 275220a0857SSami Tolvanen /* Match functions -- die_match_callback_t */ 276220a0857SSami Tolvanen #define DEFINE_MATCH(type) \ 277220a0857SSami Tolvanen static bool match_##type##_type(Dwarf_Die *die) \ 278220a0857SSami Tolvanen { \ 279220a0857SSami Tolvanen return dwarf_tag(die) == DW_TAG_##type##_type; \ 280220a0857SSami Tolvanen } 281220a0857SSami Tolvanen 282f6bb9245SSami Tolvanen DEFINE_MATCH(enumerator) 283220a0857SSami Tolvanen DEFINE_MATCH(formal_parameter) 284f6bb9245SSami Tolvanen DEFINE_MATCH(member) 285c772f1d1SSami Tolvanen DEFINE_MATCH(subrange) 286220a0857SSami Tolvanen 287f2856884SSami Tolvanen bool match_all(Dwarf_Die *die) 288f2856884SSami Tolvanen { 289f2856884SSami Tolvanen return true; 290f2856884SSami Tolvanen } 291f2856884SSami Tolvanen 2920c1c7627SSami Tolvanen int process_die_container(struct state *state, struct die *cache, 2930c1c7627SSami Tolvanen Dwarf_Die *die, die_callback_t func, 2940c1c7627SSami Tolvanen die_match_callback_t match) 295f2856884SSami Tolvanen { 296f2856884SSami Tolvanen Dwarf_Die current; 297f2856884SSami Tolvanen int res; 298f2856884SSami Tolvanen 299220a0857SSami Tolvanen /* Track the first item in lists. */ 300220a0857SSami Tolvanen if (state) 301220a0857SSami Tolvanen state->first_list_item = true; 302220a0857SSami Tolvanen 303f2856884SSami Tolvanen res = checkp(dwarf_child(die, ¤t)); 304f2856884SSami Tolvanen while (!res) { 305f2856884SSami Tolvanen if (match(¤t)) { 306f2856884SSami Tolvanen /* <0 = error, 0 = continue, >0 = stop */ 3070c1c7627SSami Tolvanen res = checkp(func(state, cache, ¤t)); 308f2856884SSami Tolvanen if (res) 309220a0857SSami Tolvanen goto out; 310f2856884SSami Tolvanen } 311f2856884SSami Tolvanen 312f2856884SSami Tolvanen res = checkp(dwarf_siblingof(¤t, ¤t)); 313f2856884SSami Tolvanen } 314f2856884SSami Tolvanen 315220a0857SSami Tolvanen res = 0; 316220a0857SSami Tolvanen out: 317220a0857SSami Tolvanen if (state) 318220a0857SSami Tolvanen state->first_list_item = false; 319220a0857SSami Tolvanen 320220a0857SSami Tolvanen return res; 321f2856884SSami Tolvanen } 322f2856884SSami Tolvanen 3230c1c7627SSami Tolvanen static int process_type(struct state *state, struct die *parent, 3240c1c7627SSami Tolvanen Dwarf_Die *die); 3255b7780e8SSami Tolvanen 3260c1c7627SSami Tolvanen static void process_type_attr(struct state *state, struct die *cache, 3270c1c7627SSami Tolvanen Dwarf_Die *die) 3285b7780e8SSami Tolvanen { 3295b7780e8SSami Tolvanen Dwarf_Die type; 3305b7780e8SSami Tolvanen 3315b7780e8SSami Tolvanen if (get_ref_die_attr(die, DW_AT_type, &type)) { 3320c1c7627SSami Tolvanen check(process_type(state, cache, &type)); 3335b7780e8SSami Tolvanen return; 3345b7780e8SSami Tolvanen } 3355b7780e8SSami Tolvanen 3365b7780e8SSami Tolvanen /* Compilers can omit DW_AT_type -- print out 'void' to clarify */ 3370c1c7627SSami Tolvanen process(cache, "base_type void"); 3385b7780e8SSami Tolvanen } 3395b7780e8SSami Tolvanen 340220a0857SSami Tolvanen static void process_list_comma(struct state *state, struct die *cache) 341220a0857SSami Tolvanen { 342220a0857SSami Tolvanen if (state->first_list_item) { 343220a0857SSami Tolvanen state->first_list_item = false; 344220a0857SSami Tolvanen } else { 345220a0857SSami Tolvanen process(cache, " ,"); 346220a0857SSami Tolvanen process_linebreak(cache, 0); 347220a0857SSami Tolvanen } 348220a0857SSami Tolvanen } 349220a0857SSami Tolvanen 350220a0857SSami Tolvanen /* Comma-separated with DW_AT_type */ 351220a0857SSami Tolvanen static void __process_list_type(struct state *state, struct die *cache, 352220a0857SSami Tolvanen Dwarf_Die *die, const char *type) 353220a0857SSami Tolvanen { 354220a0857SSami Tolvanen const char *name = get_name_attr(die); 355220a0857SSami Tolvanen 356220a0857SSami Tolvanen process_list_comma(state, cache); 357220a0857SSami Tolvanen process(cache, type); 358220a0857SSami Tolvanen process_type_attr(state, cache, die); 359220a0857SSami Tolvanen if (name) { 360220a0857SSami Tolvanen process(cache, " "); 361220a0857SSami Tolvanen process(cache, name); 362220a0857SSami Tolvanen } 363f6bb9245SSami Tolvanen process_accessibility_attr(cache, die); 364f6bb9245SSami Tolvanen process_bit_size_attr(cache, die); 365f6bb9245SSami Tolvanen process_data_bit_offset_attr(cache, die); 366f6bb9245SSami Tolvanen process_data_member_location_attr(cache, die); 367220a0857SSami Tolvanen } 368220a0857SSami Tolvanen 369220a0857SSami Tolvanen #define DEFINE_PROCESS_LIST_TYPE(type) \ 370220a0857SSami Tolvanen static void process_##type##_type(struct state *state, \ 371220a0857SSami Tolvanen struct die *cache, Dwarf_Die *die) \ 372220a0857SSami Tolvanen { \ 373220a0857SSami Tolvanen __process_list_type(state, cache, die, #type " "); \ 374220a0857SSami Tolvanen } 375220a0857SSami Tolvanen 376220a0857SSami Tolvanen DEFINE_PROCESS_LIST_TYPE(formal_parameter) 377f6bb9245SSami Tolvanen DEFINE_PROCESS_LIST_TYPE(member) 378220a0857SSami Tolvanen 37906b8b036SSami Tolvanen /* Container types with DW_AT_type */ 38006b8b036SSami Tolvanen static void __process_type(struct state *state, struct die *cache, 38106b8b036SSami Tolvanen Dwarf_Die *die, const char *type) 38206b8b036SSami Tolvanen { 38306b8b036SSami Tolvanen process(cache, type); 38406b8b036SSami Tolvanen process_fqn(cache, die); 38506b8b036SSami Tolvanen process(cache, " {"); 38606b8b036SSami Tolvanen process_linebreak(cache, 1); 38706b8b036SSami Tolvanen process_type_attr(state, cache, die); 38806b8b036SSami Tolvanen process_linebreak(cache, -1); 38906b8b036SSami Tolvanen process(cache, "}"); 39006b8b036SSami Tolvanen process_byte_size_attr(cache, die); 39106b8b036SSami Tolvanen process_alignment_attr(cache, die); 39206b8b036SSami Tolvanen } 39306b8b036SSami Tolvanen 39406b8b036SSami Tolvanen #define DEFINE_PROCESS_TYPE(type) \ 39506b8b036SSami Tolvanen static void process_##type##_type(struct state *state, \ 39606b8b036SSami Tolvanen struct die *cache, Dwarf_Die *die) \ 39706b8b036SSami Tolvanen { \ 39806b8b036SSami Tolvanen __process_type(state, cache, die, #type "_type"); \ 39906b8b036SSami Tolvanen } 40006b8b036SSami Tolvanen 40106b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(atomic) 40206b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(const) 40306b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(immutable) 40406b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(packed) 40506b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(pointer) 40606b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(reference) 40706b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(restrict) 40806b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(rvalue_reference) 40906b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(shared) 410f6bb9245SSami Tolvanen DEFINE_PROCESS_TYPE(template_type_parameter) 41106b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(volatile) 41206b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(typedef) 41306b8b036SSami Tolvanen 414c772f1d1SSami Tolvanen static void process_subrange_type(struct state *state, struct die *cache, 415c772f1d1SSami Tolvanen Dwarf_Die *die) 416c772f1d1SSami Tolvanen { 417c772f1d1SSami Tolvanen Dwarf_Word count = 0; 418c772f1d1SSami Tolvanen 419c772f1d1SSami Tolvanen if (get_udata_attr(die, DW_AT_count, &count)) 420c772f1d1SSami Tolvanen process_fmt(cache, "[%" PRIu64 "]", count); 421c772f1d1SSami Tolvanen else if (get_udata_attr(die, DW_AT_upper_bound, &count)) 422c772f1d1SSami Tolvanen process_fmt(cache, "[%" PRIu64 "]", count + 1); 423c772f1d1SSami Tolvanen else 424c772f1d1SSami Tolvanen process(cache, "[]"); 425c772f1d1SSami Tolvanen } 426c772f1d1SSami Tolvanen 427c772f1d1SSami Tolvanen static void process_array_type(struct state *state, struct die *cache, 428c772f1d1SSami Tolvanen Dwarf_Die *die) 429c772f1d1SSami Tolvanen { 430c772f1d1SSami Tolvanen process(cache, "array_type"); 431c772f1d1SSami Tolvanen /* Array size */ 432c772f1d1SSami Tolvanen check(process_die_container(state, cache, die, process_type, 433c772f1d1SSami Tolvanen match_subrange_type)); 434c772f1d1SSami Tolvanen process(cache, " {"); 435c772f1d1SSami Tolvanen process_linebreak(cache, 1); 436c772f1d1SSami Tolvanen process_type_attr(state, cache, die); 437c772f1d1SSami Tolvanen process_linebreak(cache, -1); 438c772f1d1SSami Tolvanen process(cache, "}"); 439c772f1d1SSami Tolvanen } 440c772f1d1SSami Tolvanen 441220a0857SSami Tolvanen static void __process_subroutine_type(struct state *state, struct die *cache, 442220a0857SSami Tolvanen Dwarf_Die *die, const char *type) 443220a0857SSami Tolvanen { 444220a0857SSami Tolvanen process(cache, type); 445220a0857SSami Tolvanen process(cache, " ("); 446220a0857SSami Tolvanen process_linebreak(cache, 1); 447220a0857SSami Tolvanen /* Parameters */ 448220a0857SSami Tolvanen check(process_die_container(state, cache, die, process_type, 449220a0857SSami Tolvanen match_formal_parameter_type)); 450220a0857SSami Tolvanen process_linebreak(cache, -1); 451220a0857SSami Tolvanen process(cache, ")"); 452220a0857SSami Tolvanen process_linebreak(cache, 0); 453220a0857SSami Tolvanen /* Return type */ 454220a0857SSami Tolvanen process(cache, "-> "); 455220a0857SSami Tolvanen process_type_attr(state, cache, die); 456220a0857SSami Tolvanen } 457220a0857SSami Tolvanen 458220a0857SSami Tolvanen static void process_subroutine_type(struct state *state, struct die *cache, 459220a0857SSami Tolvanen Dwarf_Die *die) 460220a0857SSami Tolvanen { 461220a0857SSami Tolvanen __process_subroutine_type(state, cache, die, "subroutine_type"); 462220a0857SSami Tolvanen } 463220a0857SSami Tolvanen 464f6bb9245SSami Tolvanen static void process_variant_type(struct state *state, struct die *cache, 465f6bb9245SSami Tolvanen Dwarf_Die *die) 466f6bb9245SSami Tolvanen { 467f6bb9245SSami Tolvanen process_list_comma(state, cache); 468f6bb9245SSami Tolvanen process(cache, "variant {"); 469f6bb9245SSami Tolvanen process_linebreak(cache, 1); 470f6bb9245SSami Tolvanen check(process_die_container(state, cache, die, process_type, 471f6bb9245SSami Tolvanen match_member_type)); 472f6bb9245SSami Tolvanen process_linebreak(cache, -1); 473f6bb9245SSami Tolvanen process(cache, "}"); 474f6bb9245SSami Tolvanen process_discr_value_attr(cache, die); 475f6bb9245SSami Tolvanen } 476f6bb9245SSami Tolvanen 477f6bb9245SSami Tolvanen static void process_variant_part_type(struct state *state, struct die *cache, 478f6bb9245SSami Tolvanen Dwarf_Die *die) 479f6bb9245SSami Tolvanen { 480f6bb9245SSami Tolvanen process_list_comma(state, cache); 481f6bb9245SSami Tolvanen process(cache, "variant_part {"); 482f6bb9245SSami Tolvanen process_linebreak(cache, 1); 483f6bb9245SSami Tolvanen check(process_die_container(state, cache, die, process_type, 484f6bb9245SSami Tolvanen match_all)); 485f6bb9245SSami Tolvanen process_linebreak(cache, -1); 486f6bb9245SSami Tolvanen process(cache, "}"); 487f6bb9245SSami Tolvanen } 488f6bb9245SSami Tolvanen 489f6bb9245SSami Tolvanen static int ___process_structure_type(struct state *state, struct die *cache, 490f6bb9245SSami Tolvanen Dwarf_Die *die) 491f6bb9245SSami Tolvanen { 492f6bb9245SSami Tolvanen switch (dwarf_tag(die)) { 493f6bb9245SSami Tolvanen case DW_TAG_member: 494f6bb9245SSami Tolvanen case DW_TAG_variant_part: 495f6bb9245SSami Tolvanen return check(process_type(state, cache, die)); 496f6bb9245SSami Tolvanen case DW_TAG_class_type: 497f6bb9245SSami Tolvanen case DW_TAG_enumeration_type: 498f6bb9245SSami Tolvanen case DW_TAG_structure_type: 499f6bb9245SSami Tolvanen case DW_TAG_template_type_parameter: 500f6bb9245SSami Tolvanen case DW_TAG_union_type: 501f6bb9245SSami Tolvanen case DW_TAG_subprogram: 502f6bb9245SSami Tolvanen /* Skip non-member types, including member functions */ 503f6bb9245SSami Tolvanen return 0; 504f6bb9245SSami Tolvanen default: 505f6bb9245SSami Tolvanen error("unexpected structure_type child: %x", dwarf_tag(die)); 506f6bb9245SSami Tolvanen } 507f6bb9245SSami Tolvanen } 508f6bb9245SSami Tolvanen 509f6bb9245SSami Tolvanen static void __process_structure_type(struct state *state, struct die *cache, 510f6bb9245SSami Tolvanen Dwarf_Die *die, const char *type, 511f6bb9245SSami Tolvanen die_callback_t process_func, 512f6bb9245SSami Tolvanen die_match_callback_t match_func) 513f6bb9245SSami Tolvanen { 514f936c129SSami Tolvanen bool expand; 515f936c129SSami Tolvanen 516f6bb9245SSami Tolvanen process(cache, type); 517f6bb9245SSami Tolvanen process_fqn(cache, die); 518f6bb9245SSami Tolvanen process(cache, " {"); 519f6bb9245SSami Tolvanen process_linebreak(cache, 1); 520f6bb9245SSami Tolvanen 521*936cf61cSSami Tolvanen expand = state->expand.expand && is_kabi_definition(cache, die); 522f936c129SSami Tolvanen 523f936c129SSami Tolvanen if (expand) { 524*936cf61cSSami Tolvanen state->expand.current_fqn = cache->fqn; 525f6bb9245SSami Tolvanen check(process_die_container(state, cache, die, process_func, 526f6bb9245SSami Tolvanen match_func)); 527f936c129SSami Tolvanen } 528f6bb9245SSami Tolvanen 529f6bb9245SSami Tolvanen process_linebreak(cache, -1); 530f6bb9245SSami Tolvanen process(cache, "}"); 531f6bb9245SSami Tolvanen 532f936c129SSami Tolvanen if (expand) { 533f6bb9245SSami Tolvanen process_byte_size_attr(cache, die); 534f6bb9245SSami Tolvanen process_alignment_attr(cache, die); 535f6bb9245SSami Tolvanen } 536f936c129SSami Tolvanen } 537f6bb9245SSami Tolvanen 538f6bb9245SSami Tolvanen #define DEFINE_PROCESS_STRUCTURE_TYPE(structure) \ 539f6bb9245SSami Tolvanen static void process_##structure##_type( \ 540f6bb9245SSami Tolvanen struct state *state, struct die *cache, Dwarf_Die *die) \ 541f6bb9245SSami Tolvanen { \ 542f6bb9245SSami Tolvanen __process_structure_type(state, cache, die, \ 543f6bb9245SSami Tolvanen #structure "_type", \ 544f6bb9245SSami Tolvanen ___process_structure_type, \ 545f6bb9245SSami Tolvanen match_all); \ 546f6bb9245SSami Tolvanen } 547f6bb9245SSami Tolvanen 548f6bb9245SSami Tolvanen DEFINE_PROCESS_STRUCTURE_TYPE(class) 549f6bb9245SSami Tolvanen DEFINE_PROCESS_STRUCTURE_TYPE(structure) 550f6bb9245SSami Tolvanen DEFINE_PROCESS_STRUCTURE_TYPE(union) 551f6bb9245SSami Tolvanen 552f6bb9245SSami Tolvanen static void process_enumerator_type(struct state *state, struct die *cache, 553f6bb9245SSami Tolvanen Dwarf_Die *die) 554f6bb9245SSami Tolvanen { 555*936cf61cSSami Tolvanen bool overridden = false; 556f6bb9245SSami Tolvanen Dwarf_Word value; 557f6bb9245SSami Tolvanen 558*936cf61cSSami Tolvanen if (stable) { 559*936cf61cSSami Tolvanen /* Get the fqn before we process anything */ 560*936cf61cSSami Tolvanen update_fqn(cache, die); 561*936cf61cSSami Tolvanen 562*936cf61cSSami Tolvanen if (kabi_is_enumerator_ignored(state->expand.current_fqn, 563*936cf61cSSami Tolvanen cache->fqn)) 564*936cf61cSSami Tolvanen return; 565*936cf61cSSami Tolvanen 566*936cf61cSSami Tolvanen overridden = kabi_get_enumerator_value( 567*936cf61cSSami Tolvanen state->expand.current_fqn, cache->fqn, &value); 568*936cf61cSSami Tolvanen } 569*936cf61cSSami Tolvanen 570f6bb9245SSami Tolvanen process_list_comma(state, cache); 571f6bb9245SSami Tolvanen process(cache, "enumerator"); 572f6bb9245SSami Tolvanen process_fqn(cache, die); 573f6bb9245SSami Tolvanen 574*936cf61cSSami Tolvanen if (overridden || get_udata_attr(die, DW_AT_const_value, &value)) { 575f6bb9245SSami Tolvanen process(cache, " = "); 576f6bb9245SSami Tolvanen process_fmt(cache, "%" PRIu64, value); 577f6bb9245SSami Tolvanen } 578f6bb9245SSami Tolvanen } 579f6bb9245SSami Tolvanen 580f6bb9245SSami Tolvanen static void process_enumeration_type(struct state *state, struct die *cache, 581f6bb9245SSami Tolvanen Dwarf_Die *die) 582f6bb9245SSami Tolvanen { 583f6bb9245SSami Tolvanen __process_structure_type(state, cache, die, "enumeration_type", 584f6bb9245SSami Tolvanen process_type, match_enumerator_type); 585f6bb9245SSami Tolvanen } 586f6bb9245SSami Tolvanen 5870c1c7627SSami Tolvanen static void process_base_type(struct state *state, struct die *cache, 5880c1c7627SSami Tolvanen Dwarf_Die *die) 5895b7780e8SSami Tolvanen { 5900c1c7627SSami Tolvanen process(cache, "base_type"); 5910c1c7627SSami Tolvanen process_fqn(cache, die); 5920c1c7627SSami Tolvanen process_byte_size_attr(cache, die); 5930c1c7627SSami Tolvanen process_encoding_attr(cache, die); 5940c1c7627SSami Tolvanen process_alignment_attr(cache, die); 5950c1c7627SSami Tolvanen } 5960c1c7627SSami Tolvanen 597f6bb9245SSami Tolvanen static void process_unspecified_type(struct state *state, struct die *cache, 598f6bb9245SSami Tolvanen Dwarf_Die *die) 599f6bb9245SSami Tolvanen { 600f6bb9245SSami Tolvanen /* 601f6bb9245SSami Tolvanen * These can be emitted for stand-alone assembly code, which means we 602f6bb9245SSami Tolvanen * might run into them in vmlinux.o. 603f6bb9245SSami Tolvanen */ 604f6bb9245SSami Tolvanen process(cache, "unspecified_type"); 605f6bb9245SSami Tolvanen } 606f6bb9245SSami Tolvanen 6070c1c7627SSami Tolvanen static void process_cached(struct state *state, struct die *cache, 6080c1c7627SSami Tolvanen Dwarf_Die *die) 6090c1c7627SSami Tolvanen { 6100c1c7627SSami Tolvanen struct die_fragment *df; 6110c1c7627SSami Tolvanen Dwarf_Die child; 6120c1c7627SSami Tolvanen 6130c1c7627SSami Tolvanen list_for_each_entry(df, &cache->fragments, list) { 6140c1c7627SSami Tolvanen switch (df->type) { 6150c1c7627SSami Tolvanen case FRAGMENT_STRING: 616d2ffdc1cSSami Tolvanen die_debug_b("cache %p STRING '%s'", cache, 617d2ffdc1cSSami Tolvanen df->data.str); 6180c1c7627SSami Tolvanen process(NULL, df->data.str); 6190c1c7627SSami Tolvanen break; 62006b8b036SSami Tolvanen case FRAGMENT_LINEBREAK: 62106b8b036SSami Tolvanen process_linebreak(NULL, df->data.linebreak); 62206b8b036SSami Tolvanen break; 6230c1c7627SSami Tolvanen case FRAGMENT_DIE: 6240c1c7627SSami Tolvanen if (!dwarf_die_addr_die(dwarf_cu_getdwarf(die->cu), 6250c1c7627SSami Tolvanen (void *)df->data.addr, &child)) 6260c1c7627SSami Tolvanen error("dwarf_die_addr_die failed"); 627d2ffdc1cSSami Tolvanen die_debug_b("cache %p DIE addr %" PRIxPTR " tag %x", 628d2ffdc1cSSami Tolvanen cache, df->data.addr, dwarf_tag(&child)); 6290c1c7627SSami Tolvanen check(process_type(state, NULL, &child)); 6300c1c7627SSami Tolvanen break; 6310c1c7627SSami Tolvanen default: 6320c1c7627SSami Tolvanen error("empty die_fragment"); 6330c1c7627SSami Tolvanen } 6340c1c7627SSami Tolvanen } 6355b7780e8SSami Tolvanen } 6365b7780e8SSami Tolvanen 637f936c129SSami Tolvanen static void state_init(struct state *state) 638f936c129SSami Tolvanen { 639f936c129SSami Tolvanen state->expand.expand = true; 640*936cf61cSSami Tolvanen state->expand.current_fqn = NULL; 641f936c129SSami Tolvanen cache_init(&state->expansion_cache); 642f936c129SSami Tolvanen } 643f936c129SSami Tolvanen 644f936c129SSami Tolvanen static void expansion_state_restore(struct expansion_state *state, 645f936c129SSami Tolvanen struct expansion_state *saved) 646f936c129SSami Tolvanen { 647f936c129SSami Tolvanen state->expand = saved->expand; 648*936cf61cSSami Tolvanen state->current_fqn = saved->current_fqn; 649f936c129SSami Tolvanen } 650f936c129SSami Tolvanen 651f936c129SSami Tolvanen static void expansion_state_save(struct expansion_state *state, 652f936c129SSami Tolvanen struct expansion_state *saved) 653f936c129SSami Tolvanen { 654f936c129SSami Tolvanen expansion_state_restore(saved, state); 655f936c129SSami Tolvanen } 656f936c129SSami Tolvanen 657f936c129SSami Tolvanen static bool is_expanded_type(int tag) 658f936c129SSami Tolvanen { 659f936c129SSami Tolvanen return tag == DW_TAG_class_type || tag == DW_TAG_structure_type || 660f936c129SSami Tolvanen tag == DW_TAG_union_type || tag == DW_TAG_enumeration_type; 661f936c129SSami Tolvanen } 662f936c129SSami Tolvanen 6635b7780e8SSami Tolvanen #define PROCESS_TYPE(type) \ 6645b7780e8SSami Tolvanen case DW_TAG_##type##_type: \ 6650c1c7627SSami Tolvanen process_##type##_type(state, cache, die); \ 6665b7780e8SSami Tolvanen break; 6675b7780e8SSami Tolvanen 6680c1c7627SSami Tolvanen static int process_type(struct state *state, struct die *parent, Dwarf_Die *die) 6695b7780e8SSami Tolvanen { 670f936c129SSami Tolvanen enum die_state want_state = DIE_COMPLETE; 6710c1c7627SSami Tolvanen struct die *cache; 672f936c129SSami Tolvanen struct expansion_state saved; 6735b7780e8SSami Tolvanen int tag = dwarf_tag(die); 6745b7780e8SSami Tolvanen 675f936c129SSami Tolvanen expansion_state_save(&state->expand, &saved); 676f936c129SSami Tolvanen 6770c1c7627SSami Tolvanen /* 678f936c129SSami Tolvanen * Structures and enumeration types are expanded only once per 679f936c129SSami Tolvanen * exported symbol. This is sufficient for detecting ABI changes 680f936c129SSami Tolvanen * within the structure. 681f936c129SSami Tolvanen */ 682f936c129SSami Tolvanen if (is_expanded_type(tag)) { 683f936c129SSami Tolvanen if (cache_was_expanded(&state->expansion_cache, die->addr)) 684f936c129SSami Tolvanen state->expand.expand = false; 685f936c129SSami Tolvanen 686f936c129SSami Tolvanen if (state->expand.expand) 687f936c129SSami Tolvanen cache_mark_expanded(&state->expansion_cache, die->addr); 688f936c129SSami Tolvanen else 689f936c129SSami Tolvanen want_state = DIE_UNEXPANDED; 690f936c129SSami Tolvanen } 691f936c129SSami Tolvanen 692f936c129SSami Tolvanen /* 693f936c129SSami Tolvanen * If we have want_state already cached, use it instead of walking 6940c1c7627SSami Tolvanen * through DWARF. 6950c1c7627SSami Tolvanen */ 696f936c129SSami Tolvanen cache = die_map_get(die, want_state); 6970c1c7627SSami Tolvanen 698f936c129SSami Tolvanen if (cache->state == want_state) { 699d2ffdc1cSSami Tolvanen die_debug_g("cached addr %p tag %x -- %s", die->addr, tag, 700d2ffdc1cSSami Tolvanen die_state_name(cache->state)); 701d2ffdc1cSSami Tolvanen 7020c1c7627SSami Tolvanen process_cached(state, cache, die); 7030c1c7627SSami Tolvanen die_map_add_die(parent, cache); 704f936c129SSami Tolvanen 705f936c129SSami Tolvanen expansion_state_restore(&state->expand, &saved); 7060c1c7627SSami Tolvanen return 0; 7070c1c7627SSami Tolvanen } 7080c1c7627SSami Tolvanen 709d2ffdc1cSSami Tolvanen die_debug_g("addr %p tag %x -- %s -> %s", die->addr, tag, 710d2ffdc1cSSami Tolvanen die_state_name(cache->state), die_state_name(want_state)); 711d2ffdc1cSSami Tolvanen 7125b7780e8SSami Tolvanen switch (tag) { 71306b8b036SSami Tolvanen /* Type modifiers */ 71406b8b036SSami Tolvanen PROCESS_TYPE(atomic) 71506b8b036SSami Tolvanen PROCESS_TYPE(const) 71606b8b036SSami Tolvanen PROCESS_TYPE(immutable) 71706b8b036SSami Tolvanen PROCESS_TYPE(packed) 71806b8b036SSami Tolvanen PROCESS_TYPE(pointer) 71906b8b036SSami Tolvanen PROCESS_TYPE(reference) 72006b8b036SSami Tolvanen PROCESS_TYPE(restrict) 72106b8b036SSami Tolvanen PROCESS_TYPE(rvalue_reference) 72206b8b036SSami Tolvanen PROCESS_TYPE(shared) 72306b8b036SSami Tolvanen PROCESS_TYPE(volatile) 724f6bb9245SSami Tolvanen /* Container types */ 725f6bb9245SSami Tolvanen PROCESS_TYPE(class) 726f6bb9245SSami Tolvanen PROCESS_TYPE(structure) 727f6bb9245SSami Tolvanen PROCESS_TYPE(union) 728f6bb9245SSami Tolvanen PROCESS_TYPE(enumeration) 729220a0857SSami Tolvanen /* Subtypes */ 730f6bb9245SSami Tolvanen PROCESS_TYPE(enumerator) 731220a0857SSami Tolvanen PROCESS_TYPE(formal_parameter) 732f6bb9245SSami Tolvanen PROCESS_TYPE(member) 733c772f1d1SSami Tolvanen PROCESS_TYPE(subrange) 734f6bb9245SSami Tolvanen PROCESS_TYPE(template_type_parameter) 735f6bb9245SSami Tolvanen PROCESS_TYPE(variant) 736f6bb9245SSami Tolvanen PROCESS_TYPE(variant_part) 73706b8b036SSami Tolvanen /* Other types */ 738c772f1d1SSami Tolvanen PROCESS_TYPE(array) 7395b7780e8SSami Tolvanen PROCESS_TYPE(base) 740220a0857SSami Tolvanen PROCESS_TYPE(subroutine) 74106b8b036SSami Tolvanen PROCESS_TYPE(typedef) 742f6bb9245SSami Tolvanen PROCESS_TYPE(unspecified) 7435b7780e8SSami Tolvanen default: 744f6bb9245SSami Tolvanen error("unexpected type: %x", tag); 7455b7780e8SSami Tolvanen } 7465b7780e8SSami Tolvanen 747d2ffdc1cSSami Tolvanen die_debug_r("parent %p cache %p die addr %p tag %x", parent, cache, 748d2ffdc1cSSami Tolvanen die->addr, tag); 749d2ffdc1cSSami Tolvanen 7500c1c7627SSami Tolvanen /* Update cache state and append to the parent (if any) */ 7510c1c7627SSami Tolvanen cache->tag = tag; 752f936c129SSami Tolvanen cache->state = want_state; 7530c1c7627SSami Tolvanen die_map_add_die(parent, cache); 7540c1c7627SSami Tolvanen 755f936c129SSami Tolvanen expansion_state_restore(&state->expand, &saved); 7565b7780e8SSami Tolvanen return 0; 7575b7780e8SSami Tolvanen } 7585b7780e8SSami Tolvanen 759f2856884SSami Tolvanen /* 760f2856884SSami Tolvanen * Exported symbol processing 761f2856884SSami Tolvanen */ 76271378888SSami Tolvanen static struct die *get_symbol_cache(struct state *state, Dwarf_Die *die) 76371378888SSami Tolvanen { 76471378888SSami Tolvanen struct die *cache; 76571378888SSami Tolvanen 76671378888SSami Tolvanen cache = die_map_get(die, DIE_SYMBOL); 76771378888SSami Tolvanen 76871378888SSami Tolvanen if (cache->state != DIE_INCOMPLETE) 76971378888SSami Tolvanen return NULL; /* We already processed a symbol for this DIE */ 77071378888SSami Tolvanen 77171378888SSami Tolvanen cache->tag = dwarf_tag(die); 77271378888SSami Tolvanen return cache; 77371378888SSami Tolvanen } 77471378888SSami Tolvanen 775f2856884SSami Tolvanen static void process_symbol(struct state *state, Dwarf_Die *die, 776f2856884SSami Tolvanen die_callback_t process_func) 777f2856884SSami Tolvanen { 77871378888SSami Tolvanen struct die *cache; 77971378888SSami Tolvanen 78071378888SSami Tolvanen symbol_set_die(state->sym, die); 78171378888SSami Tolvanen 78271378888SSami Tolvanen cache = get_symbol_cache(state, die); 78371378888SSami Tolvanen if (!cache) 78471378888SSami Tolvanen return; 78571378888SSami Tolvanen 786f2856884SSami Tolvanen debug("%s", state->sym->name); 78771378888SSami Tolvanen check(process_func(state, cache, die)); 78871378888SSami Tolvanen cache->state = DIE_SYMBOL; 789f2856884SSami Tolvanen if (dump_dies) 790f2856884SSami Tolvanen fputs("\n", stderr); 791f2856884SSami Tolvanen } 792f2856884SSami Tolvanen 7930c1c7627SSami Tolvanen static int __process_subprogram(struct state *state, struct die *cache, 7940c1c7627SSami Tolvanen Dwarf_Die *die) 795f2856884SSami Tolvanen { 796220a0857SSami Tolvanen __process_subroutine_type(state, cache, die, "subprogram"); 797f2856884SSami Tolvanen return 0; 798f2856884SSami Tolvanen } 799f2856884SSami Tolvanen 800f2856884SSami Tolvanen static void process_subprogram(struct state *state, Dwarf_Die *die) 801f2856884SSami Tolvanen { 802f2856884SSami Tolvanen process_symbol(state, die, __process_subprogram); 803f2856884SSami Tolvanen } 804f2856884SSami Tolvanen 8050c1c7627SSami Tolvanen static int __process_variable(struct state *state, struct die *cache, 8060c1c7627SSami Tolvanen Dwarf_Die *die) 807f2856884SSami Tolvanen { 8080c1c7627SSami Tolvanen process(cache, "variable "); 8090c1c7627SSami Tolvanen process_type_attr(state, cache, die); 810f2856884SSami Tolvanen return 0; 811f2856884SSami Tolvanen } 812f2856884SSami Tolvanen 813f2856884SSami Tolvanen static void process_variable(struct state *state, Dwarf_Die *die) 814f2856884SSami Tolvanen { 815f2856884SSami Tolvanen process_symbol(state, die, __process_variable); 816f2856884SSami Tolvanen } 817f2856884SSami Tolvanen 8180c1c7627SSami Tolvanen static int process_exported_symbols(struct state *unused, struct die *cache, 8190c1c7627SSami Tolvanen Dwarf_Die *die) 820f2856884SSami Tolvanen { 821f2856884SSami Tolvanen int tag = dwarf_tag(die); 822f2856884SSami Tolvanen 823f2856884SSami Tolvanen switch (tag) { 824f2856884SSami Tolvanen /* Possible containers of exported symbols */ 825f2856884SSami Tolvanen case DW_TAG_namespace: 826f2856884SSami Tolvanen case DW_TAG_class_type: 827f2856884SSami Tolvanen case DW_TAG_structure_type: 828f2856884SSami Tolvanen return check(process_die_container( 8290c1c7627SSami Tolvanen NULL, cache, die, process_exported_symbols, match_all)); 830f2856884SSami Tolvanen 831f2856884SSami Tolvanen /* Possible exported symbols */ 832f2856884SSami Tolvanen case DW_TAG_subprogram: 833f2856884SSami Tolvanen case DW_TAG_variable: { 834f2856884SSami Tolvanen struct state state; 835f2856884SSami Tolvanen 836f2856884SSami Tolvanen if (!match_export_symbol(&state, die)) 837f2856884SSami Tolvanen return 0; 838f2856884SSami Tolvanen 839f936c129SSami Tolvanen state_init(&state); 840f936c129SSami Tolvanen 841f2856884SSami Tolvanen if (tag == DW_TAG_subprogram) 842f2856884SSami Tolvanen process_subprogram(&state, &state.die); 843f2856884SSami Tolvanen else 844f2856884SSami Tolvanen process_variable(&state, &state.die); 845f2856884SSami Tolvanen 846f936c129SSami Tolvanen cache_free(&state.expansion_cache); 847f2856884SSami Tolvanen return 0; 848f2856884SSami Tolvanen } 849f2856884SSami Tolvanen default: 850f2856884SSami Tolvanen return 0; 851f2856884SSami Tolvanen } 852f2856884SSami Tolvanen } 853f2856884SSami Tolvanen 854f2856884SSami Tolvanen void process_cu(Dwarf_Die *cudie) 855f2856884SSami Tolvanen { 8560c1c7627SSami Tolvanen check(process_die_container(NULL, NULL, cudie, process_exported_symbols, 857f2856884SSami Tolvanen match_all)); 858f936c129SSami Tolvanen 859f936c129SSami Tolvanen cache_free(&srcfile_cache); 860f2856884SSami Tolvanen } 861