Commit Graph

45 Commits

Author SHA1 Message Date
Domenico Andreoli e714d2eaa1 Adopt SPDX-License-Identifier
Signed-off-by: Domenico Andreoli <domenico.andreoli@linux.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-18 15:41:48 -03:00
Arnaldo Carvalho de Melo 1182664d6a dwarves_fprintf: Handle negative bit_offsets in packed structs with bitfields
Andrii reported that structs with bitfields and with __attribute__((packed)) were
not producing correct output, that is because pahole and friends didn't
knew about something Yonghong discovered: DW_AT_bit_offset may be
negative when a bitfield straddles a 4 byte boundary, fix it so that we
produce a saner output:

  $ cat examples/yonghong/packed_bitfield.c
  struct packed {
          char x1: 1;
          char x2: 3;
          char x3: 3;
          int y1: 7;
          int y2: 20;
  } __attribute__((packed));
  struct packed g;
  $

  cc -g -c examples/yonghong/packed_bitfield.c

  $ readelf -wi packed_bitfield.o | grep bit_offset
    <37>   DW_AT_bit_offset  : 7
    <46>   DW_AT_bit_offset  : 4
    <55>   DW_AT_bit_offset  : 1
    <64>   DW_AT_bit_offset  : 18
    <73>   DW_AT_bit_offset  : -2
  $

Before:

  $ pahole packed_bitfield.o
  struct packed {
          char                       x1:1;                 /*     0: 7  1 */
          char                       x2:3;                 /*     0: 4  1 */
          char                       x3:3;                 /*     0: 1  1 */
          int                        y1:7;                 /*     0:18  4 */
          int                        y2:20;                /*     0:4294967294  4 */

          /* size: 5, cachelines: 1, members: 5 */
          /* padding: 1 */
          /* bit_padding: 254 bits */
          /* last cacheline: 5 bytes */

          /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */
  };
  $

Now:

  $ pahole packed_bitfield.o
  struct packed {
          char                       x1:1;                 /*     0: 7  1 */
          char                       x2:3;                 /*     0: 4  1 */
          char                       x3:3;                 /*     0: 1  1 */
          int                        y1:7;                 /*     0:18  4 */
          int                        y2:20;                /*     4:30  4 */

          /* size: 5, cachelines: 1, members: 5 */
          /* padding: 1 */
          /* bit_padding: 254 bits */
          /* last cacheline: 5 bytes */

          /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */
  };
  $

And for two big endian archs, one 32-bit and the other 64-bit:

  $ file ~acme/git/tmp/packed_bitfield.powerpc.o
  /home/acme/git/tmp/packed_bitfield.powerpc.o: ELF 32-bit MSB relocatable, PowerPC or cisco 4500, version 1 (SYSV), with debug_info, not stripped
  $ pahole ~acme/git/tmp/packed_bitfield.powerpc.o
  struct packed {
          char                       x1:1;                 /*     0: 0  1 */
          char                       x2:3;                 /*     0: 1  1 */
          char                       x3:3;                 /*     0: 4  1 */
          int                        y1:7;                 /*     0: 7  4 */
          int                        y2:20;                /*     0:14  4 */

          /* size: 5, cachelines: 1, members: 5 */
          /* padding: 1 */
          /* bit_padding: 254 bits */
          /* last cacheline: 5 bytes */

          /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */
  };
  $
  $ file ~acme/git/tmp/packed_bitfield.sparc64.o
  /home/acme/git/tmp/packed_bitfield.sparc64.o: ELF 64-bit MSB relocatable, SPARC V9, relaxed memory ordering, version 1 (SYSV), with debug_info, not stripped
  $
  $ pahole ~acme/git/tmp/packed_bitfield.sparc64.o
  struct packed {
          char                       x1:1;                 /*     0: 0  1 */
          char                       x2:3;                 /*     0: 1  1 */
          char                       x3:3;                 /*     0: 4  1 */
          int                        y1:7;                 /*     0: 7  4 */
          int                        y2:20;                /*     0:14  4 */

          /* size: 5, cachelines: 1, members: 5 */
          /* padding: 1 */
          /* bit_padding: 254 bits */
          /* last cacheline: 5 bytes */

          /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */
  };

Now to fix the holes calculations.

Reported-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Acked-by: Yonghong Song <yhs@fb.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Martin Lau <kafai@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-15 15:12:38 -03:00
Arnaldo Carvalho de Melo 2d0b70664f dwarves_fprintf: Separate basic type stats into separate type__fprintf() method
So that we can use it for unions, in the next cset.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-01-10 15:26:53 -03:00
Arnaldo Carvalho de Melo 70ef8c7f07 dwarves_fprintf: Set conf.cachelinep in union__fprintf() too
union__fprintf() unconditionally uses conf.cachelinep, assuming there is
where the current cacheline is being kept, but if we call
union__fprintf() from something other than __class__fprintf(), then that
pointer is NULL, fix that.

Reported-by: Eric Blake <eblake@redhat.com>
Tested-by: Eric Blake <eblake@redhat.com>
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1633348
Fixes: e975ff247a ("dwarves_fprintf: Print cacheline boundaries in multiple union members")
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-10-03 10:38:44 -03:00
Arnaldo Carvalho de Melo bfdea37668 dwarves_fprintf: Print the scope of variables
E.g.:

$ pfunct -iVT ../build/v4.18.0+/kernel/sched/core.o  -f tg_cfs_schedulable_down
int tg_cfs_schedulable_down(struct task_group * tg, void * data);
{ /* low_pc=0x10340 */
	struct cfs_schedulable_data * d; /* scope: optimized */       //  6681
	struct cfs_bandwidth * cfs_b; /* scope: optimized */          //  6682
	s64 quota; /* scope: optimized */                             //  6683
	s64 parent_quota; /* scope: register */                       //  6683
	{
		struct cfs_bandwidth * parent_b; /* scope: optimized */ //  6688
		{
			bool branch; /* scope: optimized */           //  6698
			arch_static_branch(struct static_key * key,
						bool branch); /* size=30, low_pc=0x103a3 */ //  6698
		} /* lexblock size=0 */
		{
			s64 __UNIQUE_ID___x272; /* scope: optimized *///  6699
			s64 __UNIQUE_ID___y273; /* scope: optimized *///  6699
		} /* lexblock size=0 */
		normalize_cfs_quota(struct task_group * tg,
					struct cfs_schedulable_data * d); /* size=94, low_pc=0x10355 */ //  6690
	} /* lexblock size=0 */
}/* size: 240, variables: 4 */

This is part of an investigation on how to lookup the struct types associated
to registers in instructions with offsets from registers.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-09-26 16:45:25 -03:00
Arnaldo Carvalho de Melo c65f2cf436 dwarves: Rename variable->location to ->scope
We'll use location in the DWARF sense, i.e. location lists, etc, i.e.
where is this variable? In a register? The stack? etc.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-09-26 16:45:25 -03:00
Arnaldo Carvalho de Melo e975ff247a dwarves_fprintf: Print cacheline boundaries in multiple union members
In 'struct audit_context' we have an union that have member structs that
straddles cacheline boundaries, the existing logic was showing those
cacheline boundaries only for the first struct in the union where that
straddling took place, all the subsequent structs where straddling also
takes place were not showing it, the struct:

struct audit_context {
<SNIP>
	union {
		struct {
			int        nargs;                /*   824     4 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			long int   args[6];              /*   832    48 */
		} socketcall;                            /*   824    56 */
		struct {
			kuid_t     uid;                  /*   824     4 */
			kgid_t     gid;                  /*   828     4 */
			umode_t    mode;                 /*   832     2 */

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

			u32        osid;                 /*   836     4 */
			int        has_perm;             /*   840     4 */
			uid_t      perm_uid;             /*   844     4 */
			gid_t      perm_gid;             /*   848     4 */
			umode_t    perm_mode;            /*   852     2 */

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

			long unsigned int qbytes;        /*   856     8 */
		} ipc;                                   /*   824    40 */
		struct {
			mqd_t      mqdes;                /*   824     4 */

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

			struct mq_attr mqstat;           /*   832    64 */
		} mq_getsetattr;                         /*   824    72 */
		struct {
			mqd_t      mqdes;                /*   824     4 */
			int        sigev_signo;          /*   828     4 */
		} mq_notify;                             /*   824     8 */
		struct {
			mqd_t      mqdes;                /*   824     4 */

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

			size_t     msg_len;              /*   832     8 */
			unsigned int msg_prio;           /*   840     4 */

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

			struct timespec64 abs_timeout;   /*   848    16 */
		} mq_sendrecv;                           /*   824    40 */
		struct {
			int        oflag;                /*   824     4 */
			umode_t    mode;                 /*   828     2 */

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

			struct mq_attr attr;             /*   832    64 */
		} mq_open;                               /*   824    72 */
		struct {
			pid_t      pid;                  /*   824     4 */
			struct audit_cap_data cap;       /*   828    32 */
		} capset;                                /*   824    36 */
		struct {
			int        fd;                   /*   824     4 */
			int        flags;                /*   828     4 */
		} mmap;                                  /*   824     8 */
		struct {
			int        argc;                 /*   824     4 */
		} execve;                                /*   824     4 */
		struct {
			char *     name;                 /*   824     8 */
		} module;                                /*   824     8 */
	};                                               /*   824    72 */
	/* --- cacheline 14 boundary (896 bytes) --- */
	int                        fds[2];               /*   896     8 */
	struct audit_proctitle     proctitle;            /*   904    16 */

	/* size: 920, cachelines: 15, members: 46 */
	/* sum members: 912, holes: 2, sum holes: 8 */
	/* last cacheline: 24 bytes */
};

With this fix:

struct audit_context {
<SNIP>
	union {
		struct {
			int        nargs;                /*   824     4 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			long int   args[6];              /*   832    48 */
		} socketcall;                            /*   824    56 */
		struct {
			kuid_t     uid;                  /*   824     4 */
			kgid_t     gid;                  /*   828     4 */
			/* --- cacheline 13 boundary (832 bytes) --- */
			umode_t    mode;                 /*   832     2 */

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

			u32        osid;                 /*   836     4 */
			int        has_perm;             /*   840     4 */
			uid_t      perm_uid;             /*   844     4 */
			gid_t      perm_gid;             /*   848     4 */
			umode_t    perm_mode;            /*   852     2 */

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

			long unsigned int qbytes;        /*   856     8 */
		} ipc;                                   /*   824    40 */
		struct {
			mqd_t      mqdes;                /*   824     4 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			struct mq_attr mqstat;           /*   832    64 */
		} mq_getsetattr;                         /*   824    72 */
		struct {
			mqd_t      mqdes;                /*   824     4 */
			int        sigev_signo;          /*   828     4 */
		} mq_notify;                             /*   824     8 */
		struct {
			mqd_t      mqdes;                /*   824     4 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			size_t     msg_len;              /*   832     8 */
			unsigned int msg_prio;           /*   840     4 */

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

			struct timespec64 abs_timeout;   /*   848    16 */
		} mq_sendrecv;                           /*   824    40 */
		struct {
			int        oflag;                /*   824     4 */
			umode_t    mode;                 /*   828     2 */

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

			/* --- cacheline 13 boundary (832 bytes) --- */
			struct mq_attr attr;             /*   832    64 */
		} mq_open;                               /*   824    72 */
		struct {
			pid_t      pid;                  /*   824     4 */
			struct audit_cap_data cap;       /*   828    32 */
		} capset;                                /*   824    36 */
		struct {
			int        fd;                   /*   824     4 */
			int        flags;                /*   828     4 */
		} mmap;                                  /*   824     8 */
		struct {
			int        argc;                 /*   824     4 */
		} execve;                                /*   824     4 */
		struct {
			char *     name;                 /*   824     8 */
		} module;                                /*   824     8 */
	};                                               /*   824    72 */
	/* --- cacheline 14 boundary (896 bytes) --- */
	int                        fds[2];               /*   896     8 */
	struct audit_proctitle     proctitle;            /*   904    16 */

	/* size: 920, cachelines: 15, members: 46 */
	/* sum members: 912, holes: 2, sum holes: 8 */
	/* last cacheline: 24 bytes */
};

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2018-07-28 14:25:30 -03:00
Arnaldo Carvalho de Melo 81466af0d4 pahole: Show the file where a struct was used
To help with using just that object file, avoiding processing big files
such as vmlinux, e.g.:

  $ pahole -I vmlinux
<SNIP>
  /* Used at: /home/acme/git/perf/init/main.c */
  /* <1f4a5> /home/acme/git/perf/arch/x86/include/asm/orc_types.h:85 */
  struct orc_entry {
          s16                        sp_offset;            /*     0     2 */
          s16                        bp_offset;            /*     2     2 */
          unsigned int               sp_reg:4;             /*     4:28  4 */
          unsigned int               bp_reg:4;             /*     4:24  4 */
          unsigned int               type:2;               /*     4:22  4 */

          /* size: 6, cachelines: 1, members: 5 */
          /* padding: 65534 */
          /* bit_padding: 22 bits */
          /* last cacheline: 6 bytes */

          /* BRAIN FART ALERT! 6 != 8 + 0(holes), diff = -2 */
  };
<SNIP>

So I noticed that BFA, need to work on it, to make the testing process
faster, better not process vmlinux.o, instead, do:

  $ pahole -C orc_entry ${kernel_build_dir}/init/main.o

Much faster, as main.o is much smaller than the vmlinux file.

Now to fix the processing of 'struct orc_entry'.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-12-15 15:30:38 -03:00
Arnaldo Carvalho de Melo 2dd87be78b dwarves_fprintf: Show offsets at union members
In complex structs with multiple complex unions figuring out the offset
for a given union member is difficult, as one needs to figure out the
union, go to the end of it to see the offset.

So just turn struct_member__fprintf() into class_member__fprintf() and
pass a 'union_member' boolean to share all the aspects of struct and
union members, just not advancing the offset when processing union
members.

This way, for instance, the Linux kernel's 'struct page' goes from:

struct page {
	long unsigned int          flags;                /*     0     8 */
	union {
		struct address_space * mapping;          /*     8     8 */
		void *             s_mem;                /*     8     8 */
		atomic_t           compound_mapcount;    /*     8     4 */
	};                                               /*     8     8 */
	union {
		long unsigned int  index;                /*    16     8 */
		void *             freelist;             /*    16     8 */
	};                                               /*    16     8 */
	union {
		long unsigned int  counters;             /*    24     8 */
		struct {
			union {
				atomic_t _mapcount;      /*    24     4 */
				unsigned int active;     /*    24     4 */
				struct {
					unsigned int inuse:16; /*    24:16  4 */
					unsigned int objects:15; /*    24: 1  4 */
					unsigned int frozen:1; /*    24: 0  4 */
				};                       /*    24     4 */
				int units;               /*    24     4 */
			};                               /*    24     4 */
			atomic_t   _refcount;            /*    28     4 */
		};                                       /*    24     8 */
	};                                               /*    24     8 */
	union {
		struct list_head   lru;                  /*    32    16 */
		struct dev_pagemap * pgmap;              /*    32     8 */
		struct {
			struct page * next;              /*    32     8 */
			int        pages;                /*    40     4 */
			int        pobjects;             /*    44     4 */
		};                                       /*    32    16 */
		struct callback_head callback_head;      /*    32    16 */
		struct {
			long unsigned int compound_head; /*    32     8 */
			unsigned int compound_dtor;      /*    40     4 */
			unsigned int compound_order;     /*    44     4 */
		};                                       /*    32    16 */
		struct {
			long unsigned int __pad;         /*    32     8 */
			pgtable_t  pmd_huge_pte;         /*    40     8 */
		};                                       /*    32    16 */
	};                                               /*    32    16 */
	union {
		long unsigned int  private;              /*    48     8 */
		spinlock_t         ptl;                  /*    48     4 */
		struct kmem_cache * slab_cache;          /*    48     8 */
	};                                               /*    48     8 */
	struct mem_cgroup *        mem_cgroup;           /*    56     8 */

	/* size: 64, cachelines: 1, members: 7 */
};

To:

struct page {
	long unsigned int          flags;                /*     0     8 */
	union {
		struct address_space * mapping;          /*     8     8 */
		void *             s_mem;                /*     8     8 */
		atomic_t           compound_mapcount;    /*     8     4 */
	};                                               /*     8     8 */
	union {
		long unsigned int  index;                /*    16     8 */
		void *             freelist;             /*    16     8 */
	};                                               /*    16     8 */
	union {
		long unsigned int  counters;             /*    24     8 */
		struct {
			union {
				atomic_t _mapcount;      /*    24     4 */
				unsigned int active;     /*    24     4 */
				struct {
					unsigned int inuse:16; /*    24:16  4 */
					unsigned int objects:15; /*    24: 1  4 */
					unsigned int frozen:1; /*    24: 0  4 */
				};                       /*    24     4 */
				int units;               /*    24     4 */
			};                               /*    24     4 */
			atomic_t   _refcount;            /*    28     4 */
		};                                       /*    24     8 */
	};                                               /*    24     8 */
	union {
		struct list_head   lru;                  /*    32    16 */
		struct dev_pagemap * pgmap;              /*    32     8 */
		struct {
			struct page * next;              /*    32     8 */
			int        pages;                /*    40     4 */
			int        pobjects;             /*    44     4 */
		};                                       /*    32    16 */
		struct callback_head callback_head;      /*    32    16 */
		struct {
			long unsigned int compound_head; /*    32     8 */
			unsigned int compound_dtor;      /*    40     4 */
			unsigned int compound_order;     /*    44     4 */
		};                                       /*    32    16 */
		struct {
			long unsigned int __pad;         /*    32     8 */
			pgtable_t  pmd_huge_pte;         /*    40     8 */
		};                                       /*    32    16 */
	};                                               /*    32    16 */
	union {
		long unsigned int  private;              /*    48     8 */
		spinlock_t         ptl;                  /*    48     4 */
		struct kmem_cache * slab_cache;          /*    48     8 */
	};                                               /*    48     8 */
	struct mem_cgroup *        mem_cgroup;           /*    56     8 */

	/* size: 64, cachelines: 1, members: 7 */
};

Suggested-by: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2017-12-15 13:33:10 -03:00
Arnaldo Carvalho de Melo b52386d041 dwarves_fprintf: Find holes when expanding types
When --expand_types/-E is used we go on expanding internal types, and
when doing that for structs we were not looking for holes in them, only
on the main struct, fix it.

With that we can see these extra holes in a expanded Linux kernel's
'struct task_struct':

@@ -46,6 +46,9 @@
 			struct list_head * prev;                                         /*   176     8 */
 		} group_node; /*   168    16 */
 		unsigned int       on_rq;                                                /*   184     4 */
+
+		/* XXX 4 bytes hole, try to pack */
+
 		/* --- cacheline 3 boundary (192 bytes) --- */
 		/* typedef u64 */ long long unsigned int exec_start;                     /*   192     8 */
 		/* typedef u64 */ long long unsigned int sum_exec_runtime;               /*   200     8 */
@@ -86,9 +89,15 @@
 		} statistics; /*   232   216 */
 		/* --- cacheline 7 boundary (448 bytes) --- */
 		int                depth;                                                /*   448     4 */
+
+		/* XXX 4 bytes hole, try to pack */
+
 		struct sched_entity * parent;                                            /*   456     8 */
 		struct cfs_rq *    cfs_rq;                                               /*   464     8 */
 		struct cfs_rq *    my_q;                                                 /*   472     8 */
+
+		/* XXX 32 bytes hole, try to pack */
+
 		/* --- cacheline 8 boundary (512 bytes) --- */
 		struct sched_avg {
 			/* typedef u64 */ long long unsigned int last_update_time;       /*   512     8 */
@@ -153,6 +162,9 @@
 			struct hrtimer_clock_base * base;                                /*   768     8 */
 			/* typedef u8 */ unsigned char state;                            /*   776     1 */
 			/* typedef u8 */ unsigned char is_rel;                           /*   777     1 */
+
+			/* XXX 2 bytes hole, try to pack */
+
 			int        start_pid;                                            /*   780     4 */
 			void *     start_site;                                           /*   784     8 */
 			char       start_comm[16];                                       /*   792    16 */
@@ -197,6 +209,9 @@
 	} tasks; /*   912    16 */
 	struct plist_node {
 		int                prio;                                                 /*   928     4 */
+
+		/* XXX 4 bytes hole, try to pack */
+
 		struct list_head {
 			struct list_head * next;                                         /*   936     8 */
 			struct list_head * prev;                                         /*   944     8 */
@@ -258,12 +273,18 @@
 				/* typedef u32 */ unsigned int val;                      /*  1136     4 */
 				/* typedef u32 */ unsigned int flags;                    /*  1140     4 */
 				/* typedef u32 */ unsigned int bitset;                   /*  1144     4 */
+
+				/* XXX 4 bytes hole, try to pack */
+
 				/* --- cacheline 18 boundary (1152 bytes) --- */
 				/* typedef u64 */ long long unsigned int time;           /*  1152     8 */
 				u32 * uaddr2;                                            /*  1160     8 */
 			} futex;                                                         /*          40 */
 			struct {
 				/* typedef clockid_t -> __kernel_clockid_t */ int clockid; /*  1128     4 */
+
+				/* XXX 4 bytes hole, try to pack */
+
 				struct timespec * rmtp;                                  /*  1136     8 */
 				struct compat_timespec * compat_rmtp;                    /*  1144     8 */
 				/* typedef u64 */ long long unsigned int expires;        /*  1152     8 */
@@ -426,6 +447,9 @@
 	unsigned int               sessionid;                                            /*  1804     4 */
 	struct seccomp {
 		int                mode;                                                 /*  1808     4 */
+
+		/* XXX 4 bytes hole, try to pack */
+
 		struct seccomp_filter * filter;                                          /*  1816     8 */
 	} seccomp; /*  1808    16 */
 	/* typedef u32 */ unsigned int               parent_exec_id;                     /*  1824     4 */
@@ -602,6 +626,9 @@
 		long unsigned int  backtrace[12];                                        /*  2472    96 */
 		/* --- cacheline 40 boundary (2560 bytes) was 8 bytes ago --- */
 		unsigned int       count;                                                /*  2568     4 */
+
+		/* XXX 4 bytes hole, try to pack */
+
 		long unsigned int  time;                                                 /*  2576     8 */
 		long unsigned int  max;                                                  /*  2584     8 */
 	} latency_record[32]; /*  2472  3840 */
@@ -686,12 +713,18 @@
 		long unsigned int * io_bitmap_ptr;                                       /*  6600     8 */
 		long unsigned int  iopl;                                                 /*  6608     8 */
 		unsigned int       io_bitmap_max;                                        /*  6616     4 */
+
+		/* XXX 36 bytes hole, try to pack */
+
 		/* --- cacheline 104 boundary (6656 bytes) --- */
 		struct fpu {
 			unsigned int last_cpu;                                           /*  6656     4 */
 			unsigned char fpstate_active;                                    /*  6660     1 */
 			unsigned char fpregs_active;                                     /*  6661     1 */
 			unsigned char counter;                                           /*  6662     1 */
+
+			/* XXX 57 bytes hole, try to pack */
+
 			/* --- cacheline 105 boundary (6720 bytes) --- */
 			union fpregs_state {
 				struct fregs_state {
@@ -751,6 +784,9 @@
 					/* typedef u8 */ unsigned char no_update;        /*  6831     1 */
 					/* typedef u8 */ unsigned char rm;               /*  6832     1 */
 					/* typedef u8 */ unsigned char alimit;           /*  6833     1 */
+
+					/* XXX 6 bytes hole, try to pack */
+
 					struct math_emu_info * info;                     /*  6840     8 */
 					/* typedef u32 */ unsigned int entry_eip;        /*  6848     4 */
 				} soft; /*         136 */

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-06-30 16:30:28 -03:00
Arnaldo Carvalho de Melo 103e89bb25 dwarves_fprintf: Find holes on structs embedded in other structs
Take 'struct task_struct' in the Linux kernel, these fields:

        /* --- cacheline 2 boundary (128 bytes) --- */
        struct sched_entity        se;                   /*   128   448 */

        /* XXX last struct has 24 bytes of padding */

        /* --- cacheline 9 boundary (576 bytes) --- */
        struct sched_rt_entity     rt;                   /*   576    48 */

The sched_entity struct has 24 bytes of padding, and that info would
only appear when printing 'struct task_struct' if class__find_holes()
had previously been run on 'struct sched_entity' which wasn't always the
case, make sure that happens.

This results in this extra stat being printed for 'struct task_struct':

	/* paddings: 4, sum paddings: 38 */

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-06-30 16:18:11 -03:00
Arnaldo Carvalho de Melo ab97c07a7e dwarves_fprintf: Fixup cacheline boundary printing on expanded structs
A diff for 'pahole -EC task_struct vmlinux' should clarify what this fixes:

  [acme@jouet linux]$ diff -u /tmp/before.c /tmp/after.c | head -30
  --- /tmp/before.c	2016-06-29 17:00:38.082647281 -0300
  +++ /tmp/a.c	2016-06-29 17:03:36.913124779 -0300
  @@ -43,8 +43,8 @@
 			struct list_head * prev;                                         /*   176     8 */
 		} group_node; /*   168    16 */
 		unsigned int       on_rq;                                                /*   184     4 */
  +		/* --- cacheline 3 boundary (192 bytes) --- */
 		/* typedef u64 */ long long unsigned int exec_start;                     /*   192     8 */
  -		/* --- cacheline 1 boundary (64 bytes) was 4 bytes ago --- */
 		/* typedef u64 */ long long unsigned int sum_exec_runtime;               /*   200     8 */
 		/* typedef u64 */ long long unsigned int vruntime;                       /*   208     8 */
 		/* typedef u64 */ long long unsigned int prev_sum_exec_runtime;          /*   216     8 */
  @@ -53,40 +53,40 @@
 			/* typedef u64 */ long long unsigned int wait_start;             /*   232     8 */
 			/* typedef u64 */ long long unsigned int wait_max;               /*   240     8 */
 			/* typedef u64 */ long long unsigned int wait_count;             /*   248     8 */
  +			/* --- cacheline 4 boundary (256 bytes) --- */
 			/* typedef u64 */ long long unsigned int wait_sum;               /*   256     8 */
 			/* typedef u64 */ long long unsigned int iowait_count;           /*   264     8 */
 			/* typedef u64 */ long long unsigned int iowait_sum;             /*   272     8 */
 			/* typedef u64 */ long long unsigned int sleep_start;            /*   280     8 */
 			/* typedef u64 */ long long unsigned int sleep_max;              /*   288     8 */
  -			/* --- cacheline 1 boundary (64 bytes) --- */
 			/* typedef s64 */ long long int sum_sleep_runtime;               /*   296     8 */
 			/* typedef u64 */ long long unsigned int block_start;            /*   304     8 */
 			/* typedef u64 */ long long unsigned int block_max;              /*   312     8 */
  +			/* --- cacheline 5 boundary (320 bytes) --- */
 			/* typedef u64 */ long long unsigned int exec_max;               /*   320     8 */
 			/* typedef u64 */ long long unsigned int slice_max;              /*   328     8 */
 			/* typedef u64 */ long long unsigned int nr_migrations_cold;     /*   336     8 */
  [acme@jouet linux]$

I.e. the boundary detection was being reset at each expanded struct, do the math globally,
using the member offset, that was already done globally and correctly.

Reported-and-Tested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-06-29 17:27:51 -03:00
Arnaldo Carvalho de Melo 046ad67af3 dwarves_fprintf: Shorten class__fprintf() sig
That conf_fprintf can be elided as it is always NULL for the root call,
i.e. only when expanding types is that it will be called recursively.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-06-29 16:19:20 -03:00
Arnaldo Carvalho de Melo 45618c7ec1 dwarf_loader: Initial support for DW_TAG_unspecified_type
Still need to check what to fprintf for this, but at least have it in
the type lists so that we can find it.

Reported-by: Christophe Fergeau <cfergeau@redhat.com>
Cc: Dodji Seketeli <dodji@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-05-17 10:05:34 -03:00
Arnaldo Carvalho de Melo 0fbb39291d dwarf_loader: Add support for DW_TAG_restrict_type
I.e. supporting the 'restrict' keyword, emitted by recent compilers:

  [acme@jouet pahole]$ pfunct -P ~/bin/perf |& grep -w restrict
  inline int vprintf(const char  * restrict  __fmt, struct __va_list_tag * __ap);
  inline size_t fread(void * restrict  __ptr, size_t __size, size_t __n, FILE * restrict  __stream);
  inline int vfprintf(FILE * restrict  __stream, const char  * restrict  __fmt, struct __va_list_tag * __ap);
  inline int vasprintf(char * * restrict  __ptr, const char  * restrict  __fmt, struct __va_list_tag * __ap);
  inline char * realpath(const char  * restrict  __name, char * restrict  __resolved);
  inline ssize_t readlink(const char  * restrict  __path, char * restrict  __buf, size_t __len);
  inline char * strcat(char * restrict  __dest, const char  * restrict  __src);
  inline char * fgets(char * restrict  __s, int __n, FILE * restrict  __stream);
  inline int snprintf(char * restrict  __s, size_t __n, const char  * restrict  __fmt, ...);
  inline int sprintf(char * restrict  __s, const char  * restrict  __fmt, ...);
  inline char * strcpy(char * restrict  __dest, const char  * restrict  __src);
  inline int asprintf(char * * restrict  __ptr, const char  * restrict  __fmt, ...);
  inline char * strncpy(char * restrict  __dest, const char  * restrict  __src, size_t __len);
  inline int fprintf(FILE * restrict  __stream, const char  * restrict  __fmt, ...);
  inline int vsnprintf(char * restrict  __s, size_t __n, const char  * restrict  __fmt, struct __va_list_tag * __ap);
  inline int printf(const char  * restrict  __fmt, ...);
  [acme@jouet pahole]$

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-05-06 15:02:17 -03:00
Arnaldo Carvalho de Melo 1896959072 dwarves_fprintf: Add the missing GNU_ suffix to DWARF_TAG_ created by the GNU project
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-19 18:07:50 -03:00
Arnaldo Carvalho de Melo d973b1d5da dwarf_fprintf: Handle DW_TAG_GNU_call_site{_parameter}
Reported-by: Diego Elio Pettenò <flameeyes@flameeyes.eu>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-11-19 18:06:41 -03:00
Mark Wielaard 943a0de067 dwarves_fprintf: DW_TAG_mutable_type doesn't exist.
DW_TAG_mutable_type was a mistake in an early DWARFv3 draft and was
removed in the final version.

http://dwarfstd.org/ShowIssue.php?issue=050223.1

Signed-off-by: Mark Wielaard <mjw@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2014-07-03 12:34:48 -03:00
Cody P Schafer 1e461ec7e0 dwarves_fprintf: Fix printf types on 64bit linux
Signed-off-by: Cody P Schafer <cody@linux.vnet.ibm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2013-03-20 15:56:38 -03:00
Arnaldo Carvalho de Melo 222f0067a9 dwarves_fprintf: Don't ignore virtual data members
When computing the size of a class, leave, caused problems in
some cases, links to the reports are in the comments.

Reported-by: Nicolas <nikos42@gmail.com>
Suggested-by: Mark Wielaard <mjw@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2013-03-20 10:38:03 -03:00
Arnaldo Carvalho de Melo 8c6378fd88 dwarves: Support static class data members
Fixes the following BFA:

[acme@sandy pahole]$ pahole brainfart.o
class ios_base {
	enum _Ios_Openmodeconst    in;                   /*     0     4 */
	typedef enum _Ios_Fmtflags fmtflags;

	/* size: 1, cachelines: 1, members: 1 */
	/* padding: 65533 */
	/* last cacheline: 1 bytes */

	/* BRAIN FART ALERT! 1 != 4 + 0(holes), diff = -3 */

};

That now produces:

[acme@sandy pahole]$ build/pahole brainfart.o
class ios_base {
	static enum _Ios_Openmodeconst    in = 8;        /*     0     0 */
	typedef enum _Ios_Fmtflags fmtflags;

	/* size: 1, cachelines: 0, members: 0, static members: 1 */
	/* last cacheline: 1 bytes */
};
[acme@sandy pahole]$

Reported-by: Nicolas <nikos42@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2012-08-20 14:42:17 -03:00
Arnaldo Carvalho de Melo a54515fa6e dwarves: Stop using 'self'
As Thomas Gleixner wisely pointed out, using 'self' is stupid, it
doesn't convey useful information, so use sensible names.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2012-08-17 18:47:15 -03:00
Tal Kelrich 4e5967a2ca Fix crash when pahole called with -R -S 2012-02-26 16:33:05 +02:00
Arnaldo Carvalho de Melo 76f687bf49 dwarf_loader: Fix the build on older systems
RHEL5 and Fedora 11 were not building due to the GNU attributes stuff,
cope with that using a define we know is not present in both RHEL5 and
Fedora 11 to #ifdef those parts. Ugly, but _ELFUTILS_PREREQ, i.e.
elfutils/version.h is not present in RHEL5 either.

Reported-by: Jon Stanley <jstanley@fedoraproject.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2011-03-17 15:33:28 -03:00
Arnaldo Carvalho de Melo dae032ea3f dwarves fprintf: Add extra GNU tags
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2010-11-20 22:23:14 -02:00
Arnaldo Carvalho de Melo 6476d24d73 pahole: Introduce --hex to print offsets and sizes in hexadecimal
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-10-20 13:59:12 -02:00
Arnaldo Carvalho de Melo 9720415091 dwarf: Detect type loops
[acme@doppio pahole]$ pahole -F ctf /media/tb/debuginfo/usr/lib/debug/usr/bin/greycstoration4integration.debug > /tmp/bla
<ERROR(tag__size:837): detected type loop: type=572, tag=const_type>
<ERROR(tag__size:837): detected type loop: type=572, tag=const_type>
[acme@doppio pahole]$

These type loops are problems in the CTF encoding, that should be fixed, but
should not cause the core code to segfault on an infinite recursion.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-14 17:07:02 -03:00
Arnaldo Carvalho de Melo 428f318599 dwarves_fprintf: '* const' support: 3rd try
[acme@doppio pahole]$ cd tests/jengelh@medozas.de
[acme@doppio jengelh@medozas.de]$ cat test.sh
for F in const_pointer pointer_const const_pointer_const ; do
	printf "%s\n-------------------\n\n" $F
	gcc -c -g $F.c -o $F
	cat $F.c; pahole $F
done
[acme@doppio jengelh@medozas.de]$ ./test.sh
const_pointer
-------------------

struct x {
	const char *s;
} y;
struct x {
	const char  *      s;    /*     0     8 */

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

struct x {
	char *const s;
} y;
struct x {
	char *const        s;    /*     0     8 */

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

struct x {
	const char *const s;
} y;
struct x {
	const char  *const s;    /*     0     8 */

	/* size: 8, cachelines: 1, members: 1 */
	/* last cacheline: 8 bytes */
};
[acme@doppio jengelh@medozas.de]$

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-12 19:42:46 -03:00
Arnaldo Carvalho de Melo 406944b404 dwarves: Add more __name() routines and remove s()
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-12 18:11:19 -03:00
Arnaldo Carvalho de Melo 7e5b39f944 dwarves_fprintf: Make tag__id_not_found_(f|sn)printf print __LINE__
Helps debugging.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-11 15:10:43 -03:00
Arnaldo Carvalho de Melo fe101bdf3d dwarves_fprintf: really fix pointers to const
[acme@doppio pahole]$ cat tests/jengelh@medozas.de/const_const.c
struct x {
	const char *const s;
} y;

int main(void)
{
	return !y.s;
}
[acme@doppio pahole]$ pahole tests/jengelh@medozas.de/const_const
struct x {
	const char  *const         s;                /*     0     8 */

	/* size: 8, cachelines: 1, members: 1 */
	/* last cacheline: 8 bytes */
};
[acme@doppio pahole]$

Look again...

One more time...

Looks ok now.

Reported-by: Jan Engelhardt <jengelh@medozas.de>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-11 01:51:22 -03:00
Arnaldo Carvalho de Melo 846927a3f8 dwarves_fprintf: Properly support pointers to const
I.e.:

[acme@doppio pahole]$ cat tests/jengelh@medozas.de/const_const.c
struct x {
	const char *const s;
} y;

int main(void)
{
	return !y.s;
}
[acme@doppio pahole]$ pahole tests/jengelh@medozas.de/const_const
struct x {
	char const  * const        s;                    /*     0     8 */

	/* size: 8, cachelines: 1, members: 1 */
	/* last cacheline: 8 bytes */
};
[acme@doppio pahole]$

One more reason to devote some time to RTT, i.e. Round Trip Testing, where
pahole will be used to regenerate the source code, then feed the result to
gcc -g, run again, use codiff, that should produce no diff.

Reported-by: Jan Engelhardt <jengelh@medozas.de>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-09-10 16:43:00 -03:00
Arnaldo Carvalho de Melo fc1269af2f pahole: Introduce --classes_as_structs
That asks dwarf_fprintf to always use "struct" in places where it would
use "class", because CTF doesn't have the "class" concept, so for
'regtest diffctf' sake, we use this.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-24 17:22:43 -03:00
Arnaldo Carvalho de Melo 02a419287a dwarves_fprintf: Bump the size passed to tag__name in imported_declaration__fprintf
As it was not enough to cover some, hum, limits in the way C++ encodes piles of
abstractions:

+++ /media/tb/pahole/regtest/after/usr/bin/enfuse.pahole -A.c   2009-08-21 09:04:15.000000000 -0300
@@ -10414,7 +10414,7 @@ struct _Vector_base<enblend::enfuseMain(

        using ::_M_deallocate;

-       using ::__uninitialized_move_a<enblend::enfuseMain(std::list<vigra::ImageImportInfo*, std::allocator<vigra::ImageImportInfo*> >&, vigra::ImageExportInfo&, vigra::Rect2D&) [with ImagePixelType = vigra::RGBValue<unsigned int, 0u, 1u, 2u>]::ImagePyramidType**, enblend::enfuseMain(std::list<vigra::ImageImportInfo*, std::allocator<vigra::ImageImportInfo*> >&, vigra::ImageExportInfo&, vigra::Rect2D&) [with ImagePixelType = vigra::RGBValue<unsigned int, 0u, 1u, 2u>]::ImagePyramidType**, std::allocator<enblend::enfuseMain(ð7K^A;
+       using ::__uninitialized_move_a<enblend::enfuseMain(std::list<vigra::ImageImportInfo*, std::allocator<vigra::ImageImportInfo*> >&, vigra::ImageExportInfo&, vigra::Rect2D&) [with ImagePixelType = vigra::RGBValue<unsigned int, 0u, 1u, 2u>]::ImagePyramidType**, enblend::enfuseMain(std::list<vigra::ImageImportInfo*, std::allocator<vigra::ImageImportInfo*> >&, vigra::ImageExportInfo&, vigra::Rect2D&) [with ImagePixelType = vigra::RGBValue<unsigned int, 0u, 1u, 2u>]::ImagePyramidType**, std::allocator<enblend::enfuseMain(std::list<vigra::ImageImportInfo*, std::allocator<vigra::ImageImportInfo*> >&, vigra::ImageExportInfo&, vigra::Rect2D&) [with ImagePixelType = vigra::RGBValue<unsigned int, 0u, 1u, 2u>]::ImagePyramidType*> >;

        using ::_M_get_Tp_allocator;

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-21 09:05:15 -03:00
Arnaldo Carvalho de Melo 36151b470a dwarves: Make tag__name support variables
As DW_TAG_imported_declaration can also point to one...

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-20 22:41:48 -03:00
Arnaldo Carvalho de Melo bd361e461e dwarf_loader/dwarves_fprintf: Support "using" pointing to data members
If it is C++ add DW_TAG_member entries to cu->tags_table and at
imported_declaration__fprintf fallback to cu__tag() if cu__function()
fails.

The right thing tho, long term, is to have a class for
"DW_TAG_imported_declaration" to register to what kind of tag this
points, if for DW_TAG_subprogram or to DW_TAG_member, the info is in the
DWARF DW_AT_import attribute, but so far we're not decoding it.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-20 18:33:52 -03:00
Arnaldo Carvalho de Melo d2581fa5aa dwarves_fprintf: Revert experimentation with const rendering
Still doesn't fixes the case "const char * const foo"...

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-19 10:04:54 -03:00
Arnaldo Carvalho de Melo 19bbecf668 dwarves: Pass the cu to destructors to free memory on the obstack
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-18 18:21:20 -03:00
Arnaldo Carvalho de Melo f7bbe7dee2 dwarves_fprintf: Support zero sized arrays in the middle of the struct
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-08-10 12:31:47 -03:00
Zack Weinberg 1298ce789e dwarves_fprintf: Honour conf.show_only_data_members for the vtable
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Zack Weinberg <zweinberg@mozilla.com>
2009-06-17 15:30:09 -03:00
Arnaldo Carvalho de Melo 4b796de4aa dwarves: export ftype__fprintf_parms
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-08 14:23:46 -03:00
Arnaldo Carvalho de Melo 7c6603189e dwarves: Make all the tags that have an IP to be derived from ip_tag
Next we'll add a new kind of tag, DW_TAG_perf_counter, that will come
from perf.data generated by 'perf report'.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-06-04 17:30:06 -03:00
Arnaldo Carvalho de Melo 071cb5fd75 fprintf: Print "interface" in class__fprintf for Java Interfaces
JAVA support needs to be checked, but from a very quick skim it
looks ok'ish.

First detected with /usr/bin/fstack from frysk.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-04-25 01:54:21 -03:00
Arnaldo Carvalho de Melo 29e67fce58 dwarf_loader: Add containing_type to dwarf_tag
Sharing the same space with abstract_origin, so that we can remove the last
Dwarf_Off in dwarf_fprintf.c.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-04-19 14:04:59 -03:00
Arnaldo Carvalho de Melo f84bf73d54 dwarves: Move the fprintf code to a new source file.
$ wc -l dwarves.c dwarves_fprintf.c
 1468 dwarves.c
 1554 dwarves_fprintf.c
 3022 total
$

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-04-19 13:48:51 -03:00