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>
diff --git a/btf_loader.c b/btf_loader.c
index 69b63a5..e579323 100644
--- a/btf_loader.c
+++ b/btf_loader.c
@@ -108,6 +108,7 @@
 		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 de6d4db..2570b09 100644
--- a/ctf_loader.c
+++ b/ctf_loader.c
@@ -157,6 +157,7 @@
 		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 03ac871..5a74035 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -564,6 +564,7 @@
 		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 f8b1500..9b7c922 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -1334,12 +1334,14 @@
 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 bbfc840..04b3de4 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 @@
 	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 @@
 		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 b153cdb..58af2dd 100644
--- a/dwarves_emit.h
+++ b/dwarves_emit.h
@@ -19,6 +19,7 @@
 
 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 */
 };