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);