core: Take arrays into account when inferring if a struct is packed

Before:

  $ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
  struct qrwlock {
  	union {
  		atomic_t           cnts;                 /*     0     4 */
  		struct {
  			u8         wlocked;              /*     0     1 */
  			u8         __lstate[3];          /*     1     3 */
  		} __attribute__((__packed__));           /*     0     4 */
  	};                                               /*     0     4 */
  	arch_spinlock_t            wait_lock;            /*     4     4 */

  	/* size: 8, cachelines: 1, members: 2 */
  	/* last cacheline: 8 bytes */
  };

I.e. __lstate's class_member->byte_size is 3, causing the misinference that that
struct was packed, it is naturally aligned, we need to look at the size of the
array's entries to figure out its natural alignment:

After:

  $ pahole -C qrwlock /home/acme/git/build/v5.1-rc4+/fs/ceph/dir.o
  struct qrwlock {
  	union {
  		atomic_t           cnts;                 /*     0     4 */
  		struct {
  			u8         wlocked;              /*     0     1 */
  			u8         __lstate[3];          /*     1     3 */
  		};                                       /*     0     4 */
  	};                                               /*     0     4 */
  	arch_spinlock_t            wait_lock;            /*     4     4 */

  	/* size: 8, cachelines: 1, members: 2 */
  	/* last cacheline: 8 bytes */
  };
  $

To further test:

  $ cat packed_array_struct.c
  struct sarray {
  	short	  array[3];
  	long long first;
  } __attribute__((__packed__));

  void foo(struct sarray *s) {}
  $ gcc -g -c packed_array_struct.c
  $ pahole packed_array_struct.o
  struct sarray {
  	short int                  array[3];             /*     0     6 */
  	long long int              first;                /*     6     8 */

  	/* size: 14, cachelines: 1, members: 2 */
  	/* last cacheline: 14 bytes */
  } __attribute__((__packed__));
  $ cat packed_array_struct.c
  struct sarray {
  	short	  array[3];
  	long long first;
  };

  void foo(struct sarray *s) {}
  $ gcc -g -c packed_array_struct.c
  $ pahole packed_array_struct.o
  struct sarray {
  	short int                  array[3];             /*     0     6 */

  	/* XXX 2 bytes hole, try to pack */

  	long long int              first;                /*     8     8 */

  	/* size: 16, cachelines: 1, members: 2 */
  	/* sum members: 14, holes: 1, sum holes: 2 */
  	/* last cacheline: 16 bytes */
  };
  $

One more test:

  $ cat packed_array_struct.c
  struct sarray {
  	short     a;
  	short	  array[3];
  	long long b;
  };

  void foo(struct sarray *s) {}
  $

Before this patch:

  $ gcc -g -c packed_array_struct.c
  $ pahole packed_array_struct.o
  struct sarray {
  	short int                  a;                    /*     0     2 */
  	short int                  array[3];             /*     2     6 */
  	long long int              b;                    /*     8     8 */

  	/* size: 16, cachelines: 1, members: 3 */
  	/* last cacheline: 16 bytes */
  } __attribute__((__packed__));

After:

  $ pahole packed_array_struct.o
  struct sarray {
  	short int                  a;                    /*     0     2 */
  	short int                  array[3];             /*     2     6 */
  	long long int              b;                    /*     8     8 */

  	/* size: 16, cachelines: 1, members: 3 */
  	/* last cacheline: 16 bytes */
  };
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Arnaldo Carvalho de Melo 2019-04-11 13:14:52 -03:00
parent 85c9936963
commit f2641ce169
1 changed files with 18 additions and 3 deletions

View File

@ -1291,6 +1291,19 @@ void class__find_holes(struct class *class)
class->holes_searched = true;
}
static size_t class_member__byte_size_for_alignment(struct class_member *member, const struct cu *cu)
{
struct tag *type = tag__strip_typedefs_and_modifiers(&member->tag, cu);
if (type->tag == DW_TAG_array_type) {
type = tag__strip_typedefs_and_modifiers(type, cu);
return tag__size(type, cu);
}
return member->byte_size;
}
bool class__infer_packed_attributes(struct class *cls, const struct cu *cu)
{
const struct type *ctype = &cls->type;
@ -1319,17 +1332,19 @@ bool class__infer_packed_attributes(struct class *cls, const struct cu *cu)
if (pos->is_static)
continue;
size_t byte_size = class_member__byte_size_for_alignment(pos, cu);
/* Always aligned: */
if (pos->byte_size == sizeof(char))
if (byte_size == sizeof(char))
continue;
if (pos->byte_size >= cu->addr_size) {
if (byte_size >= cu->addr_size) {
max_natural_alignment = cu->addr_size;
if ((pos->byte_offset % cu->addr_size) == 0)
continue;
}
uint16_t natural_alignment = __roundup_pow_of_two(pos->byte_size);
uint16_t natural_alignment = __roundup_pow_of_two(byte_size);
if (max_natural_alignment < natural_alignment)
max_natural_alignment = natural_alignment;