Re: [PATCH v2] scripts/link-vmlinux.sh: Add alias to duplicate symbols for kallsyms

From: Francis Laniel
Date: Thu Aug 24 2023 - 11:36:50 EST


Hi.

Le vendredi 21 juillet 2023, 14:40:54 CEST Alessandro Carminati a écrit :
> Hello,
>
> I apologize for being noisy today.
>
> In an effort to be collaborative, I would like to share my thoughts on why I
> see duplicate symbols in fs/binfmt_elf.c.
>
> Il giorno ven 21 lug 2023 alle ore 11:22 Alessandro Carminati
>
> <alessandro.carminati@xxxxxxxxx> ha scritto:
> > Hello Steven, Alexander, and Nick,
> >
> > Since now I realize that a lot of people are working on my very same
> > argument, I'm writing you this mail just with the intent of not leaving
> > my statements floating in the air, and help the cause by sharing my
> > experience, as little it is, to solve this problem.
> >
> > The addr2line strategy, I tried to implement, allows me to achieve the
> > level of accuracy that Luis mentioned in his comment about live-patching
> > suggestions. The addr2line-based approach is feasible, however, to make
> > this approach operable, I had to ensure that vmlinux contains the
> > necessary debug information.
> > Let me clarify.
> > During the kernel build, I do need the vmlinux to contain debug
> > information. The approach I pursued parses the nm output and, when it
> > detects a duplicate symbol, it needs to query vmlinux using addr2line to
> > resolve the address where the symbol is reported to be.
> > The whole process takes place during the building phase.
> > I've completed the work to integrate the new alias within the compilation
> > phase, and I wanted to share with you how it looks now.
> >
> > ```
> > ~ # uname -a
> > Linux (none) 6.4.0 #1 SMP PREEMPT Thu Jul 20 10:05:36 UTC 2023 aarch64
> > GNU/Linux ~ # cat /proc/kallsyms | grep gic_mask_irq
> > ffffacf2eb64dae4 t gic_mask_irq
> > ffffacf2eb64dae4 t gic_mask_irq@_drivers_irqchip_irq-gic_c_167
> > ffffacf2eb650960 t gic_mask_irq
> > ffffacf2eb650960 t gic_mask_irq@_drivers_irqchip_irq-gic-v3_c_404
> > ~ #
> > ```
> >
> > Despite this appearing to have a sufficient level of accuracy, when I
> > tested it, I realized something I really did not expect. Multiple
> > instances of the same function exist, and when I say "same function," I
> > don't just mean the name, but also the function's body. I apologize for
> > stating something that may sound obvious to you, but I found this really
> > unexpected.
> >
> > ```
> > ~ # uname -a
> > Linux (none) 6.4.0 #1 SMP PREEMPT Thu Jul 20 10:05:36 UTC 2023 aarch64
> > GNU/Linux ~ # cat /proc/kallsyms | grep -E " [ttT] " | cut -d" "
> > -f3|sort| uniq -d| grep @_
> > BIT_initDStream@_lib_zstd_common_bitstream_h_259
> > __dev_hold@_include_linux_netdevice_h_4059
> > __dev_put@_include_linux_netdevice_h_4048
> > __flush_tlb_range@_arch_arm64_include_asm_tlbflush_h_291
> > __flush_tlb_range_constprop_0@_arch_arm64_include_asm_tlbflush_h_291
> > __kern_my_cpu_offset@_arch_arm64_include_asm_percpu_h_40
> > __kvm_nvhe_$x@_arch_arm64_kvm_hyp_include_nvhe_memory_h_22
> > __kvm_nvhe___kvm_skip_instr@_arch_arm64_kvm_hyp_include_hyp_adjust_pc_h_34
> > __kvm_nvhe_hyp_page_count@_arch_arm64_kvm_hyp_include_nvhe_memory_h_47
> > __kvm_nvhe_hyp_phys_to_virt@_arch_arm64_kvm_hyp_include_nvhe_memory_h_22
> > __kvm_nvhe_hyp_virt_to_phys@_arch_arm64_kvm_hyp_include_nvhe_memory_h_27
> > __kvm_skip_instr@_arch_arm64_kvm_hyp_include_hyp_adjust_pc_h_34
> > __nodes_weight_constprop_0@_include_linux_nodemask_h_239
> > __pi_$x@_scripts_dtc_libfdt_libfdt_h_145
> > __pi_fdt32_ld@_scripts_dtc_libfdt_libfdt_h_145
> > __preempt_count_dec_and_test@_arch_arm64_include_asm_current_h_19
> > acpi_dev_filter_resource_type_cb@_include_linux_acpi_h_520
> > add_quirk@_drivers_mmc_core_card_h_158
> > bpf_enable_instrumentation@_include_linux_bpf_h_1937
> > btf_id_cmp_func@_include_linux_btf_h_469
> > copy_from_sockptr_offset_constprop_0@_include_linux_sockptr_h_44
> > cpucap_multi_entry_cap_matches@_arch_arm64_include_asm_cpufeature_h_395
> > cpufreq_register_em_with_opp@_include_linux_cpufreq_h_1228
> > cpumask_weight@_include_linux_cpumask_h_691
> > cpumask_weight_constprop_0@_include_linux_cpumask_h_690
> > css_put@_include_linux_cgroup_refcnt_h_77
> > dma_cookie_status@_drivers_dma_dmaengine_h_74
> > dst_discard@_include_net_dst_h_392
> > dst_output@_include_net_dst_h_457
> > elf_core_dump@_fs_binfmt_elf_c_2027
> > fixup_use_fwh_lock@_drivers_mtd_chips_fwh_lock_h_102
> > flush_tlb_mm@_arch_arm64_include_asm_tlbflush_h_250
> > fwh_lock_varsize@_drivers_mtd_chips_fwh_lock_h_81
> > fwh_unlock_varsize@_drivers_mtd_chips_fwh_lock_h_92
> > fwh_xxlock_oneblock@_drivers_mtd_chips_fwh_lock_h_31
> > get_net_ns@_include_net_net_namespace_h_231
> > inline_map_read_isra_0@_include_linux_mtd_map_h_393
> > inline_map_write_part_0@_include_linux_mtd_map_h_426
> > io_run_task_work@_io_uring_io_uring_h_282
> > ipv6_portaddr_hash_isra_0@_include_net_ipv6_h_732
> > irq_find_host@_include_linux_irqdomain_h_322
> > jhash@_include_linux_jhash_h_76
> > jhash_constprop_0@_include_linux_jhash_h_76
> > ktime_get_boottime@_include_linux_timekeeping_h_94
> > ktime_get_real@_include_linux_timekeeping_h_78
> > load_elf_binary@_fs_binfmt_elf_c_824
> > load_elf_phdrs@_fs_binfmt_elf_c_468
> > may_use_simd@_arch_arm64_include_asm_alternative-macros_h_232
> > netif_tx_disable@_include_linux_netdevice_h_4486
> > of_parse_phandle@_include_linux_of_h_946
> > of_parse_phandle_constprop_0@_include_linux_of_h_943
> > padzero@_fs_binfmt_elf_c_142
> > percpu_down_read_constprop_0@_include_linux_percpu-rwsem_h_47
> > percpu_ref_get_many@_include_linux_percpu-refcount_h_199
> > percpu_ref_get_many_constprop_0@_include_linux_percpu-refcount_h_198
> > percpu_ref_put_many_constprop_0@_include_linux_percpu-refcount_h_326
> > percpu_up_read@_include_linux_percpu-rwsem_h_98
> > percpu_up_read_constprop_0@_include_linux_percpu-rwsem_h_97
> > pinconf_generic_dt_node_to_map_all@_include_linux_pinctrl_pinconf-generic_
> > h_223
> > pinconf_generic_dt_node_to_map_group@_include_linux_pinctrl_pinconf-gener
> > ic_h_207
> > pinconf_generic_dt_node_to_map_pin@_include_linux_pinctrl_pinconf-generic
> > _h_215
> > platform_device_register_resndata_constprop_0@_include_linux_platform_dev
> > ice_h_125
> > ptrauth_keys_install_user@_arch_arm64_include_asm_alternative-macros_h_23
> > 2 readl@_arch_arm64_include_asm_io_h_75
> > reqsk_put@_include_net_request_sock_h_133
> > rht_key_get_hash_constprop_0_isra_0@_include_linux_rhashtable_h_133
> > rht_key_get_hash_isra_0@_include_linux_rhashtable_h_125
> > role_show@_include_linux_device_h_763
> > sdhci_and_cqhci_reset@_drivers_mmc_host_sdhci-cqhci_h_16
> > set_active_memcg_part_0@_include_linux_sched_mm_h_410
> > set_brk@_fs_binfmt_elf_c_114
> > set_is_seen@_arch_arm64_include_asm_current_h_19
> > set_lookup@_arch_arm64_include_asm_current_h_19
> > sha1_base_init@_include_crypto_sha1_base_h_22
> > sha224_base_init@_include_crypto_sha256_base_h_23
> > sha256_base_init@_include_crypto_sha256_base_h_31
> > spi_sync_transfer_constprop_0@_include_linux_spi_spi_h_1339
> > spi_write@_include_linux_spi_spi_h_1363
> > tlb_flush@_arch_arm64_include_asm_tlb_h_54
> > trace_xhci_dbg_quirks@_drivers_usb_host_xhci-trace_h_48
> > udp_lib_close@_include_net_udp_h_197
> > udp_lib_hash@_include_net_udp_h_189
> > virtio_net_hdr_to_skb_constprop_0@_include_linux_virtio_net_h_48
> > writenote@_fs_binfmt_elf_c_1479
> > zero_user_segments@_include_linux_highmem_h_271
> > zero_user_segments_constprop_0@_include_linux_highmem_h_268
> > ```
> >
> > The previous evidence demonstrates that adding a tag with a file and line
> > number does not make a symbol unique.
> >
> > Here, I inspect the function body to verify if the functions are indeed
> > the same.
> >
> > ```
> > Welcome to Buildroot
> > buildroot login: root
> > ~ # cat /proc/kallsyms | grep set_brk
> > ffffa8a9d1cf1d2c t set_brk
> > ffffa8a9d1cf1d2c t set_brk@_fs_binfmt_elf_c_114
> > ffffa8a9d1cf4454 t set_brk
> > ffffa8a9d1cf4454 t set_brk@_fs_binfmt_elf_c_114
> > ~ # QEMU: Terminated
> > $ cat System.map | grep set_brk
> > ffff8000082f1d2c t set_brk
> > ffff8000082f4454 t set_brk
> > ~ $ r2 vmlinux
> > Warning: run r2 with -e bin.cache=true to fix relocations in disassembly
> >
> > -- Reduce the delta where flag resolving by address is used with
> > cfg.delta
> >
> > [0xffff800008000000]> s 0xffff8000082f1d2c
> > [0xffff8000082f1d2c]> aa
> > [x] Analyze all flags starting with sym. and entry0 (aa)
> > [x] Analyze all functions arguments/locals
> > [0xffff8000082f1d2c]> pdf
> >
> > ; CALL XREFS from sym.load_elf_binary @ 0xffff8000082f352c(x),
> > 0xffff8000082f38d4(x), 0xffff8000082f3a68(x)>
> > ┌ 112: sym.set_brk (int64_t arg1, int64_t arg2, int64_t arg3);
> > │ ; arg int64_t arg1 @ x0
> > │ ; arg int64_t arg2 @ x1
> > │ ; arg int64_t arg3 @ x2
> > │ ; var int64_t var_10h @ sp+0x10
> > │ 0xffff8000082f1d2c 3f2303d5 paciasp ;
> > binfmt_elf.c:114 │ 0xffff8000082f1d30 fd7bbea9 stp
> > x29, x30, [sp, -0x20]! │ 0xffff8000082f1d34 00fc3f91
> > add x0, x0, 0xfff ; binfmt_elf.c:115 ; arg1 │
> > 0xffff8000082f1d38 fd030091 mov x29, sp ;
> > binfmt_elf.c:114 │ 0xffff8000082f1d3c 21fc3f91 add
> > x1, x1, 0xfff ; binfmt_elf.c:116 ; arg2 │ 0xffff8000082f1d40
> > 00cc7492 and x0, x0, 0xfffffffffffff000 ; binfmt_elf.c:114 ;
> > arg1 │ 0xffff8000082f1d44 f30b00f9 str x19, [sp,
> > 0x10] ; binfmt_elf.c:116 │ 0xffff8000082f1d48 33cc7492
> > and x19, x1, 0xfffffffffffff000 ; arg2 │ 0xffff8000082f1d4c
> > 1f0013eb cmp x0, x19 ; binfmt_elf.c:117 ; arg1 │
> > ┌─< 0xffff8000082f1d50 63010054 b.lo 0xffff8000082f1d7c │
> > ┌──> 0xffff8000082f1d54 014138d5 mrs x1, sp_el0 ;
> > binfmt_elf.c:128 │ ╎│ 0xffff8000082f1d58 22fc41f9 ldr
> > x2, [x1, 0x3f8] ; current.h:21 ; 0xd9 ; 217 │ ╎│
> > 0xffff8000082f1d5c 00008052 mov w0, 0 ;
> > binfmt_elf.c:129 │ ╎│ 0xffff8000082f1d60 539400f9 str
> > x19, [x2, 0x128] ; binfmt_elf.c:128 │ ╎│ 0xffff8000082f1d64
> > 21fc41f9 ldr x1, [x1, 0x3f8] ; current.h:17 ; 0xd9 ; 217 │ ╎│
> > 0xffff8000082f1d68 339000f9 str x19, [x1, 0x120] ;
> > binfmt_elf.c:128 │ ╎│ 0xffff8000082f1d6c f30b40f9 ldr
> > x19, [var_10h] ; binfmt_elf.c:129 ; 5 │ ╎│ 0xffff8000082f1d70
> > fd7bc2a8 ldp x29, x30, [sp], 0x20 │ ╎│ 0xffff8000082f1d74
> > bf2303d5 autiasp
> > │ ╎│ 0xffff8000082f1d78 c0035fd6 ret
> > │ ╎└─> 0xffff8000082f1d7c 42007e92 and x2, x2, 4 ;
> > binfmt_elf.c:123 ; arg3 │ ╎ 0xffff8000082f1d80 610200cb
> > sub x1, x19, x0 ; arg1 │ ╎ 0xffff8000082f1d84 cae3fc97
> > bl sym.vm_brk_flags │ └──< 0xffff8000082f1d88 60feff34
> > cbz w0, 0xffff8000082f1d54 ; binfmt_elf.c:125 │
> > 0xffff8000082f1d8c f30b40f9 ldr x19, [var_10h] ;
> > binfmt_elf.c:130 ; 5 │ 0xffff8000082f1d90 fd7bc2a8
> > ldp x29, x30, [sp], 0x20 │ 0xffff8000082f1d94 bf2303d5
> > autiasp
> > └ 0xffff8000082f1d98 c0035fd6 ret
> > [0xffff8000082f1d2c]> s 0xffff8000082f4454
> > [0xffff8000082f4454]> pdf
> >
> > ; CALL XREFS from sym.load_elf_binary_1 @
> > 0xffff8000082f5cc0(x), 0xffff8000082f5e5c(x),
> > 0xffff8000082f6648(x)>
> > ┌ 112: sym.set_brk_1 (int64_t arg1, int64_t arg2, int64_t arg3);
> > │ ; arg int64_t arg1 @ x0
> > │ ; arg int64_t arg2 @ x1
> > │ ; arg int64_t arg3 @ x2
> > │ ; var int64_t var_10h @ sp+0x10
> > │ 0xffff8000082f4454 3f2303d5 paciasp ;
> > binfmt_elf.c:114 │ 0xffff8000082f4458 fd7bbea9 stp
> > x29, x30, [sp, -0x20]! │ 0xffff8000082f445c 00fc3f91
> > add x0, x0, 0xfff ; binfmt_elf.c:115 ; arg1 │
> > 0xffff8000082f4460 fd030091 mov x29, sp ;
> > binfmt_elf.c:114 │ 0xffff8000082f4464 21fc3f91 add
> > x1, x1, 0xfff ; binfmt_elf.c:116 ; arg2 │ 0xffff8000082f4468
> > 00cc7492 and x0, x0, 0xfffffffffffff000 ; binfmt_elf.c:114 ;
> > arg1 │ 0xffff8000082f446c f30b00f9 str x19, [sp,
> > 0x10] ; binfmt_elf.c:116 │ 0xffff8000082f4470 33cc7492
> > and x19, x1, 0xfffffffffffff000 ; arg2 │ 0xffff8000082f4474
> > 1f0013eb cmp x0, x19 ; binfmt_elf.c:117 ; arg1 │
> > ┌─< 0xffff8000082f4478 63010054 b.lo 0xffff8000082f44a4 │
> > ┌──> 0xffff8000082f447c 014138d5 mrs x1, sp_el0 ;
> > binfmt_elf.c:128 │ ╎│ 0xffff8000082f4480 22fc41f9 ldr
> > x2, [x1, 0x3f8] ; current.h:21 ; 0xd9 ; 217 │ ╎│
> > 0xffff8000082f4484 00008052 mov w0, 0 ;
> > binfmt_elf.c:129 │ ╎│ 0xffff8000082f4488 539400f9 str
> > x19, [x2, 0x128] ; binfmt_elf.c:128 │ ╎│ 0xffff8000082f448c
> > 21fc41f9 ldr x1, [x1, 0x3f8] ; current.h:17 ; 0xd9 ; 217 │ ╎│
> > 0xffff8000082f4490 339000f9 str x19, [x1, 0x120] ;
> > binfmt_elf.c:128 │ ╎│ 0xffff8000082f4494 f30b40f9 ldr
> > x19, [var_10h] ; binfmt_elf.c:129 ; 5 │ ╎│ 0xffff8000082f4498
> > fd7bc2a8 ldp x29, x30, [sp], 0x20 │ ╎│ 0xffff8000082f449c
> > bf2303d5 autiasp
> > │ ╎│ 0xffff8000082f44a0 c0035fd6 ret
> > │ ╎└─> 0xffff8000082f44a4 42007e92 and x2, x2, 4 ;
> > binfmt_elf.c:123 ; arg3 │ ╎ 0xffff8000082f44a8 610200cb
> > sub x1, x19, x0 ; arg1 │ ╎ 0xffff8000082f44ac 00dafc97
> > bl sym.vm_brk_flags │ └──< 0xffff8000082f44b0 60feff34
> > cbz w0, 0xffff8000082f447c ; binfmt_elf.c:125 │
> > 0xffff8000082f44b4 f30b40f9 ldr x19, [var_10h] ;
> > binfmt_elf.c:130 ; 5 │ 0xffff8000082f44b8 fd7bc2a8
> > ldp x29, x30, [sp], 0x20 │ 0xffff8000082f44bc bf2303d5
> > autiasp
> > └ 0xffff8000082f44c0 c0035fd6 ret
> > [0xffff8000082f4454]>
> > ```
> >
> > While I can speculate on a reasonable explanation for why I see symbols
> > coming from header files being duplicated – when a header file is
> > included in a C file and it produces a function that the compiler does
> > not want to inline, it is replicated every time the file is included – I
> > have no convincing explanation as to why the fs/binfmt.c functions exist
> > in more than one instance.
> >
> > ```
> > elf_core_dump@_fs_binfmt_elf_c_2027
> > load_elf_binary@_fs_binfmt_elf_c_824
> > load_elf_phdrs@_fs_binfmt_elf_c_468
> > padzero@_fs_binfmt_elf_c_142
> > set_brk@_fs_binfmt_elf_c_114
> > writenote@_fs_binfmt_elf_c_1479
> > ```
>
> After examining the contents of built-in.a, I have come up with a new
> interpretation of what I am observing.
> According to built-in.a, System.map, and vmlinux there are two symbols named
> set_brk.
>
> ```
> ~ $ cat System.map | grep set_brk
> ffff8000082f1d2c t set_brk
> ffff8000082f4454 t set_brk
> ~ $
> ~ $ nm -n vmlinux | grep set_brk
> ffff8000082f1d2c t set_brk
> ffff8000082f4454 t set_brk
> ~ $
> ~ $ nm -n built-in.a| grep set_brk
> 00000000000000d4 t set_brk
> 00000000000000d4 t set_brk
> ~ $
> ~ $ nm -n built-in.a | grep set_brk -B100| egrep "set_brk|\.o:$"
> fs/binfmt_elf.o:
> 00000000000000d4 t set_brk
> fs/compat_binfmt_elf.o:
> 00000000000000d4 t set_brk
> ```
>
> These two symbols come from fs/binfmt_elf.o and fs/compat_binfmt_elf.o, and
> they are just two symbols that happen to share the same name, as is common
> in the kernel.
>
> at the same time, addr2line reports symbols to be generated from the same
> file.
>
> ```
> ~ $ llvm-addr2line-14 -fe vmlinux ffff8000082f1d2c ffff8000082f4454
> set_brk
> /home/alessandro/src/lka64/linux-6.4/fs/binfmt_elf.c:114
> set_brk
> /home/alessandro/src/lka64/linux-6.4/fs/binfmt_elf.c:114
> ~ $
> ~ $ addr2line -fe vmlinux ffff8000082f1d2c ffff8000082f4454
> set_brk
> /home/alessandro/src/lka64/linux-6.4/fs/binfmt_elf.c:114
> set_brk
> /home/alessandro/src/lka64/linux-6.4/fs/binfmt_elf.c:114
> ```
> looking at the source code:
> https://elixir.bootlin.com/linux/v6.4/source/fs/compat_binfmt_elf.c#L144
> the cause of this behavior, which is unexpected but correct.

Thank you for the investigation, this an interesting reading!

> The rationale is that using source file + line number iproduces better
> kallsyms table, but it is still do not produce unique names.

When I first read your cover letter, I also thought it would be cool to have
the filename rather than a serial ID.
So, your latest modification is really good as it goes into this direction.
Regarding having non unique names, I am not sure if this is a problem.
In my case, which is using kprobe to attach BPF code to trace some events,
your contribution would make me on the way to know which address I should use
because I could choose regarding the filename.

I am curious about a potential v3 of this patch!

> BR
> Alessandro
>
> > As a final note, please understand that my patch was not intended to
> > undermine anyone's work. I simply encountered a problem that I wanted to
> > help solve. Attached to this message is my code, in case anyone wants to
> > replicate it. I would appreciate being kept in the loop, as I genuinely
> > want to assist in fixing this problem.
> >
> > BR
> > Alessandro
> > ---
> >
> > init/Kconfig | 36 ++++
> > scripts/Makefile | 4 +
> > scripts/kas_alias/Makefile | 4 +
> > scripts/kas_alias/a2l.c | 268 ++++++++++++++++++++++++++++
> > scripts/kas_alias/a2l.h | 32 ++++
> > scripts/kas_alias/duplicates_list.c | 70 ++++++++
> > scripts/kas_alias/duplicates_list.h | 15 ++
> > scripts/kas_alias/item_list.c | 230 ++++++++++++++++++++++++
> > scripts/kas_alias/item_list.h | 26 +++
> > scripts/kas_alias/kas_alias.c | 217 ++++++++++++++++++++++
> > scripts/link-vmlinux.sh | 11 +-
> > 11 files changed, 910 insertions(+), 3 deletions(-)
> > create mode 100644 scripts/kas_alias/Makefile
> > create mode 100644 scripts/kas_alias/a2l.c
> > create mode 100644 scripts/kas_alias/a2l.h
> > create mode 100644 scripts/kas_alias/duplicates_list.c
> > create mode 100644 scripts/kas_alias/duplicates_list.h
> > create mode 100644 scripts/kas_alias/item_list.c
> > create mode 100644 scripts/kas_alias/item_list.h
> > create mode 100644 scripts/kas_alias/kas_alias.c
> >
> > diff --git a/init/Kconfig b/init/Kconfig
> > index f7f65af4ee12..bc69fcd9cbc8 100644
> > --- a/init/Kconfig
> > +++ b/init/Kconfig
> > @@ -1737,6 +1737,42 @@ config KALLSYMS_BASE_RELATIVE
> >
> > time constants, and no relocation pass is required at runtime to
> > fix
> > up the entries based on the runtime load address of the kernel.
> >
> > +config KALLSYMS_ALIAS
> > + bool "Produces alias for duplicated symbols" if EXPERT
> > + depends on KALLSYMS && (DEBUG_INFO_DWARF4 || DEBUG_INFO_DWARF5)
> > + help
> > + It is not uncommon for drivers or modules related to similar
> > + peripherals to have symbols with the exact same name.
> > + While this is not a problem for the kernel's binary itself, it
> > + becomes an issue when attempting to trace or probe specific
> > + functions using infrastructure like ftrace or kprobe.
> > +
> > + This option addresses this challenge by extending the symbol
> > names + with unique suffixes during the kernel build process.
> > + The newly created aliases for these duplicated symbols are
> > unique
> > + names that can be fed to the ftrace sysfs interface. By doing
> > so, it + enables previously unreachable symbols to be probed.
> > +
> > +config CONFIG_KALLSYMS_ALIAS_DATA
> > + bool "Produces alias also for data"
> > + depends on KALLSYMS_ALIAS
> > + help
> > + Sometimes it can be useful to refer to data. In live patch
> > scenarios, + you may find yourself needing to use symbols that
> > are shared with + other functions. Since symbols face the same
> > issue as functions, this + option allows you to create aliases
> > for data as well.
> > +
> > +config CONFIG_KALLSYMS_ALIAS_DATA_ALL
> > + bool "Removes all filter when producing data alias"
> > + depends on CONFIG_KALLSYMS_ALIAS_DATA
> > + help
> > + When selecting data aliases, not all symbols are included in the
> > set + This is because many symbols are unlikely to be used. If
> > you choose + to have an alias for all data symbols, be aware that
> > it will + significantly increase the size.
> > +
> > + If unsure, say N.
> > +
> >
> > # end of the "standard kernel features (expert users)" menu
> >
> > # syscall, maps, verifier
> >
> > diff --git a/scripts/Makefile b/scripts/Makefile
> > index 32b6ba722728..65fafe17cfe5 100644
> > --- a/scripts/Makefile
> > +++ b/scripts/Makefile
> > @@ -49,3 +49,7 @@ subdir-$(CONFIG_SECURITY_SELINUX) += selinux
> >
> > # Let clean descend into subdirs
> > subdir- += basic dtc gdb kconfig mod
> >
> > +
> > +# KALLSyms alias
> > +subdir-$(CONFIG_KALLSYMS_ALIAS) += kas_alias
> > +
> > diff --git a/scripts/kas_alias/Makefile b/scripts/kas_alias/Makefile
> > new file mode 100644
> > index 000000000000..e1fde69232b4
> > --- /dev/null
> > +++ b/scripts/kas_alias/Makefile
> > @@ -0,0 +1,4 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +hostprogs-always-$(CONFIG_KALLSYMS_ALIAS) += kas_alias
> > +
> > +kas_alias-objs := duplicates_list.o item_list.o kas_alias.o a2l.o
> > diff --git a/scripts/kas_alias/a2l.c b/scripts/kas_alias/a2l.c
> > new file mode 100644
> > index 000000000000..a9692ac30180
> > --- /dev/null
> > +++ b/scripts/kas_alias/a2l.c
> > @@ -0,0 +1,268 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <sys/types.h>
> > +#include <sys/wait.h>
> > +#include <string.h>
> > +#include <stdint.h>
> > +#include <stdbool.h>
> > +
> > +#include "a2l.h"
> > +
> > +int addr2line_pid = -1;
> > +int a2l_in[2];
> > +int a2l_out[2];
> > +char line[MAX_BUF];
> > +char vmlinux_path[MAX_BUF];
> > +char addr2line_cmd[MAX_CMD_LEN];
> > +FILE *a2l_stdin, *a2l_stdout;
> > +
> > +static char *normalize_path(const char *input_path, char *output_path)
> > +{
> > + char *prev_token = NULL;
> > + char *delimiter = "/";
> > + char inbuf[MAX_BUF];
> > + char *token;
> > + char *pos;
> > +
> > + memset(inbuf, 0, MAX_BUF);
> > + *output_path = '\0';
> > + strncpy(inbuf, input_path, MAX_BUF);
> > + if (!input_path || !output_path || strlen(input_path) == 0)
> > + return NULL;
> > +
> > + token = strtok(inbuf, delimiter);
> > + while (token) {
> > + if (strcmp(token, "..") == 0 && prev_token) {
> > + pos = strrchr(output_path, '/');
> > + if (pos)
> > + *pos = '\0';
> > +
> > + } else if (strcmp(token, ".") != 0) {
> > + strcat(output_path, "/");
> > + strcat(output_path, token);
> > + }
> > +
> > + prev_token = token;
> > + token = strtok(NULL, delimiter);
> > + }
> > +
> > + return output_path;
> > +}
> > +
> > +static void path_of(const char *full_path, char *path)
> > +{
> > + const char *last_slash = strrchr(full_path, '/');
> > + size_t path_length;
> > + char cwd[MAX_BUF];
> > +
> > + if (!last_slash) {
> > + if (getcwd(cwd, sizeof(cwd)))
> > + strcpy(path, cwd);
> > + else
> > + strcpy(path, ".");
> > + } else {
> > + path_length = last_slash - full_path;
> > + strncpy(path, full_path, path_length);
> > + path[path_length] = '\0';
> > + }
> > +}
> > +
> > +static bool file_exists(const char *file_path)
> > +{
> > + FILE *file;
> > +
> > + file = fopen(file_path, "r");
> > + if (file) {
> > + fclose(file);
> > + return true;
> > + }
> > + return false;
> > +}
> > +
> > +int addr2line_init(const char *cmd, const char *vmlinux)
> > +{
> > + if ((!file_exists(cmd)) || (!file_exists(vmlinux))) {
> > + printf("file not found\n");
> > + return 0;
> > + }
> > +
> > + path_of(vmlinux, vmlinux_path);
> > + if (pipe(a2l_in) == -1) {
> > + printf("Failed to create pipe\n");
> > + return 0;
> > + }
> > +
> > + if (pipe(a2l_out) == -1) {
> > + printf("Failed to create pipe\n");
> > + return 0;
> > + }
> > +
> > + addr2line_pid = fork();
> > + if (addr2line_pid == -1) {
> > + printf("Failed to fork process\n");
> > + close(a2l_in[P_READ]);
> > + close(a2l_in[P_WRITE]);
> > + close(a2l_out[P_READ]);
> > + close(a2l_out[P_WRITE]);
> > + return 0;
> > + }
> > +
> > + if (addr2line_pid == 0) {
> > + dup2(a2l_in[P_READ], 0);
> > + dup2(a2l_out[P_WRITE], 1);
> > + close(a2l_in[P_WRITE]);
> > + close(a2l_out[P_READ]);
> > +
> > + execlp(cmd, cmd, ADDR2LINE_ARGS, vmlinux, NULL);
> > +
> > + printf("Failed to execute addr2line command\n");
> > + exit(1);
> > + } else {
> > + close(a2l_in[P_READ]);
> > + close(a2l_out[P_WRITE]);
> > + }
> > +
> > + a2l_stdin = fdopen(a2l_in[P_WRITE], "w");
> > + if (!a2l_stdin) {
> > + printf("Failed to open pipe a2l_in\n");
> > + return 0;
> > + }
> > +
> > + a2l_stdout = fdopen(a2l_out[P_READ], "r");
> > + if (!a2l_stdout) {
> > + printf("Failed to open pipe a2l_out\n");
> > + fclose(a2l_stdin);
> > + return 0;
> > + }
> > +
> > + return 1;
> > +}
> > +
> > +const char *remove_subdir(const char *home, const char *f_path)
> > +{
> > + int i = 0;
> > +
> > + while (*(home + i) == *(f_path + i))
> > + i++;
> > +
> > + return (strlen(home) != i) ? NULL : f_path + i;
> > +}
> > +
> > +char *addr2line_get_lines(uint64_t address)
> > +{
> > + char buf[MAX_BUF];
> > +
> > + fprintf(a2l_stdin, "%08lx\n", address);
> > + fflush(a2l_stdin);
> > +
> > + if (!fgets(line, sizeof(line), a2l_stdout)) {
> > + printf("Failed to read lines from addr2line\n");
> > + return NULL;
> > + }
> > +
> > + if (!fgets(line, sizeof(line), a2l_stdout)) {
> > + printf("Failed to read lines from addr2line\n");
> > + return NULL;
> > + }
> > +
> > + line[strcspn(line, "\n")] = '\0';
> > + strncpy(buf, line, MAX_BUF);
> > + return normalize_path(buf, line);
> > +}
> > +
> > +int addr2line_cleanup(void)
> > +{
> > + int status;
> > +
> > + if (addr2line_pid != -1) {
> > + kill(addr2line_pid, SIGKILL);
> > + waitpid(addr2line_pid, &status, 0);
> > + fclose(a2l_stdin);
> > + fclose(a2l_stdout);
> > + addr2line_pid = -1;
> > + }
> > +
> > + return 1;
> > +}
> > +
> > +static char *find_executable(const char *command)
> > +{
> > + char *path_env = getenv("PATH");
> > + char *executable_path;
> > + char *path_copy;
> > + char *path;
> > + int n;
> > +
> > + if (!path_env)
> > + return NULL;
> > +
> > + path_copy = strdup(path_env);
> > + if (!path_copy)
> > + return NULL;
> > +
> > + path = strtok(path_copy, ":");
> > + while (path) {
> > + n = snprintf(0, 0, "%s/%s", path, command);
> > + executable_path = (char *)malloc(n + 1);
> > + snprintf(executable_path, n + 1, "%s/%s", path, command);
> > + if (access(executable_path, X_OK) == 0) {
> > + free(path_copy);
> > + return executable_path;
> > + }
> > +
> > + path = strtok(NULL, ":");
> > + free(executable_path);
> > + executable_path = NULL;
> > + }
> > +
> > + free(path_copy);
> > + if (executable_path)
> > + free(executable_path);
> > + return NULL;
> > +}
> > +
> > +const char *get_addr2line(int mode)
> > +{
> > + char *buf = "";
> > +
> > + switch (mode) {
> > + case A2L_CROSS:
> > + buf = getenv("CROSS_COMPILE");
> > + memcpy(addr2line_cmd, buf, strlen(buf));
> > + case A2L_DEFAULT:
> > + memcpy(addr2line_cmd + strlen(buf), ADDR2LINE,
> > strlen(ADDR2LINE)); + buf = find_executable(addr2line_cmd);
> > + if (buf) {
> > + memcpy(addr2line_cmd, buf, strlen(buf));
> > + free(buf);
> > + }
> > + return addr2line_cmd;
> > + case A2L_LLVM:
> > + default:
> > + return NULL;
> > + }
> > +}
> > +
> > +char *get_vmlinux(char *input)
> > +{
> > + const char *match_string1 = ".syms";
> > + const char *match_string2 = ".tmp_vmlinux.kallsyms";
> > + char *result = NULL;
> > + char *match_pos;
> > +
> > + match_pos = strstr(input, match_string1);
> > + if (!match_pos)
> > + return NULL;
> > +
> > + match_pos = strstr(input, match_string2);
> > + if (!match_pos)
> > + return NULL;
> > +
> > + result = strdup(input);
> > + match_pos = strstr(result, match_string1);
> > + *match_pos = '\0';
> > + return result;
> > +}
> > diff --git a/scripts/kas_alias/a2l.h b/scripts/kas_alias/a2l.h
> > new file mode 100644
> > index 000000000000..ca6419229dde
> > --- /dev/null
> > +++ b/scripts/kas_alias/a2l.h
> > @@ -0,0 +1,32 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +#ifndef A2L_H
> > +#define A2L_H
> > +#include <stdint.h>
> > +
> > +#define ADDR2LINE "addr2line"
> > +#define ADDR2LINE_ARGS "-fe"
> > +//#define VMLINUX "vmlinux"
> > +#define MAX_BUF 4096
> > +#define MAX_CMD_LEN 256
> > +#define P_READ 0
> > +#define P_WRITE 1
> > +#define A2L_DEFAULT 1
> > +#define A2L_CROSS 2
> > +#define A2L_LLVM 3
> > +#define A2L_MAKE_VALUE 2
> > +
> > +extern int addr2line_pid;
> > +extern int a2l_in[2];
> > +extern int a2l_out[2];
> > +extern char line[MAX_BUF];
> > +extern char vmlinux_path[MAX_BUF];
> > +extern char addr2line_cmd[MAX_CMD_LEN];
> > +
> > +int addr2line_init(const char *cmd, const char *vmlinux);
> > +char *addr2line_get_lines(uint64_t address);
> > +int addr2line_cleanup(void);
> > +const char *remove_subdir(const char *home, const char *f_path);
> > +const char *get_addr2line(int mode);
> > +char *get_vmlinux(char *input);
> > +
> > +#endif
> > diff --git a/scripts/kas_alias/duplicates_list.c
> > b/scripts/kas_alias/duplicates_list.c new file mode 100644
> > index 000000000000..e7a3d2917937
> > --- /dev/null
> > +++ b/scripts/kas_alias/duplicates_list.c
> > @@ -0,0 +1,70 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +#include <stdint.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <stdlib.h>
> > +#include <stdbool.h>
> > +
> > +#include "item_list.h"
> > +#include "duplicates_list.h"
> > +
> > +struct duplicate_item *find_duplicates(struct item *list)
> > +{
> > + struct duplicate_item *current_duplicate = NULL;
> > + struct duplicate_item *duplicates = NULL;
> > + struct duplicate_item *new_duplicate;
> > + struct item *current_item = list;
> > + bool prev_was_duplicate = false;
> > + struct item *prev_item = NULL;
> > +
> > + while (current_item) {
> > + if ((prev_item && (strcmp(current_item->symb_name,
> > prev_item->symb_name) == 0)) || + prev_was_duplicate) {
> > + if (!duplicates) {
> > + duplicates = malloc(sizeof(struct
> > duplicate_item)); + if (!duplicates)
> > + return NULL;
> > +
> > + duplicates->original_item = prev_item;
> > + duplicates->next = NULL;
> > + current_duplicate = duplicates;
> > + } else {
> > + new_duplicate = malloc(sizeof(struct
> > duplicate_item)); + if (!new_duplicate) {
> > + free_duplicates(&duplicates);
> > + return NULL;
> > + }
> > +
> > + new_duplicate->original_item = prev_item;
> > + new_duplicate->next = NULL;
> > + current_duplicate->next = new_duplicate;
> > + current_duplicate = new_duplicate;
> > +
> > + if ((strcmp(current_item->symb_name,
> > prev_item->symb_name) != 0) && +
> > (prev_was_duplicate))
> > + prev_was_duplicate = false;
> > + else
> > + prev_was_duplicate = true;
> > + }
> > + }
> > +
> > + prev_item = current_item;
> > + current_item = current_item->next;
> > + }
> > +
> > + return duplicates;
> > +}
> > +
> > +void free_duplicates(struct duplicate_item **duplicates)
> > +{
> > + struct duplicate_item *duplicates_iterator = *duplicates;
> > + struct duplicate_item *app;
> > +
> > + while (duplicates_iterator) {
> > + app = duplicates_iterator;
> > + duplicates_iterator = duplicates_iterator->next;
> > + free(app);
> > + }
> > +
> > + *duplicates = NULL;
> > +}
> > diff --git a/scripts/kas_alias/duplicates_list.h
> > b/scripts/kas_alias/duplicates_list.h new file mode 100644
> > index 000000000000..76aa73e584bc
> > --- /dev/null
> > +++ b/scripts/kas_alias/duplicates_list.h
> > @@ -0,0 +1,15 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +#ifndef DUPLICATES_LIST_H
> > +#define DUPLICATES_LIST_H
> > +
> > +#include "item_list.h"
> > +
> > +struct duplicate_item {
> > + struct item *original_item;
> > + struct duplicate_item *next;
> > +};
> > +
> > +struct duplicate_item *find_duplicates(struct item *list);
> > +void free_duplicates(struct duplicate_item **duplicates);
> > +
> > +#endif
> > diff --git a/scripts/kas_alias/item_list.c b/scripts/kas_alias/item_list.c
> > new file mode 100644
> > index 000000000000..48f2e525592a
> > --- /dev/null
> > +++ b/scripts/kas_alias/item_list.c
> > @@ -0,0 +1,230 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdint.h>
> > +#include <string.h>
> > +#include <stdbool.h>
> > +#include <assert.h>
> > +#include "item_list.h"
> > +
> > +#define CHECK_ORDER_BY_ADDRESS(sort_by, current, temp, op) \
> > + ((sort_by) == BY_ADDRESS && (current)->addr op (temp)->addr)
> > +#define CHECK_ORDER_BY_NAME(sort_by, current, temp, op) \
> > + ((sort_by) == BY_NAME && strcmp((current)->symb_name,
> > (temp)->symb_name) op 0) +
> > +struct item *list_index[96] = {0};
> > +
> > +void build_index(struct item *list)
> > +{
> > + char current_first_letter = ' ';
> > + struct item *current = list;
> > +
> > + while (current) {
> > + if (current->symb_name[0] != current_first_letter) {
> > + current_first_letter = current->symb_name[0];
> > + list_index[current_first_letter - 32] = current;
> > + }
> > + current = current->next;
> > + }
> > +}
> > +
> > +struct item *add_item(struct item **list, const char *name, char stype,
> > uint64_t addr) +{
> > + struct item *new_item;
> > + struct item *current;
> > +
> > + new_item = malloc(sizeof(struct item));
> > + if (!new_item)
> > + return NULL;
> > +
> > + strncpy(new_item->symb_name, name, MAX_NAME_SIZE);
> > + new_item->symb_name[MAX_NAME_SIZE - 1] = '\0';
> > + new_item->addr = addr;
> > + new_item->stype = stype;
> > + new_item->next = NULL;
> > +
> > + if (!(*list)) {
> > + *list = new_item;
> > + } else {
> > + current = *list;
> > + while (current->next)
> > + current = current->next;
> > +
> > + current->next = new_item;
> > + }
> > + return new_item;
> > +}
> > +
> > +void sort_list(struct item **list, int sort_by)
> > +{
> > + struct item *current = *list;
> > + struct item *sorted = NULL;
> > + struct item *next_item;
> > + struct item *temp;
> > +
> > + if (!(*list) || !((*list)->next))
> > + return;
> > +
> > + while (current) {
> > + next_item = current->next;
> > + if (!sorted ||
> > + (CHECK_ORDER_BY_ADDRESS(sort_by, current, sorted, <)
> > ||
> > + CHECK_ORDER_BY_NAME(sort_by, current, sorted, >=))) {
> > + current->next = sorted;
> > + sorted = current;
> > + } else {
> > + temp = sorted;
> > + while (temp->next &&
> > + (CHECK_ORDER_BY_ADDRESS(sort_by, current,
> > temp->next, >=) || +
> > CHECK_ORDER_BY_NAME(sort_by, current, temp->next, >=))) +
> > temp = temp->next;
> > +
> > + current->next = temp->next;
> > + temp->next = current;
> > + }
> > + current = next_item;
> > + }
> > +
> > + *list = sorted;
> > +}
> > +
> > +struct item *merge(struct item *left, struct item *right, int sort_by)
> > +{
> > + struct item *current = NULL;
> > + struct item *result = NULL;
> > +
> > + if (!left)
> > + return right;
> > + if (!right)
> > + return left;
> > +
> > + if (sort_by == BY_NAME) {
> > + if (strcmp(left->symb_name, right->symb_name) <= 0) {
> > + result = left;
> > + left = left->next;
> > + } else {
> > + result = right;
> > + right = right->next;
> > + }
> > + } else {
> > + if (sort_by == BY_ADDRESS) {
> > + if (left->addr <= right->addr) {
> > + result = left;
> > + left = left->next;
> > + } else {
> > + result = right;
> > + right = right->next;
> > + }
> > + }
> > + }
> > +
> > + current = result;
> > +
> > + while (left && right) {
> > + if (sort_by == BY_NAME) {
> > + if (strcmp(left->symb_name, right->symb_name) <=
> > 0) { + current->next = left;
> > + left = left->next;
> > + } else {
> > + current->next = right;
> > + right = right->next;
> > + }
> > + } else {
> > + if (sort_by == BY_ADDRESS) {
> > + if (left->addr <= right->addr) {
> > + current->next = left;
> > + left = left->next;
> > + } else {
> > + current->next = right;
> > + right = right->next;
> > + }
> > + }
> > + }
> > +
> > + current = current->next;
> > + }
> > +
> > + if (left) {
> > + current->next = left;
> > + } else {
> > + if (right)
> > + current->next = right;
> > + }
> > +
> > + return result;
> > +}
> > +
> > +struct item *merge_sort(struct item *head, int sort_by)
> > +{
> > + struct item *right;
> > + struct item *slow;
> > + struct item *fast;
> > + struct item *left;
> > +
> > + if (!head || !head->next)
> > + return head;
> > +
> > + slow = head;
> > + fast = head->next;
> > +
> > + while (fast && fast->next) {
> > + slow = slow->next;
> > + fast = fast->next->next;
> > + }
> > +
> > + left = head;
> > + right = slow->next;
> > + slow->next = NULL;
> > +
> > + left = merge_sort(left, sort_by);
> > + right = merge_sort(right, sort_by);
> > +
> > + return merge(left, right, sort_by);
> > +}
> > +
> > +void sort_list_m(struct item **head, int sort_by)
> > +{
> > + if (!(*head) || !((*head)->next))
> > + return;
> > +
> > + *head = merge_sort(*head, sort_by);
> > +}
> > +
> > +int insert_after(struct item *list, const uint64_t search_addr,
> > + const char *name, uint64_t addr, char stype)
> > +{
> > + struct item *new_item;
> > + struct item *current;
> > + int ret = 0;
> > +
> > + current = (list_index[name[0] - 32]) ? list_index[name[0] - 32] :
> > list; + while (current) {
> > + if (current->addr == search_addr) {
> > + new_item = malloc(sizeof(struct item));
> > + if (!new_item)
> > + return ret;
> > + strncpy(new_item->symb_name, name, MAX_NAME_SIZE);
> > + new_item->symb_name[MAX_NAME_SIZE - 1] = '\0';
> > + new_item->addr = addr;
> > + new_item->stype = stype;
> > + new_item->next = current->next;
> > + current->next = new_item;
> > + ret = 1;
> > + break;
> > + }
> > + current = current->next;
> > + }
> > + return ret;
> > +}
> > +
> > +void free_items(struct item **head)
> > +{
> > + struct item *app, *item_iterator = *head;
> > +
> > + while (item_iterator) {
> > + app = item_iterator;
> > + item_iterator = item_iterator->next;
> > + free(app);
> > + }
> > + *head = NULL;
> > +}
> > diff --git a/scripts/kas_alias/item_list.h b/scripts/kas_alias/item_list.h
> > new file mode 100644
> > index 000000000000..b4891cb088ee
> > --- /dev/null
> > +++ b/scripts/kas_alias/item_list.h
> > @@ -0,0 +1,26 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +#ifndef ITEM_LIST_H
> > +#define ITEM_LIST_H
> > +#include <stdint.h>
> > +
> > +#define MAX_NAME_SIZE 256
> > +#define BY_ADDRESS 1
> > +#define BY_NAME 2
> > +
> > +struct item {
> > + char symb_name[MAX_NAME_SIZE];
> > + uint64_t addr;
> > + char stype;
> > + struct item *next;
> > +};
> > +
> > +void build_index(struct item *list);
> > +struct item *add_item(struct item **list, const char *name, char stype,
> > uint64_t addr); +void sort_list(struct item **list, int sort_by);
> > +struct item *merge(struct item *left, struct item *right, int sort_by);
> > +struct item *merge_sort(struct item *head, int sort_by);
> > +void sort_list_m(struct item **head, int sort_by);
> > +int insert_after(struct item *list, const uint64_t search_addr,
> > + const char *name, uint64_t addr, char stype);
> > +void free_items(struct item **head);
> > +#endif
> > diff --git a/scripts/kas_alias/kas_alias.c b/scripts/kas_alias/kas_alias.c
> > new file mode 100644
> > index 000000000000..532aeb39f851
> > --- /dev/null
> > +++ b/scripts/kas_alias/kas_alias.c
> > @@ -0,0 +1,217 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <stdint.h>
> > +#include <unistd.h>
> > +#include <string.h>
> > +#include <stdbool.h>
> > +#include <stdarg.h>
> > +#include <regex.h>
> > +
> > +#include "item_list.h"
> > +#include "duplicates_list.h"
> > +#include "a2l.h"
> > +
> > +#define SYMB_IS_TEXT(s) ((((s)->stype) == 't') || (((s)->stype) == 'T'))
> > +#define SYMB_IS_DATA(s) ((((s)->stype) == 'b') || (((s)->stype) == 'B')
> > || \ + (((s)->stype) == 'd') || (((s)->stype) ==
> > 'D') || \ + (((s)->stype) == 'r') ||
> > (((s)->stype) == 'R')) +#ifdef CONFIG_KALLSYMS_ALIAS_DATA
> > +#define SYMB_NEEDS_ALIAS(s) (SYMB_IS_TEXT(s) || SYMB_IS_DATA(s))
> > +#else
> > +#define SYMB_NEEDS_ALIAS(s) SYMB_IS_TEXT(s)
> > +#endif
> > +#define FNOMATCH 0
> > +#define FMATCH 1
> > +#define EREGEX 2
> > +
> > +const char *ignore_regex[] = {
> > + "^__cfi_.*$", // __cfi_ preamble
> > +#ifndef CONFIG_KALLSYMS_ALIAS_DATA_ALL
> > + "^_*TRACE_SYSTEM.*$",
> > + "^__already_done\\.[0-9]+$", // Call a function once
> > data + "^___tp_str\\.[0-9]+$",
> > + "^___done\\.[0-9]+$",
> > + "^__print_once\\.[0-9]+$",
> > + "^_rs\\.[0-9]+$",
> > + "^__compound_literal\\.[0-9]+$",
> > + "^___once_key\\.[0-9]+$",
> > + "^__func__\\.[0-9]+$",
> > + "^__msg\\.[0-9]+$",
> > + "^CSWTCH\\.[0-9]+$",
> > + "^__flags\\.[0-9]+$",
> > + "^__wkey.*$",
> > + "^__mkey.*$",
> > + "^__key.*$",
> > +#endif
> > + "^__pfx_.*$" // NOP-padding
> > +};
> > +
> > +int suffix_serial;
> > +
> > +static inline void verbose_msg(bool verbose, const char *fmt, ...)
> > +{
> > + va_list args;
> > +
> > + va_start(args, fmt);
> > + if (verbose)
> > + printf(fmt, args);
> > +
> > + va_end(args);
> > +}
> > +
> > +static void create_suffix(const char *name, char *output_suffix)
> > +{
> > + sprintf(output_suffix, "%s__alias__%d", name, suffix_serial++);
> > +}
> > +
> > +static void create_file_suffix(const char *name, uint64_t address, char
> > *output_suffix, char *cwd) +{
> > + const char *f_path;
> > + char *buf;
> > + int i = 0;
> > +
> > + buf = addr2line_get_lines(address);
> > + f_path = remove_subdir(cwd, buf);
> > + if (f_path) {
> > + sprintf(output_suffix, "%s@%s", name, f_path);
> > + while (*(output_suffix + i) != '\0') {
> > + switch (*(output_suffix + i)) {
> > + case '/':
> > + case ':':
> > + case '.':
> > + *(output_suffix + i) = '_';
> > + break;
> > + default:
> > + }
> > + i++;
> > + }
> > + } else {
> > + create_suffix(name, output_suffix);
> > + }
> > +}
> > +
> > +static int filter_symbols(char *symbol, const char **ignore_list, int
> > regex_no) +{
> > + regex_t regex;
> > + int res, i;
> > +
> > + for (i = 0; i < regex_no; i++) {
> > + res = regcomp(&regex, ignore_list[i], REG_EXTENDED);
> > + if (res)
> > + return -EREGEX;
> > +
> > + res = regexec(&regex, symbol, 0, NULL, 0);
> > + regfree(&regex);
> > + switch (res) {
> > + case 0:
> > + return FMATCH;
> > + case REG_NOMATCH:
> > + break;
> > + default:
> > + return -EREGEX;
> > + }
> > + }
> > +
> > + return FNOMATCH;
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > + char t, sym_name[MAX_NAME_SIZE], new_name[MAX_NAME_SIZE + 15];
> > + struct duplicate_item *duplicate_iterator;
> > + struct duplicate_item *duplicate;
> > + struct item *head = {NULL};
> > + bool need_2_process = true;
> > + struct item *last = {NULL};
> > + struct item *current;
> > + int verbose_mode = 0;
> > + uint64_t address;
> > + FILE *fp;
> > + int res;
> > +
> > + if (argc < 2 || argc > 3) {
> > + printf("Usage: %s <nmfile> [-verbose]\n", argv[0]);
> > + return 1;
> > + }
> > +
> > + if (argc == 3 && strcmp(argv[2], "-verbose") == 0)
> > + verbose_mode = 1;
> > +
> > + verbose_msg(verbose_mode, "Scanning nm data(%s)\n", argv[1]);
> > +
> > + fp = fopen(argv[1], "r");
> > + if (!fp) {
> > + printf("Can't open input file.\n");
> > + return 1;
> > + }
> > +
> > + if (!addr2line_init(get_addr2line(A2L_DEFAULT),
> > get_vmlinux(argv[1]))) + return 1;
> > +
> > + while (fscanf(fp, "%lx %c %99s\n", &address, &t, sym_name) == 3) {
> > + if (strstr(sym_name, "@_")) {
> > + if (verbose_mode && need_2_process)
> > + printf("Already processed\n");
> > + need_2_process = false;
> > + }
> > + last = add_item(&last, sym_name, t, address);
> > + if (!last) {
> > + printf("Error in allocate memory\n");
> > + free_items(&head);
> > + return 1;
> > + }
> > +
> > + if (!head)
> > + head = last;
> > + }
> > +
> > + fclose(fp);
> > +
> > + if (need_2_process) {
> > + verbose_msg(verbose_mode, "Sorting nm data\n");
> > + sort_list_m(&head, BY_NAME);
> > + verbose_msg(verbose_mode, "Scanning nm data for
> > duplicates\n"); + duplicate = find_duplicates(head);
> > + if (!duplicate) {
> > + printf("Error in duplicates list\n");
> > + return 1;
> > + }
> > +
> > + verbose_msg(verbose_mode, "Applying suffixes\n");
> > + build_index(head);
> > + duplicate_iterator = duplicate;
> > + while (duplicate_iterator) {
> > + res =
> > filter_symbols(duplicate_iterator->original_item->symb_name, +
> > ignore_regex, sizeof(ignore_regex) / +
> > sizeof(ignore_regex[0])); +
> > if (res != FMATCH &&
> > +
> > SYMB_NEEDS_ALIAS(duplicate_iterator->original_item)) { +
> > if (res < 0)
> > + return 1;
> > +
> > +
> > create_file_suffix(duplicate_iterator->original_item->symb_name, +
> >
> > duplicate_iterator->original_item->addr, +
> > new_name, vmlinux_path); +
> > if (!insert_after(head, duplicate_iterator->original_item->addr, +
> > new_name,
> > duplicate_iterator->original_item->addr, +
> > duplicate_iterator->original_item->stype)) +
> > return 1;
> > + }
> > +
> > + duplicate_iterator = duplicate_iterator->next;
> > + }
> > +
> > + sort_list_m(&head, BY_ADDRESS);
> > + }
> > + current = head;
> > + while (current) {
> > + printf("%08lx %c %s\n", current->addr, current->stype,
> > current->symb_name); + current = current->next;
> > + }
> > +
> > + free_items(&head);
> > + free_duplicates(&duplicate);
> > + addr2line_cleanup();
> > + return 0;
> > +}
> > diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
> > index a432b171be82..cacf60b597ce 100755
> > --- a/scripts/link-vmlinux.sh
> > +++ b/scripts/link-vmlinux.sh
> > @@ -89,8 +89,9 @@ vmlinux_link()
> >
> > ldflags="${ldflags} ${wl}--script=${objtree}/${KBUILD_LDS}"
> >
> > - # The kallsyms linking does not need debug symbols included.
> > - if [ "$output" != "${output#.tmp_vmlinux.kallsyms}" ] ; then
> > + # The kallsyms linking does not need debug symbols included,
> > unless the KALLSYMS_ALIAS. + if [ ! is_enabled
> > CONFIG_KALLSYMS_ALIAS ] && \
> > + [ "$output" != "${output#.tmp_vmlinux.kallsyms}" ] ; then
> >
> > ldflags="${ldflags} ${wl}--strip-debug"
> >
> > fi
> >
> > @@ -161,7 +162,11 @@ kallsyms()
> >
> > fi
> >
> > info KSYMS ${2}
> >
> > - scripts/kallsyms ${kallsymopt} ${1} > ${2}
> > + if is_enabled CONFIG_KALLSYMS_ALIAS; then
> > + ALIAS=".alias"
> > + scripts/kas_alias/kas_alias ${1} >${1}${ALIAS}
> > + fi
> > + scripts/kallsyms ${kallsymopt} ${1}${ALIAS} > ${2}
> >
> > }
> >
> > # Perform one step in kallsyms generation, including temporary linking of
> >
> > --
> > 2.34.1

Best regards.