namhyung / uftrace

Function graph tracer for C/C++/Rust/Python
https://uftrace.github.io/slide/
GNU General Public License v2.0
3.04k stars 473 forks source link

Support a way to open kernel source code based on uftrace data for kernel #414

Open honggyukim opened 6 years ago

honggyukim commented 6 years ago

It'd be useful to add a tool called mkdbg to create .dbg file from given ELF file. The purposed use case for this is to create .dbg file for vmlinuz kernel image with its debug line info.

Otherwise, we have to provide an additional option such as --kernel-image=[vmlinux] to generate source line information during record time.

It can be used to follow source code of ftrace recorded function graph data in TUI mode.

honggyukim commented 6 years ago

It can be related to #401.

honggyukim commented 6 years ago

At first, we have to fix incorrect kernel address shown in TUI mode. For example, handle_mm_fault is shown 0xffff811c4dd0 but it's actually at 0xffffffff811c4dd0. It's because uftrace only saves 48-bits for address but it has to show in 64-bit address space.

honggyukim commented 6 years ago

Thinking again, I found a way to do it without such mkdbg tool. The source line info can simply be extracted by nm tool with -l option.

$ nm -l /usr/lib/debug/boot/vmlinux-4.4.0-116-generic | grep "^[0-9a-f]\+ [tT] .*:[0-9]\+" | head
ffffffff813a55e0 t aa_af_perm.constprop.3       /build/linux-fQ94TU/linux-4.4.0/security/apparmor/net.c:183
ffffffff81393340 T aa_alloc_profile     /build/linux-fQ94TU/linux-4.4.0/security/apparmor/policy.c:259
ffffffff8139dad0 T aa_alloc_proxy       /build/linux-fQ94TU/linux-4.4.0/security/apparmor/label.c:63
ffffffff81fa2fb6 T aa_alloc_root_ns     /build/linux-fQ94TU/linux-4.4.0/security/apparmor/policy_ns.c:333
ffffffff8139b920 T aa_alloc_sid /build/linux-fQ94TU/linux-4.4.0/security/apparmor/sid.c:35
ffffffff8138a3d0 T aa_alloc_task_context        /build/linux-fQ94TU/linux-4.4.0/security/apparmor/context.c:38
ffffffff8138bbf0 T aa_apply_modes_to_perms      /build/linux-fQ94TU/linux-4.4.0/security/apparmor/lib.c:308
ffffffff81389e70 T aa_audit     /build/linux-fQ94TU/linux-4.4.0/security/apparmor/audit.c:132
ffffffff8139bc40 T aa_audit_file        /build/linux-fQ94TU/linux-4.4.0/security/apparmor/file.c:103
ffffffff8138ba00 T aa_audit_perm_mask   /build/linux-fQ94TU/linux-4.4.0/security/apparmor/lib.c:257

$ nm -l /usr/lib/debug/boot/vmlinux-4.4.0-116-generic | grep "^[0-9a-f]\+ [tT] .*:[0-9]\+" | tail
ffffffff81444910 t zx_direction_output  /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:69
ffffffff81444990 t zx_get_value /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:93
ffffffff820c0101 t zx_gpio_driver_exit  /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:300
ffffffff81fa8ca6 t zx_gpio_driver_init  /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:30i
ffffffff81444ce0 t zx_gpio_probe        /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:218
ffffffff81444ba0 t zx_irq_handler       /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:160
ffffffff81444ae0 t zx_irq_mask  /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:181
ffffffff814449e0 t zx_irq_type  /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:110
ffffffff81444b40 t zx_irq_unmask        /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:196
ffffffff814449b0 t zx_set_value /build/linux-fQ94TU/linux-4.4.0/drivers/gpio/gpio-zx.c:100

The remaining problem is to change the filepath to the user's source location of prebuilt kernel image. It could be simpler if the user creates the same filepath using softlink to their kernel source location.

honggyukim commented 6 years ago

I got the above kernel image from the link below: (just leaving this note for later reference) https://launchpad.net/ubuntu/xenial/amd64/linux-image-4.4.0-116-generic-dbgsym/4.4.0-116.140

And ubuntu kernel source is downloaded and set the kernel version as follows:

$ git clone git://kernel.ubuntu.com/ubuntu/ubuntu-xenial
$ cd ubuntu-xenial
$ git checkout Ubuntu-4.4.0-116.140 -b Ubuntu-4.4.0-116.140
honggyukim commented 6 years ago

Hmm.. I thought about it again. What about putting the filepath and line info inside .sym and kallsyms? The layout looks just same as the output from nm with -l/--line-numbers option.

$ nm --line-numbers /usr/lib/debug/boot/vmlinux-4.4.0-116-generic | grep "[tT] handle_mm_fault"
ffffffff811c4dd0 T handle_mm_fault      /build/linux-fQ94TU/linux-4.4.0/mm/memory.c:3435

Its layout is as follows:

(address) (type) (symbol_name)<tab>(filepath:line_number)

I think it's much easier to parse than using .dbg separately. We can just skip if <tab>(filepath:line_number) part doesn't exist.

Instead of just copying from /proc/kallsyms, we can just run the below command with this change:

$ nm -l <kernel_image_with_debuginfo> | grep "^[0-9a-f]\+ [tT] " > uftrace.data/kallsyms

Then we can ask users to create a soft link properly based on the debug info source location to the kernel source directory.

For example, I made the soft link as follows to make the source location same with its debug info location:

$ readlink /build/linux-fQ94TU/linux-4.4.0
/home/honggyu/work/kernel/ubuntu/ubuntu-xenial
honggyukim commented 6 years ago

One more small benefit of using nm tool for getting source location is that we can make uftrace free from libdw-dev.

namhyung commented 6 years ago

I think it's better (and intuitive) to keep debug info (including line numbers) in .dbg files. Using nm -l to collect line info with libdw looks useful.

honggyukim commented 6 years ago

nm uses libbfd-*-system.so instead of libdw so I think we can verify our source location with nm tool.