[PATCH dwarves 0/4] Emit global variables in BTF

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello all,

Currently, pahole has the "var" feature which emits a single DATASEC for
the ".data..percpu" section, and emits only the variables from that
section. I work on the drgn debugger [1] and have been working specifically
on features that allow users to debug their kernel without necessarily
having DWARF debuginfo [2]. To that end, I'd like to see *all* global
variables included in the BTF, not just percpu variables. But this woudln't
just be useful for debuggers: libbpf already supports resolution of global
variables with __ksym annotations, but these have to be declared as void.
For example, in tools/bpf/bpftool/skeleton/pid_iter.bpf.c we have:

    extern const void bpf_map_fops __ksym;

With global variable information, declarations like these would be able to
use the actial variable types, for example:

    extern const struct file_operations bpf_map_fops __ksym;

To that end, this patch series adds a pahole feature "global_var", which
includes global variable type information in the BTF. Most of the important
code comes in patch 4. The major difficulty is in deciding which DWARF
variables should be emitted. The current pahole implementation considers
any variable with a static memory address a global, but that includes
static local variables, so I've added a flag to indicate when variables are
declared at the top level of a CU. There are some other useless kernel
variables which are generated by macros, etc. I filter these by name, which
isn't ideal, but works well.

To test and measure the size impact, I've built v6.11-rc7 on x86_64 with a
defconfig, and enabled the necessary BTF support. For one build, I used
pahole built from master, and for the other, I used these patches on top.
Here is a comparison of total vmlinux and module BTF size for old and new.

                      Before                   After
  vmlinux BTF size    0x5f4a03 (5.95 MiB)      0x77e948 (7.49 MiB)
                      increase:                1.54 MiB (25.8%)
  #modules            10                       10
  module BTF size     0x20c5 (8.19 KiB)        0x3235 (12.55 KiB)
                      increase:                4.36 KiB (53.2%)

The module size increases more compared to the vmlinux, because each
module's BTF doesn't define many types, so the variables are larger as a
percentage of the total. These are also rather small modules (whichever few
were enabled for the build of an x86_64 defconfig), I'd expect larger
modules to have a smaller relative increase, because they would define more
of their own types.

To sanity check the output, I looked at the "DATASEC" generated for the
percpu section, and verified that it was nearly identical. The only
difference (besides the type IDs) was the addition of the fixed_percpu_data
variable, which had been omitted by pahole's master branch:

    --- percpu_datasec_master.txt   2024-09-12 00:04:37.255240578 +0000
    +++ percpu_datasec_global_var.txt       2024-09-12 00:04:24.214980821 +0000
    @@ -1,4 +1,5 @@
    -DATASEC '.data..percpu' size=199384 vlen=302
    +DATASEC '.data..percpu' size=199384 vlen=303
    +offset=0 size=48 (VAR 'fixed_percpu_data')
     offset=4096 size=4096 (VAR 'cpu_debug_store')
     offset=8192 size=16384 (VAR 'irq_stack_backing_store')
     offset=24576 size=20480 (VAR 'cpu_tss_rw')

Finally, you can find below a summary of the vmlinux DATASEC outputs which
were added by this patch in this build scenario.

    DATASEC '.rodata' size=2910928 vlen=6514
    DATASEC '__init_rodata' size=48 vlen=1
    DATASEC '__param' size=21640 vlen=537
    DATASEC '__modver' size=1008 vlen=14
    DATASEC '.data' size=2953985 vlen=16451
    DATASEC '.orc_header' size=20 vlen=1
    DATASEC '.vvar' size=656 vlen=2
    DATASEC '.data..percpu' size=199384 vlen=303
    DATASEC '.init.data' size=690040 vlen=4830
    DATASEC '.x86_cpu_dev.init' size=40 vlen=5
    DATASEC '.apicdrivers' size=16 vlen=1
    DATASEC '.data_nosave' size=4 vlen=1
    DATASEC '.bss' size=693060 vlen=2532
    DATASEC '.brk' size=196608 vlen=2

I know the overheads are non-negligible, but I think there will be
considerable value in having the global variables present. Thanks for
reading this and I look forward to discussing!

[1]: https://github.com/osandov/drgn
[2]: https://github.com/osandov/drgn/issues/176

PS: Previous iterations were sent in 2022:
v1 https://lore.kernel.org/dwarves/20220826184911.168442-1-stephen.s.brennan@xxxxxxxxxx/
v2 https://lore.kernel.org/dwarves/20221104231103.752040-1-stephen.s.brennan@xxxxxxxxxx/

Difference from these: I've gotten a much better understanding of DWARF,
BTF, and the pahole code since then. In particular, the older patches did
not include DATASEC for anything other than percpu variables. Also, since
those older patches, I've dramatically improved the variable filtering,
including using DW_AT_artificial, name filtering, and getting rid of static
local variables.

Stephen Brennan (4):
  dutil: return ELF section name when looked up by index
  dwarf_loader: add "artificial" and "top_level" variable flags
  btf_encoder: cache all ELF section info
  btf_encoder: add global_var feature to encode globals

 btf_encoder.c      | 371 ++++++++++++++++++++++-----------------------
 btf_encoder.h      |   8 +
 dutil.c            |   9 +-
 dutil.h            |   2 +-
 dwarf_loader.c     |  12 +-
 dwarves.h          |   3 +
 man-pages/pahole.1 |   8 +-
 pahole.c           |  11 +-
 8 files changed, 223 insertions(+), 201 deletions(-)

-- 
2.43.5





[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux