--- /dev/null
+From ea8f3cd25e2e185e97cb30ceacf0f7671743221c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Dec 2022 13:15:04 -0800
+Subject: libbpf: Fix BTF-to-C converter's padding logic
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Andrii Nakryiko <andrii@kernel.org>
+
+[ Upstream commit ea2ce1ba99aa6a60c8d8a706e3abadf3de372163 ]
+
+Turns out that btf_dump API doesn't handle a bunch of tricky corner
+cases, as reported by Per, and further discovered using his testing
+Python script ([0]).
+
+This patch revamps btf_dump's padding logic significantly, making it
+more correct and also avoiding unnecessary explicit padding, where
+compiler would pad naturally. This overall topic turned out to be very
+tricky and subtle, there are lots of subtle corner cases. The comments
+in the code tries to give some clues, but comments themselves are
+supposed to be paired with good understanding of C alignment and padding
+rules. Plus some experimentation to figure out subtle things like
+whether `long :0;` means that struct is now forced to be long-aligned
+(no, it's not, turns out).
+
+Anyways, Per's script, while not completely correct in some known
+situations, doesn't show any obvious cases where this logic breaks, so
+this is a nice improvement over the previous state of this logic.
+
+Some selftests had to be adjusted to accommodate better use of natural
+alignment rules, eliminating some unnecessary padding, or changing it to
+`type: 0;` alignment markers.
+
+Note also that for when we are in between bitfields, we emit explicit
+bit size, while otherwise we use `: 0`, this feels much more natural in
+practice.
+
+Next patch will add few more test cases, found through randomized Per's
+script.
+
+ [0] https://lore.kernel.org/bpf/85f83c333f5355c8ac026f835b18d15060725fcb.camel@ericsson.com/
+
+Reported-by: Per Sundström XP <per.xp.sundstrom@ericsson.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Link: https://lore.kernel.org/bpf/20221212211505.558851-6-andrii@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/lib/bpf/btf_dump.c | 169 +++++++++++++-----
+ .../bpf/progs/btf_dump_test_case_bitfields.c | 2 +-
+ .../bpf/progs/btf_dump_test_case_padding.c | 58 ++++--
+ 3 files changed, 164 insertions(+), 65 deletions(-)
+
+diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
+index f620911ad3bb5..77fcc5883a954 100644
+--- a/tools/lib/bpf/btf_dump.c
++++ b/tools/lib/bpf/btf_dump.c
+@@ -817,6 +817,25 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
+ }
+ }
+
++static int btf_natural_align_of(const struct btf *btf, __u32 id)
++{
++ const struct btf_type *t = btf__type_by_id(btf, id);
++ int i, align, vlen;
++ const struct btf_member *m;
++
++ if (!btf_is_composite(t))
++ return btf__align_of(btf, id);
++
++ align = 1;
++ m = btf_members(t);
++ vlen = btf_vlen(t);
++ for (i = 0; i < vlen; i++, m++) {
++ align = max(align, btf__align_of(btf, m->type));
++ }
++
++ return align;
++}
++
+ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
+ const struct btf_type *t)
+ {
+@@ -824,16 +843,16 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
+ int align, i, bit_sz;
+ __u16 vlen;
+
+- align = btf__align_of(btf, id);
+- /* size of a non-packed struct has to be a multiple of its alignment*/
+- if (align && t->size % align)
++ align = btf_natural_align_of(btf, id);
++ /* size of a non-packed struct has to be a multiple of its alignment */
++ if (align && (t->size % align) != 0)
+ return true;
+
+ m = btf_members(t);
+ vlen = btf_vlen(t);
+ /* all non-bitfield fields have to be naturally aligned */
+ for (i = 0; i < vlen; i++, m++) {
+- align = btf__align_of(btf, m->type);
++ align = btf_natural_align_of(btf, m->type);
+ bit_sz = btf_member_bitfield_size(t, i);
+ if (align && bit_sz == 0 && m->offset % (8 * align) != 0)
+ return true;
+@@ -846,44 +865,97 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
+ return false;
+ }
+
+-static int chip_away_bits(int total, int at_most)
+-{
+- return total % at_most ? : at_most;
+-}
+-
+ static void btf_dump_emit_bit_padding(const struct btf_dump *d,
+- int cur_off, int m_off, int m_bit_sz,
+- int align, int lvl)
++ int cur_off, int next_off, int next_align,
++ bool in_bitfield, int lvl)
+ {
+- int off_diff = m_off - cur_off;
+- int ptr_bits = d->ptr_sz * 8;
++ const struct {
++ const char *name;
++ int bits;
++ } pads[] = {
++ {"long", d->ptr_sz * 8}, {"int", 32}, {"short", 16}, {"char", 8}
++ };
++ int new_off, pad_bits, bits, i;
++ const char *pad_type;
++
++ if (cur_off >= next_off)
++ return; /* no gap */
++
++ /* For filling out padding we want to take advantage of
++ * natural alignment rules to minimize unnecessary explicit
++ * padding. First, we find the largest type (among long, int,
++ * short, or char) that can be used to force naturally aligned
++ * boundary. Once determined, we'll use such type to fill in
++ * the remaining padding gap. In some cases we can rely on
++ * compiler filling some gaps, but sometimes we need to force
++ * alignment to close natural alignment with markers like
++ * `long: 0` (this is always the case for bitfields). Note
++ * that even if struct itself has, let's say 4-byte alignment
++ * (i.e., it only uses up to int-aligned types), using `long:
++ * X;` explicit padding doesn't actually change struct's
++ * overall alignment requirements, but compiler does take into
++ * account that type's (long, in this example) natural
++ * alignment requirements when adding implicit padding. We use
++ * this fact heavily and don't worry about ruining correct
++ * struct alignment requirement.
++ */
++ for (i = 0; i < ARRAY_SIZE(pads); i++) {
++ pad_bits = pads[i].bits;
++ pad_type = pads[i].name;
+
+- if (off_diff <= 0)
+- /* no gap */
+- return;
+- if (m_bit_sz == 0 && off_diff < align * 8)
+- /* natural padding will take care of a gap */
+- return;
++ new_off = roundup(cur_off, pad_bits);
++ if (new_off <= next_off)
++ break;
++ }
+
+- while (off_diff > 0) {
+- const char *pad_type;
+- int pad_bits;
+-
+- if (ptr_bits > 32 && off_diff > 32) {
+- pad_type = "long";
+- pad_bits = chip_away_bits(off_diff, ptr_bits);
+- } else if (off_diff > 16) {
+- pad_type = "int";
+- pad_bits = chip_away_bits(off_diff, 32);
+- } else if (off_diff > 8) {
+- pad_type = "short";
+- pad_bits = chip_away_bits(off_diff, 16);
+- } else {
+- pad_type = "char";
+- pad_bits = chip_away_bits(off_diff, 8);
++ if (new_off > cur_off && new_off <= next_off) {
++ /* We need explicit `<type>: 0` aligning mark if next
++ * field is right on alignment offset and its
++ * alignment requirement is less strict than <type>'s
++ * alignment (so compiler won't naturally align to the
++ * offset we expect), or if subsequent `<type>: X`,
++ * will actually completely fit in the remaining hole,
++ * making compiler basically ignore `<type>: X`
++ * completely.
++ */
++ if (in_bitfield ||
++ (new_off == next_off && roundup(cur_off, next_align * 8) != new_off) ||
++ (new_off != next_off && next_off - new_off <= new_off - cur_off))
++ /* but for bitfields we'll emit explicit bit count */
++ btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type,
++ in_bitfield ? new_off - cur_off : 0);
++ cur_off = new_off;
++ }
++
++ /* Now we know we start at naturally aligned offset for a chosen
++ * padding type (long, int, short, or char), and so the rest is just
++ * a straightforward filling of remaining padding gap with full
++ * `<type>: sizeof(<type>);` markers, except for the last one, which
++ * might need smaller than sizeof(<type>) padding.
++ */
++ while (cur_off != next_off) {
++ bits = min(next_off - cur_off, pad_bits);
++ if (bits == pad_bits) {
++ btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, pad_bits);
++ cur_off += bits;
++ continue;
++ }
++ /* For the remainder padding that doesn't cover entire
++ * pad_type bit length, we pick the smallest necessary type.
++ * This is pure aesthetics, we could have just used `long`,
++ * but having smallest necessary one communicates better the
++ * scale of the padding gap.
++ */
++ for (i = ARRAY_SIZE(pads) - 1; i >= 0; i--) {
++ pad_type = pads[i].name;
++ pad_bits = pads[i].bits;
++ if (pad_bits < bits)
++ continue;
++
++ btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, bits);
++ cur_off += bits;
++ break;
+ }
+- btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, pad_bits);
+- off_diff -= pad_bits;
+ }
+ }
+
+@@ -903,9 +975,11 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
+ {
+ const struct btf_member *m = btf_members(t);
+ bool is_struct = btf_is_struct(t);
+- int align, i, packed, off = 0;
++ bool packed, prev_bitfield = false;
++ int align, i, off = 0;
+ __u16 vlen = btf_vlen(t);
+
++ align = btf__align_of(d->btf, id);
+ packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
+
+ btf_dump_printf(d, "%s%s%s {",
+@@ -915,33 +989,36 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
+
+ for (i = 0; i < vlen; i++, m++) {
+ const char *fname;
+- int m_off, m_sz;
++ int m_off, m_sz, m_align;
++ bool in_bitfield;
+
+ fname = btf_name_of(d, m->name_off);
+ m_sz = btf_member_bitfield_size(t, i);
+ m_off = btf_member_bit_offset(t, i);
+- align = packed ? 1 : btf__align_of(d->btf, m->type);
++ m_align = packed ? 1 : btf__align_of(d->btf, m->type);
+
+- btf_dump_emit_bit_padding(d, off, m_off, m_sz, align, lvl + 1);
++ in_bitfield = prev_bitfield && m_sz != 0;
++
++ btf_dump_emit_bit_padding(d, off, m_off, m_align, in_bitfield, lvl + 1);
+ btf_dump_printf(d, "\n%s", pfx(lvl + 1));
+ btf_dump_emit_type_decl(d, m->type, fname, lvl + 1);
+
+ if (m_sz) {
+ btf_dump_printf(d, ": %d", m_sz);
+ off = m_off + m_sz;
++ prev_bitfield = true;
+ } else {
+ m_sz = max((__s64)0, btf__resolve_size(d->btf, m->type));
+ off = m_off + m_sz * 8;
++ prev_bitfield = false;
+ }
++
+ btf_dump_printf(d, ";");
+ }
+
+ /* pad at the end, if necessary */
+- if (is_struct) {
+- align = packed ? 1 : btf__align_of(d->btf, id);
+- btf_dump_emit_bit_padding(d, off, t->size * 8, 0, align,
+- lvl + 1);
+- }
++ if (is_struct)
++ btf_dump_emit_bit_padding(d, off, t->size * 8, align, false, lvl + 1);
+
+ if (vlen)
+ btf_dump_printf(d, "\n");
+diff --git a/tools/testing/selftests/bpf/progs/btf_dump_test_case_bitfields.c b/tools/testing/selftests/bpf/progs/btf_dump_test_case_bitfields.c
+index 8f44767a75fa5..22a7cd8fd9acf 100644
+--- a/tools/testing/selftests/bpf/progs/btf_dump_test_case_bitfields.c
++++ b/tools/testing/selftests/bpf/progs/btf_dump_test_case_bitfields.c
+@@ -53,7 +53,7 @@ struct bitfields_only_mixed_types {
+ */
+ /* ------ END-EXPECTED-OUTPUT ------ */
+ struct bitfield_mixed_with_others {
+- long: 4; /* char is enough as a backing field */
++ char: 4; /* char is enough as a backing field */
+ int a: 4;
+ /* 8-bit implicit padding */
+ short b; /* combined with previous bitfield */
+diff --git a/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c b/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c
+index db5458da61826..28833f2694e9c 100644
+--- a/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c
++++ b/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c
+@@ -19,7 +19,7 @@ struct padded_implicitly {
+ /*
+ *struct padded_explicitly {
+ * int a;
+- * int: 32;
++ * long: 0;
+ * int b;
+ *};
+ *
+@@ -28,41 +28,28 @@ struct padded_implicitly {
+
+ struct padded_explicitly {
+ int a;
+- int: 1; /* algo will explicitly pad with full 32 bits here */
++ int: 1; /* algo will emit aligning `long: 0;` here */
+ int b;
+ };
+
+ /* ----- START-EXPECTED-OUTPUT ----- */
+-/*
+- *struct padded_a_lot {
+- * int a;
+- * long: 32;
+- * long: 64;
+- * long: 64;
+- * int b;
+- *};
+- *
+- */
+-/* ------ END-EXPECTED-OUTPUT ------ */
+-
+ struct padded_a_lot {
+ int a;
+- /* 32 bit of implicit padding here, which algo will make explicit */
+ long: 64;
+ long: 64;
+ int b;
+ };
+
++/* ------ END-EXPECTED-OUTPUT ------ */
++
+ /* ----- START-EXPECTED-OUTPUT ----- */
+ /*
+ *struct padded_cache_line {
+ * int a;
+- * long: 32;
+ * long: 64;
+ * long: 64;
+ * long: 64;
+ * int b;
+- * long: 32;
+ * long: 64;
+ * long: 64;
+ * long: 64;
+@@ -85,7 +72,7 @@ struct padded_cache_line {
+ *struct zone {
+ * int a;
+ * short b;
+- * short: 16;
++ * long: 0;
+ * struct zone_padding __pad__;
+ *};
+ *
+@@ -108,6 +95,39 @@ struct padding_wo_named_members {
+ long: 64;
+ };
+
++struct padding_weird_1 {
++ int a;
++ long: 64;
++ short: 16;
++ short b;
++};
++
++/* ------ END-EXPECTED-OUTPUT ------ */
++
++/* ----- START-EXPECTED-OUTPUT ----- */
++/*
++ *struct padding_weird_2 {
++ * long: 56;
++ * char a;
++ * long: 56;
++ * char b;
++ * char: 8;
++ *};
++ *
++ */
++/* ------ END-EXPECTED-OUTPUT ------ */
++struct padding_weird_2 {
++ int: 32; /* these paddings will be collapsed into `long: 56;` */
++ short: 16;
++ char: 8;
++ char a;
++ int: 32; /* these paddings will be collapsed into `long: 56;` */
++ short: 16;
++ char: 8;
++ char b;
++ char: 8;
++};
++
+ /* ------ END-EXPECTED-OUTPUT ------ */
+
+ int f(struct {
+@@ -117,6 +137,8 @@ int f(struct {
+ struct padded_cache_line _4;
+ struct zone _5;
+ struct padding_wo_named_members _6;
++ struct padding_weird_1 _7;
++ struct padding_weird_2 _8;
+ } *_)
+ {
+ return 0;
+--
+2.39.2
+
--- /dev/null
+From 1b8a880612f1ec5714f8de5c9404f61767dbe98a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 15 Dec 2022 10:36:05 -0800
+Subject: libbpf: Fix btf_dump's packed struct determination
+
+From: Andrii Nakryiko <andrii@kernel.org>
+
+[ Upstream commit 4fb877aaa179dcdb1676d55216482febaada457e ]
+
+Fix bug in btf_dump's logic of determining if a given struct type is
+packed or not. The notion of "natural alignment" is not needed and is
+even harmful in this case, so drop it altogether. The biggest difference
+in btf_is_struct_packed() compared to its original implementation is
+that we don't really use btf__align_of() to determine overall alignment
+of a struct type (because it could be 1 for both packed and non-packed
+struct, depending on specifci field definitions), and just use field's
+actual alignment to calculate whether any field is requiring packing or
+struct's size overall necessitates packing.
+
+Add two simple test cases that demonstrate the difference this change
+would make.
+
+Fixes: ea2ce1ba99aa ("libbpf: Fix BTF-to-C converter's padding logic")
+Reported-by: Eduard Zingerman <eddyz87@gmail.com>
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/bpf/20221215183605.4149488-1-andrii@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/lib/bpf/btf_dump.c | 33 ++++---------------
+ .../bpf/progs/btf_dump_test_case_packing.c | 19 +++++++++++
+ 2 files changed, 25 insertions(+), 27 deletions(-)
+
+diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
+index 77fcc5883a954..8b1ba4b725e31 100644
+--- a/tools/lib/bpf/btf_dump.c
++++ b/tools/lib/bpf/btf_dump.c
+@@ -817,47 +817,26 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
+ }
+ }
+
+-static int btf_natural_align_of(const struct btf *btf, __u32 id)
+-{
+- const struct btf_type *t = btf__type_by_id(btf, id);
+- int i, align, vlen;
+- const struct btf_member *m;
+-
+- if (!btf_is_composite(t))
+- return btf__align_of(btf, id);
+-
+- align = 1;
+- m = btf_members(t);
+- vlen = btf_vlen(t);
+- for (i = 0; i < vlen; i++, m++) {
+- align = max(align, btf__align_of(btf, m->type));
+- }
+-
+- return align;
+-}
+-
+ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
+ const struct btf_type *t)
+ {
+ const struct btf_member *m;
+- int align, i, bit_sz;
++ int max_align = 1, align, i, bit_sz;
+ __u16 vlen;
+
+- align = btf_natural_align_of(btf, id);
+- /* size of a non-packed struct has to be a multiple of its alignment */
+- if (align && (t->size % align) != 0)
+- return true;
+-
+ m = btf_members(t);
+ vlen = btf_vlen(t);
+ /* all non-bitfield fields have to be naturally aligned */
+ for (i = 0; i < vlen; i++, m++) {
+- align = btf_natural_align_of(btf, m->type);
++ align = btf__align_of(btf, m->type);
+ bit_sz = btf_member_bitfield_size(t, i);
+ if (align && bit_sz == 0 && m->offset % (8 * align) != 0)
+ return true;
++ max_align = max(align, max_align);
+ }
+-
++ /* size of a non-packed struct has to be a multiple of its alignment */
++ if (t->size % max_align != 0)
++ return true;
+ /*
+ * if original struct was marked as packed, but its layout is
+ * naturally aligned, we'll detect that it's not packed
+diff --git a/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c b/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c
+index 3f7755247591c..22dbd12134347 100644
+--- a/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c
++++ b/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c
+@@ -116,6 +116,23 @@ struct usb_host_endpoint {
+ long: 0;
+ };
+
++/* ----- START-EXPECTED-OUTPUT ----- */
++struct nested_packed_struct {
++ int a;
++ char b;
++} __attribute__((packed));
++
++struct outer_nonpacked_struct {
++ short a;
++ struct nested_packed_struct b;
++};
++
++struct outer_packed_struct {
++ short a;
++ struct nested_packed_struct b;
++} __attribute__((packed));
++
++/* ------ END-EXPECTED-OUTPUT ------ */
+
+ int f(struct {
+ struct packed_trailing_space _1;
+@@ -128,6 +145,8 @@ int f(struct {
+ union jump_code_union _8;
+ struct outer_implicitly_packed_struct _9;
+ struct usb_host_endpoint _10;
++ struct outer_nonpacked_struct _11;
++ struct outer_packed_struct _12;
+ } *_)
+ {
+ return 0;
+--
+2.39.2
+
--- /dev/null
+From 5122fe6d9c30bbbe9d13e148bc4c59cac14db4e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Dec 2022 13:15:05 -0800
+Subject: selftests/bpf: Add few corner cases to test padding handling of
+ btf_dump
+
+From: Andrii Nakryiko <andrii@kernel.org>
+
+[ Upstream commit b148c8b9b926e257a59c8eb2cd6fa3adfd443254 ]
+
+Add few hand-crafted cases and few randomized cases found using script
+from [0] that tests btf_dump's padding logic.
+
+ [0] https://lore.kernel.org/bpf/85f83c333f5355c8ac026f835b18d15060725fcb.camel@ericsson.com/
+
+Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Link: https://lore.kernel.org/bpf/20221212211505.558851-7-andrii@kernel.org
+Stable-dep-of: 4fb877aaa179 ("libbpf: Fix btf_dump's packed struct determination")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../bpf/progs/btf_dump_test_case_packing.c | 61 +++++++++-
+ .../bpf/progs/btf_dump_test_case_padding.c | 104 ++++++++++++++++++
+ 2 files changed, 164 insertions(+), 1 deletion(-)
+
+diff --git a/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c b/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c
+index 1cef3bec1dc7f..3f7755247591c 100644
+--- a/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c
++++ b/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c
+@@ -58,7 +58,64 @@ union jump_code_union {
+ } __attribute__((packed));
+ };
+
+-/*------ END-EXPECTED-OUTPUT ------ */
++/* ----- START-EXPECTED-OUTPUT ----- */
++/*
++ *struct nested_packed_but_aligned_struct {
++ * int x1;
++ * int x2;
++ *};
++ *
++ *struct outer_implicitly_packed_struct {
++ * char y1;
++ * struct nested_packed_but_aligned_struct y2;
++ *} __attribute__((packed));
++ *
++ */
++/* ------ END-EXPECTED-OUTPUT ------ */
++
++struct nested_packed_but_aligned_struct {
++ int x1;
++ int x2;
++} __attribute__((packed));
++
++struct outer_implicitly_packed_struct {
++ char y1;
++ struct nested_packed_but_aligned_struct y2;
++};
++/* ----- START-EXPECTED-OUTPUT ----- */
++/*
++ *struct usb_ss_ep_comp_descriptor {
++ * char: 8;
++ * char bDescriptorType;
++ * char bMaxBurst;
++ * short wBytesPerInterval;
++ *};
++ *
++ *struct usb_host_endpoint {
++ * long: 64;
++ * char: 8;
++ * struct usb_ss_ep_comp_descriptor ss_ep_comp;
++ * long: 0;
++ *} __attribute__((packed));
++ *
++ */
++/* ------ END-EXPECTED-OUTPUT ------ */
++
++struct usb_ss_ep_comp_descriptor {
++ char: 8;
++ char bDescriptorType;
++ char bMaxBurst;
++ int: 0;
++ short wBytesPerInterval;
++} __attribute__((packed));
++
++struct usb_host_endpoint {
++ long: 64;
++ char: 8;
++ struct usb_ss_ep_comp_descriptor ss_ep_comp;
++ long: 0;
++};
++
+
+ int f(struct {
+ struct packed_trailing_space _1;
+@@ -69,6 +126,8 @@ int f(struct {
+ union union_is_never_packed _6;
+ union union_does_not_need_packing _7;
+ union jump_code_union _8;
++ struct outer_implicitly_packed_struct _9;
++ struct usb_host_endpoint _10;
+ } *_)
+ {
+ return 0;
+diff --git a/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c b/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c
+index 28833f2694e9c..0b3cdffbfcf71 100644
+--- a/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c
++++ b/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c
+@@ -128,6 +128,98 @@ struct padding_weird_2 {
+ char: 8;
+ };
+
++/* ----- START-EXPECTED-OUTPUT ----- */
++struct exact_1byte {
++ char x;
++};
++
++struct padded_1byte {
++ char: 8;
++};
++
++struct exact_2bytes {
++ short x;
++};
++
++struct padded_2bytes {
++ short: 16;
++};
++
++struct exact_4bytes {
++ int x;
++};
++
++struct padded_4bytes {
++ int: 32;
++};
++
++struct exact_8bytes {
++ long x;
++};
++
++struct padded_8bytes {
++ long: 64;
++};
++
++struct ff_periodic_effect {
++ int: 32;
++ short magnitude;
++ long: 0;
++ short phase;
++ long: 0;
++ int: 32;
++ int custom_len;
++ short *custom_data;
++};
++
++struct ib_wc {
++ long: 64;
++ long: 64;
++ int: 32;
++ int byte_len;
++ void *qp;
++ union {} ex;
++ long: 64;
++ int slid;
++ int wc_flags;
++ long: 64;
++ char smac[6];
++ long: 0;
++ char network_hdr_type;
++};
++
++struct acpi_object_method {
++ long: 64;
++ char: 8;
++ char type;
++ short reference_count;
++ char flags;
++ short: 0;
++ char: 8;
++ char sync_level;
++ long: 64;
++ void *node;
++ void *aml_start;
++ union {} dispatch;
++ long: 64;
++ int aml_length;
++};
++
++struct nested_unpacked {
++ int x;
++};
++
++struct nested_packed {
++ struct nested_unpacked a;
++ char c;
++} __attribute__((packed));
++
++struct outer_mixed_but_unpacked {
++ struct nested_packed b1;
++ short a1;
++ struct nested_packed b2;
++};
++
+ /* ------ END-EXPECTED-OUTPUT ------ */
+
+ int f(struct {
+@@ -139,6 +231,18 @@ int f(struct {
+ struct padding_wo_named_members _6;
+ struct padding_weird_1 _7;
+ struct padding_weird_2 _8;
++ struct exact_1byte _100;
++ struct padded_1byte _101;
++ struct exact_2bytes _102;
++ struct padded_2bytes _103;
++ struct exact_4bytes _104;
++ struct padded_4bytes _105;
++ struct exact_8bytes _106;
++ struct padded_8bytes _107;
++ struct ff_periodic_effect _200;
++ struct ib_wc _201;
++ struct acpi_object_method _202;
++ struct outer_mixed_but_unpacked _203;
+ } *_)
+ {
+ return 0;
+--
+2.39.2
+