18c2ecf20Sopenharmony_ci#!/usr/bin/env perl 28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only 38c2ecf20Sopenharmony_ci# (c) 2008, Steven Rostedt <srostedt@redhat.com> 48c2ecf20Sopenharmony_ci# 58c2ecf20Sopenharmony_ci# recordmcount.pl - makes a section called __mcount_loc that holds 68c2ecf20Sopenharmony_ci# all the offsets to the calls to mcount. 78c2ecf20Sopenharmony_ci# 88c2ecf20Sopenharmony_ci# 98c2ecf20Sopenharmony_ci# What we want to end up with this is that each object file will have a 108c2ecf20Sopenharmony_ci# section called __mcount_loc that will hold the list of pointers to mcount 118c2ecf20Sopenharmony_ci# callers. After final linking, the vmlinux will have within .init.data the 128c2ecf20Sopenharmony_ci# list of all callers to mcount between __start_mcount_loc and __stop_mcount_loc. 138c2ecf20Sopenharmony_ci# Later on boot up, the kernel will read this list, save the locations and turn 148c2ecf20Sopenharmony_ci# them into nops. When tracing or profiling is later enabled, these locations 158c2ecf20Sopenharmony_ci# will then be converted back to pointers to some function. 168c2ecf20Sopenharmony_ci# 178c2ecf20Sopenharmony_ci# This is no easy feat. This script is called just after the original 188c2ecf20Sopenharmony_ci# object is compiled and before it is linked. 198c2ecf20Sopenharmony_ci# 208c2ecf20Sopenharmony_ci# When parse this object file using 'objdump', the references to the call 218c2ecf20Sopenharmony_ci# sites are offsets from the section that the call site is in. Hence, all 228c2ecf20Sopenharmony_ci# functions in a section that has a call site to mcount, will have the 238c2ecf20Sopenharmony_ci# offset from the beginning of the section and not the beginning of the 248c2ecf20Sopenharmony_ci# function. 258c2ecf20Sopenharmony_ci# 268c2ecf20Sopenharmony_ci# But where this section will reside finally in vmlinx is undetermined at 278c2ecf20Sopenharmony_ci# this point. So we can't use this kind of offsets to record the final 288c2ecf20Sopenharmony_ci# address of this call site. 298c2ecf20Sopenharmony_ci# 308c2ecf20Sopenharmony_ci# The trick is to change the call offset referring the start of a section to 318c2ecf20Sopenharmony_ci# referring a function symbol in this section. During the link step, 'ld' will 328c2ecf20Sopenharmony_ci# compute the final address according to the information we record. 338c2ecf20Sopenharmony_ci# 348c2ecf20Sopenharmony_ci# e.g. 358c2ecf20Sopenharmony_ci# 368c2ecf20Sopenharmony_ci# .section ".sched.text", "ax" 378c2ecf20Sopenharmony_ci# [...] 388c2ecf20Sopenharmony_ci# func1: 398c2ecf20Sopenharmony_ci# [...] 408c2ecf20Sopenharmony_ci# call mcount (offset: 0x10) 418c2ecf20Sopenharmony_ci# [...] 428c2ecf20Sopenharmony_ci# ret 438c2ecf20Sopenharmony_ci# .globl fun2 448c2ecf20Sopenharmony_ci# func2: (offset: 0x20) 458c2ecf20Sopenharmony_ci# [...] 468c2ecf20Sopenharmony_ci# [...] 478c2ecf20Sopenharmony_ci# ret 488c2ecf20Sopenharmony_ci# func3: 498c2ecf20Sopenharmony_ci# [...] 508c2ecf20Sopenharmony_ci# call mcount (offset: 0x30) 518c2ecf20Sopenharmony_ci# [...] 528c2ecf20Sopenharmony_ci# 538c2ecf20Sopenharmony_ci# Both relocation offsets for the mcounts in the above example will be 548c2ecf20Sopenharmony_ci# offset from .sched.text. If we choose global symbol func2 as a reference and 558c2ecf20Sopenharmony_ci# make another file called tmp.s with the new offsets: 568c2ecf20Sopenharmony_ci# 578c2ecf20Sopenharmony_ci# .section __mcount_loc 588c2ecf20Sopenharmony_ci# .quad func2 - 0x10 598c2ecf20Sopenharmony_ci# .quad func2 + 0x10 608c2ecf20Sopenharmony_ci# 618c2ecf20Sopenharmony_ci# We can then compile this tmp.s into tmp.o, and link it back to the original 628c2ecf20Sopenharmony_ci# object. 638c2ecf20Sopenharmony_ci# 648c2ecf20Sopenharmony_ci# In our algorithm, we will choose the first global function we meet in this 658c2ecf20Sopenharmony_ci# section as the reference. But this gets hard if there is no global functions 668c2ecf20Sopenharmony_ci# in this section. In such a case we have to select a local one. E.g. func1: 678c2ecf20Sopenharmony_ci# 688c2ecf20Sopenharmony_ci# .section ".sched.text", "ax" 698c2ecf20Sopenharmony_ci# func1: 708c2ecf20Sopenharmony_ci# [...] 718c2ecf20Sopenharmony_ci# call mcount (offset: 0x10) 728c2ecf20Sopenharmony_ci# [...] 738c2ecf20Sopenharmony_ci# ret 748c2ecf20Sopenharmony_ci# func2: 758c2ecf20Sopenharmony_ci# [...] 768c2ecf20Sopenharmony_ci# call mcount (offset: 0x20) 778c2ecf20Sopenharmony_ci# [...] 788c2ecf20Sopenharmony_ci# .section "other.section" 798c2ecf20Sopenharmony_ci# 808c2ecf20Sopenharmony_ci# If we make the tmp.s the same as above, when we link together with 818c2ecf20Sopenharmony_ci# the original object, we will end up with two symbols for func1: 828c2ecf20Sopenharmony_ci# one local, one global. After final compile, we will end up with 838c2ecf20Sopenharmony_ci# an undefined reference to func1 or a wrong reference to another global 848c2ecf20Sopenharmony_ci# func1 in other files. 858c2ecf20Sopenharmony_ci# 868c2ecf20Sopenharmony_ci# Since local objects can reference local variables, we need to find 878c2ecf20Sopenharmony_ci# a way to make tmp.o reference the local objects of the original object 888c2ecf20Sopenharmony_ci# file after it is linked together. To do this, we convert func1 898c2ecf20Sopenharmony_ci# into a global symbol before linking tmp.o. Then after we link tmp.o 908c2ecf20Sopenharmony_ci# we will only have a single symbol for func1 that is global. 918c2ecf20Sopenharmony_ci# We can convert func1 back into a local symbol and we are done. 928c2ecf20Sopenharmony_ci# 938c2ecf20Sopenharmony_ci# Here are the steps we take: 948c2ecf20Sopenharmony_ci# 958c2ecf20Sopenharmony_ci# 1) Record all the local and weak symbols by using 'nm' 968c2ecf20Sopenharmony_ci# 2) Use objdump to find all the call site offsets and sections for 978c2ecf20Sopenharmony_ci# mcount. 988c2ecf20Sopenharmony_ci# 3) Compile the list into its own object. 998c2ecf20Sopenharmony_ci# 4) Do we have to deal with local functions? If not, go to step 8. 1008c2ecf20Sopenharmony_ci# 5) Make an object that converts these local functions to global symbols 1018c2ecf20Sopenharmony_ci# with objcopy. 1028c2ecf20Sopenharmony_ci# 6) Link together this new object with the list object. 1038c2ecf20Sopenharmony_ci# 7) Convert the local functions back to local symbols and rename 1048c2ecf20Sopenharmony_ci# the result as the original object. 1058c2ecf20Sopenharmony_ci# 8) Link the object with the list object. 1068c2ecf20Sopenharmony_ci# 9) Move the result back to the original object. 1078c2ecf20Sopenharmony_ci# 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciuse warnings; 1108c2ecf20Sopenharmony_ciuse strict; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cimy $P = $0; 1138c2ecf20Sopenharmony_ci$P =~ s@.*/@@g; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cimy $V = '0.1'; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ciif ($#ARGV != 11) { 1188c2ecf20Sopenharmony_ci print "usage: $P arch endian bits objdump objcopy cc ld nm rm mv is_module inputfile\n"; 1198c2ecf20Sopenharmony_ci print "version: $V\n"; 1208c2ecf20Sopenharmony_ci exit(1); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cimy ($arch, $endian, $bits, $objdump, $objcopy, $cc, 1248c2ecf20Sopenharmony_ci $ld, $nm, $rm, $mv, $is_module, $inputfile) = @ARGV; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci# This file refers to mcount and shouldn't be ftraced, so lets' ignore it 1278c2ecf20Sopenharmony_ciif ($inputfile =~ m,kernel/trace/ftrace\.o$,) { 1288c2ecf20Sopenharmony_ci exit(0); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci# Acceptable sections to record. 1328c2ecf20Sopenharmony_cimy %text_sections = ( 1338c2ecf20Sopenharmony_ci ".text" => 1, 1348c2ecf20Sopenharmony_ci ".init.text" => 1, 1358c2ecf20Sopenharmony_ci ".ref.text" => 1, 1368c2ecf20Sopenharmony_ci ".sched.text" => 1, 1378c2ecf20Sopenharmony_ci ".spinlock.text" => 1, 1388c2ecf20Sopenharmony_ci ".irqentry.text" => 1, 1398c2ecf20Sopenharmony_ci ".softirqentry.text" => 1, 1408c2ecf20Sopenharmony_ci ".kprobes.text" => 1, 1418c2ecf20Sopenharmony_ci ".cpuidle.text" => 1, 1428c2ecf20Sopenharmony_ci ".text.unlikely" => 1, 1438c2ecf20Sopenharmony_ci); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci# Acceptable section-prefixes to record. 1468c2ecf20Sopenharmony_cimy %text_section_prefixes = ( 1478c2ecf20Sopenharmony_ci ".text." => 1, 1488c2ecf20Sopenharmony_ci); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci# Note: we are nice to C-programmers here, thus we skip the '||='-idiom. 1518c2ecf20Sopenharmony_ci$objdump = 'objdump' if (!$objdump); 1528c2ecf20Sopenharmony_ci$objcopy = 'objcopy' if (!$objcopy); 1538c2ecf20Sopenharmony_ci$cc = 'gcc' if (!$cc); 1548c2ecf20Sopenharmony_ci$ld = 'ld' if (!$ld); 1558c2ecf20Sopenharmony_ci$nm = 'nm' if (!$nm); 1568c2ecf20Sopenharmony_ci$rm = 'rm' if (!$rm); 1578c2ecf20Sopenharmony_ci$mv = 'mv' if (!$mv); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#print STDERR "running: $P '$arch' '$objdump' '$objcopy' '$cc' '$ld' " . 1608c2ecf20Sopenharmony_ci# "'$nm' '$rm' '$mv' '$inputfile'\n"; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cimy %locals; # List of local (static) functions 1638c2ecf20Sopenharmony_cimy %weak; # List of weak functions 1648c2ecf20Sopenharmony_cimy %convert; # List of local functions used that needs conversion 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cimy $type; 1678c2ecf20Sopenharmony_cimy $local_regex; # Match a local function (return function) 1688c2ecf20Sopenharmony_cimy $weak_regex; # Match a weak function (return function) 1698c2ecf20Sopenharmony_cimy $section_regex; # Find the start of a section 1708c2ecf20Sopenharmony_cimy $function_regex; # Find the name of a function 1718c2ecf20Sopenharmony_ci # (return offset and func name) 1728c2ecf20Sopenharmony_cimy $mcount_regex; # Find the call site to mcount (return offset) 1738c2ecf20Sopenharmony_cimy $mcount_adjust; # Address adjustment to mcount offset 1748c2ecf20Sopenharmony_cimy $alignment; # The .align value to use for $mcount_section 1758c2ecf20Sopenharmony_cimy $section_type; # Section header plus possible alignment command 1768c2ecf20Sopenharmony_cimy $can_use_local = 0; # If we can use local function references 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci# Shut up recordmcount if user has older objcopy 1798c2ecf20Sopenharmony_cimy $quiet_recordmcount = ".tmp_quiet_recordmcount"; 1808c2ecf20Sopenharmony_cimy $print_warning = 1; 1818c2ecf20Sopenharmony_ci$print_warning = 0 if ( -f $quiet_recordmcount); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci## 1848c2ecf20Sopenharmony_ci# check_objcopy - whether objcopy supports --globalize-symbols 1858c2ecf20Sopenharmony_ci# 1868c2ecf20Sopenharmony_ci# --globalize-symbols came out in 2.17, we must test the version 1878c2ecf20Sopenharmony_ci# of objcopy, and if it is less than 2.17, then we can not 1888c2ecf20Sopenharmony_ci# record local functions. 1898c2ecf20Sopenharmony_cisub check_objcopy 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci open (IN, "$objcopy --version |") or die "error running $objcopy"; 1928c2ecf20Sopenharmony_ci while (<IN>) { 1938c2ecf20Sopenharmony_ci if (/objcopy.*\s(\d+)\.(\d+)/) { 1948c2ecf20Sopenharmony_ci $can_use_local = 1 if ($1 > 2 || ($1 == 2 && $2 >= 17)); 1958c2ecf20Sopenharmony_ci last; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci close (IN); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (!$can_use_local && $print_warning) { 2018c2ecf20Sopenharmony_ci print STDERR "WARNING: could not find objcopy version or version " . 2028c2ecf20Sopenharmony_ci "is less than 2.17.\n" . 2038c2ecf20Sopenharmony_ci "\tLocal function references are disabled.\n"; 2048c2ecf20Sopenharmony_ci open (QUIET, ">$quiet_recordmcount"); 2058c2ecf20Sopenharmony_ci printf QUIET "Disables the warning from recordmcount.pl\n"; 2068c2ecf20Sopenharmony_ci close QUIET; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ciif ($arch =~ /(x86(_64)?)|(i386)/) { 2118c2ecf20Sopenharmony_ci if ($bits == 64) { 2128c2ecf20Sopenharmony_ci $arch = "x86_64"; 2138c2ecf20Sopenharmony_ci } else { 2148c2ecf20Sopenharmony_ci $arch = "i386"; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci# 2198c2ecf20Sopenharmony_ci# We base the defaults off of i386, the other archs may 2208c2ecf20Sopenharmony_ci# feel free to change them in the below if statements. 2218c2ecf20Sopenharmony_ci# 2228c2ecf20Sopenharmony_ci$local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)"; 2238c2ecf20Sopenharmony_ci$weak_regex = "^[0-9a-fA-F]+\\s+([wW])\\s+(\\S+)"; 2248c2ecf20Sopenharmony_ci$section_regex = "Disassembly of section\\s+(\\S+):"; 2258c2ecf20Sopenharmony_ci$function_regex = "^([0-9a-fA-F]+)\\s+<([^^]*?)>:"; 2268c2ecf20Sopenharmony_ci$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s(mcount|__fentry__)\$"; 2278c2ecf20Sopenharmony_ci$section_type = '@progbits'; 2288c2ecf20Sopenharmony_ci$mcount_adjust = 0; 2298c2ecf20Sopenharmony_ci$type = ".long"; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ciif ($arch eq "x86_64") { 2328c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s(mcount|__fentry__)([+-]0x[0-9a-zA-Z]+)?\$"; 2338c2ecf20Sopenharmony_ci $type = ".quad"; 2348c2ecf20Sopenharmony_ci $alignment = 8; 2358c2ecf20Sopenharmony_ci $mcount_adjust = -1; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci # force flags for this arch 2388c2ecf20Sopenharmony_ci $ld .= " -m elf_x86_64"; 2398c2ecf20Sopenharmony_ci $objdump .= " -M x86-64"; 2408c2ecf20Sopenharmony_ci $objcopy .= " -O elf64-x86-64"; 2418c2ecf20Sopenharmony_ci $cc .= " -m64"; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci} elsif ($arch eq "i386") { 2448c2ecf20Sopenharmony_ci $alignment = 4; 2458c2ecf20Sopenharmony_ci $mcount_adjust = -1; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci # force flags for this arch 2488c2ecf20Sopenharmony_ci $ld .= " -m elf_i386"; 2498c2ecf20Sopenharmony_ci $objdump .= " -M i386"; 2508c2ecf20Sopenharmony_ci $objcopy .= " -O elf32-i386"; 2518c2ecf20Sopenharmony_ci $cc .= " -m32"; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci} elsif ($arch eq "s390" && $bits == 64) { 2548c2ecf20Sopenharmony_ci if ($cc =~ /-DCC_USING_HOTPATCH/) { 2558c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(brcl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$"; 2568c2ecf20Sopenharmony_ci $mcount_adjust = 0; 2578c2ecf20Sopenharmony_ci } else { 2588c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$"; 2598c2ecf20Sopenharmony_ci $mcount_adjust = -14; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci $alignment = 8; 2628c2ecf20Sopenharmony_ci $type = ".quad"; 2638c2ecf20Sopenharmony_ci $ld .= " -m elf64_s390"; 2648c2ecf20Sopenharmony_ci $cc .= " -m64"; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci} elsif ($arch eq "sh") { 2678c2ecf20Sopenharmony_ci $alignment = 2; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci # force flags for this arch 2708c2ecf20Sopenharmony_ci $ld .= " -m shlelf_linux"; 2718c2ecf20Sopenharmony_ci if ($endian eq "big") { 2728c2ecf20Sopenharmony_ci $objcopy .= " -O elf32-shbig-linux"; 2738c2ecf20Sopenharmony_ci } else { 2748c2ecf20Sopenharmony_ci $objcopy .= " -O elf32-sh-linux"; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci} elsif ($arch eq "powerpc") { 2788c2ecf20Sopenharmony_ci my $ldemulation; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)"; 2818c2ecf20Sopenharmony_ci # See comment in the sparc64 section for why we use '\w'. 2828c2ecf20Sopenharmony_ci $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?\\w*?)>:"; 2838c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$"; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if ($endian eq "big") { 2868c2ecf20Sopenharmony_ci $cc .= " -mbig-endian "; 2878c2ecf20Sopenharmony_ci $ld .= " -EB "; 2888c2ecf20Sopenharmony_ci $ldemulation = "ppc" 2898c2ecf20Sopenharmony_ci } else { 2908c2ecf20Sopenharmony_ci $cc .= " -mlittle-endian "; 2918c2ecf20Sopenharmony_ci $ld .= " -EL "; 2928c2ecf20Sopenharmony_ci $ldemulation = "lppc" 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci if ($bits == 64) { 2958c2ecf20Sopenharmony_ci $type = ".quad"; 2968c2ecf20Sopenharmony_ci $cc .= " -m64 "; 2978c2ecf20Sopenharmony_ci $ld .= " -m elf64".$ldemulation." "; 2988c2ecf20Sopenharmony_ci } else { 2998c2ecf20Sopenharmony_ci $cc .= " -m32 "; 3008c2ecf20Sopenharmony_ci $ld .= " -m elf32".$ldemulation." "; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci} elsif ($arch eq "arm") { 3048c2ecf20Sopenharmony_ci $alignment = 2; 3058c2ecf20Sopenharmony_ci $section_type = '%progbits'; 3068c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_ARM_(CALL|PC24|THM_CALL)" . 3078c2ecf20Sopenharmony_ci "\\s+(__gnu_mcount_nc|mcount)\$"; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci} elsif ($arch eq "arm64") { 3108c2ecf20Sopenharmony_ci $alignment = 3; 3118c2ecf20Sopenharmony_ci $section_type = '%progbits'; 3128c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_AARCH64_CALL26\\s+_mcount\$"; 3138c2ecf20Sopenharmony_ci $type = ".quad"; 3148c2ecf20Sopenharmony_ci} elsif ($arch eq "ia64") { 3158c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; 3168c2ecf20Sopenharmony_ci $type = "data8"; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if ($is_module eq "0") { 3198c2ecf20Sopenharmony_ci $cc .= " -mconstant-gp"; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci} elsif ($arch eq "sparc64") { 3228c2ecf20Sopenharmony_ci # In the objdump output there are giblets like: 3238c2ecf20Sopenharmony_ci # 0000000000000000 <igmp_net_exit-0x18>: 3248c2ecf20Sopenharmony_ci # As there's some data blobs that get emitted into the 3258c2ecf20Sopenharmony_ci # text section before the first instructions and the first 3268c2ecf20Sopenharmony_ci # real symbols. We don't want to match that, so to combat 3278c2ecf20Sopenharmony_ci # this we use '\w' so we'll match just plain symbol names, 3288c2ecf20Sopenharmony_ci # and not those that also include hex offsets inside of the 3298c2ecf20Sopenharmony_ci # '<>' brackets. Actually the generic function_regex setting 3308c2ecf20Sopenharmony_ci # could safely use this too. 3318c2ecf20Sopenharmony_ci $function_regex = "^([0-9a-fA-F]+)\\s+<(\\w*?)>:"; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci # Sparc64 calls '_mcount' instead of plain 'mcount'. 3348c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci $alignment = 8; 3378c2ecf20Sopenharmony_ci $type = ".xword"; 3388c2ecf20Sopenharmony_ci $ld .= " -m elf64_sparc"; 3398c2ecf20Sopenharmony_ci $cc .= " -m64"; 3408c2ecf20Sopenharmony_ci $objcopy .= " -O elf64-sparc"; 3418c2ecf20Sopenharmony_ci} elsif ($arch eq "mips") { 3428c2ecf20Sopenharmony_ci # To enable module support, we need to enable the -mlong-calls option 3438c2ecf20Sopenharmony_ci # of gcc for module, after using this option, we can not get the real 3448c2ecf20Sopenharmony_ci # offset of the calling to _mcount, but the offset of the lui 3458c2ecf20Sopenharmony_ci # instruction or the addiu one. herein, we record the address of the 3468c2ecf20Sopenharmony_ci # first one, and then we can replace this instruction by a branch 3478c2ecf20Sopenharmony_ci # instruction to jump over the profiling function to filter the 3488c2ecf20Sopenharmony_ci # indicated functions, or switch back to the lui instruction to trace 3498c2ecf20Sopenharmony_ci # them, which means dynamic tracing. 3508c2ecf20Sopenharmony_ci # 3518c2ecf20Sopenharmony_ci # c: 3c030000 lui v1,0x0 3528c2ecf20Sopenharmony_ci # c: R_MIPS_HI16 _mcount 3538c2ecf20Sopenharmony_ci # c: R_MIPS_NONE *ABS* 3548c2ecf20Sopenharmony_ci # c: R_MIPS_NONE *ABS* 3558c2ecf20Sopenharmony_ci # 10: 64630000 daddiu v1,v1,0 3568c2ecf20Sopenharmony_ci # 10: R_MIPS_LO16 _mcount 3578c2ecf20Sopenharmony_ci # 10: R_MIPS_NONE *ABS* 3588c2ecf20Sopenharmony_ci # 10: R_MIPS_NONE *ABS* 3598c2ecf20Sopenharmony_ci # 14: 03e0082d move at,ra 3608c2ecf20Sopenharmony_ci # 18: 0060f809 jalr v1 3618c2ecf20Sopenharmony_ci # 3628c2ecf20Sopenharmony_ci # for the kernel: 3638c2ecf20Sopenharmony_ci # 3648c2ecf20Sopenharmony_ci # 10: 03e0082d move at,ra 3658c2ecf20Sopenharmony_ci # 14: 0c000000 jal 0 <loongson_halt> 3668c2ecf20Sopenharmony_ci # 14: R_MIPS_26 _mcount 3678c2ecf20Sopenharmony_ci # 14: R_MIPS_NONE *ABS* 3688c2ecf20Sopenharmony_ci # 14: R_MIPS_NONE *ABS* 3698c2ecf20Sopenharmony_ci # 18: 00020021 nop 3708c2ecf20Sopenharmony_ci if ($is_module eq "0") { 3718c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$"; 3728c2ecf20Sopenharmony_ci } else { 3738c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$"; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci $objdump .= " -Melf-trad".$endian."mips "; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if ($endian eq "big") { 3788c2ecf20Sopenharmony_ci $endian = " -EB "; 3798c2ecf20Sopenharmony_ci $ld .= " -melf".$bits."btsmip"; 3808c2ecf20Sopenharmony_ci } else { 3818c2ecf20Sopenharmony_ci $endian = " -EL "; 3828c2ecf20Sopenharmony_ci $ld .= " -melf".$bits."ltsmip"; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci $cc .= " -mno-abicalls -fno-pic -mabi=" . $bits . $endian; 3868c2ecf20Sopenharmony_ci $ld .= $endian; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if ($bits == 64) { 3898c2ecf20Sopenharmony_ci $function_regex = 3908c2ecf20Sopenharmony_ci "^([0-9a-fA-F]+)\\s+<(.|[^\$]L.*?|\$[^L].*?|[^\$][^L].*?)>:"; 3918c2ecf20Sopenharmony_ci $type = ".dword"; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci} elsif ($arch eq "microblaze") { 3948c2ecf20Sopenharmony_ci # Microblaze calls '_mcount' instead of plain 'mcount'. 3958c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; 3968c2ecf20Sopenharmony_ci} elsif ($arch eq "riscv") { 3978c2ecf20Sopenharmony_ci $function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:"; 3988c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL(_PLT)?\\s_?mcount\$"; 3998c2ecf20Sopenharmony_ci $type = ".quad"; 4008c2ecf20Sopenharmony_ci $alignment = 2; 4018c2ecf20Sopenharmony_ci} elsif ($arch eq "nds32") { 4028c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_NDS32_HI20_RELA\\s+_mcount\$"; 4038c2ecf20Sopenharmony_ci $alignment = 2; 4048c2ecf20Sopenharmony_ci} elsif ($arch eq "csky") { 4058c2ecf20Sopenharmony_ci $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_CKCORE_PCREL_JSR_IMM26BY2\\s+_mcount\$"; 4068c2ecf20Sopenharmony_ci $alignment = 2; 4078c2ecf20Sopenharmony_ci} else { 4088c2ecf20Sopenharmony_ci die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cimy $text_found = 0; 4128c2ecf20Sopenharmony_cimy $read_function = 0; 4138c2ecf20Sopenharmony_cimy $opened = 0; 4148c2ecf20Sopenharmony_cimy $mcount_section = "__mcount_loc"; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cimy $dirname; 4178c2ecf20Sopenharmony_cimy $filename; 4188c2ecf20Sopenharmony_cimy $prefix; 4198c2ecf20Sopenharmony_cimy $ext; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ciif ($inputfile =~ m,^(.*)/([^/]*)$,) { 4228c2ecf20Sopenharmony_ci $dirname = $1; 4238c2ecf20Sopenharmony_ci $filename = $2; 4248c2ecf20Sopenharmony_ci} else { 4258c2ecf20Sopenharmony_ci $dirname = "."; 4268c2ecf20Sopenharmony_ci $filename = $inputfile; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ciif ($filename =~ m,^(.*)(\.\S),) { 4308c2ecf20Sopenharmony_ci $prefix = $1; 4318c2ecf20Sopenharmony_ci $ext = $2; 4328c2ecf20Sopenharmony_ci} else { 4338c2ecf20Sopenharmony_ci $prefix = $filename; 4348c2ecf20Sopenharmony_ci $ext = ""; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cimy $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s"; 4388c2ecf20Sopenharmony_cimy $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o"; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cicheck_objcopy(); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci# 4438c2ecf20Sopenharmony_ci# Step 1: find all the local (static functions) and weak symbols. 4448c2ecf20Sopenharmony_ci# 't' is local, 'w/W' is weak 4458c2ecf20Sopenharmony_ci# 4468c2ecf20Sopenharmony_ciopen (IN, "$nm $inputfile|") || die "error running $nm"; 4478c2ecf20Sopenharmony_ciwhile (<IN>) { 4488c2ecf20Sopenharmony_ci if (/$local_regex/) { 4498c2ecf20Sopenharmony_ci $locals{$1} = 1; 4508c2ecf20Sopenharmony_ci } elsif (/$weak_regex/) { 4518c2ecf20Sopenharmony_ci $weak{$2} = $1; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ciclose(IN); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cimy @offsets; # Array of offsets of mcount callers 4578c2ecf20Sopenharmony_cimy $ref_func; # reference function to use for offsets 4588c2ecf20Sopenharmony_cimy $offset = 0; # offset of ref_func to section beginning 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci## 4618c2ecf20Sopenharmony_ci# update_funcs - print out the current mcount callers 4628c2ecf20Sopenharmony_ci# 4638c2ecf20Sopenharmony_ci# Go through the list of offsets to callers and write them to 4648c2ecf20Sopenharmony_ci# the output file in a format that can be read by an assembler. 4658c2ecf20Sopenharmony_ci# 4668c2ecf20Sopenharmony_cisub update_funcs 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci return unless ($ref_func and @offsets); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci # Sanity check on weak function. A weak function may be overwritten by 4718c2ecf20Sopenharmony_ci # another function of the same name, making all these offsets incorrect. 4728c2ecf20Sopenharmony_ci if (defined $weak{$ref_func}) { 4738c2ecf20Sopenharmony_ci die "$inputfile: ERROR: referencing weak function" . 4748c2ecf20Sopenharmony_ci " $ref_func for mcount\n"; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci # is this function static? If so, note this fact. 4788c2ecf20Sopenharmony_ci if (defined $locals{$ref_func}) { 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci # only use locals if objcopy supports globalize-symbols 4818c2ecf20Sopenharmony_ci if (!$can_use_local) { 4828c2ecf20Sopenharmony_ci return; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci $convert{$ref_func} = 1; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci # Loop through all the mcount caller offsets and print a reference 4888c2ecf20Sopenharmony_ci # to the caller based from the ref_func. 4898c2ecf20Sopenharmony_ci if (!$opened) { 4908c2ecf20Sopenharmony_ci open(FILE, ">$mcount_s") || die "can't create $mcount_s\n"; 4918c2ecf20Sopenharmony_ci $opened = 1; 4928c2ecf20Sopenharmony_ci print FILE "\t.section $mcount_section,\"a\",$section_type\n"; 4938c2ecf20Sopenharmony_ci print FILE "\t.align $alignment\n" if (defined($alignment)); 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci foreach my $cur_offset (@offsets) { 4968c2ecf20Sopenharmony_ci printf FILE "\t%s %s + %d\n", $type, $ref_func, $cur_offset - $offset; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci# 5018c2ecf20Sopenharmony_ci# Step 2: find the sections and mcount call sites 5028c2ecf20Sopenharmony_ci# 5038c2ecf20Sopenharmony_ciopen(IN, "LANG=C $objdump -hdr $inputfile|") || die "error running $objdump"; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cimy $text; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci# read headers first 5098c2ecf20Sopenharmony_cimy $read_headers = 1; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ciwhile (<IN>) { 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if ($read_headers && /$mcount_section/) { 5148c2ecf20Sopenharmony_ci # 5158c2ecf20Sopenharmony_ci # Somehow the make process can execute this script on an 5168c2ecf20Sopenharmony_ci # object twice. If it does, we would duplicate the mcount 5178c2ecf20Sopenharmony_ci # section and it will cause the function tracer self test 5188c2ecf20Sopenharmony_ci # to fail. Check if the mcount section exists, and if it does, 5198c2ecf20Sopenharmony_ci # warn and exit. 5208c2ecf20Sopenharmony_ci # 5218c2ecf20Sopenharmony_ci print STDERR "ERROR: $mcount_section already in $inputfile\n" . 5228c2ecf20Sopenharmony_ci "\tThis may be an indication that your build is corrupted.\n" . 5238c2ecf20Sopenharmony_ci "\tDelete $inputfile and try again. If the same object file\n" . 5248c2ecf20Sopenharmony_ci "\tstill causes an issue, then disable CONFIG_DYNAMIC_FTRACE.\n"; 5258c2ecf20Sopenharmony_ci exit(-1); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci # is it a section? 5298c2ecf20Sopenharmony_ci if (/$section_regex/) { 5308c2ecf20Sopenharmony_ci $read_headers = 0; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci # Only record text sections that we know are safe 5338c2ecf20Sopenharmony_ci $read_function = defined($text_sections{$1}); 5348c2ecf20Sopenharmony_ci if (!$read_function) { 5358c2ecf20Sopenharmony_ci foreach my $prefix (keys %text_section_prefixes) { 5368c2ecf20Sopenharmony_ci if (substr($1, 0, length $prefix) eq $prefix) { 5378c2ecf20Sopenharmony_ci $read_function = 1; 5388c2ecf20Sopenharmony_ci last; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci # print out any recorded offsets 5438c2ecf20Sopenharmony_ci update_funcs(); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci # reset all markers and arrays 5468c2ecf20Sopenharmony_ci $text_found = 0; 5478c2ecf20Sopenharmony_ci undef($ref_func); 5488c2ecf20Sopenharmony_ci undef(@offsets); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci # section found, now is this a start of a function? 5518c2ecf20Sopenharmony_ci } elsif ($read_function && /$function_regex/) { 5528c2ecf20Sopenharmony_ci $text_found = 1; 5538c2ecf20Sopenharmony_ci $text = $2; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci # if this is either a local function or a weak function 5568c2ecf20Sopenharmony_ci # keep looking for functions that are global that 5578c2ecf20Sopenharmony_ci # we can use safely. 5588c2ecf20Sopenharmony_ci if (!defined($locals{$text}) && !defined($weak{$text})) { 5598c2ecf20Sopenharmony_ci $ref_func = $text; 5608c2ecf20Sopenharmony_ci $read_function = 0; 5618c2ecf20Sopenharmony_ci $offset = hex $1; 5628c2ecf20Sopenharmony_ci } else { 5638c2ecf20Sopenharmony_ci # if we already have a function, and this is weak, skip it 5648c2ecf20Sopenharmony_ci if (!defined($ref_func) && !defined($weak{$text}) && 5658c2ecf20Sopenharmony_ci # PPC64 can have symbols that start with .L and 5668c2ecf20Sopenharmony_ci # gcc considers these special. Don't use them! 5678c2ecf20Sopenharmony_ci $text !~ /^\.L/) { 5688c2ecf20Sopenharmony_ci $ref_func = $text; 5698c2ecf20Sopenharmony_ci $offset = hex $1; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci # is this a call site to mcount? If so, record it to print later 5748c2ecf20Sopenharmony_ci if ($text_found && /$mcount_regex/) { 5758c2ecf20Sopenharmony_ci push(@offsets, (hex $1) + $mcount_adjust); 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci# dump out anymore offsets that may have been found 5808c2ecf20Sopenharmony_ciupdate_funcs(); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci# If we did not find any mcount callers, we are done (do nothing). 5838c2ecf20Sopenharmony_ciif (!$opened) { 5848c2ecf20Sopenharmony_ci exit(0); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ciclose(FILE); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci# 5908c2ecf20Sopenharmony_ci# Step 3: Compile the file that holds the list of call sites to mcount. 5918c2ecf20Sopenharmony_ci# 5928c2ecf20Sopenharmony_ci`$cc -o $mcount_o -c $mcount_s`; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cimy @converts = keys %convert; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci# 5978c2ecf20Sopenharmony_ci# Step 4: Do we have sections that started with local functions? 5988c2ecf20Sopenharmony_ci# 5998c2ecf20Sopenharmony_ciif ($#converts >= 0) { 6008c2ecf20Sopenharmony_ci my $globallist = ""; 6018c2ecf20Sopenharmony_ci my $locallist = ""; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci foreach my $con (@converts) { 6048c2ecf20Sopenharmony_ci $globallist .= " --globalize-symbol $con"; 6058c2ecf20Sopenharmony_ci $locallist .= " --localize-symbol $con"; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci my $globalobj = $dirname . "/.tmp_gl_" . $filename; 6098c2ecf20Sopenharmony_ci my $globalmix = $dirname . "/.tmp_mx_" . $filename; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci # 6128c2ecf20Sopenharmony_ci # Step 5: set up each local function as a global 6138c2ecf20Sopenharmony_ci # 6148c2ecf20Sopenharmony_ci `$objcopy $globallist $inputfile $globalobj`; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci # 6178c2ecf20Sopenharmony_ci # Step 6: Link the global version to our list. 6188c2ecf20Sopenharmony_ci # 6198c2ecf20Sopenharmony_ci `$ld -r $globalobj $mcount_o -o $globalmix`; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci # 6228c2ecf20Sopenharmony_ci # Step 7: Convert the local functions back into local symbols 6238c2ecf20Sopenharmony_ci # 6248c2ecf20Sopenharmony_ci `$objcopy $locallist $globalmix $inputfile`; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci # Remove the temp files 6278c2ecf20Sopenharmony_ci `$rm $globalobj $globalmix`; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci} else { 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci my $mix = $dirname . "/.tmp_mx_" . $filename; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci # 6348c2ecf20Sopenharmony_ci # Step 8: Link the object with our list of call sites object. 6358c2ecf20Sopenharmony_ci # 6368c2ecf20Sopenharmony_ci `$ld -r $inputfile $mcount_o -o $mix`; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci # 6398c2ecf20Sopenharmony_ci # Step 9: Move the result back to the original object. 6408c2ecf20Sopenharmony_ci # 6418c2ecf20Sopenharmony_ci `$mv $mix $inputfile`; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci# Clean up the temp files 6458c2ecf20Sopenharmony_ci`$rm $mcount_o $mcount_s`; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ciexit(0); 648