Commit Graph

396 Commits

Author SHA1 Message Date
Arnaldo Carvalho de Melo 0d13bc50ee core: Ditch unused cu__find_struct_by_sname()
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:17 -03:00
Arnaldo Carvalho de Melo 46f3f37241 core: Convert cu__find_base_type_by_sname_and_size to search for a string
It looked for an index into a string table, a string_t, but since for
multithreading we'd be growing the string table while looking up stuff,
we'd be looking at realloc'ed memory, so lets move to stable char
pointer strings.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo f84e8777ea core: Convert cu__find_enumeration_by_sname_and_size to search for a string
It looked for an index into a string table, a string_t, but since for
multithreading we'd be growing the string table while looking up stuff,
we'd be looking at realloc'ed memory, so lets move to stable char
pointer strings.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 82e5b5101a core: Make function->name a real string
For the threaded code we want to access strings in tags at the same time
that the string table may grow in another thread making the previous
pointer invalid, so, to avoid excessive locking, use plain strings.

The way the tools work will either consume the just produced CU straight
away or keep just one copy of each data structure when we keep all CUs
in memory, so lets try stopping using strings_t for strings.

For the function->name case we get the bonus of removing the need of a
debug_fmt_ops->function() callback receiving the 'cu', just access the
string directly.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 41a283c65d core: Protect cus->cus with a mutex
Paving the way for having multiple threads creating CUs and possibly
adding them to cus->cus.

The mutex will also be used to ask elfutils-libdwfl to read the next CU,
after a thread finishes reading one.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 972065482a core: Make 'struct cus' opaque, only visible in dwarves.c
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 3895b29060 core: Introduce helper to return number of cu entries in a 'struct cus'
Provide a helper so that we can make 'struct cus' opaque.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 874e750fb8 core: Move cus__find_pair() from codiff to the core
To avoid touching 'struct cus' internal state outside dwarves.c

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo bf74fc1fcf core: Introduce helper to return if there is no cu entries in a 'struct cus'
Provide a helper so that we can make 'struct cus' opaque.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 7020f92143 core: Prepare cus__find_cu_by_name() for locking
By having just one exit point.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 4bf7285b37 core: Prepare cus__find_function_at_addr() for locking
By having just one exit point.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 73a2fd1e5a core: Prepare __cus__find_struct_by_name() for locking
By having just one exit point.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo 5020bf721b core: Prepare cus__find_type_by_name() for locking
By having just one exit point.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:18:16 -03:00
Arnaldo Carvalho de Melo d124926baf core: Initialize cu->priv in cu__new()
cus__load_btf() may bail out if btf__parse_split() fails, for instance
when processing a malformed detached BTF file, and then call
cu__delete(cu) that in turn calls btf__cu_delete(cu->priv), and as
cu->priv wasn't initialized, a segfault ensues.

Fix it by initializing cu->priv in cu__new().

This fix was in the 'next'/'tmp.master' branch and was also found and
fixed by Thomas Weißschuh <thomas@t-8ch.de>.

Link: https://git.kernel.org/pub/scm/devel/pahole/pahole.git/commit/?h=tmp.master&id=e9f3028efbeff225d8ced3c0bfa9fe82857b0a14
Link: https://lore.kernel.org/dwarves/20210728175459.143265-1-thomas@t-8ch.de/
Reported-by: Thomas Weißschuh <thomas@t-8ch.de>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-07-28 15:13:08 -03:00
Arnaldo Carvalho de Melo 790dfbda79 headers: Rebame __unused to __maybe_unused to avoid clashes with system headers
Andrii reported that __unused is a field in /usr/include/bits/stat.h and
vmlinux.h (generated by bpftool), so use the Linux kernel jargon for
this and rename it to '__maybe_unused'.

Reported-by: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-06-13 10:25:35 -03:00
Arnaldo Carvalho de Melo 7fb31d787d btf_loader: Stop using libbtf.h and the btf_elf class
Now we just use libbpf's API to do everything.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-06-04 17:28:56 -03:00
Arnaldo Carvalho de Melo fb418f9d83 dwarves: Make handling of NULL by destructos consistent
All should accept a NULL and bail out, just like free().

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo db37185d16 dwarves: Use zfree()
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo 972001e58e dutil: Adopt zfree(), to use it more pervasively
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo 5847901abf dwarves: Plug leaks in cu__new() found by covscan
Error: GCC_ANALYZER_WARNING (CWE-401):
  dwarves-1.21/dwarves.c: scope_hint: In function 'cu__new'
  dwarves-1.21/dwarves.c:604:16: warning[-Wanalyzer-malloc-leak]: leak of '<unknown>'
  #  602|         }
  #  603|   out:
  #  604|->       return cu;
  #  605|   out_free_name:
  #  606|         free(cu->name);

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo 8772c9d827 dwarves: Accept NULL in cu__delete(), just like free() accepts
To facilitate error handling, where we would be checking for NULL in
multiple places.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo 674063b1ea loaders: Plug enumeration__delete() leak detected by covscan
Error: RESOURCE_LEAK (CWE-772):
  dwarves-1.21/btf_loader.c:293: alloc_fn: Storage is returned from allocation function "type__new".
  dwarves-1.21/btf_loader.c:293: var_assign: Assigning: "enumeration" = storage returned from "type__new(DW_TAG_enumeration_type, tp->name_off, ((*tp).size ? (*tp).size * 8U : 32UL))".
  dwarves-1.21/btf_loader.c:315: noescape: Resource "enumeration" is not freed or pointed-to in "enumeration__delete".
  dwarves-1.21/btf_loader.c:316: leaked_storage: Variable "enumeration" going out of scope leaks the storage it points to.
  #  314|   out_free:
  #  315|         enumeration__delete(enumeration, btfe->priv);
  #  316|->       return -ENOMEM;
  #  317|   }
  #  318|

  Error: RESOURCE_LEAK (CWE-772):
  dwarves-1.21/ctf_loader.c:398: alloc_fn: Storage is returned from allocation function "type__new".
  dwarves-1.21/ctf_loader.c:398: var_assign: Assigning: "enumeration" = storage returned from "type__new(DW_TAG_enumeration_type, ctf__get32(ctf, &tp->base.ctf_name), (size ?: 32UL))".
  dwarves-1.21/ctf_loader.c:421: noescape: Resource "enumeration" is not freed or pointed-to in "enumeration__delete".
  dwarves-1.21/ctf_loader.c:422: leaked_storage: Variable "enumeration" going out of scope leaks the storage it points to.
  #  420|   out_free:
  #  421|         enumeration__delete(enumeration, ctf->priv);
  #  422|->       return -ENOMEM;
  #  423|   }
  #  424|

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-17 16:47:34 -03:00
Arnaldo Carvalho de Melo 505a1f5615 dwarves: Stop using obstacks
When the CTF and later the BTF loaders were implemented they didn't use
obstacks, and then over time some functions, like type__delete(),
class__delete(), enumeration__delete() were shared, which can lead to
crashes by corrupting the obstack by not following its requirements or
to leaks, to avoid such corruption, stop using it.

There is a penalty, but I think its not worth the complexity to keep
using it.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-17 16:20:52 -03:00
Arnaldo Carvalho de Melo b1eaf0da6d dwarves: Make enum prefix search more robust
In function ‘enumeration__calc_prefix’,
      inlined from ‘enumeration__calc_prefix’ at /home/acme/git/pahole/dwarves.c:1661:6:
  /home/acme/git/pahole/dwarves.c:1683:38: warning: ‘strndup’ specified bound 2147483647 exceeds source size 1 [-Wstringop-overread]
   1683 |         enumeration->member_prefix = strndup(curr_name, common_part);
        |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  $ gcc --version | head -1
  gcc (GCC) 11.0.0 20210123 (Red Hat 11.0.0-0)
  $

So check if we actually found the common part, even with that meaning
the enumeration has no entries.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-02 09:30:00 -03:00
Arnaldo Carvalho de Melo bc1afd4585 pahole: Introduce --numeric_version for use in scripts and Makefiles
In Makefiles we want to do purely numeric comparisions, such as in the
Linux kernel Makefiles and scripts, that have things like this at the
moment:

  $ grep PAHOLE */*.sh
  scripts/link-vmlinux.sh:	if ! [ -x "$(command -v ${PAHOLE})" ]; then
  scripts/link-vmlinux.sh:		echo >&2 "BTF: ${1}: pahole (${PAHOLE}) is not available"
  scripts/link-vmlinux.sh:	pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/')
  scripts/link-vmlinux.sh:		echo >&2 "BTF: ${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.16"
  scripts/link-vmlinux.sh:	LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1}
  $

So just provide:

  $ pahole --numeric_version
  118
  $

While keeping the --version output for older Makefiles and scripts.

Cc: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-11-10 13:04:22 -03:00
Arnaldo Carvalho de Melo 784c3dfbd6 dwarves: Switch from a string based version to major/minor numbers
Nothing changes now, this continues to work just the same:

  $ pahole --version
  v1.18
  $ pfunct --version
  v1.18
  $

This just paves the way for us to have a '--numeric-version' that will
do away with the dot and the leading 'v' and that can be used in
Makefiles to check if the required minimum version is available, to
avoid what we have now in the Linux kernel:

  config PAHOLE_HAS_SPLIT_BTF
         def_bool $(success, test `$(PAHOLE) --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/'` -ge "119")

With the next cset we'll be able to do just:

	 test `$(PAHOLE) --numeric-version` -ge "119"

Cc: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-11-10 12:41:42 -03:00
Arnaldo Carvalho de Melo 75f3520fed strings: Rename strings.h to avoid clashing with /usr/include/strings.h
This was detected with:

  In file included from /home/acme/git/pahole/strings.h:9,
                   from /usr/include/string.h:432,
                   from /home/acme/git/pahole/lib/bpf/src/libbpf_common.h:12,
                   from /home/acme/git/pahole/lib/bpf/src/libbpf.h:20,
                   from /home/acme/git/pahole/lib/bpf/src/ringbuf.c:20:
  /home/acme/git/pahole/lib/bpf/src/btf.h:33:11: error: expected ‘;’ before ‘void’
     33 | LIBBPF_API void btf__free(struct btf *btf);
        |           ^~~~~
        |           ;

libbpf_common.h has:

  #include <string.h>

  #ifndef LIBBPF_API
  #define LIBBPF_API __attribute__((visibility("default")))
  #endif

So before defining LIBBPF_API it includes libc's string.h that in turn
includes pahole's strings.h and now it includes:

  #include "lib/bpf/src/btf.h"

That will need the LIBBPF_API, b00m.

So lets just rename pahole's strings.h to pahole_strings.h to avoid this
pitfall.

This patch was moved to before this problem takes place so that we keep
everything bisectable.

Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-10-20 17:11:34 -03:00
Andrii Nakryiko 0a9b89910e dwarves: Expose and maintain active debug info loader operations
Maintain a pointer to debug_fmt_ops corresponding to currently used debug info
format loader (DWARF, BTF, or CTF), to allow various parts of libdwarves to do
things like resolve string offset to actual string pointer in
a format-agnostic format. This allows to, say, load DWARF debug info, and use
it for BTF generation, without either of them making assumptions about how
strings are actually stored internally.

This is going to be used in the next patch to allow BTF loader and encoder to
use a very different way of storing strings (not a global shared gobuffer).

Committer notes:

Since it is available in multiple object files, add a dwarves__ prefix
namespace and add an extern for it in dwarves.h.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-10-09 12:43:40 -03:00
Arnaldo Carvalho de Melo 3d616609ee dwarf_loader: Add minimal handling of DW_TAG_subrange_type
This was found in a ADA object, part of gdb's test suite, for now just
make the code a bit more robust when not finding a type for some struct
member, etc, which avoids segfaults and produces output from ADA
objects, but there are other problems to solve as this is a _type tag, I
need to provide some better support so that type resolution works.

  [foo.debug.gz](https://github.com/acmel/dwarves/files/5257332/foo.debug.gz)

  Foo.debug, an ada exec:
  ```
  $ ~/dwarves/build/pahole foo.debug
  die__process_unit: DW_TAG_subrange_type (0x21) @ <0x10b> not handled!
  die__process_unit: DW_TAG_subrange_type (0x21) @ <0x134> not handled!
  die__process_unit: DW_TAG_subrange_type (0x21) @ <0x148> not handled!
  die__process_class: DW_TAG_subrange_type (0x21) @ <0x201> not handled!
  Segmentation fault (core dumped)
  $

These are fixed, the warnings continue to be produced.

Reported-by: Tom de Vries
Bugtracker: https://github.com/acmel/dwarves/issues/9#issuecomment-696282005
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-09-22 09:51:37 -03:00
Arnaldo Carvalho de Melo f5847773d9 fprintf: Support DW_TAG_string_type
We don't really reconstruct source code for FORTRAN, we just print it as
if it was C:

  $ pahole examples/fortran95/derived-type.debug
  struct bar {
  	integer(kind=4)            c;                    /*     0     4 */
  	real(kind=4)               d;                    /*     4     4 */

  	/* size: 8, cachelines: 1, members: 2 */
  	/* last cacheline: 8 bytes */
  };
  struct foo {
  	real(kind=4)               a;                    /*     0     4 */
  	struct bar                 x;                    /*     4     8 */
  	string                     b[7];                 /*    12     7 */

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

This comes from GCC build tests:

  $ readelf -wi examples/fortran95/derived-type.debug | grep Fortran -A2
      <9c>   DW_AT_producer    : (indirect string, offset: 0x1fb): GNU Fortran2008 10.2.1 20200728 [revision c0438ced53bcf57e4ebb1c38c226e41571aca892] -mtune=generic -march=x86-64 -g -fno-stack-protector -J /home/vries/gdb_versions/devel/build/gdb/testsuite/outputs/gdb.fortran/derived-type -fintrinsic-modules-path /usr/lib64/gcc/x86_64-suse-linux/10/finclude -fpre-include=/usr/include/finclude/math-vector-fortran.h
      <a0>   DW_AT_language    : 14     (Fortran 95)
      <a1>   DW_AT_identifier_case: 2   (down_case)
      <a2>   DW_AT_name        : (indirect string, offset: 0x365): /home/vries/gdb_versions/devel/src/gdb/testsuite/gdb.fortran/derived-type.f90
  [acme@five pahole]$ readelf -wi examples/fortran95/derived-type.debug | grep DW_TAG_string_type -A2
   <1><122>: Abbrev Number: 6 (DW_TAG_string_type)
      <123>   DW_AT_byte_size   : 7
  $

Now lets see whats more that is there segfaulting pahole, but for now I
think I don't have any segfaults, so just wait a bit for Hao to submit
the patch to selectively encode the per-cpu variables in BTF and then
cut v1.18.

Reported-by: Tom de Vries
Bugtracker: https://github.com/acmel/dwarves/issues/9
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-09-18 18:19:22 -03:00
Arnaldo Carvalho de Melo 0d9c3c9835 dwarves: Check if a member type wasn't found and avoid a NULL deref
This dodges a SEGFAULT at type__check_structs_at_unnatural_alignments()
so that we can finish processing, give the warnings and produce as much
as we can:

  $ pahole examples/fortran95/derived-type.debug
  die__process_unit: DW_TAG_string_type (0x12) @ <0x122> not handled!
  namespace__recode_dwarf_types: couldn't find 0x122 type for 0x116 (member)!
  struct bar {
  	integer(kind=4)            c;                    /*     0     4 */
  	real(kind=4)               d;                    /*     4     4 */

  	/* size: 8, cachelines: 1, members: 2 */
  	/* last cacheline: 8 bytes */
  };
  struct foo {
  	real(kind=4)               a;                    /*     0     4 */
  	struct bar                 x;                    /*     4     8 */
  	<ERROR(__class__fprintf:1519): 0 not found!>

  	/* size: 20, cachelines: 1, members: 3 */
  	/* padding: 8 */
  	/* last cacheline: 20 bytes */
  };
  $

Reported-by: Tom de Vries
Bugtracker: https://github.com/acmel/dwarves/issues/9
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-09-18 17:29:24 -03:00
Arnaldo Carvalho de Melo fda1825f0b dwarves: Introduce tag_cu_node, so that we can have the leaner tag_cu
With just tag + cu pointers.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo c50b6d37e9 pahole: Add infrastructure to have multiple concatenated type_enum
As sometimes we have multiple enums to represent some struct type, like
with perf_event_attr->type, that has 'enum perf_event_type' in Linux's
UAPI and 'enum perf_user_event_type' for purely userspace types, like
the ones synthesized for Intel PT, like PERF_RECORD_AUXTRACE, etc.

This patch just transforms type->type_enum into a list, the support for
multiple types comes next.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo dd3c0e9eb0 dwarves: Move the common initialization of fields for 'struct type'
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo 4ece15c37b dwarves: Find common enumerators prefix
Allowing for filters such as 'type==MMAP', equivalent to
'type==PERF_RECORD_MMAP'.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo 7c12b234ee dwarves: Introduce cus__find_type_by_name()
To find a type in all CUs.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo 163c330d31 dwarves: Introduce cu__find_enumeration_by_name()
We'll use it in an upcoming feature, to pretty print fields that albeit
not declared as an enum, have values coming from one.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-08-05 15:16:19 -03:00
Arnaldo Carvalho de Melo 1b2cdda38c dwarves: Introduce tag__is_array()
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-06-27 09:40:51 -03:00
Arnaldo Carvalho de Melo cc65946e30 dwarves: Adopt tag__is_base_type() from ctrace.c
We'll need it in pahole when pretty printing raw data as structs, etc.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-06-24 14:14:33 -03:00
Arnaldo Carvalho de Melo 0b2621d426 dwarves: Avoid truncation when concatenating paths for dir entries
To cope with this warning on s390x:

  /usr/bin/cc -DDWARVES_VERSION=\"v1.16\" -D_GNU_SOURCE -Ddwarves_EXPORTS -I/builddir/build/BUILD/dwarves-1.16 -I/builddir/build/BUILD/dwarves-1.16/lib/bpf/include/uapi  -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=zEC12 -mtune=z13 -fasynchronous-unwind-tables -fstack-clash-protection -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Werror -ggdb -O2 -fPIC   -o CMakeFiles/dwarves.dir/libctf.c.o   -c /builddir/build/BUILD/dwarves-1.16/libctf.c
  /builddir/build/BUILD/dwarves-1.16/dwarves.h: In function 'cus__load_dir':
  /builddir/build/BUILD/dwarves-1.16/dwarves.c:1663:44: error: '%s' directive output may be truncated writing up to 255 bytes into a region of size between 0 and 4095 [-Werror=format-truncation=]
   1663 |   snprintf(pathname, sizeof(pathname), "%s/%s",
        |                                            ^~
  In file included from /usr/include/stdio.h:867,
                   from /builddir/build/BUILD/dwarves-1.16/dwarves.c:18:
  /usr/include/bits/stdio2.h:67:10: note: '__builtin___snprintf_chk' output between 2 and 4352 bytes into a destination of size 4096
     67 |   return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
        |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     68 |        __bos (__s), __fmt, __va_arg_pack ());
        |        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  /builddir/build/BUILD/dwarves-1.16/dwarves.c:1663:44: error: '%s' directive output may be truncated writing up to 255 bytes into a region of size between 0 and 4095 [-Werror=format-truncation=]
   1663 |   snprintf(pathname, sizeof(pathname), "%s/%s",
        |                                            ^~
  In file included from /usr/include/stdio.h:867,
                   from /builddir/build/BUILD/dwarves-1.16/dwarves.c:18:
  /usr/include/bits/stdio2.h:67:10: note: '__builtin___snprintf_chk' output between 2 and 4352 bytes into a destination of size 4096

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-02-12 16:28:49 -03:00
Arnaldo Carvalho de Melo d7b3510795 dwarves: Don't use conf if its NULL in cus__load_running_kernel()
Don't use it if NULL, fixing a segfault with dtagnames as reported in:

https://bugzilla.redhat.com/show_bug.cgi?id=1795379

Reported-by: Jan Pokorný <jpokorny@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-02-12 16:10:09 -03:00
Arnaldo Carvalho de Melo dde3eb086d dwarves: Make list__for_all_tags() more robust
Return if passed a zeroed list or an empty one.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-02-12 16:04:31 -03:00
Arnaldo Carvalho de Melo ded5d36f9c dwarves: Introduce cu__find_type_by_name
To look at all the 'struct type' descendants, like enums, typedefs,
structs, unions, etc.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-15 13:45:47 -03:00
Arnaldo Carvalho de Melo 617f5ac2e6 dwarves: Move BTF loader ahead of the CTF one
When we call the tools without specifying a file format, all the
available format loaders are called, in sequence, till we find the
relevant information, now that we support raw BTF we better move it in
front of the CTF one, as it is way more common in the Linux community.

With this we will not see this warning anymore:

  $ pahole -C list_head  /sys/kernel/btf/vmlinux
  ctf__new: cannot get elf header.
  struct list_head {
  	struct list_head *         next;                 /*     0     8 */
  	struct list_head *         prev;                 /*     8     8 */

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

That warning has to go, so that other formats, if present after the CTF
one, can be tried.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-06 13:09:27 -03:00
Arnaldo Carvalho de Melo cdd5e1399b btf loader: Support raw BTF as available in /sys/kernel/btf/vmlinux
Be it automatically when no -F option is passed and
/sys/kernel/btf/vmlinux is available, or when /sys/kernel/btf/vmlinux is
passed as the filename to the tool, i.e.:

  $ pahole -C list_head
  struct list_head {
  	struct list_head *         next;                 /*     0     8 */
  	struct list_head *         prev;                 /*     8     8 */

  	/* size: 16, cachelines: 1, members: 2 */
  	/* last cacheline: 16 bytes */
  };
  $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/
  openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3
  $
  $ pahole -C list_head /sys/kernel/btf/vmlinux
  struct list_head {
  	struct list_head *         next;                 /*     0     8 */
  	struct list_head *         prev;                 /*     8     8 */

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

If one wants to grab the matching vmlinux to use its DWARF info instead,
which is useful to compare the results with what we have from BTF, for
instance, its just a matter of using '-F dwarf'.

This in turn shows something that at first came as a surprise, but then
has a simple explanation:

For very common data structures, that will probably appear in all of the
DWARF CUs (Compilation Units), like 'struct list_head', using '-F dwarf'
is faster:

  [acme@quaco pahole]$ perf stat -e cycles pahole -F btf -C list_head > /dev/null

   Performance counter stats for 'pahole -F btf -C list_head':

          45,722,518      cycles:u

         0.023717300 seconds time elapsed

         0.016474000 seconds user
         0.007212000 seconds sys

  [acme@quaco pahole]$ perf stat -e cycles pahole -F dwarf -C list_head > /dev/null

   Performance counter stats for 'pahole -F dwarf -C list_head':

          14,170,321      cycles:u

         0.006668904 seconds time elapsed

         0.005562000 seconds user
         0.001109000 seconds sys

  [acme@quaco pahole]$

But for something that is more specific to a subsystem, the DWARF loader
will have to process way more stuff till it gets to that struct:

  $ perf stat -e cycles pahole -F dwarf -C tcp_sock > /dev/null

   Performance counter stats for 'pahole -F dwarf -C tcp_sock':

      31,579,795,238      cycles:u

         8.332272930 seconds time elapsed

         8.032124000 seconds user
         0.286537000 seconds sys

  $

While using the BTF loader the time should be constant, as it loads
everything from /sys/kernel/btf/vmlinux:

  $ perf stat -e cycles pahole -F btf -C tcp_sock > /dev/null

   Performance counter stats for 'pahole -F btf -C tcp_sock':

          48,823,488      cycles:u

         0.024102760 seconds time elapsed

         0.012035000 seconds user
         0.012046000 seconds sys

  $

Above I used '-F btf' just to show that it can be used, but its not
really needed, i.e. those are equivalent:

  $ strace -e openat pahole -F btf -C list_head |& grep /sys/kernel/btf/vmlinux
  openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3
  $ strace -e openat pahole -C list_head |& grep /sys/kernel/btf/vmlinux
  openat(AT_FDCWD, "/sys/kernel/btf/vmlinux", O_RDONLY) = 3
  $

The btf_raw__load() function that ends up being grafted into the
preexisting btf_elf routines was based on libbpf's btf_load_raw().

Acked-by: Alexei Starovoitov <ast@fb.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2020-01-06 13:09:16 -03:00
Arnaldo Carvalho de Melo 5c590fc29d ptr_table: Zero out new id ranges
Since we iterate over these ptr_tables entry by entry, we better zero
out the new ranges, i.e. whatever is after the previous allocated space
up to the new one, returned by realloc.

Fixes a bug found using pahole -F btf on a vmlinux file, now btfdiff on
this same file comes clean, i.e. the output from its BTF tags is the
same as with its DWARF ones, for the features present in both type
information formats.

Tested-by: Alexei Starovoitov <ast@fb.com>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-12-16 11:19:07 -03:00
Gareth Lloyd be37b64aef dwarves: Ignore static members for alignment
It was possible to have an infinite loop trying to determine the
alignment of a type that had a static data member of its own type.

Example code illustrating the problem.
struct X { static X thing; };

Committer testing:

Before:

  $ pwd
  /home/acme/git/pahole/examples/gareth
  $ cat static_member.cpp
  struct X { static X thing; };

  static struct X f;
  $ g++ -g -c static_member.cpp -o static_member.o
  $ pahole static_member.o
  Segmentation fault (core dumped)
  $

After:

  $ pahole static_member.o
  struct X {
  	static struct X           thing;                 /*     0     0 */

  	/* XXX last struct has 1 byte of padding */

  	/* size: 1, cachelines: 0, members: 0, static members: 1 */
  	/* padding: 1 */
  	/* paddings: 1, sum paddings: 1 */
  	/* last cacheline: 1 bytes */
  };
  $

Signed-off-by: Gareth Lloyd <gareth.lloyd@uk.ibm.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-11-12 17:47:50 -03:00
Arnaldo Carvalho de Melo ccf3eebfcd btf_loader: Add support for BTF_KIND_FUNC
Some changes to the fprintf routines were needed, as BTF has as the
function type just a BTF_KIND_FUNC_PROTO, while DWARF has as the type
for a function its return value type. With a function->btf flag this was
overcome and all the other goodies in pfunct are present, for instance:

  $ pahole -JV examples/tcp.o | grep -w FUNC | head
  [4068] FUNC tcp_init type_id=4067
  [4070] FUNC tcp_abort type_id=4069
  [4072] FUNC tcp_done type_id=4071
  [4074] FUNC tcp_md5_hash_key type_id=4073
  [4076] FUNC tcp_md5_hash_skb_data type_id=4075
  [4078] FUNC tcp_get_md5sig_pool type_id=4077
  [4080] FUNC tcp_alloc_md5sig_pool type_id=4079
  [4082] FUNC compat_tcp_getsockopt type_id=4081
  [4084] FUNC tcp_getsockopt type_id=4083
  [4086] FUNC tcp_get_timestamping_opt_stats type_id=4085
  $

  $ pfunct -F btf examples/tcp.o  | head
  memset
  memcpy
  tcp_enter_memory_pressure
  tcp_leave_memory_pressure
  tcp_init_sock
  tcp_init_transfer
  tcp_poll
  tcp_ioctl
  tcp_splice_read
  sk_stream_alloc_skb
  $

  $ pfunct --prototype -F btf examples/tcp.o | head
  void * memset(void * p, int c, __kernel_size_t size);
  void * memcpy(void * p, const void  * q, __kernel_size_t size);
  void tcp_enter_memory_pressure(struct sock * sk);
  void tcp_leave_memory_pressure(struct sock * sk);
  void tcp_init_sock(struct sock * sk);
  void tcp_init_transfer(struct sock * sk, int bpf_op);
  __poll_t tcp_poll(struct file * file, struct socket * sock, poll_table * wait);
  int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
  ssize_t tcp_splice_read(struct socket * sock, loff_t * ppos, struct pipe_inode_info * pipe, size_t len, unsigned int flags);
  struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
  $

Now to ask just for the 'struct sock' 'methods', i.e. functions that
have as one of its arguments a pointer to the given 'class' name:

  $ pfunct --class sock -F btf examples/tcp.o | head
  tcp_abort
  tcp_done
  compat_tcp_getsockopt
  tcp_getsockopt
  tcp_get_info
  compat_tcp_setsockopt
  tcp_setsockopt
  tcp_disconnect
  tcp_write_queue_purge
  tcp_close
  $

Then ask for the prototypes, which requires -V, should have that fixed:

  $ pfunct -V --prototypes --class sock -F btf examples/tcp.o | head
  int tcp_abort(struct sock * sk, int err);
  void tcp_done(struct sock * sk);
  int compat_tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
  int tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
  void tcp_get_info(struct sock * sk, struct tcp_info * info);
  int compat_tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
  int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
  int tcp_disconnect(struct sock * sk, int flags);
  void tcp_write_queue_purge(struct sock * sk);
  void tcp_close(struct sock * sk, long int timeout);
  $

Don't like prototypes with parm names, got you covered:

  $ pfunct --no_parm_names -V --prototypes --class sock -F btf examples/tcp.o | head
  int tcp_abort(struct sock *, int);
  void tcp_done(struct sock *);
  int compat_tcp_getsockopt(struct sock *, int, int, char *, int *);
  int tcp_getsockopt(struct sock *, int, int, char *, int *);
  void tcp_get_info(struct sock *, struct tcp_info *);
  int compat_tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
  int tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
  int tcp_disconnect(struct sock *, int);
  void tcp_write_queue_purge(struct sock *);
  void tcp_close(struct sock *, long int);
  $

Don't like long options and want just one function?

  $ pfunct -f tcp_setsockopt -F btf examples/tcp.o
  int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
  $

Want to generate compileable code for all of those functions, full with
the necessary types, etc?

  $ pfunct -F btf --compile examples/tcp.o  > a.c
  $ gcc -c -o a.o a.c
  $ pfunct -F dwarf --prototypes --class sock a.o | head
  pfunct: a.o: No debugging information found
  $ gcc -g -c -o a.o a.c
  $ pfunct -V -F dwarf --prototypes --class sock a.o | head
  void tcp_enter_memory_pressure(struct sock * sk);
  void tcp_leave_memory_pressure(struct sock * sk);
  void tcp_init_sock(struct sock * sk);
  void tcp_init_transfer(struct sock * sk, int bpf_op);
  int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
  struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
  ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
  int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
  int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
  int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
  $

Now lets go full circle and encode BTF for this a.o generated from
source code generated from the original BTF info in that examples/tcp.o
file:

  $ pahole -JV a.o | tail
  [465] FUNC_PROTO (anon) return=35 args=(392 hp, 393 skb, 5 header_len)
  [466] FUNC tcp_md5_hash_skb_data type_id=465
  [467] FUNC_PROTO (anon) return=35 args=(392 hp, 394 key)
  [468] FUNC tcp_md5_hash_key type_id=467
  [469] FUNC_PROTO (anon) return=0 args=(49 sk)
  [470] FUNC tcp_done type_id=469
  [471] FUNC_PROTO (anon) return=35 args=(49 sk, 35 err)
  [472] FUNC tcp_abort type_id=471
  [473] FUNC_PROTO (anon) return=0 args=(void)
  [474] FUNC tcp_init type_id=473
  $

  $ pfunct -F btf -V --prototypes --class=sock a.o | head
  void tcp_enter_memory_pressure(struct sock * sk);
  void tcp_leave_memory_pressure(struct sock * sk);
  void tcp_init_sock(struct sock * sk);
  void tcp_init_transfer(struct sock * sk, int bpf_op);
  int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
  struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
  ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
  int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
  int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
  int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
  $

Curious about the code generated by 'pfunct -F btf --compile examples/tcp.o?

  http://vger.kernel.org/~acme/pahole/pfunct-F-BTF--compile-examples-tcp.o.txt

Cc: Alexei Starovoitov <ast@fb.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-11-05 12:04:23 -03:00
Arnaldo Carvalho de Melo 5965ce015e dwarves: Fix ptr_table__add_with_id() handling of pt->nr_entries
To agree with what ptr_table__add() does, i.e. the number of entries
(pt->nr_entries) is in fact the max id number in the table + 1, we can't
allow to add an id that is not contiguous and simply increment
nr_entries, as cu__for_each_variable(cu, id, pos) will iterate based on
nr_entries, skipping NULL buckets.

Detected when adding support for BTF variables, that share the id space
with types, but end up in different ptr_tables, so we end up with:

    cu__table_add_tag(BTF_KIND_VAR)
	ptr_table__add_with_id(cu->tags_table)

but:

     cu__table_add_tag()
	ptr_table__add_with_id(cu->types_table)

for all the other BTF_KIND_s, fix it so that ptr->nr_entries copes with
not receiving strictly monotonically incremented by one ids.

We'll have to fix this more properly by defining which tags are
supported by some debugging format and this what should go to a
ptr_table so that we have all its entries monononically incremented by
one and avoid tag__check_id_drift() returning true in the per debugging
format encoders (e.g.: btf_encoder.c).

This patch allows us to move forward and apply the BTF_KIND_VAR patch
where we'll at least produce, for global variables and a simple BPF
program with both DWARF and BTF tags the same results:

  [root@quaco tracebuffer]# pglobal -F dwarf -v bristot.o
  struct ____btf_map_tracebuffer__bristot ____btf_map_tracebuffer__bristot;; /* 0 */

  char                       _license[4];; /* 0 */

  int                        _version;; /* 0 */

  struct bpf_map     tracebuffer__bristot;; /* 0 */

  [root@quaco tracebuffer]# pglobal -F btf -v bristot.o
  BTF: idx: 17, off: 352, Unknown kind 15
  BTF: idx: 18, off: 364, Unknown kind 0
  BTF: idx: 19, off: 376, Unknown kind 15
  BTF: idx: 20, off: 388, Unknown kind 0
  BTF: idx: 21, off: 400, Unknown kind 15
  BTF: idx: 22, off: 412, Unknown kind 0
  BTF: idx: 23, off: 424, Unknown kind 15
  BTF: idx: 24, off: 436, Unknown kind 0
  struct ____btf_map_tracebuffer__bristot ____btf_map_tracebuffer__bristot;; /* 0 */

  char                       _license[4];; /* 0 */

  int                        _version;; /* 0 */

  struct bpf_map     tracebuffer__bristot;; /* 0 */

  [root@quaco tracebuffer]#

Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Daniel Bristot de Oliveira <bristot@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-10-24 16:56:40 -03:00
Arnaldo Carvalho de Melo fe87354c31 dwarves: Ditch unused asprintf() function
Not used at all, brought when adding vmlinux searching, but ended up not
being used, ditch it.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-07-02 10:25:43 -03:00