Commit Graph

41 Commits

Author SHA1 Message Date
Douglas RAILLARD 54ae2f7f5e Revert "fprintf: Allow making struct/enum/union anonymous"
This reverts commit 7c5e35b63b.

Dropped since it could not cope with recursive types. A new attempt will
be made on 1.24.

Signed-off-by: Douglas RAILLARD <douglas.raillard@arm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-12-08 08:52:51 -03:00
Douglas Raillard 7c5e35b63b fprintf: Allow making struct/enum/union anonymous
Allow making inner struct enums and union anonymous, so that when using
-E to expand types we don't end up with multiple definitions for
expanded inner structs, allowing the resulting expanded struct to be
compilable.

Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
[ Applied it manually to cover some fuzz due to other patches ]
Link: https://lore.kernel.org/all/20211019100724.325570-2-douglas.raillard@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-11-26 15:36:44 -03:00
Arnaldo Carvalho de Melo 3ff11828fe core: enumeration__emit_definitions() doesn't need a 'cu' argument
With the conversion of ->name members to plain char strings, no need
to use 'cu' to get the old string_t index and find the per-cu string
table.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-12 09:39:46 -03:00
Arnaldo Carvalho de Melo 0947d6e795 core: enumeration__fprintf() doesn't need a 'cu' argument
With the conversion of ->name members to plain char strings, no need
to use 'cu' to get the old string_t index and find the per-cu string
table.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-12 09:39:46 -03:00
Arnaldo Carvalho de Melo 7721cc17ac emit: type__emit_fwd_decl() isn't used outside emit.c, make it static
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-12 09:39:46 -03:00
Arnaldo Carvalho de Melo 9aa5db7acd emit: type__emit_fwd_decl() doesn't need a cu arg
Due to previous simplifications in the FOO__name() methods.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-12 09:39:46 -03:00
Arnaldo Carvalho de Melo c46f91ef6f emit: type_emissions__find_definition() doesn't need a cu arg
Due to previous simplifications in the FOO__name() methods.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-12 09:39:46 -03:00
Arnaldo Carvalho de Melo 00e8c5fe21 core: type__name() doesn't need a cu arg
Now that namespace->name is a real char string.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-08-12 09:39:46 -03:00
Arnaldo Carvalho de Melo 71c4f83f28 emit: Remove unused 'is_pointer' variable
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-07-02 10:27:16 -03:00
Arnaldo Carvalho de Melo 7b967744db emit: Emit the types for inline structs defined in pointer members
I.e. before:

  $ pfunct --compile /home/acme/git/build/v5.1-rc4+/block/partitions/sgi.o > a.c
    $ gcc -g -c a.c
  a.c:9:3: error: unknown type name ‘sector_t’
     sector_t           from;                 /*     0     8 */
     ^~~~~~~~
  a.c:10:3: error: unknown type name ‘sector_t’
     sector_t           size;                 /*     8     8 */
     ^~~~~~~~
  a.c:13:30: error: field ‘info’ has incomplete type
     struct partition_meta_info info;         /*    21   101 */
                                ^~~~
  $

After:

  $ pfunct --compile /home/acme/git/build/v5.1-rc4+/block/partitions/sgi.o > a.c
  $ gcc -g -c a.c
  $ head -40 a.c
  struct block_device;

  typedef long unsigned int sector_t;

  typedef _Bool bool;

  typedef unsigned char __u8;
  typedef __u8 u8;

  struct partition_meta_info {
  	char                       uuid[37];             /*     0    37 */
  	u8                         volname[64];          /*    37    64 */

  	/* size: 101, cachelines: 2, members: 2 */
  	/* last cacheline: 37 bytes */
  };

  struct parsed_partitions {
  	struct block_device * bdev;                      /*     0     8 */
  	char                       name[32];             /*     8    32 */
  	struct {
  		sector_t           from;                 /*     0     8 */
  		sector_t           size;                 /*     8     8 */
  		int                flags;                /*    16     4 */
  		bool               has_info;             /*    20     1 */
  		struct partition_meta_info info;         /*    21   101 */
  	} * parts; /*    40     8 */
  	int                        next;                 /*    48     4 */
  	int                        limit;                /*    52     4 */
  	bool                       access_beyond_eod;    /*    56     1 */

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

  	/* --- cacheline 1 boundary (64 bytes) --- */
  	char *                     pp_buf;               /*    64     8 */

  	/* size: 72, cachelines: 2, members: 7 */
  	/* sum members: 65, holes: 1, sum holes: 7 */
  	/* last cacheline: 8 bytes */
  };
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-16 14:47:53 -03:00
Arnaldo Carvalho de Melo cfa377c238 emit: Do not emit a forward declararion to a nameless struct
This was happening here:

  $ pfunct --compile /home/acme/git/build/v5.1-rc4+/block/partitions/check.o > a.c ; head -29 a.c
  struct block_device;

  struct (null);

  typedef _Bool bool;

  struct parsed_partitions {
  	struct block_device * bdev;                      /*     0     8 */
  	char                       name[32];             /*     8    32 */
  	struct {
  		sector_t           from;                 /*    40     8 */
  		sector_t           size;                 /*    48     8 */
  		int                flags;                /*    56     4 */
  		bool               has_info;             /*    60     1 */
  		struct partition_meta_info info;         /*    61   101 */
  	} * parts; /*    40     8 */
  	int                        next;                 /*    48     4 */
  	int                        limit;                /*    52     4 */
  	bool                       access_beyond_eod;    /*    56     1 */

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

  	/* --- cacheline 1 boundary (64 bytes) --- */
  	char *                     pp_buf;               /*    64     8 */

  	/* size: 72, cachelines: 2, members: 7 */
  	/* sum members: 65, holes: 1, sum holes: 7 */
  	/* last cacheline: 8 bytes */
  };
  $

I.e. we saw a pointer to a struct, so all we need is a forward
declaration for that function, right? Not if it is defined inline, so
just don't emit the forward declaration if the struct name is NULL.

Oops, the offsets in a struct defined inline and that the member is a
pointer need to have its offset restarted from zero...

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-16 14:34:04 -03:00
Arnaldo Carvalho de Melo 05921c47f5 emit: Handle typedefs that are a pointer to typedefs
Before:

  $ pfunct --compile /home/acme/git/build/v5.1-rc4+/kernel/sched/autogroup.o > a.c
  $ gcc -g -c a.c
  a.c:1656:9: error: unknown type name ‘__signalfn_t’
   typedef __signalfn_t * __sighandler_t;
           ^~~~~~~~~~~~
  a.c:1658:9: error: unknown type name ‘__restorefn_t’
   typedef __restorefn_t * __sigrestore_t;
           ^~~~~~~~~~~~~
  $

After:

  $ pfunct --compile /home/acme/git/build/v5.1-rc4+/kernel/sched/autogroup.o > a.c
  $ gcc -g -c a.c
  $ egrep  '__(restore|signal)fn_t' -A10 a.c
  typedef void (__signalfn_t)(int);
  typedef __signalfn_t * __sighandler_t;

  typedef void (__restorefn_t)(void);
  typedef __restorefn_t * __sigrestore_t;

  struct sigaction {
	  __sighandler_t             sa_handler;           /*     0     8 */
	  long unsigned int          sa_flags;             /*     8     8 */
	  __sigrestore_t             sa_restorer;          /*    16     8 */
	  sigset_t                   sa_mask;              /*    24     8 */

	  /* size: 32, cachelines: 1, members: 4 */
	  /* last cacheline: 32 bytes */
  };
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-16 13:49:29 -03:00
Arnaldo Carvalho de Melo 56c50b8dbe emit: Make find_fwd_decl a bit more robust
We need to dig deeper in some emit cases, but for now lets make this
a bit more robust by checking if the types are unnamed.

Things like:

struct b {
	struct {
		int a;
	};
}

This is well handled in the main fprintf routines, but its interaction
with the emit routines need more work, lets at least remove the segfault
and leave fixing this for good for v1.14.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 20:53:40 -03:00
Arnaldo Carvalho de Melo c8fc6f5a7a core: Use unnatural alignment of struct embedded in another to infer __packed__
Since we don't have something like DW_AT_alignment for
__attribute__((__packed__)), we need to use whatever hints that are
there in the alignments to figure out if a naturally packed struct has
the __attribute__((packed)) in the original sources, because that is
needed to waiver its natural alignment requisites.

For instance,

  /* Used at: btrfs.c */
  /* <1e7b> /home/acme/git/pahole/btrfs.c:199 */
  struct btrfs_block_group_cache {
          struct btrfs_key   key;                          /*     0    17 */
          struct btrfs_block_group_item item;              /*    17    24 */

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

          struct btrfs_fs_info *     fs_info;              /*    48     8 */
          struct inode *             inode;                /*    56     8 */

In the original source code, btrfs_block_group_item is marked
__packed__, and being so, even seemingly unnecessarily, makes it, when
embedded in another struct, like the above, forfeit its natural
alingment, that would be 8 bytes, and instead appear right at the 17th
byte offset...

  struct btrfs_block_group_item {
          __le64                     used;                 /*     0     8 */
          __le64                     chunk_objectid;       /*     8     8 */
          __le64                     flags;                /*    16     8 */

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

So we need to, seeing its use at a unnatural offset, go backwards to the
btrfs_block_group_item pahole internal data structure, 'struct type' and
mark is_packed field as 'true', despite it not looking like a packed
struct.

Same thing with:

  struct ieee80211_mcs_info {
          u8                         rx_mask[10];          /*     0    10 */
          __le16                     rx_highest;           /*    10     2 */
          u8                         tx_params;            /*    12     1 */
          u8                         reserved[3];          /*    13     3 */

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

That is naturally aligned and as 16 bytes, a power of two, then when it appears at the end of:

  $ pahole -IC ieee80211_sta_ht_cap vht.o
  /* Used at: vht.c */
  /* <31ea> /home/acme/git/pahole/vht.c:1769 */
  struct ieee80211_sta_ht_cap {
  	u16                        cap;                  /*     0     2 */
  	bool                       ht_supported;         /*     2     1 */
  	u8                         ampdu_factor;         /*     3     1 */
  	u8                         ampdu_density;        /*     4     1 */

  	/* XXX 1 byte hole, try to pack */

  	struct ieee80211_mcs_info mcs;                   /*     6    16 */

  	/* size: 22, cachelines: 1, members: 5 */
  	/* sum members: 21, holes: 1, sum holes: 1 */
  	/* last cacheline: 22 bytes */
  };
  $

We get that one byte hole if ieee80211_mcs_info isn't marked __packed__, as soon as we mark it:

  $ pahole -IC ieee80211_sta_ht_cap vht.o
  /* Used at: vht.c */
  /* <31ea> /home/acme/git/pahole/vht.c:1769 */
  struct ieee80211_sta_ht_cap {
  	u16                        cap;                  /*     0     2 */
  	bool                       ht_supported;         /*     2     1 */
  	u8                         ampdu_factor;         /*     3     1 */
  	u8                         ampdu_density;        /*     4     1 */
  	struct ieee80211_mcs_info mcs;                   /*     5    16 */

  	/* size: 22, cachelines: 1, members: 5 */
  	/* padding: 1 */
  	/* last cacheline: 22 bytes */
  };
  [acme@quaco pahole]$

It works, so __packed__ in this case just says: trow away the natural
alignment, make it 1 in whatever container structs.

So, before emitting the types for some struct, we go back looking at
each of its members and checking for such unnatural offsets, marking the
types as __packed__. Now:

  $ pfunct --compile /home/acme/git/build/v5.1-rc4+/net/mac80211/vht.o | grep "^struct ieee80211_mcs_info" -A8
  struct ieee80211_mcs_info {
  	u8                         rx_mask[10];          /*     0    10 */
  	__le16                     rx_highest;           /*    10     2 */
  	u8                         tx_params;            /*    12     1 */
  	u8                         reserved[3];          /*    13     3 */

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

  $ pfunct --compile /home/acme/git/build/v5.1-rc4+/fs/btrfs/free-space-tree.o | grep "^struct btrfs_block_group_item" -A7
  struct btrfs_block_group_item {
  	__le64                     used;                 /*     0     8 */
  	__le64                     chunk_objectid;       /*     8     8 */
  	__le64                     flags;                /*    16     8 */

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

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-15 15:51:16 -03:00
Arnaldo Carvalho de Melo b5e8fab596 emit: Cover void ** as a function parameter
Like in:

  static int
  cifs_setlease(struct file *file, long arg, struct file_lock **lease, void **priv)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-11 11:19:32 -03:00
Arnaldo Carvalho de Melo e7ebc05d12 emit: Unwind the definitions for typedefs in type__emit_definitions()
For instance, with the existing code we ended up with:

  typedef __kernel_size_t size_t;
  size_t tcp_opt_stats_get_size(void)
  {
  }

Which lacks unwinding what a __kernel_size_t is, i.e.
type__emit_definitions() was only emitting definitions for the members
of structs and unions, do it for typedefs too, and then we end up what
we need, which is:

  typedef long unsigned int __kernel_ulong_t;
  typedef __kernel_ulong_t __kernel_size_t;
  typedef __kernel_size_t size_t;
  size_t tcp_opt_stats_get_size(void)
  {
  }

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-04-04 21:59:23 -03:00
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 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
Arnaldo Carvalho de Melo 870afee9ce core: Stop using strings__ptr(strings, i) directly
Instead pass thru cu__strings(cu, i) so that we can figure out if the
underlying debugging format handler can do that more efficiently, such as by
looking up directly the ELF section ".strtab".

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-04-02 17:54:43 -03:00
Arnaldo Carvalho de Melo 140712f06a cu: Rename cu__find_{type,tag}_by_id to cu__{type,tag}
To shorten the name and to reflect the fact that we're no longer
"finding" a type, but merely accessing an array with a bounds check in
this function.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-18 12:17:07 -03:00
Arnaldo Carvalho de Melo 4d44276d85 coding style: remove trailing whitespaces, etc
Amazing how many crept up over time, should have set the
execute bit of .git/hooks/pre-commit already, duh.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-14 13:50:36 -03:00
Arnaldo Carvalho de Melo b902f563b3 dwarves: find holes when adding a fresh compile unit
To take advantage of cache effects and to avoid calling cu__find_holes
more than once on the same struct.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 11:48:33 -03:00
Arnaldo Carvalho de Melo fa82c1b623 dwarves: remove now unused 'cu' argument to {type,class}__name
And also make then pure functions.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 10:57:41 -03:00
Arnaldo Carvalho de Melo 3f4e4457e2 dwarves: Add DW_TAG_ptr_to_member_type to tag__is_tag_type
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-03 15:12:29 -03:00
Arnaldo Carvalho de Melo 964c6b0666 dwarves_emit: Adopt type_emissions
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-10-01 12:51:58 -03:00
Arnaldo Carvalho de Melo f07b4e8047 dwarves_emit: Move the __emit_definitions methods from cus to the emitted classes
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-10-01 12:43:01 -03:00
Arnaldo Carvalho de Melo c3f6f8b79f dwarves_emit: Introduce type_emissions
We may want to work on just one object file, not on a multi cu.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-10-01 11:26:51 -03:00
Arnaldo Carvalho de Melo 993bcbde35 pfunct: Implement --expand_types
So that one can get an skeleton from where a function can be
reimplemented, or a probe can be written to attach to a tracepoint.

Right now it will only expand the types for
struct/union/typedef/enumeration types, but it is a good start.

[acme@doppio pahole]$ pfunct --expand_types --function inet6_ioctl ipv6.ko > a.c
[acme@doppio pahole]$ echo "int main(void) { return 0; }" >> a.c
[acme@doppio pahole]$ gcc -Wall -g a.c -o a
[acme@doppio pahole]$ grep ^#include a.c
[acme@doppio pahole]$

No errors, no includes.

This is present in ctracer, where we don't want to _require_ any header
files, just the object file with the function we want to probe. From
there we get the function signature, and reconstruct the types needed to
access members of structs passed as parameters.

We still need to add padding to reconstruct __attribute__ alignment
effects.

Also, if we can detect what are the exact members accessed in the probe,
we can reconstruct just what is needed to access those members,
hopefully reducing the time needed for gcc to digest the resulting
source code. And also reducing the size of the output, which can
hopefully be interesting to help focus on what the probe is doing.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-09-30 17:30:42 -03:00
Arnaldo Carvalho de Melo fb809733cc [DWARVES]: Introduce tag__assert_search_result
For correctly created and completely parsed debugging information the type will
always be found, but as we still need to parse more tags and expecting
debugging information to be always correctly built is not sane... sprinkle some
asserts.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2008-04-20 18:56:36 -03:00
Arnaldo Carvalho de Melo 6d2dbb484a [DWARVES_EMIT]: Export cus__find_definition
Needed in the next ctracer cset.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-11-16 15:48:57 -02:00
Arnaldo Carvalho de Melo 8ebd39d70d [DWARVES_EMIT]: Add missing newline in cus__emit_type_definitions
At that point we are emitting the definitions for the member types,
so we have to print a newline after each.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-11-15 15:17:01 -02:00
Arnaldo Carvalho de Melo 9050b05a18 [DWARVES_EMIT]: cus__emit_enumeration_definitions requires a conf
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2007-11-12 14:01:08 -02:00
Arnaldo Carvalho de Melo 59099b3481 [LIB]: Make array_type__fprintf use type__fprintf
This way it can handle arrays of anonymous structs.

Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-07-01 20:04:19 -03:00
Arnaldo Carvalho de Melo 9486197977 [LIB]: Introduce tag__is_{enumeration,union,namespace}
Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-31 02:21:36 -03:00
Arnaldo Carvalho de Melo cf124f1636 [LIB]: Introduce tag__is_struct() for a common idiom
And also to get this less, ho-hum, DWARF specific.

Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-31 01:53:01 -03:00
Arnaldo Carvalho de Melo 48a1d89ec0 [LIB]: Introduce conf_fprintf.no_semicolon
To indicate wheter the semicolon should be supressed. Useful for
prototype/function emission, etc.

Also move the struct stats to be inside its body, to simplify tag__fprintf,
that now looks at conf.no_semicolon after calling the tag type specific
__fprintf method.

Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-31 01:39:44 -03:00
Arnaldo Carvalho de Melo e59b1ebb05 [LIB]: Support DW_AT_specification in DW_TAG_structure_type tags
C++ uses this, and to cache the result of the lookup at type__name time we need
to pass the cu to class__name and type__name. Big fallout because of that :-\

But now the output is mucho embelished by the humongous strings representing
C++ templates.

Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-24 18:45:34 -03:00
Arnaldo Carvalho de Melo 9bf0fda9b0 [LIB]: Introduce struct namespace
For now its just the direct ancestor of struct type. But it will exists by
itself, to represent the DW_TAG_namespace DWARF tag, that is how the C++
'namespace' (and other languages too, heck, I'd love to get my hands on a
binary with DWARF info built from, say, ADA source code, objectiveC... COBOL!
:-P).

Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-24 12:16:59 -03:00
Arnaldo Carvalho de Melo 230d9310aa [LIB]: Introduce type__name()
This is in preparation for the introduction of struct namespace, that will be
struct type ancestor.

Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-24 11:56:12 -03:00
Arnaldo Carvalho de Melo c0cbf4fa94 [LIB]: Introduce type__for_each_member
Will be useful to show that the intent is to traverse just the DW_TAG_member
entries in the type list. Right now there are both DW_TAG_inheritance and
DW_TAG_member entries in the ->members type list. But there will be many more
tags, like enumerations, classes, etc, that are defined inside classes, a C++
feature. This will also help with DW_TAG_namespace support.

Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-23 21:43:01 -03:00
Arnaldo Carvalho de Melo 05351ece16 [LIB]: Move the __emit functions to a separate library, libdwarves_emit
To isolate functionality only used in utilities such as ctracer.

Signed-off-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
2007-05-06 14:50:28 -03:00