aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2022-10-13 13:05:13 -0300
committerArnaldo Carvalho de Melo <acme@redhat.com>2022-10-13 13:13:49 -0300
commit8c2b37ec71423067b028eeaea8a450abe99a601c (patch)
treef0e889fd122c94c71b494020f8662ff9911b72a3
parenta4f3a79da8d4ed8b8199d98241c387c3f7684df3 (diff)
downloadpahole-8c2b37ec71423067b028eeaea8a450abe99a601c.tar.gz
emit: Emit typedefs for atomic_ prefixed base types
That appear as DW_TAG_base_type, and since: atomic_int foo; is equivalent to: _Atomic int foo; Emit: typedef _Atomic int atomic_int; So that we can make 'pahole --compile' work in these cases as well. This will be selectable in pahole, in case we find some compiler that either emits DWARF tags for these typedefs or that recognizes them directly, without the need for these typedefs. Doing this with an openvswitch file: $ pahole --compile eelco/ovs-vswitchd_rhel8 > vswitchd_rhel8.c ; echo "static struct dpif_userdata data;" >> vswitchd_rhel8.c ; gcc -g -c vswitchd_rhel8.c -o vswitchd_rhel8.o |& head vswitchd_rhel8.c:8493:33: error: redeclaration of enumerator ‘ADD’ 8493 | ADD = 0, | ^~~ vswitchd_rhel8.c:6229:9: note: previous definition of ‘ADD’ with type ‘enum bond_op’ 6229 | ADD = 0, | ^~~ vswitchd_rhel8.c:12910:9: error: redeclaration of enumerator ‘ADD’ 12910 | ADD = 0, | ^~~ vswitchd_rhel8.c:8493:33: note: previous definition of ‘ADD’ with type ‘enum <anonymous>’ Fails at first for some unrelated reason, i.e. multiple different enums from multiple compile units that have the sane enumerator, if we manually go and make them unique, adding some different suffixes, we go to: $ vim vswitchd_rhel8.c $ gcc -g -c vswitchd_rhel8.c -o vswitchd_rhel8.o $ grep "typedef _Atomic " vswitchd_rhel8.c typedef _Atomic size_t atomic_size_t; typedef _Atomic unsigned long atomic_ulong; typedef _Atomic unsigned int atomic_uint; typedef _Atomic _Bool atomic_bool; typedef _Atomic long long atomic_llong; typedef _Atomic unsigned int atomic_uint32_t; typedef _Atomic unsigned long long atomic_ullong; typedef _Atomic unsigned short atomic_uint16_t; typedef _Atomic unsigned char atomic_uint8_t; typedef _Atomic int atomic_int; $ Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--btf_loader.c1
-rw-r--r--ctf_loader.c1
-rw-r--r--dwarf_loader.c1
-rw-r--r--dwarves.h2
-rw-r--r--dwarves_emit.c88
-rw-r--r--dwarves_emit.h1
6 files changed, 94 insertions, 0 deletions
diff --git a/btf_loader.c b/btf_loader.c
index 69b63a52..e579323b 100644
--- a/btf_loader.c
+++ b/btf_loader.c
@@ -108,6 +108,7 @@ static struct base_type *base_type__new(const char *name, uint32_t attrs,
bt->is_bool = attrs & BTF_INT_BOOL;
bt->name_has_encoding = false;
bt->float_type = float_type;
+ INIT_LIST_HEAD(&bt->node);
}
return bt;
}
diff --git a/ctf_loader.c b/ctf_loader.c
index de6d4dbf..2570b094 100644
--- a/ctf_loader.c
+++ b/ctf_loader.c
@@ -157,6 +157,7 @@ static struct base_type *base_type__new(const char *name, uint32_t attrs,
bt->is_varargs = attrs & CTF_TYPE_INT_VARARGS;
bt->name_has_encoding = false;
bt->float_type = float_type;
+ INIT_LIST_HEAD(&bt->node);
}
return bt;
}
diff --git a/dwarf_loader.c b/dwarf_loader.c
index 03ac8718..5a74035c 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -564,6 +564,7 @@ static struct base_type *base_type__new(Dwarf_Die *die, struct cu *cu, struct co
bt->is_varargs = false;
bt->name_has_encoding = true;
bt->float_type = encoding_to_float_type(encoding);
+ INIT_LIST_HEAD(&bt->node);
}
return bt;
diff --git a/dwarves.h b/dwarves.h
index f8b15002..9b7c9227 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -1334,12 +1334,14 @@ enum base_type_float_type {
struct base_type {
struct tag tag;
const char *name;
+ struct list_head node;
uint16_t bit_size;
uint8_t name_has_encoding:1;
uint8_t is_signed:1;
uint8_t is_bool:1;
uint8_t is_varargs:1;
uint8_t float_type:4;
+ uint8_t definition_emitted:1;
};
static inline struct base_type *tag__base_type(const struct tag *tag)
diff --git a/dwarves_emit.c b/dwarves_emit.c
index bbfc8409..04b3de4b 100644
--- a/dwarves_emit.c
+++ b/dwarves_emit.c
@@ -15,6 +15,7 @@
void type_emissions__init(struct type_emissions *emissions)
{
+ INIT_LIST_HEAD(&emissions->base_type_definitions);
INIT_LIST_HEAD(&emissions->definitions);
INIT_LIST_HEAD(&emissions->fwd_decls);
}
@@ -253,6 +254,91 @@ static int type__emit_fwd_decl(struct type *ctype, struct type_emissions *emissi
return 1;
}
+static struct base_type *base_type_emissions__find_definition(const struct type_emissions *emissions, const char *name)
+{
+ struct base_type *pos;
+
+ if (name == NULL)
+ return NULL;
+
+ list_for_each_entry(pos, &emissions->base_type_definitions, node)
+ if (strcmp(__base_type__name(pos), name) == 0)
+ return pos;
+
+ return NULL;
+}
+
+static void base_type_emissions__add_definition(struct type_emissions *emissions, struct base_type *type)
+{
+ type->definition_emitted = 1;
+ if (!list_empty(&type->node))
+ list_del(&type->node);
+ list_add_tail(&type->node, &emissions->base_type_definitions);
+}
+
+static const char *base_type__stdint2simple(const char *name)
+{
+ if (strcmp(name, "int32_t") == 0)
+ return "int";
+ if (strcmp(name, "int16_t") == 0)
+ return "short";
+ if (strcmp(name, "int8_t") == 0)
+ return "char";
+ if (strcmp(name, "int64_t") == 0)
+ return "long";
+ return name;
+}
+
+static int base_type__emit_definitions(struct base_type *type, struct type_emissions *emissions, FILE *fp)
+{
+#define base_type__prefix "atomic_"
+ const size_t prefixlen = sizeof(base_type__prefix) - 1;
+ const char *name = __base_type__name(type);
+
+ // See if it was already emitted in this CU
+ if (type->definition_emitted)
+ return 0;
+
+ // We're only emitting for "atomic_" prefixed base types
+ if (strncmp(name, base_type__prefix, prefixlen) != 0)
+ return 0;
+
+ // See if it was already emitted in another CU
+ if (base_type_emissions__find_definition(emissions, name)) {
+ type->definition_emitted = 1;
+ return 0;
+ }
+
+ const char *non_atomic_name = name + prefixlen;
+
+ fputs("typedef _Atomic", fp);
+
+ if (non_atomic_name[0] == 's' &&
+ non_atomic_name[1] != 'i' && non_atomic_name[1] != 'h') // exclude atomic_size_t and atomic_short
+ fprintf(fp, " signed %s", non_atomic_name + 1);
+ else if (non_atomic_name[0] == 'l' && non_atomic_name[1] == 'l')
+ fprintf(fp, " long long");
+ else if (non_atomic_name[0] == 'u') {
+ fprintf(fp, " unsigned");
+ if (non_atomic_name[1] == 'l') {
+ fprintf(fp, " long");
+ if (non_atomic_name[2] == 'l')
+ fprintf(fp, " long");
+ } else
+ fprintf(fp, " %s", base_type__stdint2simple(non_atomic_name + 1));
+ } else if (non_atomic_name[0] == 'b')
+ fprintf(fp, " _Bool");
+ else
+ fprintf(fp, " %s", base_type__stdint2simple(non_atomic_name));
+
+ fprintf(fp, " %s;\n", name);
+
+ base_type_emissions__add_definition(emissions, type);
+ return 1;
+
+#undef base_type__prefix
+}
+
static int tag__emit_definitions(struct tag *tag, struct cu *cu,
struct type_emissions *emissions, FILE *fp)
{
@@ -263,6 +349,8 @@ static int tag__emit_definitions(struct tag *tag, struct cu *cu,
return 0;
next_indirection:
switch (type->tag) {
+ case DW_TAG_base_type:
+ return base_type__emit_definitions(tag__base_type(type), emissions, fp);
case DW_TAG_pointer_type:
case DW_TAG_reference_type:
pointer = 1;
diff --git a/dwarves_emit.h b/dwarves_emit.h
index b153cdb0..58af2dd1 100644
--- a/dwarves_emit.h
+++ b/dwarves_emit.h
@@ -19,6 +19,7 @@ struct type;
struct type_emissions {
struct list_head definitions; /* struct type entries */
+ struct list_head base_type_definitions; /* struct base_type entries */
struct list_head fwd_decls; /* struct class entries */
};