loaders: Strip away volatile/const/restrict when fixing bitfields

btf_loader and ctf_loader didn't remove const/volatile/restrict, so
bitfields using modifiers were not adjusted properly.

This patch abstracts logic of stripping aways typedefs and access
modifiers into tag__strip_typedefs_and_modifiers, which handles any
interleaving of typedefs and modifiers. dwarf_loader was adapter to
reuse this function as well, instead of custom goto loop.

REPRO:

  $ cat vc_map.c
  typedef unsigned int u32;
  typedef volatile u32 vu32;
  typedef vu32 vu32_t;

  typedef struct vc_map {
          volatile unsigned int tx: 1;
          vu32_t rx: 1;
          void *x1, *x2;
  } vc_map;

  int main() {
          struct vc_map s;
          return 0;
  }

BEFORE:

  $ ~/pahole/build/pahole -F btf vc_map
  struct vc_map {
          volatile unsigned int      tx:1;                 /*     0: 0  4 */
          vu32_t                     rx:1;                 /*     0: 0  4 */

          /* XXX 30 bits hole, try to pack */
          /* XXX 4 bytes hole, try to pack */

          void *                     x1;                   /*     8     8 */
          void *                     x2;                   /*    16     8 */

          /* size: 24, cachelines: 1, members: 4 */
          /* sum members: 20, holes: 1, sum holes: 4 */
          /* bit holes: 1, sum bit holes: 30 bits */
          /* last cacheline: 24 bytes */
  };

AFTER:

  $ ~/pahole/build/pahole -F btf vc_map
  struct vc_map {
          volatile unsigned int      tx:1;                 /*     0:31  4 */
          vu32_t                     rx:1;                 /*     0:30  4 */

          /* XXX 30 bits hole, try to pack */
          /* XXX 4 bytes hole, try to pack */

          void *                     x1;                   /*     8     8 */
          void *                     x2;                   /*    16     8 */

          /* size: 24, cachelines: 1, members: 4 */
          /* sum members: 20, holes: 1, sum holes: 4 */
          /* bit holes: 1, sum bit holes: 30 bits */
          /* last cacheline: 24 bytes */
  };

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
diff --git a/btf_loader.c b/btf_loader.c
index 9a0714a..e04175e 100644
--- a/btf_loader.c
+++ b/btf_loader.c
@@ -457,7 +457,7 @@
 	struct type *tag_type = tag__type(tag);
 
 	type__for_each_data_member(tag_type, pos) {
-		struct tag *type = tag__follow_typedef(&pos->tag, cu);
+		struct tag *type = tag__strip_typedefs_and_modifiers(&pos->tag, cu);
 
 		if (type == NULL) /* FIXME: C++ BTF... */
 			continue;
diff --git a/ctf_loader.c b/ctf_loader.c
index 1631ea7..68479e2 100644
--- a/ctf_loader.c
+++ b/ctf_loader.c
@@ -613,7 +613,7 @@
 	struct type *tag_type = tag__type(tag);
 
 	type__for_each_data_member(tag_type, pos) {
-		struct tag *type = tag__follow_typedef(&pos->tag, cu);
+		struct tag *type = tag__strip_typedefs_and_modifiers(&pos->tag, cu);
 
 		if (type == NULL) /* FIXME: C++ CTF... */
 			continue;
diff --git a/dwarf_loader.c b/dwarf_loader.c
index c2abdad..28d1393 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -2123,12 +2123,7 @@
 	}
 
 	if (member->bitfield_size != 0) {
-		struct tag *type = tag__follow_typedef(&member->tag, cu);
-check_volatile:
-		if (tag__is_volatile(type) || tag__is_const(type)) {
-			type = tag__follow_typedef(type, cu);
-			goto check_volatile;
-		}
+		struct tag *type = tag__strip_typedefs_and_modifiers(&member->tag, cu);
 
 		uint16_t type_bit_size;
 		size_t integral_bit_size;
diff --git a/dwarves.c b/dwarves.c
index 4c6a12c..0b95d37 100644
--- a/dwarves.c
+++ b/dwarves.c
@@ -128,6 +128,16 @@
 	return type;
 }
 
+struct tag *tag__strip_typedefs_and_modifiers(const struct tag *tag, const struct cu *cu)
+{
+	struct tag *type = cu__type(cu, tag->type);
+
+	while (type != NULL && (tag__is_typedef(type) || tag__is_modifier(type)))
+		type = cu__type(cu, type->type);
+
+	return type;
+}
+
 size_t __tag__id_not_found_fprintf(FILE *fp, type_id_t id,
 				   const char *fn, int line)
 {
diff --git a/dwarves.h b/dwarves.h
index 67ec014..f65dbe2 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -411,6 +411,18 @@
 	return tag->tag == DW_TAG_volatile_type;
 }
 
+static inline bool tag__is_restrict(const struct tag *tag)
+{
+	return tag->tag == DW_TAG_restrict_type;
+}
+
+static inline int tag__is_modifier(const struct tag *tag)
+{
+	return tag__is_const(tag) ||
+	       tag__is_volatile(tag) ||
+	       tag__is_restrict(tag);
+}
+
 static inline bool tag__has_namespace(const struct tag *tag)
 {
 	return tag__is_struct(tag) ||
@@ -498,6 +510,7 @@
 size_t tag__size(const struct tag *tag, const struct cu *cu);
 size_t tag__nr_cachelines(const struct tag *tag, const struct cu *cu);
 struct tag *tag__follow_typedef(const struct tag *tag, const struct cu *cu);
+struct tag *tag__strip_typedefs_and_modifiers(const struct tag *tag, const struct cu *cu);
 
 size_t __tag__id_not_found_fprintf(FILE *fp, type_id_t id,
 				   const char *fn, int line);