Commit Graph

1594 Commits

Author SHA1 Message Date
Arnaldo Carvalho de Melo d0f6a4a1da gobuffer: Use zfree() and make delete accept NULL, 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 e7e86c75e1 libbtf: 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 32114e611a dwarf_loader: Call dwarf_cu__delete() when aborting the load
Addressing these covscan report entry:

  Error: GCC_ANALYZER_WARNING (CWE-401):
  dwarves-1.21/dwarf_loader.c:2645:40: warning[-Wanalyzer-malloc-leak]: leak of 'dcu'
  # 2643|                                      filename);
  # 2644|                         if (cu == NULL || cu__set_common(cu, conf, mod, elf) != 0)
  # 2645|->                         	return DWARF_CB_ABORT;
  # 2646|
  # 2647|                         dcu = malloc(sizeof(struct dwarf_cu));

  Error: RESOURCE_LEAK (CWE-772):
  dwarves-1.21/dwarf_loader.c:2647: alloc_fn: Storage is returned from allocation function "malloc".
  dwarves-1.21/dwarf_loader.c:2647: var_assign: Assigning: "dcu" = storage returned from "malloc(120UL)".
  dwarves-1.21/dwarf_loader.c:2663: leaked_storage: Variable "dcu" going out of scope leaks the storage it points to.
  # 2661|                         }
  # 2662|                         if (hashtags__bits < default_hbits)
  # 2663|->                               return DWARF_CB_ABORT;
  # 2664|
  # 2665|                         dcu->cu = cu;

  Error: CLANG_WARNING:
  dwarves-1.21/dwarf_loader.c:2663:12: warning[unix.Malloc]: Potential leak of memory pointed to by 'dcu'
  # 2661|                         }
  # 2662|                         if (hashtags__bits < default_hbits)
  # 2663|->                               return DWARF_CB_ABORT;
  # 2664|
  # 2665|                         dcu->cu = cu;

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo 26bd4c4164 dwarf_loader: Delete the allocated CU when aborting
As in this case we're not adding it to the cus->cus in
finalize_cu_immediately().

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo d8940df90b dwarf_loader: Make all ABORT returns go thru a single exit label
No change in logic, just prepping the way for proper deletion of
objects.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo 3ba54ee43a dwarf_loader: Use zalloc() to allocate dwarf_cu
We were allocating it with malloc and then trying to initialize it with
dwarf_cu__init(), which may fail and leave the dwarf_cu instance not
completely initialized which would lead to problems when calling
dwarf_cu__delete(), use zalloc to make sure all is zeroed.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo f3957627bb dwarf_loader: Make dwarf_cu__delete() accept NULL, just like free()
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 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 25cc0c7754 dwarf_loader: Check if we have a CU after the loop in cus__merge_and_process_cu()
Theoretically possible, silences covscan/gcc analyser:

  Error: GCC_ANALYZER_WARNING (CWE-476):
  dwarves-1.21/dwarf_loader.c:2218:27: warning[-Wanalyzer-null-dereference]: dereference of NULL 'cu'
  # 2216|         uint32_t i;
  # 2217|
  # 2218|->       for (i = 0; i < pt->nr_entries; ++i) {
  # 2219|                 struct tag *tag = pt->entries[i];
  # 2220|

  Error: CLANG_WARNING:
  dwarves-1.21/dwarf_loader.c:2245:13: warning[core.NullDereference]: Access to field 'nr_entries' results in a dereference of a null pointer (loaded from variable 'pt')
  # 2243|                                         uint32_t i)
  # 2244|   {
  # 2245|->       for (; i < pt->nr_entries; ++i) {
  # 2246|                 struct tag *tag = pt->entries[i];

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo 2f30062b54 dwarf_loader: Check tag__recode_dwarf_bitfield() return, may be NULL
Found by covscan:

  Error: GCC_ANALYZER_WARNING (CWE-476):
  dwarves-1.21/dwarf_loader.c:718:29: warning[-Wanalyzer-null-dereference]: dereference of NULL 'dtype'
  #  716|                 struct dwarf_tag *dtype = dwarf_cu__find_type_by_ref(cu->priv,
  #  717|                                                                      &dtag->type);
  #  718|->               struct tag *type = dtype->tag;
  #  719|
  #  720|                 id = tag__recode_dwarf_bitfield(type, cu, bit_size);

  Error: GCC_ANALYZER_WARNING (CWE-476):
  dwarves-1.21/dwarf_loader.c:740:29: warning[-Wanalyzer-null-dereference]: dereference of NULL 'dtype'
  #  738|                 const struct dwarf_tag *dtag = tag->priv;
  #  739|                 struct dwarf_tag *dtype = dwarf_cu__find_type_by_ref(cu->priv, &dtag->type);
  #  740|->               struct tag *type = dtype->tag;
  #  741|
  #  742|                 id = tag__recode_dwarf_bitfield(type, cu, bit_size);

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo d68fd2bbc5 ctracer: Initialize the 'parm_list' variable, detected by covscan
It may be used uninitialized, fix it.

  Error: UNINIT (CWE-457):
  dwarves-1.21/ctracer.c:401: var_decl: Declaring variable "parm_list" without initializer.
  dwarves-1.21/ctracer.c:470: uninit_use_in_call: Using uninitialized value "*parm_list" as argument to "%s" when calling "fprintf". [Note: The source code implementation of the function has been overridden by a builtin model.]
  #  468|                                                1, "entry,exit");
  #  469|         }
  #  470|->       fprintf(fp_converter,
  #  471|                 "\\n\",\n\t\t\t %s);\n"
  #  472|                 "\t}\n"

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo 5b0fb9745e codiff: Fix usage of negative errno values with strerror(), reported by covscan
Error: NEGATIVE_RETURNS (CWE-394):
  dwarves-1.21/codiff.c:816: negative_return_fn: Function "cus__load_file(old_cus, &conf_load, old_filename)" returns a negative number.
  dwarves-1.21/codiff.c:816: assign: Assigning: "err" = "cus__load_file(old_cus, &conf_load, old_filename)".
  dwarves-1.21/codiff.c:818: negative_returns: "err" is passed to a parameter that cannot be negative.
  #  816|                 err = cus__load_file(old_cus, &conf_load, old_filename);
  #  817|                 if (err != 0) {
  #  818|->                       cus__print_error_msg("codiff", old_cus, old_filename, err);
  #  819|                         goto out_cus_delete_priv;
  #  820|                 }

  Error: NEGATIVE_RETURNS (CWE-394):
  dwarves-1.21/codiff.c:830: negative_return_fn: Function "cus__load_file(new_cus, &conf_load, new_filename)" returns a negative number.
  dwarves-1.21/codiff.c:830: assign: Assigning: "err" = "cus__load_file(new_cus, &conf_load, new_filename)".
  dwarves-1.21/codiff.c:832: negative_returns: "err" is passed to a parameter that cannot be negative.
  #  830|                 err = cus__load_file(new_cus, &conf_load, new_filename);
  #  831|                 if (err != 0) {
  #  832|->                       cus__print_error_msg("codiff", new_cus, new_filename, err);
  #  833|                         goto out_cus_delete_priv;
  #  834|                 }

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:18 -03:00
Arnaldo Carvalho de Melo cba940fb86 btf_loader: Fix some memory leaks found by covscan
Error: RESOURCE_LEAK (CWE-772):
  dwarves-1.21/btf_loader.c:554: alloc_fn: Storage is returned from allocation function "btf_elf__new".
  dwarves-1.21/btf_loader.c:554: var_assign: Assigning: "btfe" = storage returned from "btf_elf__new(filename, NULL, base_btf)".
  dwarves-1.21/btf_loader.c:561: leaked_storage: Variable "btfe" going out of scope leaks the storage it points to.
  #  559|         struct cu *cu = cu__new(filename, btfe->wordsize, NULL, 0, filename);
  #  560|         if (cu == NULL)
  #  561|->               return -1;
  #  562|
  #  563|         cu->language = LANG_C;

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-27 11:00:14 -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
Sevan Janiyan 872658b880 CMakeLists.txt: Specify the file extension of srcs
cmake complains about policy CMP0115 otherwise.

Signed-off-by: Sevan Janiyan <venture37@geeklan.co.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-10 21:32:16 -03:00
Sevan Janiyan aa8519378a README: Mention how to specify another prefix
Signed-off-by: Sevan Janiyan <venture37@geeklan.co.uk>
Link: https://github.com/acmel/dwarves/pull/20
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-10 21:32:13 -03:00
Martin KaFai Lau 58a98f76ac btf: Remove ftrace filter
BTF is currently generated for functions that are in ftrace list
or extern.

A recent use case also needs BTF generated for functions included in
allowlist.

In particular, the kernel commit:

  e78aea8b2170 ("bpf: tcp: Put some tcp cong functions in allowlist for bpf-tcp-cc")

allows bpf program to directly call a few tcp cc kernel functions. Those
kernel functions are currently allowed only if CONFIG_DYNAMIC_FTRACE
is set to ensure they are in the ftrace list but this kconfig dependency
is unnecessary.

Those kernel functions are specified under an ELF section .BTF_ids.
There was an earlier attempt [0] to add another filter for the functions in
the .BTF_ids section.  That discussion concluded that the ftrace filter
should be removed instead.

This patch is to remove the ftrace filter and its related functions.

Number of BTF FUNC with and without is_ftrace_func():
My kconfig in x86: 40643 vs 46225
Jiri reported on arm: 25022 vs 55812

[0]: https://lore.kernel.org/dwarves/20210423213728.3538141-1-kafai@fb.com/

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Tested-by: Nathan Chancellor <nathan@kernel.org> # build
Acked-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Jiri Slaby <jirislaby@kernel.org>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-05-08 11:26:29 -03:00
Arnaldo Carvalho de Melo 7c60b0443c pahole: Fix error message when --header couldn't be read
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-14 12:32:58 -03:00
Arnaldo Carvalho de Melo 7eea706c14 pahole: Introduce --with_flexible_array option to show just types ending in a flexible array
The kernel has lotsa:

  $ pahole --sizes --with_flexible_array | wc -l
  1134
  $

  $ pahole --with_flexible_array | tail -18
  struct pci_setup_rom {
  	struct setup_data          data;                 /*     0    16 */
  	uint16_t                   vendor;               /*    16     2 */
  	uint16_t                   devid;                /*    18     2 */

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

  	uint64_t                   pcilen;               /*    24     8 */
  	long unsigned int          segment;              /*    32     8 */
  	long unsigned int          bus;                  /*    40     8 */
  	long unsigned int          device;               /*    48     8 */
  	long unsigned int          function;             /*    56     8 */
  	/* --- cacheline 1 boundary (64 bytes) --- */
  	uint8_t                    romdata[];            /*    64     0 */

  	/* size: 64, cachelines: 1, members: 9 */
  	/* sum members: 60, holes: 1, sum holes: 4 */
  };
  $

Works together with other filters:

  $ pahole --contains setup_data --with_flexible_array
  pci_setup_rom
  $ pahole pci_setup_rom
  struct pci_setup_rom {
  	struct setup_data          data;                 /*     0    16 */
  	uint16_t                   vendor;               /*    16     2 */
  	uint16_t                   devid;                /*    18     2 */

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

  	uint64_t                   pcilen;               /*    24     8 */
  	long unsigned int          segment;              /*    32     8 */
  	long unsigned int          bus;                  /*    40     8 */
  	long unsigned int          device;               /*    48     8 */
  	long unsigned int          function;             /*    56     8 */
  	/* --- cacheline 1 boundary (64 bytes) --- */
  	uint8_t                    romdata[];            /*    64     0 */

  	/* size: 64, cachelines: 1, members: 9 */
  	/* sum members: 60, holes: 1, sum holes: 4 */
  };
  $

  $ pahole --find_pointers_to net_device --with_flexible_array
  neighbour: dev
  pneigh_entry: dev
  xsk_buff_pool: netdev
  cfg80211_sched_scan_request: dev
  switchdev_deferred_item: dev
  $ pahole xsk_buff_pool
  struct xsk_buff_pool {
  	struct device *            dev;                  /*     0     8 */
  	struct net_device *        netdev;               /*     8     8 */
  	struct list_head           xsk_tx_list;          /*    16    16 */
  	spinlock_t                 xsk_tx_list_lock;     /*    32     4 */
  	refcount_t                 users;                /*    36     4 */
  	struct xdp_umem *          umem;                 /*    40     8 */
  	struct work_struct         work;                 /*    48    32 */
  	/* --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- */
  	struct list_head           free_list;            /*    80    16 */
  	u32                        heads_cnt;            /*    96     4 */
  	u16                        queue_id;             /*   100     2 */

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

  	/* --- cacheline 2 boundary (128 bytes) --- */
  	struct xsk_queue *         fq;                   /*   128     8 */
  	struct xsk_queue *         cq;                   /*   136     8 */
  	dma_addr_t *               dma_pages;            /*   144     8 */
  	struct xdp_buff_xsk *      heads;                /*   152     8 */
  	u64                        chunk_mask;           /*   160     8 */
  	u64                        addrs_cnt;            /*   168     8 */
  	u32                        free_list_cnt;        /*   176     4 */
  	u32                        dma_pages_cnt;        /*   180     4 */
  	u32                        free_heads_cnt;       /*   184     4 */
  	u32                        headroom;             /*   188     4 */
  	/* --- cacheline 3 boundary (192 bytes) --- */
  	u32                        chunk_size;           /*   192     4 */
  	u32                        frame_len;            /*   196     4 */
  	u8                         cached_need_wakeup;   /*   200     1 */
  	bool                       uses_need_wakeup;     /*   201     1 */
  	bool                       dma_need_sync;        /*   202     1 */
  	bool                       unaligned;            /*   203     1 */

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

  	void *                     addrs;                /*   208     8 */
  	spinlock_t                 cq_lock;              /*   216     4 */

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

  	struct xdp_buff_xsk *      free_heads[];         /*   224     0 */

  	/* size: 256, cachelines: 4, members: 29 */
  	/* sum members: 190, holes: 3, sum holes: 34 */
  	/* padding: 32 */
  };
  $

Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-12 13:52:34 -03:00
Arnaldo Carvalho de Melo 25ad41e7b5 pahole: Prep 1.21
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-09 19:39:15 -03:00
Andrii Nakryiko c3ee1fcd49 spec: Fix dates in RPM spec
Two dates have invalid days of the week. Fix that.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-09 16:10:10 -03:00
Yonghong Song ae0b7dde1f dwarf_loader: Handle DWARF5 DW_OP_addrx properly
Currently, when DWARF5 is enabled in kernel, DEBUG_INFO_BTF needs to be
disabled. I hacked the kernel to enable DEBUG_INFO_BTF like:

  --- a/lib/Kconfig.debug
  +++ b/lib/Kconfig.debug
  @@ -286,7 +286,6 @@ config DEBUG_INFO_DWARF5
          bool "Generate DWARF Version 5 debuginfo"
          depends on GCC_VERSION >= 50000 || CC_IS_CLANG
          depends on CC_IS_GCC || $(success,$(srctree)/scripts/test_dwarf5_support.sh $(CC) $(CLANG_FLAGS))
  -       depends on !DEBUG_INFO_BTF
          help

and tried DWARF5 with latest trunk clang, thin-LTO and no LTO.

In both cases, I got a few additional failures like:

  $ ./test_progs -n 55/2
  ...
  libbpf: extern (var ksym) 'bpf_prog_active': failed to find BTF ID in kernel BTF(s).
  libbpf: failed to load object 'kfunc_call_test_subprog'
  libbpf: failed to load BPF skeleton 'kfunc_call_test_subprog': -22
  test_subprog:FAIL:skel unexpected error: 0
  #55/2 subprog:FAIL

Here, bpf_prog_active is a percpu global variable and pahole is supposed to
put into BTF, but it is not there.

Further analysis shows this is due to encoding difference between DWARF4
and DWARF5. In DWARF5, a new section .debug_addr and several new ops,
e.g. DW_OP_addrx, are introduced.  DW_OP_addrx is actually an index into
.debug_addr section starting from an offset encoded with DW_AT_addr_base
in DW_TAG_compile_unit.

For the above 'bpf_prog_active' example, with DWARF4, we have

  0x02281a96:   DW_TAG_variable
                  DW_AT_name      ("bpf_prog_active")
                  DW_AT_decl_file ("/home/yhs/work/bpf-next/include/linux/bpf.h")
                  DW_AT_decl_line (1170)
                  DW_AT_decl_column       (0x01)
                  DW_AT_type      (0x0226d171 "int")
                  DW_AT_external  (true)
                  DW_AT_declaration       (true)

  0x02292f04:   DW_TAG_variable
                  DW_AT_specification     (0x02281a96 "bpf_prog_active")
                  DW_AT_decl_file ("/home/yhs/work/bpf-next/kernel/bpf/syscall.c")
                  DW_AT_decl_line (45)
                  DW_AT_location  (DW_OP_addr 0x28940)

For DWARF5, we have

  0x0138b0a1:   DW_TAG_variable
                  DW_AT_name      ("bpf_prog_active")
                  DW_AT_type      (0x013760b9 "int")
                  DW_AT_external  (true)
                  DW_AT_decl_file ("/home/yhs/work/bpf-next/kernel/bpf/syscall.c")
                  DW_AT_decl_line (45)
                  DW_AT_location  (DW_OP_addrx 0x16)

This patch added support for DW_OP_addrx. With the patch, the above
failing bpf selftest and other similar failed selftests succeeded.

Signed-off-by: Yonghong Song <yhs@fb.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Bill Wendling <morbo@google.com>
Cc: David Blaikie <dblaikie@gmail.com>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: Sedat Dilek <sedat.dilek@gmail.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Link: https://lore.kernel.org/r/20210403184158.2834387-1-yhs@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-06 10:10:29 -03:00
Yonghong Song 9adb014930 dwarf_loader: Handle subprogram ret type with abstract_origin properly
With latest bpf-next built with clang LTO (thin or full), I hit one test
failures:

  $ ./test_progs -t tcp
  ...
  libbpf: extern (func ksym) 'tcp_slow_start': func_proto [23] incompatible with kernel [115303]
  libbpf: failed to load object 'bpf_cubic'
  libbpf: failed to load BPF skeleton 'bpf_cubic': -22
  test_cubic:FAIL:bpf_cubic__open_and_load failed
  #9/2 cubic:FAIL
  ...

The reason of the failure is due to bpf program 'tcp_slow_start' func
signature is different from vmlinux BTF. bpf program uses the following
signature:

  extern __u32 tcp_slow_start(struct tcp_sock *tp, __u32 acked);

which is identical to the kernel definition in linux:include/net/tcp.h:

  u32 tcp_slow_start(struct tcp_sock *tp, u32 acked);

While vmlinux BTF definition like:

  [115303] FUNC_PROTO '(anon)' ret_type_id=0 vlen=2
          'tp' type_id=39373
          'acked' type_id=18
  [115304] FUNC 'tcp_slow_start' type_id=115303 linkage=static

The above is dumped with `bpftool btf dump file vmlinux`.

You can see the ret_type_id is 0 and this caused the problem.

Looking at dwarf, we have:

0x11f2ec67:   DW_TAG_subprogram
                DW_AT_low_pc    (0xffffffff81ed2330)
                DW_AT_high_pc   (0xffffffff81ed235c)
                DW_AT_frame_base        ()
                DW_AT_GNU_all_call_sites        (true)
                DW_AT_abstract_origin   (0x11f2ed66 "tcp_slow_start")
...
0x11f2ed66:   DW_TAG_subprogram
                DW_AT_name      ("tcp_slow_start")
                DW_AT_decl_file ("/home/yhs/work/bpf-next/net/ipv4/tcp_cong.c")
                DW_AT_decl_line (392)
                DW_AT_prototyped        (true)
                DW_AT_type      (0x11f130c2 "u32")
                DW_AT_external  (true)
                DW_AT_inline    (DW_INL_inlined)

We have a subprogram which has an abstract_origin pointing to the
subprogram prototype with return type. Current one pass recoding cannot
easily resolve this easily since at the time recoding for 0x11f2ec67,
the return type in 0x11f2ed66 has not been resolved.

To simplify implementation, I just added another pass to go through all
functions after recoding pass. This should resolve the above issue.

With this patch, among total 250999 functions in vmlinux, 4821 functions
needs return type adjustment from type id 0 to correct values. The above
failed bpf selftest passed too.

Committer testing:

Before:

  $ pfunct tcp_slow_start
  void tcp_slow_start(struct tcp_sock * tp, u32 acked);
  $
  $ pfunct --prototypes /sys/kernel/btf/vmlinux > before
  $ head before
  int fb_is_primary_device(struct fb_info * info);
  int arch_resume_nosmt(void);
  int relocate_restore_code(void);
  int arch_hibernation_header_restore(void * addr);
  int get_e820_md5(struct e820_table * table, void * buf);
  int arch_hibernation_header_save(void * addr, unsigned int max_size);
  int pfn_is_nosave(long unsigned int pfn);
  int swsusp_arch_resume(void);
  int amd_bus_cpu_online(unsigned int cpu);
  void pci_enable_pci_io_ecs(void);
  $

After:

  $ pfunct -F btf ../build/bpf_clang_thin_lto/vmlinux -f tcp_slow_start
  u32 tcp_slow_start(struct tcp_sock * tp, u32 acked);
  $
  $ pfunct -F btf --prototypes ../build/bpf_clang_thin_lto/vmlinux > after
  $
  $ head after
  int fb_is_primary_device(struct fb_info * info);
  int arch_resume_nosmt(void);
  int relocate_restore_code(void);
  int arch_hibernation_header_restore(void * addr);
  int get_e820_md5(struct e820_table * table, void * buf);
  int arch_hibernation_header_save(void * addr, unsigned int max_size);
  int pfn_is_nosave(long unsigned int pfn);
  int swsusp_arch_resume(void);
  int amd_bus_cpu_online(unsigned int cpu);
  void pci_enable_pci_io_ecs(void);
  $
  $ diff -u before after | grep ^+ | wc -l
  1604
  $

  $ diff -u before after | grep tcp_slow_start
  -void tcp_slow_start(struct tcp_sock * tp, u32 acked);
  +u32 tcp_slow_start(struct tcp_sock * tp, u32 acked);
  $
  $ diff -u before after | grep ^[+-] | head
  --- before	2021-04-02 11:35:15.578160795 -0300
  +++ after	2021-04-02 11:33:34.204847317 -0300
  -void set_bf_sort(const struct dmi_system_id  * d);
  +int set_bf_sort(const struct dmi_system_id  * d);
  -void raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 val);
  -void raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 * val);
  +int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 val);
  +int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 * val);
  -void xen_find_device_domain_owner(struct pci_dev * dev);
  +int xen_find_device_domain_owner(struct pci_dev * dev);
  $

The same results are obtained if using /sys/kernel/btf/vmlinux after
rebooting with the kernel built from the ../build/bpf_clang_thin_lto/vmlinux
file used in the above 'after' examples.

Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: David Blaikie <dblaikie@gmail.com>
Link: https://lore.kernel.org/bpf/82dfd420-96f9-aedc-6cdc-bf20042455db@fb.com/
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Bill Wendling <morbo@google.com>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-03 14:15:03 -03:00
Yonghong Song 5752d1951d dwarf_loader: Check .notes section for LTO build info
In [1], linux introduced a note with type BUILD_COMPILER_LTO_INFO.  If
this note type exist, there is no need to scan .debug_abbrev section for
cross-cu reference. With a kernel built with [1], the cus__merging_cu()
overhead is about 3us for either LTO or non-LTO vmlinux.

 [1] https://lore.kernel.org/bpf/20210401012406.1800957-1-yhs@fb.com/

Committer testing:

Using a thin-LTO built vmlinux that doesn't have the
LINUX_ELFNOTE_BUILD_LTO note:

  $ readelf --notes vmlinux.clang.thin.LTO

  Displaying notes found in: .notes
    Owner                Data size 	Description
    Xen                  0x00000006	Unknown note type: (0x00000006)
     description data: 6c 69 6e 75 78 00
    Xen                  0x00000004	Unknown note type: (0x00000007)
     description data: 32 2e 36 00
    Xen                  0x00000008	Unknown note type: (0x00000005)
     description data: 78 65 6e 2d 33 2e 30 00
    Xen                  0x00000008	Unknown note type: (0x00000003)
     description data: 00 00 00 80 ff ff ff ff
    Xen                  0x00000008	Unknown note type: (0x0000000f)
     description data: 00 00 00 00 80 00 00 00
    Xen                  0x00000008	NT_VERSION (version)
     description data: c0 e1 33 83 ff ff ff ff
    Xen                  0x00000008	NT_ARCH (architecture)
     description data: 00 20 00 81 ff ff ff ff
    Xen                  0x00000029	Unknown note type: (0x0000000a)
     description data: 21 77 72 69 74 61 62 6c 65 5f 70 61 67 65 5f 74 61 62 6c 65 73 7c 70 61 65 5f 70 67 64 69 72 5f 61 62 6f 76 65 5f 34 67 62
    Xen                  0x00000004	Unknown note type: (0x00000011)
     description data: 01 88 00 00
    Xen                  0x00000004	Unknown note type: (0x00000009)
     description data: 79 65 73 00
    Xen                  0x00000008	Unknown note type: (0x00000008)
     description data: 67 65 6e 65 72 69 63 00
    Xen                  0x00000010	Unknown note type: (0x0000000d)
     description data: 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
    Xen                  0x00000004	Unknown note type: (0x0000000e)
     description data: 01 00 00 00
    Xen                  0x00000004	Unknown note type: (0x00000010)
     description data: 01 00 00 00
    Xen                  0x00000008	Unknown note type: (0x0000000c)
     description data: 00 00 00 00 00 80 ff ff
    Xen                  0x00000008	Unknown note type: (0x00000004)
     description data: 00 00 00 00 00 00 00 00
    Xen                  0x00000008	Unknown note type: (0x00000012)
     description data: e0 02 00 01 00 00 00 00
    Linux                0x00000017	OPEN
     description data: 34 2e 31 39 2e 34 2d 33 30 30 2e 66 63 32 39 2e 78 38 36 5f 36 34 00
    GNU                  0x00000014	NT_GNU_BUILD_ID (unique build ID bitstring)
      Build ID: 354f81317b1b3c35f3f81f8d9f04d0c8caccb09a
  $

Then with one with the new ELF note stating that this binary was built
with LTO:

  [acme@five pahole]$ readelf --notes vmlinux.clang.thin.LTO+ELF_note

  Displaying notes found in: .notes
    Owner                Data size 	Description
    Xen                  0x00000006	Unknown note type: (0x00000006)
     description data: 6c 69 6e 75 78 00
    Xen                  0x00000004	Unknown note type: (0x00000007)
     description data: 32 2e 36 00
    Xen                  0x00000008	Unknown note type: (0x00000005)
     description data: 78 65 6e 2d 33 2e 30 00
    Xen                  0x00000008	Unknown note type: (0x00000003)
     description data: 00 00 00 80 ff ff ff ff
    Xen                  0x00000008	Unknown note type: (0x0000000f)
     description data: 00 00 00 00 80 00 00 00
    Xen                  0x00000008	NT_VERSION (version)
     description data: c0 e1 33 83 ff ff ff ff
    Xen                  0x00000008	NT_ARCH (architecture)
     description data: 00 20 00 81 ff ff ff ff
    Xen                  0x00000029	Unknown note type: (0x0000000a)
     description data: 21 77 72 69 74 61 62 6c 65 5f 70 61 67 65 5f 74 61 62 6c 65 73 7c 70 61 65 5f 70 67 64 69 72 5f 61 62 6f 76 65 5f 34 67 62
    Xen                  0x00000004	Unknown note type: (0x00000011)
     description data: 01 88 00 00
    Xen                  0x00000004	Unknown note type: (0x00000009)
     description data: 79 65 73 00
    Xen                  0x00000008	Unknown note type: (0x00000008)
     description data: 67 65 6e 65 72 69 63 00
    Xen                  0x00000010	Unknown note type: (0x0000000d)
     description data: 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00
    Xen                  0x00000004	Unknown note type: (0x0000000e)
     description data: 01 00 00 00
    Xen                  0x00000004	Unknown note type: (0x00000010)
     description data: 01 00 00 00
    Xen                  0x00000008	Unknown note type: (0x0000000c)
     description data: 00 00 00 00 00 80 ff ff
    Xen                  0x00000008	Unknown note type: (0x00000004)
     description data: 00 00 00 00 00 00 00 00
    Xen                  0x00000008	Unknown note type: (0x00000012)
     description data: e0 02 00 01 00 00 00 00
    Linux                0x00000017	OPEN
     description data: 34 2e 31 39 2e 34 2d 33 30 30 2e 66 63 32 39 2e 78 38 36 5f 36 34 00
    Linux                0x00000004	func
     description data: 01 00 00 00
    GNU                  0x00000014	NT_GNU_BUILD_ID (unique build ID bitstring)
      Build ID: aeba9ffc929acd3cd573b4d1afc8df9af4f3694d
  $

Now to see the diff:

  $ readelf --notes vmlinux.clang.thin.LTO+ELF_note > with-note
  $ readelf --notes vmlinux.clang.thin.LTO > without-note
  $ diff -u without-note with-note
  --- without-note	2021-04-02 10:23:57.545349084 -0300
  +++ with-note	2021-04-02 10:23:50.690196102 -0300
  @@ -37,5 +37,7 @@
      description data: e0 02 00 01 00 00 00 00
     Linux                0x00000017	OPEN
      description data: 34 2e 31 39 2e 34 2d 33 30 30 2e 66 63 32 39 2e 78 38 36 5f 36 34 00
  +  Linux                0x00000004	func
  +   description data: 01 00 00 00
     GNU                  0x00000014	NT_GNU_BUILD_ID (unique build ID bitstring)
  -    Build ID: 354f81317b1b3c35f3f81f8d9f04d0c8caccb09a
  +    Build ID: aeba9ffc929acd3cd573b4d1afc8df9af4f3694d
  $

Signed-off-by: Yonghong Song <yhs@fb.com>
Suggested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Bill Wendling <morbo@google.com>
Tested-by: Nick Desaulniers <ndesaulniers@google.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: David Blaikie <dblaikie@gmail.com>
Cc: Fāng-ruì Sòng <maskray@google.com>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-02 11:59:54 -03:00
Yonghong Song 209e45424f dwarf_loader: Check .debug_abbrev for cross-CU references
Commit 39227909db checked compilation flags to see whether the binary
is built with LTO or not (-flto).

Currently, for clang LTO build, default setting won't put compilation
flags in dwarf due to size concern.

David Blaikie suggested in [1] to scan through .debug_abbrev for
DW_FORM_ref_addr which should be most faster than scanning through CU's.

This patch implemented this suggestion and replaced the previous
compilation flag matching approach. Indeed, it seems that the overhead
for this approach is indeed managable.

I did some change to measure the overhead of cus_merging_cu():
  @@ -2650,7 +2652,15 @@ static int cus__load_module(struct cus *cus, struct conf_load *conf,
                  }
          }

  -       if (cus__merging_cu(dw)) {
  +       bool do_merging;
  +       struct timeval start, end;
  +       gettimeofday(&start, NULL);
  +       do_merging = cus__merging_cu(dw);
  +       gettimeofday(&end, NULL);
  +       fprintf(stderr, "%ld %ld -> %ld %ld\n", start.tv_sec, start.tv_usec,
  +                       end.tv_sec, end.tv_usec);
  +
  +       if (do_merging) {
                  res = cus__merge_and_process_cu(cus, conf, mod, dw, elf, filename,
                                                  build_id, build_id_len,
                                                  type_cu ? &type_dcu : NULL);

For LTO vmlinux, the cus__merging_cu() checking takes 130us over total
"pahole -J vmlinux" time 65sec as the function bail out earlier due to
detecting a merging CU condition.

For non-LTO vmlinux, the cus__merging_cu() checking takes ~171368us over
total pahole time 36sec, roughly 0.5% overhead.

 [1] https://lore.kernel.org/bpf/20210328064121.2062927-1-yhs@fb.com/

Suggested-by: David Blaikie <blaikie@google.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Bill Wendling <morbo@google.com>
Tested-by: Nick Desaulniers <ndesaulniers@google.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: David Blaikie <dblaikie@gmail.com>
Cc: Fāng-ruì Sòng <maskray@google.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-02 11:59:49 -03:00
Yonghong Song 39227909db dwarf_loader: Permit merging all DWARF CU's for clang LTO built binary
For vmlinux built with clang thin-LTO or LTO (Link Time Optimizationq,
there exists cross CU type references. For example, this can happen:

  compile unit 1:
     tag 10:  type A
  compile unit 2:
     ...
       refer to type A (tag 10 in compile unit 1)

I only checked a few but have seen type A may be a simple type like
"unsigned char" or a complex type like an array of base types.

To resolve this issue, the tag DW_AT_producer of the first few
DW_TAG_compile_unit is checked. If the binary is built with clang LTO,
all debuginfo DWARF CU's will be merged into one pahole CU which will
resolve the above cross-CU tag reference issue. To test whether a binary
is built with clang LTO or not, the "clang version" and "-flto" will be
checked against DW_AT_producer string for the first 5 debuginfo CU's.
The reason is that a few linux objects disabled LTO for various reasons.

Merging CU's will create a single CU with lots of types, tags and
functions. For example with clang thin-LTO built vmlinux, I saw 9M
entries in types table, 5.2M in tags table. The below are pahole
wallclock time for different hashbits:

command line: time pahole -J vmlinux

      # of hashbits            wallclock time in seconds
          15                       460
          16                       255
          17                       131
          18                       97
          19                       75
          20                       69
          21                       64
          22                       62
          23                       58
          24                       64

The problem is with hashtags__find(), esp. the loop

    uint32_t bucket = hashtags__fn(id);
    const struct hlist_head *head = hashtable + bucket;
    hlist_for_each_entry(tpos, pos, head, hash_node) {
            if (tpos->id == id)
                    return tpos;
    }

Say we have 9M types and (1 << 15) buckets, that means each bucket will
have roughly 64 elements. So each lookup will traverse the loop 32
iterations on average.

If we have 1 << 21 buckets, then each buckets will have 4 elements, and
the average number of loop iterations for hashtags__find() will be 2.

Note that the number of hashbits 24 makes performance worse than 23. The
reason could be that 23 hashbits can cover 8M buckets (close to 9M for
the number of entries in types table).  Higher number of hash bits
allocates more memory and becomes less cache efficient compared to 23
hashbits.

This patch picks # of hashbits 21 as the starting value and will try to
allocate memory based on that, if memory allocation fails, we will go
with less hashbits until we reach hashbits 15 which is the default for
non merge-CU case.

Committer notes:

To test this we need this patch to be applied on bpf-next/master:

  https://lore.kernel.org/bpf/20210328064121.2062927-1-yhs@fb.com/

Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Bill Wendling <morbo@google.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-03-30 15:06:57 -03:00
Yonghong Song 763475ca11 dwarf_loader: Factor out common code to initialize a cu
Both cus__load_debug_types() and cus__load_module() created new cu's
followed by initialization. The initialization codes are identical so
let us refactor into a common function which can be used later as well
when dealing with merging cu's.

Signed-off-by: Yonghong Song <yhs@fb.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Bill Wendling <morbo@google.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-03-30 15:06:57 -03:00
Yonghong Song d0d3fbd474 dwarf_loader: Permit a flexible HASHTAGS__BITS
Currently, types/tags hash table has fixed HASHTAGS__BITS = 15.

That means the number of buckets will be 1UL << 15 = 32768.

In my experiments, a thin-LTO built vmlinux has roughly 9M entries
in types table and 5.2M entries in tags table. So the number
of buckets is too less for an efficient lookup. This patch
refactored the code to allow the number of buckets to be changed.

In addition, currently hashtags__fn(key) return value is
assigned to uint16_t. Change to uint32_t as in a later patch
the number of hashtag bits can be increased to be more than 16.

Committer notes:

Since we keep a pointer to the 'struct dwarf_cu' in cu->priv and now we
want to release the hashtables it contains, we need to make it also be
dynamicly allocated, otherwise tools such as 'codiff' will fail when
calling cus__delete() -> cu__delete() -> dwarf_cu__delelete().

Signed-off-by: Yonghong Song <yhs@fb.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Bill Wendling <morbo@google.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-03-30 15:06:56 -03:00
Ilya Leoshkevich ffe0ef4d73 btf: Add --btf_gen_all flag
By default, pahole makes use only of BTF features introduced with kernel
v5.2. Features that are added later need to be turned on with explicit
feature flags, such as --btf_gen_floats. According to [1], this will
hinder the people who generate BTF for kernels externally (e.g. for old
kernels to support BPF CO-RE).

Introduce --btf_gen_all that allows using all BTF features supported
by pahole.

[1] https://lore.kernel.org/dwarves/CAEf4Bzbyugfb2RkBkRuxNGKwSk40Tbq4zAvhQT8W=fVMYWuaxA@mail.gmail.com/

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-03-12 10:36:45 -03:00
Ilya Leoshkevich de708b3311 btf: Add support for the floating-point types
Some BPF programs compiled on s390 fail to load, because s390
arch-specific linux headers contain float and double types.

Fix as follows:

- Make the DWARF loader fill base_type.float_type.

- Introduce the --btf_gen_floats command-line parameter, so that
  pahole could be used to build both the older and the newer kernels.

- libbpf introduced the support for the floating-point types in commit
  986962fade5, so update the libbpf submodule to that version and use
  the new btf__add_float() function in order to emit the floating-point
  types when not in the compatibility mode.

- Make the BTF loader recognize the new BTF kind.

Example of the resulting entry in the vmlinux BTF:

    [7164] FLOAT 'double' size=8

when building with:

    LLVM_OBJCOPY=${OBJCOPY} ${PAHOLE} -J ${1} --btf_gen_floats

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-03-11 14:45:38 -03:00
Arnaldo Carvalho de Melo 4b7f8c04d0 fprintf: Honour conf_fprintf.hex when printing enumerations
Now this works:

  $ pahole --hex perf_event_type
  enum perf_event_type {
  	PERF_RECORD_MMAP            = 0x1,
  	PERF_RECORD_LOST            = 0x2,
  	PERF_RECORD_COMM            = 0x3,
  	PERF_RECORD_EXIT            = 0x4,
  	PERF_RECORD_THROTTLE        = 0x5,
  	PERF_RECORD_UNTHROTTLE      = 0x6,
  	PERF_RECORD_FORK            = 0x7,
  	PERF_RECORD_READ            = 0x8,
  	PERF_RECORD_SAMPLE          = 0x9,
  	PERF_RECORD_MMAP2           = 0xa,
  	PERF_RECORD_AUX             = 0xb,
  	PERF_RECORD_ITRACE_START    = 0xc,
  	PERF_RECORD_LOST_SAMPLES    = 0xd,
  	PERF_RECORD_SWITCH          = 0xe,
  	PERF_RECORD_SWITCH_CPU_WIDE = 0xf,
  	PERF_RECORD_NAMESPACES      = 0x10,
  	PERF_RECORD_KSYMBOL         = 0x11,
  	PERF_RECORD_BPF_EVENT       = 0x12,
  	PERF_RECORD_CGROUP          = 0x13,
  	PERF_RECORD_TEXT_POKE       = 0x14,
  	PERF_RECORD_MAX             = 0x15,
  };
  $

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-20 08:41:11 -03:00
Ian Rogers f2889ff163 Avoid warning when building with NDEBUG
The assert macro is compiled out with NDEBUG which can lead to an unused
variable warning if the variable is only read in the assert. This is
seen just here:

dwarf_loader.c:957:17: error: unused variable 'tag' [-Werror,-Wunused-variable]
        const uint16_t tag = dwarf_tag(die);

Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-18 16:21:48 -03:00
Jiri Olsa 8e1f8c904e btf_encoder: Match ftrace addresses within ELF functions
Currently when processing a DWARF function, we check its entrypoint
against ftrace addresses, assuming that the ftrace address matches with
the function's entrypoint.

This is not the case on some architectures as reported by Nathan
when building kernel on arm [1].

Fix the check to take into account the whole function, not just the
entrypoint.

Most of the is_ftrace_func code was contributed by Andrii.

[1] https://lore.kernel.org/bpf/20210209034416.GA1669105@ubuntu-m3-large-x86/

Committer notes:

Test comments by Nathan:

"I did several builds with CONFIG_DEBUG_INFO_BTF enabled (arm64, ppc64le,
 and x86_64) and saw no build errors. I did not do any runtime testing."

Test comments by Sedat:

Linux v5.11-rc7+ and LLVM/Clang v12.0.0-rc1 on x86 (64bit)

Reported-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Tested-by: Nathan Chancellor <nathan@kernel.org>
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Hao Luo <haoluo@google.com>
Cc: John Fastabend <john.fastabend@gmail.com>
Cc: KP Singh <kpsingh@chromium.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Song Liu <songliubraving@fb.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: netdev@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-17 09:44:25 -03:00
Bill Wendling 9fecc77ed8 dwarf_loader: Use a better hashing function, from libbpf
This hashing function[1] produces better hash table bucket
distributions. The original hashing function always produced zeros in
the three least significant bits. The new hashing function gives a
modest performance boost:

  Original: 0:11.373s
  New:      0:11.110s

for a performance improvement of ~2%.

[1] From the hash function used in libbpf.

Committer notes:

Bill found the suboptimality of the hash function being used, Andrii
suggested using the libbpf one, which ended up being better.

Signed-off-by: Bill Wendling <morbo@google.com>
Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-12 09:35:53 -03:00
Giuliano Procida 0125de3a4c btf_encoder: Funnel ELF error reporting through a macro
This adds elf_error() which prepends error messages with the function
and appends a readable ELF error status.

Also capitalise ELF consistently in error messages.

Signed-off-by: Giuliano Procida <gprocida@google.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Matthias Maennich <maennich@google.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Cc: kernel-team@android.com
Cc: kernel-team@fb.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-09 09:29:33 -03:00
Yonghong Song 7d8e829f63 btf_encoder: Sanitize non-regular int base type
clang with dwarf5 may generate non-regular int base type, i.e., not a
signed/unsigned char/short/int/longlong/__int128.  Such base types are
often used to describe how an actual parameter or variable is generated.
For example,

0x000015cf:   DW_TAG_base_type
                DW_AT_name      ("DW_ATE_unsigned_1")
                DW_AT_encoding  (DW_ATE_unsigned)
                DW_AT_byte_size (0x00)

0x00010ed9:         DW_TAG_formal_parameter
                      DW_AT_location    (DW_OP_lit0,
                                         DW_OP_not,
                                         DW_OP_convert (0x000015cf) "DW_ATE_unsigned_1",
                                         DW_OP_convert (0x000015d4) "DW_ATE_unsigned_8",
                                         DW_OP_stack_value)
                      DW_AT_abstract_origin     (0x00013984 "branch")

What it does is with a literal "0", did a "not" operation, and the converted to
one-bit unsigned int and then 8-bit unsigned int.

Another example,

0x000e97e4:   DW_TAG_base_type
                DW_AT_name      ("DW_ATE_unsigned_24")
                DW_AT_encoding  (DW_ATE_unsigned)
                DW_AT_byte_size (0x03)

0x000f88f8:     DW_TAG_variable
                  DW_AT_location        (indexed (0x3c) loclist = 0x00008fb0:
                     [0xffffffff82808812, 0xffffffff82808817):
                         DW_OP_breg0 RAX+0,
                         DW_OP_convert (0x000e97d5) "DW_ATE_unsigned_64",
                         DW_OP_convert (0x000e97df) "DW_ATE_unsigned_8",
                         DW_OP_stack_value,
                         DW_OP_piece 0x1,
                         DW_OP_breg0 RAX+0,
                         DW_OP_convert (0x000e97d5) "DW_ATE_unsigned_64",
                         DW_OP_convert (0x000e97da) "DW_ATE_unsigned_32",
                         DW_OP_lit8,
                         DW_OP_shr,
                         DW_OP_convert (0x000e97da) "DW_ATE_unsigned_32",
                         DW_OP_convert (0x000e97e4) "DW_ATE_unsigned_24",
                         DW_OP_stack_value,
                         DW_OP_piece 0x3
                     ......

At one point, a right shift by 8 happens and the result is converted to
32-bit unsigned int and then to 24-bit unsigned int.

BTF does not need any of these DW_OP_* information and such non-regular
int types will cause libbpf to emit errors.

Let us sanitize them to generate BTF acceptable to libbpf and kernel.

Reported-by: Sedat Dilek <sedat.dilek@gmail.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
Tested-by: Nick Desaulniers <ndesaulniers@google.com>
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: bpf@vger.kernel.org
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-08 17:13:03 -03:00
Arnaldo Carvalho de Melo 0d415f68c4 pahole: Prep 1.20
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-03 21:45:01 -03:00
Arnaldo Carvalho de Melo 7943374ac5 Revert "libbpf: allow to use packaged version"
This reverts commit 82749180b2.

Getting in the way of releasing 1.20, breaking the build of a dwarves
rpm when a libbpf package is installed in a fedora 33 system:

In file included from /home/acme/rpmbuild/BUILD/dwarves-1.20/strings.c:7:
/home/acme/rpmbuild/BUILD/dwarves-1.20/pahole_strings.h:9:10: fatal error: bpf/btf.h: No such file or directory
    9 | #include <bpf/btf.h>
      |          ^~~~~~~~~~~

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-03 21:45:00 -03:00
Arnaldo Carvalho de Melo 8fb7741692 dwarf_loader: Support DWARF_TAG_call_site{_parameter} also in die__process_inline_expansion
In d783117162 ("dwarf_loader: Handle DWARF5 DW_TAG_call_site like
DW_TAG_GNU_call_site") we forgot to handle that GNU extension promotion
to be a standard, fix it.

Cc: Mark Wielaard <mark@klomp.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-02 18:34:38 -03:00
Arnaldo Carvalho de Melo 8d6f06f053 dwarf_loader: Add conditional DW_FORM_implicit_const definition for older systems
This made the build fail on libbpf CI on systems where
DW_FORM_implicit_const isn't defined, so do it conditionally.

Reported-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-02 09:45:37 -03:00
Arnaldo Carvalho de Melo 66d12e4790 dtagnames: Stop using the deprecated mallinfo() function
Bulding on fedora rawhide gets us:

  /home/acme/git/pahole/dtagnames.c:17:16: error: ‘mallinfo’ is deprecated [-Werror=deprecated-declarations]
     17 |         struct mallinfo m = mallinfo();
        |                ^~~~~~~~
  In file included from /home/acme/git/pahole/dtagnames.c:10:
  /usr/include/malloc.h:118:24: note: declared here
    118 | extern struct mallinfo mallinfo (void) __THROW __MALLOC_DEPRECATED;
        |                        ^~~~~~~~
  cc1: all warnings being treated as errors

glibc-2.32.9000-26.fc34.x86_64

So stop using it, was just for debugging/assessing memory usage.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-02 09:38:46 -03:00
Arnaldo Carvalho de Melo 1279e439b6 cmake: Bump minimum required version to 2.8.12 as per upstream support warning
When calling cmake on the build dir we got this on fedora rawhide (cmake 3.19.4):

  CMake Deprecation Warning at CMakeLists.txt:2 (cmake_minimum_required):
    Compatibility with CMake < 2.8.12 will be removed from a future version of
    CMake.

    Update the VERSION argument <min> value or use a ...<max> suffix to tell
    CMake that the project does not need compatibility with older versions.

So bump it.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-02 09:34:30 -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
Mark Wielaard d783117162 dwarf_loader: Handle DWARF5 DW_TAG_call_site like DW_TAG_GNU_call_site
DW_TAG_call_site and DW_TAG_call_site_parameter are the standardized
DWARF5 versions of DW_TAG_GNU_call_site and DW_TAG_GNU
call_site_parameter.  Handle them the same way (which is by ignoring
them).

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1922698
Signed-off-by: Mark Wielaard <mark@klomp.org>
Cc: dwarves@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-01 14:08:22 -03:00
Jiri Olsa 3ff98a6396 dwarf_loader: Support DW_FORM_implicit_const in __attr_offset()
Noticed witth selftest/bpf/test_verifier_log failing on v5.11-rc5 with a
newer gcc.

However looks like we don't handle DW_FORM_implicit_const when counting
the byte offset (when handling DW_AT_data_member_location)... It was
used for some struct members in my vmlinux, so we got zero for byte
offset and that created another unique struct.

With this patch I no longer see any struct duplication, also
test_verifier_log is working for me, but I could not reproduce the error
before.

Reported-by: Paul Moore <paul@paul-moore.com>
Reported-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: bpf <bpf@vger.kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-02-01 14:06:17 -03:00
Arnaldo Carvalho de Melo b91b19840b dwarf_loader: Support DW_AT_data_bit_offset
This appeared in DWARF4 but is supported only in gcc's -gdwarf-5,
support it in a way that makes the output be the same for both cases:

  $ gcc -gdwarf-4 -c examples/dwarf5/bf.c
  $ pahole bf.o
  struct pea {
  	long int                   a:1;                  /*     0: 0  8 */
  	long int                   b:1;                  /*     0: 1  8 */
  	long int                   c:1;                  /*     0: 2  8 */

  	/* XXX 29 bits hole, try to pack */
  	/* Bitfield combined with next fields */

  	int                        after_bitfield;       /*     4     4 */

  	/* size: 8, cachelines: 1, members: 4 */
  	/* sum members: 4 */
  	/* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */
  	/* last cacheline: 8 bytes */
  };
  $ gcc -gdwarf-5 -c examples/dwarf5/bf.c
  $ pahole bf.o
  struct pea {
  	long int                   a:1;                  /*     0: 0  8 */
  	long int                   b:1;                  /*     0: 1  8 */
  	long int                   c:1;                  /*     0: 2  8 */

  	/* XXX 29 bits hole, try to pack */
  	/* Bitfield combined with next fields */

  	int                        after_bitfield;       /*     4     4 */

  	/* size: 8, cachelines: 1, members: 4 */
  	/* sum members: 4 */
  	/* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */
  	/* last cacheline: 8 bytes */
  };
  $

Now with an integer before the bitfield:

  $ cat examples/dwarf5/bf.c
  struct pea {
  	int before_bitfield;
  	long a:1, b:1, c:1;
  	int after_bitfield;
  } p;
  $ gcc -gdwarf-4 -c examples/dwarf5/bf.c
  $ pahole bf.o
  struct pea {
  	int                        before_bitfield;      /*     0     4 */

  	/* Bitfield combined with previous fields */

  	long int                   a:1;                  /*     0:32  8 */
  	long int                   b:1;                  /*     0:33  8 */
  	long int                   c:1;                  /*     0:34  8 */

  	/* XXX 29 bits hole, try to pack */

  	int                        after_bitfield;       /*     8     4 */

  	/* size: 16, cachelines: 1, members: 5 */
  	/* sum members: 8 */
  	/* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */
  	/* padding: 4 */
  	/* last cacheline: 16 bytes */
  };
  $ gcc -gdwarf-5 -c examples/dwarf5/bf.c
  $ pahole bf.o
  struct pea {
  	int                        before_bitfield;      /*     0     4 */

  	/* Bitfield combined with previous fields */

  	long int                   a:1;                  /*     0:32  8 */
  	long int                   b:1;                  /*     0:33  8 */
  	long int                   c:1;                  /*     0:34  8 */

  	/* XXX 29 bits hole, try to pack */

  	int                        after_bitfield;       /*     8     4 */

  	/* size: 16, cachelines: 1, members: 5 */
  	/* sum members: 8 */
  	/* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */
  	/* padding: 4 */
  	/* last cacheline: 16 bytes */
  };
  $

And an array of long integers at the start, before the combination of an
integer with a long integer bitfield:

  $ cat examples/dwarf5/bf.c
  struct pea {
  	long array[3];
  	int before_bitfield;
  	long a:1, b:1, c:1;
  	int after_bitfield;
  } p;
  $ gcc -gdwarf-4 -c examples/dwarf5/bf.c
  $ pahole bf.o
  struct pea {
  	long int                   array[3];             /*     0    24 */
  	int                        before_bitfield;      /*    24     4 */

  	/* Bitfield combined with previous fields */

  	long int                   a:1;                  /*    24:32  8 */
  	long int                   b:1;                  /*    24:33  8 */
  	long int                   c:1;                  /*    24:34  8 */

  	/* XXX 29 bits hole, try to pack */

  	int                        after_bitfield;       /*    32     4 */

  	/* size: 40, cachelines: 1, members: 6 */
  	/* sum members: 32 */
  	/* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */
  	/* padding: 4 */
  	/* last cacheline: 40 bytes */
  };
  $ gcc -gdwarf-5 -c examples/dwarf5/bf.c
  $ pahole bf.o
  struct pea {
  	long int                   array[3];             /*     0    24 */
  	int                        before_bitfield;      /*    24     4 */

  	/* Bitfield combined with previous fields */

  	long int                   a:1;                  /*    24:32  8 */
  	long int                   b:1;                  /*    24:33  8 */
  	long int                   c:1;                  /*    24:34  8 */

  	/* XXX 29 bits hole, try to pack */

  	int                        after_bitfield;       /*    32     4 */

  	/* size: 40, cachelines: 1, members: 6 */
  	/* sum members: 32 */
  	/* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */
  	/* padding: 4 */
  	/* last cacheline: 40 bytes */
  };
  $

Reported-by: Mark Wielaard <mark@klomp.org>
Tested-by: "Daniel P. Berrangé" <berrange@redhat.com>
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1919965
Link: https://lore.kernel.org/dwarves/20210128121122.GA775562@kernel.org/
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-01-28 14:11:02 -03:00