| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- /* SPDX-License-Identifier: GPL-2.0 */
- /*
- * Copyright (C) 2024 Google LLC
- */
- #include <dwarf.h>
- #include <elfutils/libdw.h>
- #include <elfutils/libdwfl.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <hash.h>
- #include <hashtable.h>
- #include <xalloc.h>
- #ifndef __GENDWARFKSYMS_H
- #define __GENDWARFKSYMS_H
- /*
- * Options -- in gendwarfksyms.c
- */
- extern int debug;
- extern int dump_dies;
- extern int dump_die_map;
- extern int dump_types;
- extern int dump_versions;
- extern int stable;
- extern int symtypes;
- /*
- * Output helpers
- */
- #define __PREFIX "gendwarfksyms: "
- #define __println(prefix, format, ...) \
- fprintf(stderr, prefix __PREFIX "%s: " format "\n", __func__, \
- ##__VA_ARGS__)
- #define debug(format, ...) \
- do { \
- if (debug) \
- __println("", format, ##__VA_ARGS__); \
- } while (0)
- #define warn(format, ...) __println("warning: ", format, ##__VA_ARGS__)
- #define error(format, ...) \
- do { \
- __println("error: ", format, ##__VA_ARGS__); \
- exit(1); \
- } while (0)
- #define __die_debug(color, format, ...) \
- do { \
- if (dump_dies && dump_die_map) \
- fprintf(stderr, \
- "\033[" #color "m<" format ">\033[39m", \
- __VA_ARGS__); \
- } while (0)
- #define die_debug_r(format, ...) __die_debug(91, format, __VA_ARGS__)
- #define die_debug_g(format, ...) __die_debug(92, format, __VA_ARGS__)
- #define die_debug_b(format, ...) __die_debug(94, format, __VA_ARGS__)
- /*
- * Error handling helpers
- */
- #define __check(expr, test) \
- ({ \
- int __res = expr; \
- if (test) \
- error("`%s` failed: %d", #expr, __res); \
- __res; \
- })
- /* Error == non-zero values */
- #define check(expr) __check(expr, __res)
- /* Error == negative values */
- #define checkp(expr) __check(expr, __res < 0)
- /* Consistent aliases (DW_TAG_<type>_type) for DWARF tags */
- #define DW_TAG_enumerator_type DW_TAG_enumerator
- #define DW_TAG_formal_parameter_type DW_TAG_formal_parameter
- #define DW_TAG_member_type DW_TAG_member
- #define DW_TAG_template_type_parameter_type DW_TAG_template_type_parameter
- #define DW_TAG_typedef_type DW_TAG_typedef
- #define DW_TAG_variant_part_type DW_TAG_variant_part
- #define DW_TAG_variant_type DW_TAG_variant
- /*
- * symbols.c
- */
- /* See symbols.c:is_symbol_ptr */
- #define SYMBOL_PTR_PREFIX "__gendwarfksyms_ptr_"
- #define SYMBOL_PTR_PREFIX_LEN (sizeof(SYMBOL_PTR_PREFIX) - 1)
- static inline unsigned int addr_hash(uintptr_t addr)
- {
- return hash_ptr((const void *)addr);
- }
- enum symbol_state {
- SYMBOL_UNPROCESSED,
- SYMBOL_MAPPED,
- SYMBOL_PROCESSED
- };
- struct symbol_addr {
- uint32_t section;
- Elf64_Addr address;
- };
- struct symbol {
- const char *name;
- struct symbol_addr addr;
- struct hlist_node addr_hash;
- struct hlist_node name_hash;
- enum symbol_state state;
- uintptr_t die_addr;
- uintptr_t ptr_die_addr;
- unsigned long crc;
- };
- typedef void (*symbol_callback_t)(struct symbol *, void *arg);
- bool is_symbol_ptr(const char *name);
- int symbol_read_exports(FILE *file);
- void symbol_read_symtab(int fd);
- struct symbol *symbol_get(const char *name);
- void symbol_set_ptr(struct symbol *sym, Dwarf_Die *ptr);
- void symbol_set_die(struct symbol *sym, Dwarf_Die *die);
- void symbol_set_crc(struct symbol *sym, unsigned long crc);
- void symbol_for_each(symbol_callback_t func, void *arg);
- void symbol_print_versions(void);
- void symbol_free(void);
- /*
- * die.c
- */
- enum die_state {
- DIE_INCOMPLETE,
- DIE_FQN,
- DIE_UNEXPANDED,
- DIE_COMPLETE,
- DIE_SYMBOL,
- DIE_LAST = DIE_SYMBOL
- };
- enum die_fragment_type {
- FRAGMENT_EMPTY,
- FRAGMENT_STRING,
- FRAGMENT_LINEBREAK,
- FRAGMENT_DIE
- };
- struct die_fragment {
- enum die_fragment_type type;
- union {
- char *str;
- int linebreak;
- uintptr_t addr;
- } data;
- struct list_head list;
- };
- #define CASE_CONST_TO_STR(name) \
- case name: \
- return #name;
- static inline const char *die_state_name(enum die_state state)
- {
- switch (state) {
- CASE_CONST_TO_STR(DIE_INCOMPLETE)
- CASE_CONST_TO_STR(DIE_FQN)
- CASE_CONST_TO_STR(DIE_UNEXPANDED)
- CASE_CONST_TO_STR(DIE_COMPLETE)
- CASE_CONST_TO_STR(DIE_SYMBOL)
- }
- error("unexpected die_state: %d", state);
- }
- struct die {
- enum die_state state;
- bool mapped;
- char *fqn;
- int tag;
- uintptr_t addr;
- struct list_head fragments;
- struct hlist_node hash;
- };
- typedef void (*die_map_callback_t)(struct die *, void *arg);
- int __die_map_get(uintptr_t addr, enum die_state state, struct die **res);
- struct die *die_map_get(Dwarf_Die *die, enum die_state state);
- void die_map_add_string(struct die *pd, const char *str);
- void die_map_add_linebreak(struct die *pd, int linebreak);
- void die_map_for_each(die_map_callback_t func, void *arg);
- void die_map_add_die(struct die *pd, struct die *child);
- void die_map_free(void);
- /*
- * cache.c
- */
- #define CACHE_HASH_BITS 10
- /* A cache for addresses we've already seen. */
- struct cache {
- HASHTABLE_DECLARE(cache, 1 << CACHE_HASH_BITS);
- };
- void cache_set(struct cache *cache, unsigned long key, int value);
- int cache_get(struct cache *cache, unsigned long key);
- void cache_init(struct cache *cache);
- void cache_free(struct cache *cache);
- static inline void cache_mark_expanded(struct cache *cache, void *addr)
- {
- cache_set(cache, (unsigned long)addr, 1);
- }
- static inline bool cache_was_expanded(struct cache *cache, void *addr)
- {
- return cache_get(cache, (unsigned long)addr) == 1;
- }
- /*
- * dwarf.c
- */
- struct expansion_state {
- bool expand;
- const char *current_fqn;
- };
- struct kabi_state {
- int members;
- Dwarf_Die placeholder;
- const char *orig_name;
- };
- struct state {
- struct symbol *sym;
- Dwarf_Die die;
- /* List expansion */
- bool first_list_item;
- /* Structure expansion */
- struct expansion_state expand;
- struct cache expansion_cache;
- /* Reserved or ignored members */
- struct kabi_state kabi;
- };
- typedef int (*die_callback_t)(struct state *state, struct die *cache,
- Dwarf_Die *die);
- typedef bool (*die_match_callback_t)(Dwarf_Die *die);
- bool match_all(Dwarf_Die *die);
- int process_die_container(struct state *state, struct die *cache,
- Dwarf_Die *die, die_callback_t func,
- die_match_callback_t match);
- void process_cu(Dwarf_Die *cudie);
- /*
- * types.c
- */
- void generate_symtypes_and_versions(FILE *file);
- /*
- * kabi.c
- */
- bool kabi_get_byte_size(const char *fqn, unsigned long *value);
- bool kabi_is_enumerator_ignored(const char *fqn, const char *field);
- bool kabi_get_enumerator_value(const char *fqn, const char *field,
- unsigned long *value);
- bool kabi_is_declonly(const char *fqn);
- bool kabi_get_type_string(const char *type, const char **str);
- void kabi_read_rules(int fd);
- void kabi_free(void);
- #endif /* __GENDWARFKSYMS_H */
|