| .\" Man page for pahole |
| .\" Arnaldo Carvalho de Melo, 2009 |
| .\" Licensed under version 2 of the GNU General Public License. |
| .TH pahole 1 "January 16, 2020" "dwarves" "dwarves" |
| .\" |
| .SH NAME |
| pahole \- Shows and manipulates data structure layout. |
| .SH SYNOPSIS |
| \fBpahole\fR [\fIoptions\fR] \fIfiles\fR |
| .SH DESCRIPTION |
| .B pahole |
| shows data structure layouts encoded in debugging information formats, |
| DWARF and CTF being supported. |
| |
| This is useful for, among other things: optimizing important data structures by |
| reducing its size, figuring out what is the field sitting at an offset from the |
| start of a data structure, investigating ABI changes and more generally |
| understanding a new codebase you have to work with. |
| |
| The files must have associated debugging information. This information may be |
| inside the file itself, in ELF sections, or in another file. |
| |
| One way to have this information is to specify the \fB\-g\fR option to the |
| compiler when building it. When this is done the information will be stored in |
| an ELF section. For the DWARF debugging information format this, adds, among |
| others, the \fB.debug_info\fR ELF section. For CTF it is found in just one ELF |
| section, \fB.SUNW_ctf\fR. BTF comes in at least the \fB.BTF\fR ELF section, and |
| may come also with the \fB.BTF.ext\fR ELF section. |
| |
| The \fBdebuginfo\fR packages available in most Linux distributions are also |
| supported by \fBpahole\fR, where the debugging information is available in a |
| separate file. |
| |
| By default, \fBpahole\fR shows the layout of all named structs in the files |
| specified. |
| |
| If no files are specified, then it will look if the /sys/kernel/btf/vmlinux |
| is present, using the BTF information present in it about the running kernel, |
| i.e. this works: |
| .PP |
| .nf |
| $ pahole 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 */ |
| }; |
| $ |
| .fi |
| |
| If BTF is not present and no file is passed, then a vmlinux that matches the |
| build-id for the running kernel will be looked up in the usual places, |
| including where the kernel debuginfo packages put it, looking for DWARF info |
| instead. |
| |
| See the EXAMPLES section for more usage suggestions. |
| |
| .SH OPTIONS |
| pahole supports the following options. |
| |
| .TP |
| .B \-C, \-\-class_name=CLASS_NAMES |
| Show just these classes. This can be a comma separated list of class names |
| or file URLs (e.g.: file://class_list.txt) |
| |
| .TP |
| .B \-c, \-\-cacheline_size=SIZE |
| Set cacheline size to SIZE bytes. |
| |
| .TP |
| .B \-E, \-\-expand_types |
| Expand class members. Useful to find in what member of inner structs where an |
| offset from the beginning of a struct is. |
| |
| .TP |
| .B \-F, \-\-format_path |
| Allows specifying a list of debugging formats to try, in order. Right now this |
| includes "ctf" and "dwarf". The default format path used is equivalent to |
| "-F dwarf,ctf". |
| |
| .TP |
| .B \-\-hex |
| Print offsets and sizes in hexadecimal. |
| |
| .TP |
| .B \-r, \-\-rel_offset |
| Show relative offsets of members in inner structs. |
| |
| .TP |
| .B \-p, \-\-expand_pointers |
| Expand class pointer members. |
| |
| .TP |
| .B \-R, \-\-reorganize |
| Reorganize struct, demoting and combining bitfields, moving members to remove |
| alignment holes and padding. |
| |
| .TP |
| .B \-S, \-\-show_reorg_steps |
| Show the struct layout at each reorganization step. |
| |
| .TP |
| .B \-i, \-\-contains=CLASS_NAME |
| Show classes that contains CLASS_NAME. |
| |
| .TP |
| .B \-a, \-\-anon_include |
| Include anonymous classes. |
| |
| .TP |
| .B \-A, \-\-nested_anon_include |
| Include nested (inside other structs) anonymous classes. |
| |
| .TP |
| .B \-B, \-\-bit_holes=NR_HOLES |
| Show only structs at least NR_HOLES bit holes. |
| |
| .TP |
| .B \-d, \-\-recursive |
| Recursive mode, affects several other flags. |
| |
| .TP |
| .B \-D, \-\-decl_exclude=PREFIX |
| exclude classes declared in files with PREFIX. |
| |
| .TP |
| .B \-f, \-\-find_pointers_to=CLASS_NAME |
| Find pointers to CLASS_NAME. |
| |
| .TP |
| .B \-H, \-\-holes=NR_HOLES |
| Show only structs with at least NR_HOLES holes. |
| |
| .TP |
| .B \-I, \-\-show_decl_info |
| Show the file and line number where the tags were defined, if available in |
| the debugging information. |
| |
| .TP |
| .B \-l, \-\-show_first_biggest_size_base_type_member |
| Show first biggest size base_type member. |
| |
| .TP |
| .B \-m, \-\-nr_methods |
| Show number of methods. |
| |
| .TP |
| .B \-M, \-\-show_only_data_members |
| Show only the members that use space in the class layout. C++ methods will be |
| suppressed. |
| |
| .TP |
| .B \-n, \-\-nr_members |
| Show number of members. |
| |
| .TP |
| .B \-N, \-\-class_name_len |
| Show size of classes. |
| |
| .TP |
| .B \-O, \-\-dwarf_offset=OFFSET |
| Show tag with DWARF OFFSET. |
| |
| .TP |
| .B \-P, \-\-packable |
| Show only structs that has holes that can be packed if members are reorganized, |
| for instance when using the \fB\-\-reorganize\fR option. |
| |
| .TP |
| .B \-q, \-\-quiet |
| Be quieter. |
| |
| .TP |
| .B \-s, \-\-sizes |
| Show size of classes. |
| |
| .TP |
| .B \-t, \-\-separator=SEP |
| Use SEP as the field separator. |
| |
| .TP |
| .B \-T, \-\-nr_definitions |
| Show how many times struct was defined. |
| |
| .TP |
| .B \-u, \-\-defined_in |
| Show CUs where CLASS_NAME (-C) is defined. |
| |
| .TP |
| .B \-\-flat_arrays |
| Flatten arrays, so that array[10][2] becomes array[20]. |
| Useful when generating from both CTF/BTF and DWARF encodings |
| for the same binary for testing purposes. |
| |
| .TP |
| .B \-\-suppress_aligned_attribute |
| Suppress forced alignment markers, so that one can compare BTF or |
| CTF output, that don't have that info, to output from DWARF >= 5. |
| |
| .TP |
| .B \-\-suppress_force_paddings |
| |
| Suppress bitfield forced padding at the end of structs, as this requires |
| something like DWARF's DW_AT_alignment, so that one can compare BTF or CTF |
| output, that don't have that info. |
| |
| .TP |
| .B \-\-suppress_packed |
| |
| Suppress the output of the inference of __attribute__((__packed__)), so that |
| one can compare BTF or CTF output, the inference algorithm uses things like |
| DW_AT_alignment, so until it is improved to infer that as well for BTF, allow |
| disabling this output. |
| |
| .TP |
| .B \-\-fixup_silly_bitfields |
| Converts silly bitfields such as "int foo:32" to plain "int foo". |
| |
| .TP |
| .B \-V, \-\-verbose |
| be verbose |
| |
| .TP |
| .B \-w, \-\-word_size=WORD_SIZE |
| Change the arch word size to WORD_SIZE. |
| |
| .TP |
| .B \-x, \-\-exclude=PREFIX |
| Exclude PREFIXed classes. |
| |
| .TP |
| .B \-X, \-\-cu_exclude=PREFIX |
| Exclude PREFIXed compilation units. |
| |
| .TP |
| .B \-y, \-\-prefix_filter=PREFIX |
| Include PREFIXed classes. |
| |
| .TP |
| .B \-z, \-\-hole_size_ge=HOLE_SIZE |
| Show only structs with at least one hole greater or equal to HOLE_SIZE. |
| |
| .TP |
| .B \-\-structs |
| Show only structs, all the other filters apply, i.e. to show just the sizes of all structs |
| coimbine --structs with --sizes, etc. |
| |
| .TP |
| .B \-\-unions |
| Show only unions, all the other filters apply, i.e. to show just the sizes of all unions |
| coimbine --union with --sizes, etc. |
| |
| .SH NOTES |
| |
| To enable the generation of debugging information in the Linux kernel build |
| process select CONFIG_DEBUG_INFO. This can be done using make menuconfig by |
| this path: "Kernel Hacking" -> "Compile-time checks and compiler options" -> |
| "Compile the kernel with debug info". Consider as well enabling |
| CONFIG_DEBUG_INFO_BTF by going thru the aforementioned menuconfig path and then |
| selecting "Generate BTF typeinfo". Most modern distributions with eBPF support |
| should come with that in all its kernels, greatly facilitating the use of |
| pahole. |
| |
| Many distributions also come with debuginfo packages, so just enable it in your |
| package manager repository configuration and install the kernel-debuginfo, or |
| any other userspace program written in a language that the compiler generates |
| debuginfo (C, C++, for instance). |
| |
| .SH EXAMPLES |
| |
| All the examples here use either /sys/kernel/btf/vmlinux, if present, or lookup |
| a vmlinux file matching the running kernel, using the build-id info found in |
| /sys/kernel/notes to make sure it matches. |
| .P |
| Show a type: |
| .PP |
| .nf |
| $ pahole -C __u64 |
| typedef long long unsigned int __u64; |
| $ |
| .fi |
| |
| .P |
| Works as well if the only argument is a type name: |
| .PP |
| .nf |
| $ pahole raw_spinlock_t |
| typedef struct raw_spinlock raw_spinlock_t; |
| $ |
| .fi |
| |
| .P |
| Multiple types can be passed, separated by commas: |
| .PP |
| .nf |
| $ pahole raw_spinlock_t,raw_spinlock |
| struct raw_spinlock { |
| arch_spinlock_t raw_lock; /* 0 4 */ |
| |
| /* size: 4, cachelines: 1, members: 1 */ |
| /* last cacheline: 4 bytes */ |
| }; |
| typedef struct raw_spinlock raw_spinlock_t; |
| $ |
| .fi |
| |
| .P |
| Types can be expanded: |
| .PP |
| .nf |
| $ pahole -E raw_spinlock |
| struct raw_spinlock { |
| /* typedef arch_spinlock_t */ struct qspinlock { |
| union { |
| /* typedef atomic_t */ struct { |
| int counter; /* 0 4 */ |
| } val; /* 0 4 */ |
| struct { |
| /* typedef u8 -> __u8 */ unsigned char locked; /* 0 1 */ |
| /* typedef u8 -> __u8 */ unsigned char pending; /* 1 1 */ |
| }; /* 0 2 */ |
| struct { |
| /* typedef u16 -> __u16 */ short unsigned int locked_pending; /* 0 2 */ |
| /* typedef u16 -> __u16 */ short unsigned int tail; /* 2 2 */ |
| }; /* 0 4 */ |
| }; /* 0 4 */ |
| } raw_lock; /* 0 4 */ |
| |
| /* size: 4, cachelines: 1, members: 1 */ |
| /* last cacheline: 4 bytes */ |
| }; |
| $ |
| .fi |
| |
| .P |
| When decoding OOPSes you may want to see the offsets and sizes in hexadecimal: |
| .PP |
| .nf |
| $ pahole --hex thread_struct |
| struct thread_struct { |
| struct desc_struct tls_array[3]; /* 0 0x18 */ |
| long unsigned int sp; /* 0x18 0x8 */ |
| short unsigned int es; /* 0x20 0x2 */ |
| short unsigned int ds; /* 0x22 0x2 */ |
| short unsigned int fsindex; /* 0x24 0x2 */ |
| short unsigned int gsindex; /* 0x26 0x2 */ |
| long unsigned int fsbase; /* 0x28 0x8 */ |
| long unsigned int gsbase; /* 0x30 0x8 */ |
| struct perf_event * ptrace_bps[4]; /* 0x38 0x20 */ |
| /* --- cacheline 1 boundary (64 bytes) was 24 bytes ago --- */ |
| long unsigned int debugreg6; /* 0x58 0x8 */ |
| long unsigned int ptrace_dr7; /* 0x60 0x8 */ |
| long unsigned int cr2; /* 0x68 0x8 */ |
| long unsigned int trap_nr; /* 0x70 0x8 */ |
| long unsigned int error_code; /* 0x78 0x8 */ |
| /* --- cacheline 2 boundary (128 bytes) --- */ |
| struct io_bitmap * io_bitmap; /* 0x80 0x8 */ |
| long unsigned int iopl_emul; /* 0x88 0x8 */ |
| mm_segment_t addr_limit; /* 0x90 0x8 */ |
| unsigned int sig_on_uaccess_err:1; /* 0x98: 0 0x4 */ |
| unsigned int uaccess_err:1; /* 0x98:0x1 0x4 */ |
| |
| /* XXX 30 bits hole, try to pack */ |
| /* XXX 36 bytes hole, try to pack */ |
| |
| /* --- cacheline 3 boundary (192 bytes) --- */ |
| struct fpu fpu; /* 0xc0 0x1040 */ |
| |
| /* size: 4352, cachelines: 68, members: 20 */ |
| /* sum members: 4312, holes: 1, sum holes: 36 */ |
| /* sum bitfield members: 2 bits, bit holes: 1, sum bit holes: 30 bits */ |
| }; |
| $ |
| .fi |
| |
| .P |
| OK, I know the offset that causes its a 'struct thread_struct' and that the offset is 0x178, |
| so must be in that 'fpu' struct... No problem, expand 'struct thread_struct' and combine with \fBgrep\fR: |
| .PP |
| .nf |
| $ pahole --hex -E thread_struct | egrep '(0x178|struct fpu)' -B4 -A4 |
| /* XXX 30 bits hole, try to pack */ |
| /* XXX 36 bytes hole, try to pack */ |
| |
| /* --- cacheline 3 boundary (192 bytes) --- */ |
| struct fpu { |
| unsigned int last_cpu; /* 0xc0 0x4 */ |
| |
| /* XXX 4 bytes hole, try to pack */ |
| |
| -- |
| /* typedef u8 -> __u8 */ unsigned char alimit; /* 0x171 0x1 */ |
| |
| /* XXX 6 bytes hole, try to pack */ |
| |
| struct math_emu_info * info; /* \fI0x178\fR 0x8 */ |
| /* --- cacheline 6 boundary (384 bytes) --- */ |
| /* typedef u32 -> __u32 */ unsigned int entry_eip; /* 0x180 0x4 */ |
| } soft; /* 0x100 0x88 */ |
| struct xregs_state { |
| $ |
| .fi |
| |
| .P |
| Want to know where 'struct thread_struct' is defined in the kernel sources? |
| .PP |
| .nf |
| $ pahole -I thread_struct | head -2 |
| /* Used at: /sys/kernel/btf/vmlinux */ |
| /* <0> (null):0 */ |
| $ |
| .fi |
| |
| .P |
| Not present in BTF, so use DWARF, takes a little bit longer, and assuming it finds the matching vmlinux file: |
| .PP |
| .nf |
| $ pahole -Fdwarf -I thread_struct | head -2 |
| /* Used at: /home/acme/git/linux/arch/x86/kernel/head64.c */ |
| /* <3333> /home/acme/git/linux/arch/x86/include/asm/processor.h:485 */ |
| $ |
| .fi |
| |
| .P |
| To find the biggest data structures in the Linux kernel: |
| .PP |
| .nf |
| $ pahole -s | sort -k2 -nr | head -5 |
| cmp_data 290904 1 |
| dec_datas 274520 1 |
| cpu_entry_area 217088 0 |
| pglist_data 172928 4 |
| saved_cmdlines_buffer 131104 1 |
| $ |
| .fi |
| .P |
| The second column is the size in bytes and the third is the number of alignment holes in |
| that structure. |
| .P |
| Show data structures that have a raw spinlock and are related to the RCU mechanism: |
| .PP |
| .nf |
| $ pahole --contains raw_spinlock_t --prefix rcu |
| rcu_node |
| rcu_data |
| rcu_state |
| $ |
| .fi |
| .P |
| To see that in context, combine it with \fIgrep\fR: |
| .PP |
| .nf |
| $ pahole rcu_state | grep raw_spinlock_t -B1 -A5 |
| /* --- cacheline 52 boundary (3328 bytes) --- */ |
| raw_spinlock_t ofl_lock; /* 3328 4 */ |
| |
| /* size: 3392, cachelines: 53, members: 35 */ |
| /* sum members: 3250, holes: 7, sum holes: 82 */ |
| /* padding: 60 */ |
| }; |
| $ |
| .fi |
| .P |
| |
| .SH SEE ALSO |
| \fIeu-readelf\fR(1), \fIreadelf\fR(1), \fIobjdump\fR(1). |
| .P |
| \fIhttps://www.kernel.org/doc/ols/2007/ols2007v2-pages-35-44.pdf\fR. |
| .SH AUTHOR |
| \fBpahole\fR was written and is maintained by Arnaldo Carvalho de Melo <acme@kernel.org>. |
| .P |
| Thanks to Andrii Nakryiko and Martin KaFai Lau for providing the BTF encoder |
| and improving the codebase while making sure the BTF encoder works as needed |
| to be used in encoding the Linux kernel .BTF section from the DWARF info |
| generated by gcc. For that Andrii wrote a BTF deduplicator in libbpf that is |
| used by \fBpahole\fR. |
| .P |
| Please send bug reports to <dwarves@vger.kernel.org>. |
| .P |
| No\ subscription is required. |