summaryrefslogtreecommitdiff
path: root/scripts/gendwarfksyms
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/gendwarfksyms')
-rw-r--r--scripts/gendwarfksyms/dwarf.c14
-rw-r--r--scripts/gendwarfksyms/examples/kabi.h21
-rw-r--r--scripts/gendwarfksyms/examples/kabi_ex.c7
-rw-r--r--scripts/gendwarfksyms/examples/kabi_ex.h101
-rw-r--r--scripts/gendwarfksyms/gendwarfksyms.h16
-rw-r--r--scripts/gendwarfksyms/kabi.c143
-rw-r--r--scripts/gendwarfksyms/types.c179
7 files changed, 364 insertions, 117 deletions
diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c
index eed247d8abfc..13ea7bf1ae7d 100644
--- a/scripts/gendwarfksyms/dwarf.c
+++ b/scripts/gendwarfksyms/dwarf.c
@@ -228,12 +228,24 @@ static void process_fqn(struct die *cache, Dwarf_Die *die)
DEFINE_PROCESS_UDATA_ATTRIBUTE(accessibility)
DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment)
DEFINE_PROCESS_UDATA_ATTRIBUTE(bit_size)
-DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size)
DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding)
DEFINE_PROCESS_UDATA_ATTRIBUTE(data_bit_offset)
DEFINE_PROCESS_UDATA_ATTRIBUTE(data_member_location)
DEFINE_PROCESS_UDATA_ATTRIBUTE(discr_value)
+static void process_byte_size_attr(struct die *cache, Dwarf_Die *die)
+{
+ Dwarf_Word value;
+ unsigned long override;
+
+ if (get_udata_attr(die, DW_AT_byte_size, &value)) {
+ if (stable && kabi_get_byte_size(cache->fqn, &override))
+ value = override;
+
+ process_fmt(cache, " byte_size(%" PRIu64 ")", value);
+ }
+}
+
/* Match functions -- die_match_callback_t */
#define DEFINE_MATCH(type) \
static bool match_##type##_type(Dwarf_Die *die) \
diff --git a/scripts/gendwarfksyms/examples/kabi.h b/scripts/gendwarfksyms/examples/kabi.h
index 97a5669b083d..170733a3fba4 100644
--- a/scripts/gendwarfksyms/examples/kabi.h
+++ b/scripts/gendwarfksyms/examples/kabi.h
@@ -37,11 +37,14 @@
#define __stringify(x...) __stringify_1(x)
#endif
-#define __KABI_RULE(hint, target, value) \
+#define ___KABI_RULE(hint, target, value) \
static const char __PASTE(__gendwarfksyms_rule_, \
__COUNTER__)[] __used __aligned(1) \
__section(".discard.gendwarfksyms.kabi_rules") = \
- "1\0" #hint "\0" #target "\0" #value
+ "1\0" #hint "\0" target "\0" value
+
+#define __KABI_RULE(hint, target, value) \
+ ___KABI_RULE(hint, #target, #value)
#define __KABI_NORMAL_SIZE_ALIGN(_orig, _new) \
union { \
@@ -90,6 +93,20 @@
__KABI_RULE(enumerator_value, fqn field, value)
/*
+ * KABI_BYTE_SIZE(fqn, value)
+ * Set the byte_size attribute for the struct/union/enum fqn to
+ * value bytes.
+ */
+#define KABI_BYTE_SIZE(fqn, value) __KABI_RULE(byte_size, fqn, value)
+
+/*
+ * KABI_TYPE_STRING(type, str)
+ * For the given type, override the type string used in symtypes
+ * output and version calculation with str.
+ */
+#define KABI_TYPE_STRING(type, str) ___KABI_RULE(type_string, type, str)
+
+/*
* KABI_RESERVE
* Reserve some "padding" in a structure for use by LTS backports.
* This is normally placed at the end of a structure.
diff --git a/scripts/gendwarfksyms/examples/kabi_ex.c b/scripts/gendwarfksyms/examples/kabi_ex.c
index 0b7ffd830541..1f799eb7c756 100644
--- a/scripts/gendwarfksyms/examples/kabi_ex.c
+++ b/scripts/gendwarfksyms/examples/kabi_ex.c
@@ -28,3 +28,10 @@ struct ex2c ex2c;
struct ex3a ex3a;
struct ex3b ex3b;
struct ex3c ex3c;
+
+struct ex4a ex4a;
+
+struct ex5a ex5a;
+struct ex5b ex5b;
+
+int ex6a;
diff --git a/scripts/gendwarfksyms/examples/kabi_ex.h b/scripts/gendwarfksyms/examples/kabi_ex.h
index 1736e0f65208..785b211d9c58 100644
--- a/scripts/gendwarfksyms/examples/kabi_ex.h
+++ b/scripts/gendwarfksyms/examples/kabi_ex.h
@@ -21,6 +21,12 @@
* ./gendwarfksyms --stable --dump-dies \
* examples/kabi_ex.o 2>&1 >/dev/null | \
* FileCheck examples/kabi_ex.h --check-prefix=STABLE
+
+ * $ nm examples/kabi_ex.o | awk '{ print $NF }' | \
+ * ./gendwarfksyms --stable --dump-versions \
+ * examples/kabi_ex.o 2>&1 >/dev/null | \
+ * sort | \
+ * FileCheck examples/kabi_ex.h --check-prefix=VERSIONS
*/
#ifndef __KABI_EX_H__
@@ -170,7 +176,7 @@ struct ex2a {
/*
* STABLE: variable structure_type ex2a {
* STABLE-NEXT: member base_type int byte_size(4) encoding(5) a data_member_location(0) ,
- * STABLE-NEXT: member base_type [[ULONG:long unsigned int|unsigned long]] byte_size(8) encoding(7) b data_member_location(8)
+ * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) b data_member_location(8)
* STABLE-NEXT: member base_type int byte_size(4) encoding(5) c data_member_location(16) ,
* STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) d data_member_location(24)
* STABLE-NEXT: } byte_size(32)
@@ -227,7 +233,7 @@ struct ex3a {
/*
* STABLE: variable structure_type ex3a {
- * STABLE-NEXT: member base_type [[ULONG:long unsigned int|unsigned long]] byte_size(8) encoding(7) a data_member_location(0)
+ * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) a data_member_location(0)
* STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) unused data_member_location(8)
* STABLE-NEXT: } byte_size(16)
*/
@@ -260,4 +266,95 @@ _Static_assert(sizeof(struct ex3a) == sizeof(struct ex3c), "ex3a size doesn't ma
* STABLE-NEXT: } byte_size(16)
*/
+/*
+ * Example: An ignored field added to an end of a partially opaque struct,
+ * while keeping the byte_size attribute unchanged.
+ */
+
+struct ex4a {
+ unsigned long a;
+ KABI_IGNORE(0, unsigned long b);
+};
+
+/*
+ * This may be safe if the structure allocation is managed by the core kernel
+ * and the layout remains unchanged except for appended new members.
+ */
+KABI_BYTE_SIZE(ex4a, 8);
+
+/*
+ * STABLE: variable structure_type ex4a {
+ * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) a data_member_location(0)
+ * STABLE-NEXT: } byte_size(8)
+ */
+
+/*
+ * Example: A type string override.
+ */
+
+struct ex5a {
+ unsigned long a;
+};
+
+/*
+ * This may be safe if the structure is fully opaque to modules, even though
+ * its definition has inadvertently become part of the ABI.
+ */
+KABI_TYPE_STRING(
+ "s#ex5a",
+ "structure_type ex5a { member pointer_type { s#ex4a } byte_size(8) p data_member_location(0) } byte_size(8)");
+
+/*
+ * Make sure the fully expanded type string includes ex4a.
+ *
+ * VERSIONS: ex5a variable structure_type ex5a {
+ * VERSIONS-SAME: member pointer_type {
+ * VERSIONS-SAME: structure_type ex4a {
+ * VERSIONS-SAME: member base_type [[ULONG:long unsigned int|unsigned long]] byte_size(8) encoding(7) a data_member_location(0)
+ * VERSIONS-SAME: } byte_size(8)
+ * VERSIONS-SAME: } byte_size(8) p data_member_location(0)
+ * VERSIONS-SAME: } byte_size(8)
+ */
+
+/*
+ * Example: A type string definition for a non-existent type.
+ */
+
+struct ex5b {
+ unsigned long a;
+};
+
+/* Replace the type string for struct ex5b */
+KABI_TYPE_STRING(
+ "s#ex5b",
+ "structure_type ex5b { member pointer_type { s#ex5c } byte_size(8) p data_member_location(0) } byte_size(8)");
+
+/* Define a type string for a non-existent struct ex5c */
+KABI_TYPE_STRING(
+ "s#ex5c",
+ "structure_type ex5c { member base_type int byte_size(4) encoding(5) n data_member_location(0) } byte_size(8)");
+
+/*
+ * Make sure the fully expanded type string includes the definition for ex5c.
+ *
+ * VERSIONS: ex5b variable structure_type ex5b {
+ * VERSIONS-SAME: member pointer_type {
+ * VERSIONS-SAME: structure_type ex5c {
+ * VERSIONS-SAME: member base_type int byte_size(4) encoding(5) n data_member_location(0)
+ * VERSIONS-SAME: } byte_size(8)
+ * VERSIONS-SAME: } byte_size(8) p data_member_location(0)
+ * VERSIONS-SAME: } byte_size(8)
+ */
+
+/*
+ * Example: A type string override for a symbol.
+ */
+
+KABI_TYPE_STRING("ex6a", "variable s#ex5c");
+
+/*
+ * VERSIONS: ex6a variable structure_type ex5c {
+ * VERSIONS-SAME: member base_type int byte_size(4) encoding(5) n data_member_location(0)
+ * VERSIONS-SAME: } byte_size(8)
+ */
#endif /* __KABI_EX_H__ */
diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/gendwarfksyms.h
index 2feec168bf73..d9c06d2cb1df 100644
--- a/scripts/gendwarfksyms/gendwarfksyms.h
+++ b/scripts/gendwarfksyms/gendwarfksyms.h
@@ -216,24 +216,14 @@ 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);
+ cache_set(cache, (unsigned long)addr, 1);
}
static inline bool cache_was_expanded(struct cache *cache, void *addr)
{
- return __cache_was_expanded(cache, (uintptr_t)addr);
+ return cache_get(cache, (unsigned long)addr) == 1;
}
/*
@@ -287,10 +277,12 @@ 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);
diff --git a/scripts/gendwarfksyms/kabi.c b/scripts/gendwarfksyms/kabi.c
index 66f01fcd1607..b3ade713778f 100644
--- a/scripts/gendwarfksyms/kabi.c
+++ b/scripts/gendwarfksyms/kabi.c
@@ -54,11 +54,27 @@
*/
#define KABI_RULE_TAG_ENUMERATOR_VALUE "enumerator_value"
+/*
+ * Rule: byte_size
+ * - For the fqn_field in the target field, set the byte_size
+ * attribute to the value in the value field.
+ */
+#define KABI_RULE_TAG_BYTE_SIZE "byte_size"
+
+/*
+ * Rule: type_string
+ * - For the type reference in the fqn field, use the type string
+ * in the value field.
+ */
+#define KABI_RULE_TAG_TYPE_STRING "type_string"
+
enum kabi_rule_type {
KABI_RULE_TYPE_UNKNOWN,
KABI_RULE_TYPE_DECLONLY,
KABI_RULE_TYPE_ENUMERATOR_IGNORE,
KABI_RULE_TYPE_ENUMERATOR_VALUE,
+ KABI_RULE_TYPE_BYTE_SIZE,
+ KABI_RULE_TYPE_TYPE_STRING,
};
#define RULE_HASH_BITS 7
@@ -127,6 +143,14 @@ void kabi_read_rules(int fd)
.type = KABI_RULE_TYPE_ENUMERATOR_VALUE,
.tag = KABI_RULE_TAG_ENUMERATOR_VALUE,
},
+ {
+ .type = KABI_RULE_TYPE_BYTE_SIZE,
+ .tag = KABI_RULE_TAG_BYTE_SIZE,
+ },
+ {
+ .type = KABI_RULE_TYPE_TYPE_STRING,
+ .tag = KABI_RULE_TAG_TYPE_STRING,
+ },
};
if (!stable)
@@ -222,33 +246,55 @@ void kabi_read_rules(int fd)
check(elf_end(elf));
}
-bool kabi_is_declonly(const char *fqn)
+static char *get_enumerator_target(const char *fqn, const char *field)
+{
+ char *target = NULL;
+
+ if (asprintf(&target, "%s %s", fqn, field) < 0)
+ error("asprintf failed for '%s %s'", fqn, field);
+
+ return target;
+}
+
+static struct rule *find_rule(enum kabi_rule_type type, const char *target)
{
struct rule *rule;
if (!stable)
- return false;
- if (!fqn || !*fqn)
- return false;
+ return NULL;
+ if (!target || !*target)
+ return NULL;
hash_for_each_possible(rules, rule, hash,
- rule_values_hash(KABI_RULE_TYPE_DECLONLY, fqn)) {
- if (rule->type == KABI_RULE_TYPE_DECLONLY &&
- !strcmp(fqn, rule->target))
- return true;
+ rule_values_hash(type, target)) {
+ if (rule->type == type && !strcmp(target, rule->target))
+ return rule;
}
- return false;
+ return NULL;
}
-static char *get_enumerator_target(const char *fqn, const char *field)
+static struct rule *find_enumerator_rule(enum kabi_rule_type type,
+ const char *fqn, const char *field)
{
- char *target = NULL;
+ struct rule *rule;
+ char *target;
- if (asprintf(&target, "%s %s", fqn, field) < 0)
- error("asprintf failed for '%s %s'", fqn, field);
+ if (!stable)
+ return NULL;
+ if (!fqn || !*fqn || !field || !*field)
+ return NULL;
- return target;
+ target = get_enumerator_target(fqn, field);
+ rule = find_rule(type, target);
+
+ free(target);
+ return rule;
+}
+
+bool kabi_is_declonly(const char *fqn)
+{
+ return !!find_rule(KABI_RULE_TYPE_DECLONLY, fqn);
}
static unsigned long get_ulong_value(const char *value)
@@ -267,58 +313,49 @@ static unsigned long get_ulong_value(const char *value)
bool kabi_is_enumerator_ignored(const char *fqn, const char *field)
{
- bool match = false;
- struct rule *rule;
- char *target;
-
- if (!stable)
- return false;
- if (!fqn || !*fqn || !field || !*field)
- return false;
+ return !!find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_IGNORE, fqn,
+ field);
+}
- target = get_enumerator_target(fqn, field);
+bool kabi_get_enumerator_value(const char *fqn, const char *field,
+ unsigned long *value)
+{
+ struct rule *rule;
- hash_for_each_possible(
- rules, rule, hash,
- rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_IGNORE, target)) {
- if (rule->type == KABI_RULE_TYPE_ENUMERATOR_IGNORE &&
- !strcmp(target, rule->target)) {
- match = true;
- break;
- }
+ rule = find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_VALUE, fqn,
+ field);
+ if (rule) {
+ *value = get_ulong_value(rule->value);
+ return true;
}
- free(target);
- return match;
+ return false;
}
-bool kabi_get_enumerator_value(const char *fqn, const char *field,
- unsigned long *value)
+bool kabi_get_byte_size(const char *fqn, unsigned long *value)
{
- bool match = false;
struct rule *rule;
- char *target;
- if (!stable)
- return false;
- if (!fqn || !*fqn || !field || !*field)
- return false;
+ rule = find_rule(KABI_RULE_TYPE_BYTE_SIZE, fqn);
+ if (rule) {
+ *value = get_ulong_value(rule->value);
+ return true;
+ }
- target = get_enumerator_target(fqn, field);
+ return false;
+}
- hash_for_each_possible(rules, rule, hash,
- rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_VALUE,
- target)) {
- if (rule->type == KABI_RULE_TYPE_ENUMERATOR_VALUE &&
- !strcmp(target, rule->target)) {
- *value = get_ulong_value(rule->value);
- match = true;
- break;
- }
+bool kabi_get_type_string(const char *type, const char **str)
+{
+ struct rule *rule;
+
+ rule = find_rule(KABI_RULE_TYPE_TYPE_STRING, type);
+ if (rule) {
+ *str = rule->value;
+ return true;
}
- free(target);
- return match;
+ return false;
}
void kabi_free(void)
diff --git a/scripts/gendwarfksyms/types.c b/scripts/gendwarfksyms/types.c
index 6f37289104ff..7bd459ea6c59 100644
--- a/scripts/gendwarfksyms/types.c
+++ b/scripts/gendwarfksyms/types.c
@@ -100,7 +100,7 @@ static void type_expansion_append(struct type_expansion *type, const char *s,
#define TYPE_HASH_BITS 12
static HASHTABLE_DEFINE(type_map, 1 << TYPE_HASH_BITS);
-static int type_map_get(const char *name, struct type_expansion **res)
+static int __type_map_get(const char *name, struct type_expansion **res)
{
struct type_expansion *e;
@@ -114,11 +114,12 @@ static int type_map_get(const char *name, struct type_expansion **res)
return -1;
}
-static void type_map_add(const char *name, struct type_expansion *type)
+static struct type_expansion *type_map_add(const char *name,
+ struct type_expansion *type)
{
struct type_expansion *e;
- if (type_map_get(name, &e)) {
+ if (__type_map_get(name, &e)) {
e = xmalloc(sizeof(struct type_expansion));
type_expansion_init(e);
e->name = xstrdup(name);
@@ -130,7 +131,7 @@ static void type_map_add(const char *name, struct type_expansion *type)
} else {
/* Use the longest available expansion */
if (type->len <= e->len)
- return;
+ return e;
type_list_free(&e->expanded);
@@ -148,6 +149,34 @@ static void type_map_add(const char *name, struct type_expansion *type)
type_list_write(&e->expanded, stderr);
checkp(fputs("\n", stderr));
}
+
+ return e;
+}
+
+static void type_parse(const char *name, const char *str,
+ struct type_expansion *type);
+
+static int type_map_get(const char *name, struct type_expansion **res)
+{
+ struct type_expansion type;
+ const char *override;
+
+ if (!__type_map_get(name, res))
+ return 0;
+
+ /*
+ * If die_map didn't contain a type, we might still have
+ * a type_string kABI rule that defines it.
+ */
+ if (stable && kabi_get_type_string(name, &override)) {
+ type_expansion_init(&type);
+ type_parse(name, override, &type);
+ *res = type_map_add(name, &type);
+ type_expansion_free(&type);
+ return 0;
+ }
+
+ return -1;
}
static void type_map_write(FILE *file)
@@ -267,15 +296,18 @@ static char *get_type_name(struct die *cache)
return name;
}
-static void __calculate_version(struct version *version, struct list_head *list)
+static void __calculate_version(struct version *version,
+ struct type_expansion *type)
{
struct type_list_entry *entry;
struct type_expansion *e;
/* Calculate a CRC over an expanded type string */
- list_for_each_entry(entry, list, list) {
+ list_for_each_entry(entry, &type->expanded, list) {
if (is_type_prefix(entry->str)) {
- check(type_map_get(entry->str, &e));
+ if (type_map_get(entry->str, &e))
+ error("unknown type reference to '%s' when expanding '%s'",
+ entry->str, type->name);
/*
* It's sufficient to expand each type reference just
@@ -285,7 +317,7 @@ static void __calculate_version(struct version *version, struct list_head *list)
version_add(version, entry->str);
} else {
cache_mark_expanded(&expansion_cache, e);
- __calculate_version(version, &e->expanded);
+ __calculate_version(version, e);
}
} else {
version_add(version, entry->str);
@@ -293,44 +325,19 @@ static void __calculate_version(struct version *version, struct list_head *list)
}
}
-static void calculate_version(struct version *version, struct list_head *list)
+static void calculate_version(struct version *version,
+ struct type_expansion *type)
{
version_init(version);
- __calculate_version(version, list);
+ __calculate_version(version, type);
cache_free(&expansion_cache);
}
-static void __type_expand(struct die *cache, struct type_expansion *type,
- bool recursive);
-
-static void type_expand_child(struct die *cache, struct type_expansion *type,
- bool recursive)
-{
- struct type_expansion child;
- char *name;
-
- name = get_type_name(cache);
- if (!name) {
- __type_expand(cache, type, recursive);
- return;
- }
-
- if (recursive && !__cache_was_expanded(&expansion_cache, cache->addr)) {
- __cache_mark_expanded(&expansion_cache, cache->addr);
- type_expansion_init(&child);
- __type_expand(cache, &child, true);
- type_map_add(name, &child);
- type_expansion_free(&child);
- }
-
- type_expansion_append(type, name, name);
-}
-
-static void __type_expand(struct die *cache, struct type_expansion *type,
- bool recursive)
+static void __type_expand(struct die *cache, struct type_expansion *type)
{
struct die_fragment *df;
struct die *child;
+ char *name;
list_for_each_entry(df, &cache->fragments, list) {
switch (df->type) {
@@ -346,7 +353,12 @@ static void __type_expand(struct die *cache, struct type_expansion *type,
error("unknown child: %" PRIxPTR,
df->data.addr);
- type_expand_child(child, type, recursive);
+ name = get_type_name(child);
+ if (name)
+ type_expansion_append(type, name, name);
+ else
+ __type_expand(child, type);
+
break;
case FRAGMENT_LINEBREAK:
/*
@@ -364,12 +376,85 @@ static void __type_expand(struct die *cache, struct type_expansion *type,
}
}
-static void type_expand(struct die *cache, struct type_expansion *type,
- bool recursive)
+static void type_expand(const char *name, struct die *cache,
+ struct type_expansion *type)
{
+ const char *override;
+
type_expansion_init(type);
- __type_expand(cache, type, recursive);
- cache_free(&expansion_cache);
+
+ if (stable && kabi_get_type_string(name, &override))
+ type_parse(name, override, type);
+ else
+ __type_expand(cache, type);
+}
+
+static void type_parse(const char *name, const char *str,
+ struct type_expansion *type)
+{
+ char *fragment;
+ size_t start = 0;
+ size_t end;
+ size_t pos;
+
+ if (!*str)
+ error("empty type string override for '%s'", name);
+
+ for (pos = 0; str[pos]; ++pos) {
+ bool empty;
+ char marker = ' ';
+
+ if (!is_type_prefix(&str[pos]))
+ continue;
+
+ end = pos + 2;
+
+ /*
+ * Find the end of the type reference. If the type name contains
+ * spaces, it must be in single quotes.
+ */
+ if (str[end] == '\'') {
+ marker = '\'';
+ ++end;
+ }
+ while (str[end] && str[end] != marker)
+ ++end;
+
+ /* Check that we have a non-empty type name */
+ if (marker == '\'') {
+ if (str[end] != marker)
+ error("incomplete %c# type reference for '%s' (string : '%s')",
+ str[pos], name, str);
+ empty = end == pos + 3;
+ ++end;
+ } else {
+ empty = end == pos + 2;
+ }
+ if (empty)
+ error("empty %c# type name for '%s' (string: '%s')",
+ str[pos], name, str);
+
+ /* Append the part of the string before the type reference */
+ if (pos > start) {
+ fragment = xstrndup(&str[start], pos - start);
+ type_expansion_append(type, fragment, fragment);
+ }
+
+ /*
+ * Append the type reference -- note that if the reference
+ * is invalid, i.e. points to a non-existent type, we will
+ * print out an error when calculating versions.
+ */
+ fragment = xstrndup(&str[pos], end - pos);
+ type_expansion_append(type, fragment, fragment);
+
+ start = end;
+ pos = end - 1;
+ }
+
+ /* Append the rest of the type string, if there's any left */
+ if (str[start])
+ type_expansion_append(type, &str[start], NULL);
}
static void expand_type(struct die *cache, void *arg)
@@ -399,9 +484,9 @@ static void expand_type(struct die *cache, void *arg)
return;
debug("%s", name);
- type_expand(cache, &type, true);
- type_map_add(name, &type);
+ type_expand(name, cache, &type);
+ type_map_add(name, &type);
type_expansion_free(&type);
free(name);
}
@@ -423,11 +508,11 @@ static void expand_symbol(struct symbol *sym, void *arg)
if (__die_map_get(sym->die_addr, DIE_SYMBOL, &cache))
return; /* We'll warn about missing CRCs later. */
- type_expand(cache, &type, false);
+ type_expand(sym->name, cache, &type);
/* If the symbol already has a version, don't calculate it again. */
if (sym->state != SYMBOL_PROCESSED) {
- calculate_version(&version, &type.expanded);
+ calculate_version(&version, &type);
symbol_set_crc(sym, version.crc);
debug("%s = %lx", sym->name, version.crc);