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 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 9006b8b036SSami Tolvanen if (dump_dies && do_linebreak) { 9106b8b036SSami Tolvanen fputs("\n", stderr); 9206b8b036SSami Tolvanen for (int i = 0; i < indentation_level; i++) 9306b8b036SSami Tolvanen fputs(" ", stderr); 9406b8b036SSami Tolvanen do_linebreak = false; 9506b8b036SSami 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 215*220a0857SSami Tolvanen /* Match functions -- die_match_callback_t */ 216*220a0857SSami Tolvanen #define DEFINE_MATCH(type) \ 217*220a0857SSami Tolvanen static bool match_##type##_type(Dwarf_Die *die) \ 218*220a0857SSami Tolvanen { \ 219*220a0857SSami Tolvanen return dwarf_tag(die) == DW_TAG_##type##_type; \ 220*220a0857SSami Tolvanen } 221*220a0857SSami Tolvanen 222*220a0857SSami Tolvanen DEFINE_MATCH(formal_parameter) 223*220a0857SSami Tolvanen 224f2856884SSami Tolvanen bool match_all(Dwarf_Die *die) 225f2856884SSami Tolvanen { 226f2856884SSami Tolvanen return true; 227f2856884SSami Tolvanen } 228f2856884SSami Tolvanen 2290c1c7627SSami Tolvanen int process_die_container(struct state *state, struct die *cache, 2300c1c7627SSami Tolvanen Dwarf_Die *die, die_callback_t func, 2310c1c7627SSami Tolvanen die_match_callback_t match) 232f2856884SSami Tolvanen { 233f2856884SSami Tolvanen Dwarf_Die current; 234f2856884SSami Tolvanen int res; 235f2856884SSami Tolvanen 236*220a0857SSami Tolvanen /* Track the first item in lists. */ 237*220a0857SSami Tolvanen if (state) 238*220a0857SSami Tolvanen state->first_list_item = true; 239*220a0857SSami Tolvanen 240f2856884SSami Tolvanen res = checkp(dwarf_child(die, ¤t)); 241f2856884SSami Tolvanen while (!res) { 242f2856884SSami Tolvanen if (match(¤t)) { 243f2856884SSami Tolvanen /* <0 = error, 0 = continue, >0 = stop */ 2440c1c7627SSami Tolvanen res = checkp(func(state, cache, ¤t)); 245f2856884SSami Tolvanen if (res) 246*220a0857SSami Tolvanen goto out; 247f2856884SSami Tolvanen } 248f2856884SSami Tolvanen 249f2856884SSami Tolvanen res = checkp(dwarf_siblingof(¤t, ¤t)); 250f2856884SSami Tolvanen } 251f2856884SSami Tolvanen 252*220a0857SSami Tolvanen res = 0; 253*220a0857SSami Tolvanen out: 254*220a0857SSami Tolvanen if (state) 255*220a0857SSami Tolvanen state->first_list_item = false; 256*220a0857SSami Tolvanen 257*220a0857SSami Tolvanen return res; 258f2856884SSami Tolvanen } 259f2856884SSami Tolvanen 2600c1c7627SSami Tolvanen static int process_type(struct state *state, struct die *parent, 2610c1c7627SSami Tolvanen Dwarf_Die *die); 2625b7780e8SSami Tolvanen 2630c1c7627SSami Tolvanen static void process_type_attr(struct state *state, struct die *cache, 2640c1c7627SSami Tolvanen Dwarf_Die *die) 2655b7780e8SSami Tolvanen { 2665b7780e8SSami Tolvanen Dwarf_Die type; 2675b7780e8SSami Tolvanen 2685b7780e8SSami Tolvanen if (get_ref_die_attr(die, DW_AT_type, &type)) { 2690c1c7627SSami Tolvanen check(process_type(state, cache, &type)); 2705b7780e8SSami Tolvanen return; 2715b7780e8SSami Tolvanen } 2725b7780e8SSami Tolvanen 2735b7780e8SSami Tolvanen /* Compilers can omit DW_AT_type -- print out 'void' to clarify */ 2740c1c7627SSami Tolvanen process(cache, "base_type void"); 2755b7780e8SSami Tolvanen } 2765b7780e8SSami Tolvanen 277*220a0857SSami Tolvanen static void process_list_comma(struct state *state, struct die *cache) 278*220a0857SSami Tolvanen { 279*220a0857SSami Tolvanen if (state->first_list_item) { 280*220a0857SSami Tolvanen state->first_list_item = false; 281*220a0857SSami Tolvanen } else { 282*220a0857SSami Tolvanen process(cache, " ,"); 283*220a0857SSami Tolvanen process_linebreak(cache, 0); 284*220a0857SSami Tolvanen } 285*220a0857SSami Tolvanen } 286*220a0857SSami Tolvanen 287*220a0857SSami Tolvanen /* Comma-separated with DW_AT_type */ 288*220a0857SSami Tolvanen static void __process_list_type(struct state *state, struct die *cache, 289*220a0857SSami Tolvanen Dwarf_Die *die, const char *type) 290*220a0857SSami Tolvanen { 291*220a0857SSami Tolvanen const char *name = get_name_attr(die); 292*220a0857SSami Tolvanen 293*220a0857SSami Tolvanen process_list_comma(state, cache); 294*220a0857SSami Tolvanen process(cache, type); 295*220a0857SSami Tolvanen process_type_attr(state, cache, die); 296*220a0857SSami Tolvanen if (name) { 297*220a0857SSami Tolvanen process(cache, " "); 298*220a0857SSami Tolvanen process(cache, name); 299*220a0857SSami Tolvanen } 300*220a0857SSami Tolvanen } 301*220a0857SSami Tolvanen 302*220a0857SSami Tolvanen #define DEFINE_PROCESS_LIST_TYPE(type) \ 303*220a0857SSami Tolvanen static void process_##type##_type(struct state *state, \ 304*220a0857SSami Tolvanen struct die *cache, Dwarf_Die *die) \ 305*220a0857SSami Tolvanen { \ 306*220a0857SSami Tolvanen __process_list_type(state, cache, die, #type " "); \ 307*220a0857SSami Tolvanen } 308*220a0857SSami Tolvanen 309*220a0857SSami Tolvanen DEFINE_PROCESS_LIST_TYPE(formal_parameter) 310*220a0857SSami Tolvanen 31106b8b036SSami Tolvanen /* Container types with DW_AT_type */ 31206b8b036SSami Tolvanen static void __process_type(struct state *state, struct die *cache, 31306b8b036SSami Tolvanen Dwarf_Die *die, const char *type) 31406b8b036SSami Tolvanen { 31506b8b036SSami Tolvanen process(cache, type); 31606b8b036SSami Tolvanen process_fqn(cache, die); 31706b8b036SSami Tolvanen process(cache, " {"); 31806b8b036SSami Tolvanen process_linebreak(cache, 1); 31906b8b036SSami Tolvanen process_type_attr(state, cache, die); 32006b8b036SSami Tolvanen process_linebreak(cache, -1); 32106b8b036SSami Tolvanen process(cache, "}"); 32206b8b036SSami Tolvanen process_byte_size_attr(cache, die); 32306b8b036SSami Tolvanen process_alignment_attr(cache, die); 32406b8b036SSami Tolvanen } 32506b8b036SSami Tolvanen 32606b8b036SSami Tolvanen #define DEFINE_PROCESS_TYPE(type) \ 32706b8b036SSami Tolvanen static void process_##type##_type(struct state *state, \ 32806b8b036SSami Tolvanen struct die *cache, Dwarf_Die *die) \ 32906b8b036SSami Tolvanen { \ 33006b8b036SSami Tolvanen __process_type(state, cache, die, #type "_type"); \ 33106b8b036SSami Tolvanen } 33206b8b036SSami Tolvanen 33306b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(atomic) 33406b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(const) 33506b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(immutable) 33606b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(packed) 33706b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(pointer) 33806b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(reference) 33906b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(restrict) 34006b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(rvalue_reference) 34106b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(shared) 34206b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(volatile) 34306b8b036SSami Tolvanen DEFINE_PROCESS_TYPE(typedef) 34406b8b036SSami Tolvanen 345*220a0857SSami Tolvanen static void __process_subroutine_type(struct state *state, struct die *cache, 346*220a0857SSami Tolvanen Dwarf_Die *die, const char *type) 347*220a0857SSami Tolvanen { 348*220a0857SSami Tolvanen process(cache, type); 349*220a0857SSami Tolvanen process(cache, " ("); 350*220a0857SSami Tolvanen process_linebreak(cache, 1); 351*220a0857SSami Tolvanen /* Parameters */ 352*220a0857SSami Tolvanen check(process_die_container(state, cache, die, process_type, 353*220a0857SSami Tolvanen match_formal_parameter_type)); 354*220a0857SSami Tolvanen process_linebreak(cache, -1); 355*220a0857SSami Tolvanen process(cache, ")"); 356*220a0857SSami Tolvanen process_linebreak(cache, 0); 357*220a0857SSami Tolvanen /* Return type */ 358*220a0857SSami Tolvanen process(cache, "-> "); 359*220a0857SSami Tolvanen process_type_attr(state, cache, die); 360*220a0857SSami Tolvanen } 361*220a0857SSami Tolvanen 362*220a0857SSami Tolvanen static void process_subroutine_type(struct state *state, struct die *cache, 363*220a0857SSami Tolvanen Dwarf_Die *die) 364*220a0857SSami Tolvanen { 365*220a0857SSami Tolvanen __process_subroutine_type(state, cache, die, "subroutine_type"); 366*220a0857SSami Tolvanen } 367*220a0857SSami Tolvanen 3680c1c7627SSami Tolvanen static void process_base_type(struct state *state, struct die *cache, 3690c1c7627SSami Tolvanen Dwarf_Die *die) 3705b7780e8SSami Tolvanen { 3710c1c7627SSami Tolvanen process(cache, "base_type"); 3720c1c7627SSami Tolvanen process_fqn(cache, die); 3730c1c7627SSami Tolvanen process_byte_size_attr(cache, die); 3740c1c7627SSami Tolvanen process_encoding_attr(cache, die); 3750c1c7627SSami Tolvanen process_alignment_attr(cache, die); 3760c1c7627SSami Tolvanen } 3770c1c7627SSami Tolvanen 3780c1c7627SSami Tolvanen static void process_cached(struct state *state, struct die *cache, 3790c1c7627SSami Tolvanen Dwarf_Die *die) 3800c1c7627SSami Tolvanen { 3810c1c7627SSami Tolvanen struct die_fragment *df; 3820c1c7627SSami Tolvanen Dwarf_Die child; 3830c1c7627SSami Tolvanen 3840c1c7627SSami Tolvanen list_for_each_entry(df, &cache->fragments, list) { 3850c1c7627SSami Tolvanen switch (df->type) { 3860c1c7627SSami Tolvanen case FRAGMENT_STRING: 3870c1c7627SSami Tolvanen process(NULL, df->data.str); 3880c1c7627SSami Tolvanen break; 38906b8b036SSami Tolvanen case FRAGMENT_LINEBREAK: 39006b8b036SSami Tolvanen process_linebreak(NULL, df->data.linebreak); 39106b8b036SSami Tolvanen break; 3920c1c7627SSami Tolvanen case FRAGMENT_DIE: 3930c1c7627SSami Tolvanen if (!dwarf_die_addr_die(dwarf_cu_getdwarf(die->cu), 3940c1c7627SSami Tolvanen (void *)df->data.addr, &child)) 3950c1c7627SSami Tolvanen error("dwarf_die_addr_die failed"); 3960c1c7627SSami Tolvanen check(process_type(state, NULL, &child)); 3970c1c7627SSami Tolvanen break; 3980c1c7627SSami Tolvanen default: 3990c1c7627SSami Tolvanen error("empty die_fragment"); 4000c1c7627SSami Tolvanen } 4010c1c7627SSami Tolvanen } 4025b7780e8SSami Tolvanen } 4035b7780e8SSami Tolvanen 4045b7780e8SSami Tolvanen #define PROCESS_TYPE(type) \ 4055b7780e8SSami Tolvanen case DW_TAG_##type##_type: \ 4060c1c7627SSami Tolvanen process_##type##_type(state, cache, die); \ 4075b7780e8SSami Tolvanen break; 4085b7780e8SSami Tolvanen 4090c1c7627SSami Tolvanen static int process_type(struct state *state, struct die *parent, Dwarf_Die *die) 4105b7780e8SSami Tolvanen { 4110c1c7627SSami Tolvanen struct die *cache; 4125b7780e8SSami Tolvanen int tag = dwarf_tag(die); 4135b7780e8SSami Tolvanen 4140c1c7627SSami Tolvanen /* 4150c1c7627SSami Tolvanen * If we have the DIE already cached, use it instead of walking 4160c1c7627SSami Tolvanen * through DWARF. 4170c1c7627SSami Tolvanen */ 4180c1c7627SSami Tolvanen cache = die_map_get(die, DIE_COMPLETE); 4190c1c7627SSami Tolvanen 4200c1c7627SSami Tolvanen if (cache->state == DIE_COMPLETE) { 4210c1c7627SSami Tolvanen process_cached(state, cache, die); 4220c1c7627SSami Tolvanen die_map_add_die(parent, cache); 4230c1c7627SSami Tolvanen return 0; 4240c1c7627SSami Tolvanen } 4250c1c7627SSami Tolvanen 4265b7780e8SSami Tolvanen switch (tag) { 42706b8b036SSami Tolvanen /* Type modifiers */ 42806b8b036SSami Tolvanen PROCESS_TYPE(atomic) 42906b8b036SSami Tolvanen PROCESS_TYPE(const) 43006b8b036SSami Tolvanen PROCESS_TYPE(immutable) 43106b8b036SSami Tolvanen PROCESS_TYPE(packed) 43206b8b036SSami Tolvanen PROCESS_TYPE(pointer) 43306b8b036SSami Tolvanen PROCESS_TYPE(reference) 43406b8b036SSami Tolvanen PROCESS_TYPE(restrict) 43506b8b036SSami Tolvanen PROCESS_TYPE(rvalue_reference) 43606b8b036SSami Tolvanen PROCESS_TYPE(shared) 43706b8b036SSami Tolvanen PROCESS_TYPE(volatile) 438*220a0857SSami Tolvanen /* Subtypes */ 439*220a0857SSami Tolvanen PROCESS_TYPE(formal_parameter) 44006b8b036SSami Tolvanen /* Other types */ 4415b7780e8SSami Tolvanen PROCESS_TYPE(base) 442*220a0857SSami Tolvanen PROCESS_TYPE(subroutine) 44306b8b036SSami Tolvanen PROCESS_TYPE(typedef) 4445b7780e8SSami Tolvanen default: 4455b7780e8SSami Tolvanen debug("unimplemented type: %x", tag); 4465b7780e8SSami Tolvanen break; 4475b7780e8SSami Tolvanen } 4485b7780e8SSami Tolvanen 4490c1c7627SSami Tolvanen /* Update cache state and append to the parent (if any) */ 4500c1c7627SSami Tolvanen cache->tag = tag; 4510c1c7627SSami Tolvanen cache->state = DIE_COMPLETE; 4520c1c7627SSami Tolvanen die_map_add_die(parent, cache); 4530c1c7627SSami Tolvanen 4545b7780e8SSami Tolvanen return 0; 4555b7780e8SSami Tolvanen } 4565b7780e8SSami Tolvanen 457f2856884SSami Tolvanen /* 458f2856884SSami Tolvanen * Exported symbol processing 459f2856884SSami Tolvanen */ 460f2856884SSami Tolvanen static void process_symbol(struct state *state, Dwarf_Die *die, 461f2856884SSami Tolvanen die_callback_t process_func) 462f2856884SSami Tolvanen { 463f2856884SSami Tolvanen debug("%s", state->sym->name); 4640c1c7627SSami Tolvanen check(process_func(state, NULL, die)); 465f2856884SSami Tolvanen if (dump_dies) 466f2856884SSami Tolvanen fputs("\n", stderr); 467f2856884SSami Tolvanen } 468f2856884SSami Tolvanen 4690c1c7627SSami Tolvanen static int __process_subprogram(struct state *state, struct die *cache, 4700c1c7627SSami Tolvanen Dwarf_Die *die) 471f2856884SSami Tolvanen { 472*220a0857SSami Tolvanen __process_subroutine_type(state, cache, die, "subprogram"); 473f2856884SSami Tolvanen return 0; 474f2856884SSami Tolvanen } 475f2856884SSami Tolvanen 476f2856884SSami Tolvanen static void process_subprogram(struct state *state, Dwarf_Die *die) 477f2856884SSami Tolvanen { 478f2856884SSami Tolvanen process_symbol(state, die, __process_subprogram); 479f2856884SSami Tolvanen } 480f2856884SSami Tolvanen 4810c1c7627SSami Tolvanen static int __process_variable(struct state *state, struct die *cache, 4820c1c7627SSami Tolvanen Dwarf_Die *die) 483f2856884SSami Tolvanen { 4840c1c7627SSami Tolvanen process(cache, "variable "); 4850c1c7627SSami Tolvanen process_type_attr(state, cache, die); 486f2856884SSami Tolvanen return 0; 487f2856884SSami Tolvanen } 488f2856884SSami Tolvanen 489f2856884SSami Tolvanen static void process_variable(struct state *state, Dwarf_Die *die) 490f2856884SSami Tolvanen { 491f2856884SSami Tolvanen process_symbol(state, die, __process_variable); 492f2856884SSami Tolvanen } 493f2856884SSami Tolvanen 4940c1c7627SSami Tolvanen static int process_exported_symbols(struct state *unused, struct die *cache, 4950c1c7627SSami Tolvanen Dwarf_Die *die) 496f2856884SSami Tolvanen { 497f2856884SSami Tolvanen int tag = dwarf_tag(die); 498f2856884SSami Tolvanen 499f2856884SSami Tolvanen switch (tag) { 500f2856884SSami Tolvanen /* Possible containers of exported symbols */ 501f2856884SSami Tolvanen case DW_TAG_namespace: 502f2856884SSami Tolvanen case DW_TAG_class_type: 503f2856884SSami Tolvanen case DW_TAG_structure_type: 504f2856884SSami Tolvanen return check(process_die_container( 5050c1c7627SSami Tolvanen NULL, cache, die, process_exported_symbols, match_all)); 506f2856884SSami Tolvanen 507f2856884SSami Tolvanen /* Possible exported symbols */ 508f2856884SSami Tolvanen case DW_TAG_subprogram: 509f2856884SSami Tolvanen case DW_TAG_variable: { 510f2856884SSami Tolvanen struct state state; 511f2856884SSami Tolvanen 512f2856884SSami Tolvanen if (!match_export_symbol(&state, die)) 513f2856884SSami Tolvanen return 0; 514f2856884SSami Tolvanen 515f2856884SSami Tolvanen if (tag == DW_TAG_subprogram) 516f2856884SSami Tolvanen process_subprogram(&state, &state.die); 517f2856884SSami Tolvanen else 518f2856884SSami Tolvanen process_variable(&state, &state.die); 519f2856884SSami Tolvanen 520f2856884SSami Tolvanen return 0; 521f2856884SSami Tolvanen } 522f2856884SSami Tolvanen default: 523f2856884SSami Tolvanen return 0; 524f2856884SSami Tolvanen } 525f2856884SSami Tolvanen } 526f2856884SSami Tolvanen 527f2856884SSami Tolvanen void process_cu(Dwarf_Die *cudie) 528f2856884SSami Tolvanen { 5290c1c7627SSami Tolvanen check(process_die_container(NULL, NULL, cudie, process_exported_symbols, 530f2856884SSami Tolvanen match_all)); 531f2856884SSami Tolvanen } 532