summaryrefslogtreecommitdiff
path: root/scripts/gendwarfksyms/gendwarfksyms.h
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/gendwarfksyms/gendwarfksyms.h')
-rw-r--r--scripts/gendwarfksyms/gendwarfksyms.h296
1 files changed, 296 insertions, 0 deletions
diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/gendwarfksyms.h
new file mode 100644
index 000000000000..197a1a8123c6
--- /dev/null
+++ b/scripts/gendwarfksyms/gendwarfksyms.h
@@ -0,0 +1,296 @@
+/* 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);
+void 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_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_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, uintptr_t addr)
+{
+ cache_set(cache, addr, 1);
+}
+
+static inline bool __cache_was_expanded(struct cache *cache, uintptr_t addr)
+{
+ return cache_get(cache, addr) == 1;
+}
+
+static inline void cache_mark_expanded(struct cache *cache, void *addr)
+{
+ __cache_mark_expanded(cache, (uintptr_t)addr);
+}
+
+static inline bool cache_was_expanded(struct cache *cache, void *addr)
+{
+ return __cache_was_expanded(cache, (uintptr_t)addr);
+}
+
+/*
+ * 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_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);
+
+void kabi_read_rules(int fd);
+void kabi_free(void);
+
+#endif /* __GENDWARFKSYMS_H */