xref: /linux-6.15/scripts/recordmcount.pl (revision de5f3984)
1cb77f0d6SKamil Rytarowski#!/usr/bin/env perl
24f19048fSThomas Gleixner# SPDX-License-Identifier: GPL-2.0-only
38da3821bSSteven Rostedt# (c) 2008, Steven Rostedt <[email protected]>
48da3821bSSteven Rostedt#
58da3821bSSteven Rostedt# recordmcount.pl - makes a section called __mcount_loc that holds
68da3821bSSteven Rostedt#                   all the offsets to the calls to mcount.
78da3821bSSteven Rostedt#
88da3821bSSteven Rostedt#
9d49f6aa7SLi Hong# What we want to end up with this is that each object file will have a
10d49f6aa7SLi Hong# section called __mcount_loc that will hold the list of pointers to mcount
11d49f6aa7SLi Hong# callers. After final linking, the vmlinux will have within .init.data the
12d49f6aa7SLi Hong# list of all callers to mcount between __start_mcount_loc and __stop_mcount_loc.
13d49f6aa7SLi Hong# Later on boot up, the kernel will read this list, save the locations and turn
14d49f6aa7SLi Hong# them into nops. When tracing or profiling is later enabled, these locations
15d49f6aa7SLi Hong# will then be converted back to pointers to some function.
168da3821bSSteven Rostedt#
178da3821bSSteven Rostedt# This is no easy feat. This script is called just after the original
188da3821bSSteven Rostedt# object is compiled and before it is linked.
198da3821bSSteven Rostedt#
20d49f6aa7SLi Hong# When parse this object file using 'objdump', the references to the call
21d49f6aa7SLi Hong# sites are offsets from the section that the call site is in. Hence, all
22d49f6aa7SLi Hong# functions in a section that has a call site to mcount, will have the
23d49f6aa7SLi Hong# offset from the beginning of the section and not the beginning of the
24d49f6aa7SLi Hong# function.
258da3821bSSteven Rostedt#
26d49f6aa7SLi Hong# But where this section will reside finally in vmlinx is undetermined at
27d49f6aa7SLi Hong# this point. So we can't use this kind of offsets to record the final
28d49f6aa7SLi Hong# address of this call site.
29d49f6aa7SLi Hong#
30d49f6aa7SLi Hong# The trick is to change the call offset referring the start of a section to
31d49f6aa7SLi Hong# referring a function symbol in this section. During the link step, 'ld' will
32d49f6aa7SLi Hong# compute the final address according to the information we record.
33d49f6aa7SLi Hong#
348da3821bSSteven Rostedt# e.g.
358da3821bSSteven Rostedt#
3631b6e76eSTim Abbott#  .section ".sched.text", "ax"
378da3821bSSteven Rostedt#        [...]
38d49f6aa7SLi Hong#  func1:
39d49f6aa7SLi Hong#        [...]
40d49f6aa7SLi Hong#        call mcount  (offset: 0x10)
418da3821bSSteven Rostedt#        [...]
428da3821bSSteven Rostedt#        ret
43d49f6aa7SLi Hong#  .globl fun2
44d49f6aa7SLi Hong#  func2:             (offset: 0x20)
458da3821bSSteven Rostedt#        [...]
46d49f6aa7SLi Hong#        [...]
47d49f6aa7SLi Hong#        ret
48d49f6aa7SLi Hong#  func3:
49d49f6aa7SLi Hong#        [...]
50d49f6aa7SLi Hong#        call mcount (offset: 0x30)
518da3821bSSteven Rostedt#        [...]
528da3821bSSteven Rostedt#
538da3821bSSteven Rostedt# Both relocation offsets for the mcounts in the above example will be
54d49f6aa7SLi Hong# offset from .sched.text. If we choose global symbol func2 as a reference and
55d49f6aa7SLi Hong# make another file called tmp.s with the new offsets:
568da3821bSSteven Rostedt#
578da3821bSSteven Rostedt#  .section __mcount_loc
58d49f6aa7SLi Hong#  .quad  func2 - 0x10
59d49f6aa7SLi Hong#  .quad  func2 + 0x10
608da3821bSSteven Rostedt#
61d49f6aa7SLi Hong# We can then compile this tmp.s into tmp.o, and link it back to the original
628da3821bSSteven Rostedt# object.
638da3821bSSteven Rostedt#
64d49f6aa7SLi Hong# In our algorithm, we will choose the first global function we meet in this
65d49f6aa7SLi Hong# section as the reference. But this gets hard if there is no global functions
66d49f6aa7SLi Hong# in this section. In such a case we have to select a local one. E.g. func1:
678da3821bSSteven Rostedt#
6831b6e76eSTim Abbott#  .section ".sched.text", "ax"
69d49f6aa7SLi Hong#  func1:
708da3821bSSteven Rostedt#        [...]
71d49f6aa7SLi Hong#        call mcount  (offset: 0x10)
728da3821bSSteven Rostedt#        [...]
738da3821bSSteven Rostedt#        ret
74d49f6aa7SLi Hong#  func2:
758da3821bSSteven Rostedt#        [...]
76d49f6aa7SLi Hong#        call mcount (offset: 0x20)
778da3821bSSteven Rostedt#        [...]
78d49f6aa7SLi Hong#  .section "other.section"
798da3821bSSteven Rostedt#
808da3821bSSteven Rostedt# If we make the tmp.s the same as above, when we link together with
81d49f6aa7SLi Hong# the original object, we will end up with two symbols for func1:
828da3821bSSteven Rostedt# one local, one global.  After final compile, we will end up with
83d49f6aa7SLi Hong# an undefined reference to func1 or a wrong reference to another global
84d49f6aa7SLi Hong# func1 in other files.
858da3821bSSteven Rostedt#
868da3821bSSteven Rostedt# Since local objects can reference local variables, we need to find
878da3821bSSteven Rostedt# a way to make tmp.o reference the local objects of the original object
88d49f6aa7SLi Hong# file after it is linked together. To do this, we convert func1
898da3821bSSteven Rostedt# into a global symbol before linking tmp.o. Then after we link tmp.o
90d49f6aa7SLi Hong# we will only have a single symbol for func1 that is global.
91d49f6aa7SLi Hong# We can convert func1 back into a local symbol and we are done.
928da3821bSSteven Rostedt#
938da3821bSSteven Rostedt# Here are the steps we take:
948da3821bSSteven Rostedt#
95306dcf47SLi Hong# 1) Record all the local and weak symbols by using 'nm'
968da3821bSSteven Rostedt# 2) Use objdump to find all the call site offsets and sections for
978da3821bSSteven Rostedt#    mcount.
988da3821bSSteven Rostedt# 3) Compile the list into its own object.
998da3821bSSteven Rostedt# 4) Do we have to deal with local functions? If not, go to step 8.
1008da3821bSSteven Rostedt# 5) Make an object that converts these local functions to global symbols
1018da3821bSSteven Rostedt#    with objcopy.
1028da3821bSSteven Rostedt# 6) Link together this new object with the list object.
1038da3821bSSteven Rostedt# 7) Convert the local functions back to local symbols and rename
1048da3821bSSteven Rostedt#    the result as the original object.
1058da3821bSSteven Rostedt# 8) Link the object with the list object.
1068da3821bSSteven Rostedt# 9) Move the result back to the original object.
1078da3821bSSteven Rostedt#
1088da3821bSSteven Rostedt
109cb77f0d6SKamil Rytarowskiuse warnings;
1108da3821bSSteven Rostedtuse strict;
1118da3821bSSteven Rostedt
1128da3821bSSteven Rostedtmy $P = $0;
1138da3821bSSteven Rostedt$P =~ s@.*/@@g;
1148da3821bSSteven Rostedt
1158da3821bSSteven Rostedtmy $V = '0.1';
1168da3821bSSteven Rostedt
117e6299d26SWu Zhangjinif ($#ARGV != 11) {
118e6299d26SWu Zhangjin	print "usage: $P arch endian bits objdump objcopy cc ld nm rm mv is_module inputfile\n";
1198da3821bSSteven Rostedt	print "version: $V\n";
1208da3821bSSteven Rostedt	exit(1);
1218da3821bSSteven Rostedt}
1228da3821bSSteven Rostedt
123e6299d26SWu Zhangjinmy ($arch, $endian, $bits, $objdump, $objcopy, $cc,
12418c167fdSShaohua Li    $ld, $nm, $rm, $mv, $is_module, $inputfile) = @ARGV;
1258da3821bSSteven Rostedt
12625aac9dcSShaohua Li# This file refers to mcount and shouldn't be ftraced, so lets' ignore it
127bdd3b052SLi Hongif ($inputfile =~ m,kernel/trace/ftrace\.o$,) {
12825aac9dcSShaohua Li    exit(0);
12925aac9dcSShaohua Li}
13025aac9dcSShaohua Li
13134698bcbSSteven Rostedt# Acceptable sections to record.
13234698bcbSSteven Rostedtmy %text_sections = (
13334698bcbSSteven Rostedt     ".text" => 1,
13442c269c8SSteven Rostedt (VMware)     ".init.text" => 1,
1351274a9c2SSteven Rostedt     ".ref.text" => 1,
136d144d5eeSLiming Wang     ".sched.text" => 1,
137d144d5eeSLiming Wang     ".spinlock.text" => 1,
138a0343e82SFrederic Weisbecker     ".irqentry.text" => 1,
139e436fd61SDmitry Vyukov     ".softirqentry.text" => 1,
1409f087e76SSteven Rostedt     ".kprobes.text" => 1,
1416727ad9eSChris Metcalf     ".cpuidle.text" => 1,
1424d828949SJiri Olsa     ".text.unlikely" => 1,
14334698bcbSSteven Rostedt);
14434698bcbSSteven Rostedt
1459c8e2f6dSJoe Lawrence# Acceptable section-prefixes to record.
1469c8e2f6dSJoe Lawrencemy %text_section_prefixes = (
1479c8e2f6dSJoe Lawrence     ".text." => 1,
1489c8e2f6dSJoe Lawrence);
1499c8e2f6dSJoe Lawrence
150dfaa9e2cSWolfram Sang# Note: we are nice to C-programmers here, thus we skip the '||='-idiom.
151dfaa9e2cSWolfram Sang$objdump = 'objdump' if (!$objdump);
152dfaa9e2cSWolfram Sang$objcopy = 'objcopy' if (!$objcopy);
153dfaa9e2cSWolfram Sang$cc = 'gcc' if (!$cc);
154dfaa9e2cSWolfram Sang$ld = 'ld' if (!$ld);
155dfaa9e2cSWolfram Sang$nm = 'nm' if (!$nm);
156dfaa9e2cSWolfram Sang$rm = 'rm' if (!$rm);
157dfaa9e2cSWolfram Sang$mv = 'mv' if (!$mv);
1588da3821bSSteven Rostedt
1598da3821bSSteven Rostedt#print STDERR "running: $P '$arch' '$objdump' '$objcopy' '$cc' '$ld' " .
1608da3821bSSteven Rostedt#    "'$nm' '$rm' '$mv' '$inputfile'\n";
1618da3821bSSteven Rostedt
1628feff1caSSteven Rostedtmy %locals;		# List of local (static) functions
1638feff1caSSteven Rostedtmy %weak;		# List of weak functions
1648feff1caSSteven Rostedtmy %convert;		# List of local functions used that needs conversion
1658da3821bSSteven Rostedt
1668da3821bSSteven Rostedtmy $type;
167306dcf47SLi Hongmy $local_regex;	# Match a local function (return function)
168306dcf47SLi Hongmy $weak_regex; 	# Match a weak function (return function)
1698da3821bSSteven Rostedtmy $section_regex;	# Find the start of a section
1708feff1caSSteven Rostedtmy $function_regex;	# Find the name of a function
1718feff1caSSteven Rostedt			#    (return offset and func name)
1728da3821bSSteven Rostedtmy $mcount_regex;	# Find the call site to mcount (return offset)
173465c6ccaSMike Frysingermy $mcount_adjust;	# Address adjustment to mcount offset
1747d5222a6SMatt Flemingmy $alignment;		# The .align value to use for $mcount_section
175e58918abSJim Radfordmy $section_type;	# Section header plus possible alignment command
1768da3821bSSteven Rostedt
177b82a4045SJan Kiszkaif ($arch =~ /(x86(_64)?)|(i386)/) {
178dce9d18aSSteven Rostedt    if ($bits == 64) {
179dce9d18aSSteven Rostedt	$arch = "x86_64";
180dce9d18aSSteven Rostedt    } else {
181dce9d18aSSteven Rostedt	$arch = "i386";
182dce9d18aSSteven Rostedt    }
183dce9d18aSSteven Rostedt}
184dce9d18aSSteven Rostedt
185c204f726SSteven Rostedt#
186c204f726SSteven Rostedt# We base the defaults off of i386, the other archs may
187c204f726SSteven Rostedt# feel free to change them in the below if statements.
188c204f726SSteven Rostedt#
189306dcf47SLi Hong$local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\S+)";
190306dcf47SLi Hong$weak_regex = "^[0-9a-fA-F]+\\s+([wW])\\s+(\\S+)";
19134698bcbSSteven Rostedt$section_regex = "Disassembly of section\\s+(\\S+):";
192be358af1SSteven Rostedt$function_regex = "^([0-9a-fA-F]+)\\s+<([^^]*?)>:";
193f02b625dSJamie Iles$mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s(mcount|__fentry__)\$";
194e58918abSJim Radford$section_type = '@progbits';
195465c6ccaSMike Frysinger$mcount_adjust = 0;
196c204f726SSteven Rostedt$type = ".long";
197c204f726SSteven Rostedt
198c204f726SSteven Rostedtif ($arch eq "x86_64") {
199f02b625dSJamie Iles    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s(mcount|__fentry__)([+-]0x[0-9a-zA-Z]+)?\$";
2008da3821bSSteven Rostedt    $type = ".quad";
2017d5222a6SMatt Fleming    $alignment = 8;
202521ccb5cSMartin Schwidefsky    $mcount_adjust = -1;
203d74fcd1eSSteven Rostedt
204d74fcd1eSSteven Rostedt    # force flags for this arch
205d74fcd1eSSteven Rostedt    $ld .= " -m elf_x86_64";
206d74fcd1eSSteven Rostedt    $objdump .= " -M x86-64";
207d74fcd1eSSteven Rostedt    $objcopy .= " -O elf64-x86-64";
208d74fcd1eSSteven Rostedt    $cc .= " -m64";
209d74fcd1eSSteven Rostedt
2108da3821bSSteven Rostedt} elsif ($arch eq "i386") {
2117d5222a6SMatt Fleming    $alignment = 4;
212521ccb5cSMartin Schwidefsky    $mcount_adjust = -1;
213d74fcd1eSSteven Rostedt
214d74fcd1eSSteven Rostedt    # force flags for this arch
215d74fcd1eSSteven Rostedt    $ld .= " -m elf_i386";
216d74fcd1eSSteven Rostedt    $objdump .= " -M i386";
217d74fcd1eSSteven Rostedt    $objcopy .= " -O elf32-i386";
218d74fcd1eSSteven Rostedt    $cc .= " -m32";
219d74fcd1eSSteven Rostedt
220dfd9f7abSHeiko Carstens} elsif ($arch eq "s390" && $bits == 64) {
221e6d60b36SHeiko Carstens    if ($cc =~ /-DCC_USING_HOTPATCH/) {
2224eb1782eSHeiko Carstens	$mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*(brcl\\s*0,|jgnop\\s*)[0-9a-f]+ <([^\+]*)>\$";
223e6d60b36SHeiko Carstens	$mcount_adjust = 0;
224e6d60b36SHeiko Carstens    }
225dfd9f7abSHeiko Carstens    $alignment = 8;
226dfd9f7abSHeiko Carstens    $type = ".quad";
227dfd9f7abSHeiko Carstens    $ld .= " -m elf64_s390";
228dfd9f7abSHeiko Carstens    $cc .= " -m64";
229dfd9f7abSHeiko Carstens
2300da85c09SMatt Fleming} elsif ($arch eq "sh") {
2313a3d04aeSMatt Fleming    $alignment = 2;
2320da85c09SMatt Fleming
2330da85c09SMatt Fleming    # force flags for this arch
2340da85c09SMatt Fleming    $ld .= " -m shlelf_linux";
23593ca6963SRong Chen    if ($endian eq "big") {
23693ca6963SRong Chen	$objcopy .= " -O elf32-shbig-linux";
23793ca6963SRong Chen    } else {
2380da85c09SMatt Fleming	$objcopy .= " -O elf32-sh-linux";
23993ca6963SRong Chen    }
2400da85c09SMatt Fleming
24142e007d0SSteven Rostedt} elsif ($arch eq "powerpc") {
2421421dc6dSNicholas Piggin    my $ldemulation;
2431421dc6dSNicholas Piggin
244306dcf47SLi Hong    $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)";
2452e50c4beSUlrich Weigand    # See comment in the sparc64 section for why we use '\w'.
2462e50c4beSUlrich Weigand    $function_regex = "^([0-9a-fA-F]+)\\s+<(\\.?\\w*?)>:";
24742e007d0SSteven Rostedt    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s\\.?_mcount\$";
248c204f726SSteven Rostedt
2491421dc6dSNicholas Piggin    if ($endian eq "big") {
2501421dc6dSNicholas Piggin	    $cc .= " -mbig-endian ";
2511421dc6dSNicholas Piggin	    $ld .= " -EB ";
2521421dc6dSNicholas Piggin	    $ldemulation = "ppc"
2531421dc6dSNicholas Piggin    } else {
2541421dc6dSNicholas Piggin	    $cc .= " -mlittle-endian ";
2551421dc6dSNicholas Piggin	    $ld .= " -EL ";
2561421dc6dSNicholas Piggin	    $ldemulation = "lppc"
2571421dc6dSNicholas Piggin    }
25842e007d0SSteven Rostedt    if ($bits == 64) {
25942e007d0SSteven Rostedt	$type = ".quad";
2601421dc6dSNicholas Piggin	$cc .= " -m64 ";
2611421dc6dSNicholas Piggin	$ld .= " -m elf64".$ldemulation." ";
2621421dc6dSNicholas Piggin    } else {
2631421dc6dSNicholas Piggin	$cc .= " -m32 ";
2641421dc6dSNicholas Piggin	$ld .= " -m elf32".$ldemulation." ";
26542e007d0SSteven Rostedt    }
26642e007d0SSteven Rostedt
267e58918abSJim Radford} elsif ($arch eq "arm") {
268e58918abSJim Radford    $alignment = 2;
269e58918abSJim Radford    $section_type = '%progbits';
27072dc43a9SRabin Vincent    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_ARM_(CALL|PC24|THM_CALL)" .
2713b6c223bSRabin Vincent			"\\s+(__gnu_mcount_nc|mcount)\$";
272e58918abSJim Radford
273af64d2aaSAKASHI Takahiro} elsif ($arch eq "arm64") {
274af64d2aaSAKASHI Takahiro    $alignment = 3;
275af64d2aaSAKASHI Takahiro    $section_type = '%progbits';
276af64d2aaSAKASHI Takahiro    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_AARCH64_CALL26\\s+_mcount\$";
277af64d2aaSAKASHI Takahiro    $type = ".quad";
2789be12f9bSDavid S. Miller} elsif ($arch eq "sparc64") {
2799be12f9bSDavid S. Miller    # In the objdump output there are giblets like:
2809be12f9bSDavid S. Miller    # 0000000000000000 <igmp_net_exit-0x18>:
2819be12f9bSDavid S. Miller    # As there's some data blobs that get emitted into the
2829be12f9bSDavid S. Miller    # text section before the first instructions and the first
2839be12f9bSDavid S. Miller    # real symbols.  We don't want to match that, so to combat
2849be12f9bSDavid S. Miller    # this we use '\w' so we'll match just plain symbol names,
2859be12f9bSDavid S. Miller    # and not those that also include hex offsets inside of the
2869be12f9bSDavid S. Miller    # '<>' brackets.  Actually the generic function_regex setting
2879be12f9bSDavid S. Miller    # could safely use this too.
2889be12f9bSDavid S. Miller    $function_regex = "^([0-9a-fA-F]+)\\s+<(\\w*?)>:";
2899be12f9bSDavid S. Miller
2909be12f9bSDavid S. Miller    # Sparc64 calls '_mcount' instead of plain 'mcount'.
2919be12f9bSDavid S. Miller    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
2929be12f9bSDavid S. Miller
2939be12f9bSDavid S. Miller    $alignment = 8;
2949be12f9bSDavid S. Miller    $type = ".xword";
2959be12f9bSDavid S. Miller    $ld .= " -m elf64_sparc";
2969be12f9bSDavid S. Miller    $cc .= " -m64";
2979be12f9bSDavid S. Miller    $objcopy .= " -O elf64-sparc";
298538f1952SWu Zhangjin} elsif ($arch eq "mips") {
299538f1952SWu Zhangjin    # To enable module support, we need to enable the -mlong-calls option
300538f1952SWu Zhangjin    # of gcc for module, after using this option, we can not get the real
301538f1952SWu Zhangjin    # offset of the calling to _mcount, but the offset of the lui
302538f1952SWu Zhangjin    # instruction or the addiu one. herein, we record the address of the
303538f1952SWu Zhangjin    # first one, and then we can replace this instruction by a branch
304538f1952SWu Zhangjin    # instruction to jump over the profiling function to filter the
30508a7e621SMasahiro Yamada    # indicated functions, or switch back to the lui instruction to trace
306538f1952SWu Zhangjin    # them, which means dynamic tracing.
307538f1952SWu Zhangjin    #
308538f1952SWu Zhangjin    #       c:	3c030000 	lui	v1,0x0
309538f1952SWu Zhangjin    #			c: R_MIPS_HI16	_mcount
310538f1952SWu Zhangjin    #			c: R_MIPS_NONE	*ABS*
311538f1952SWu Zhangjin    #			c: R_MIPS_NONE	*ABS*
312538f1952SWu Zhangjin    #      10:	64630000 	daddiu	v1,v1,0
313538f1952SWu Zhangjin    #			10: R_MIPS_LO16	_mcount
314538f1952SWu Zhangjin    #			10: R_MIPS_NONE	*ABS*
315538f1952SWu Zhangjin    #			10: R_MIPS_NONE	*ABS*
316538f1952SWu Zhangjin    #      14:	03e0082d 	move	at,ra
317538f1952SWu Zhangjin    #      18:	0060f809 	jalr	v1
318538f1952SWu Zhangjin    #
319538f1952SWu Zhangjin    # for the kernel:
320538f1952SWu Zhangjin    #
321538f1952SWu Zhangjin    #     10:   03e0082d        move    at,ra
322538f1952SWu Zhangjin    #	  14:   0c000000        jal     0 <loongson_halt>
323538f1952SWu Zhangjin    #                    14: R_MIPS_26   _mcount
324538f1952SWu Zhangjin    #                    14: R_MIPS_NONE *ABS*
325538f1952SWu Zhangjin    #                    14: R_MIPS_NONE *ABS*
326538f1952SWu Zhangjin    #	 18:   00020021        nop
327538f1952SWu Zhangjin    if ($is_module eq "0") {
328a484e54fSDavid Daney	    $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_26\\s+_mcount\$";
329538f1952SWu Zhangjin    } else {
330538f1952SWu Zhangjin	    $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$";
331538f1952SWu Zhangjin    }
332538f1952SWu Zhangjin    $objdump .= " -Melf-trad".$endian."mips ";
333538f1952SWu Zhangjin
334538f1952SWu Zhangjin    if ($endian eq "big") {
335538f1952SWu Zhangjin	    $endian = " -EB ";
336538f1952SWu Zhangjin	    $ld .= " -melf".$bits."btsmip";
337538f1952SWu Zhangjin    } else {
338538f1952SWu Zhangjin	    $endian = " -EL ";
339538f1952SWu Zhangjin	    $ld .= " -melf".$bits."ltsmip";
340538f1952SWu Zhangjin    }
341538f1952SWu Zhangjin
342538f1952SWu Zhangjin    $cc .= " -mno-abicalls -fno-pic -mabi=" . $bits . $endian;
343538f1952SWu Zhangjin    $ld .= $endian;
344538f1952SWu Zhangjin
345538f1952SWu Zhangjin    if ($bits == 64) {
346538f1952SWu Zhangjin	    $function_regex =
347538f1952SWu Zhangjin		"^([0-9a-fA-F]+)\\s+<(.|[^\$]L.*?|\$[^L].*?|[^\$][^L].*?)>:";
348538f1952SWu Zhangjin	    $type = ".dword";
349538f1952SWu Zhangjin    }
3507d241ff0SMichal Simek} elsif ($arch eq "microblaze") {
3517d241ff0SMichal Simek    # Microblaze calls '_mcount' instead of plain 'mcount'.
3527d241ff0SMichal Simek    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
353a1d2a6b4SAlan Kao} elsif ($arch eq "riscv") {
354a1d2a6b4SAlan Kao    $function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:";
355*de5f3984SNathan Chancellor    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL(_PLT)?\\s_mcount\$";
356a1d2a6b4SAlan Kao    $type = ".quad";
357a1d2a6b4SAlan Kao    $alignment = 2;
35828bb030fSGuo Ren} elsif ($arch eq "csky") {
35928bb030fSGuo Ren    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_CKCORE_PCREL_JSR_IMM26BY2\\s+_mcount\$";
36028bb030fSGuo Ren    $alignment = 2;
3618da3821bSSteven Rostedt} else {
3628da3821bSSteven Rostedt    die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
3638da3821bSSteven Rostedt}
3648da3821bSSteven Rostedt
3658da3821bSSteven Rostedtmy $text_found = 0;
3668da3821bSSteven Rostedtmy $read_function = 0;
3678da3821bSSteven Rostedtmy $opened = 0;
3688da3821bSSteven Rostedtmy $mcount_section = "__mcount_loc";
3698da3821bSSteven Rostedt
3708da3821bSSteven Rostedtmy $dirname;
3718da3821bSSteven Rostedtmy $filename;
3728da3821bSSteven Rostedtmy $prefix;
3738da3821bSSteven Rostedtmy $ext;
3748da3821bSSteven Rostedt
3758da3821bSSteven Rostedtif ($inputfile =~ m,^(.*)/([^/]*)$,) {
3768da3821bSSteven Rostedt    $dirname = $1;
3778da3821bSSteven Rostedt    $filename = $2;
3788da3821bSSteven Rostedt} else {
3798da3821bSSteven Rostedt    $dirname = ".";
3808da3821bSSteven Rostedt    $filename = $inputfile;
3818da3821bSSteven Rostedt}
3828da3821bSSteven Rostedt
3838da3821bSSteven Rostedtif ($filename =~ m,^(.*)(\.\S),) {
3848da3821bSSteven Rostedt    $prefix = $1;
3858da3821bSSteven Rostedt    $ext = $2;
3868da3821bSSteven Rostedt} else {
3878da3821bSSteven Rostedt    $prefix = $filename;
3888da3821bSSteven Rostedt    $ext = "";
3898da3821bSSteven Rostedt}
3908da3821bSSteven Rostedt
3918da3821bSSteven Rostedtmy $mcount_s = $dirname . "/.tmp_mc_" . $prefix . ".s";
3928da3821bSSteven Rostedtmy $mcount_o = $dirname . "/.tmp_mc_" . $prefix . ".o";
3938da3821bSSteven Rostedt
394f2f8458eSSteven Rostedt#
3958feff1caSSteven Rostedt# Step 1: find all the local (static functions) and weak symbols.
396306dcf47SLi Hong#         't' is local, 'w/W' is weak
3978da3821bSSteven Rostedt#
3988da3821bSSteven Rostedtopen (IN, "$nm $inputfile|") || die "error running $nm";
3998da3821bSSteven Rostedtwhile (<IN>) {
400306dcf47SLi Hong    if (/$local_regex/) {
4018da3821bSSteven Rostedt	$locals{$1} = 1;
402306dcf47SLi Hong    } elsif (/$weak_regex/) {
4038feff1caSSteven Rostedt	$weak{$2} = $1;
4048da3821bSSteven Rostedt    }
4058da3821bSSteven Rostedt}
4068da3821bSSteven Rostedtclose(IN);
4078da3821bSSteven Rostedt
4088feff1caSSteven Rostedtmy @offsets;		# Array of offsets of mcount callers
4098feff1caSSteven Rostedtmy $ref_func;		# reference function to use for offsets
4108feff1caSSteven Rostedtmy $offset = 0;		# offset of ref_func to section beginning
4118feff1caSSteven Rostedt
4128feff1caSSteven Rostedt##
4138feff1caSSteven Rostedt# update_funcs - print out the current mcount callers
4148feff1caSSteven Rostedt#
4158feff1caSSteven Rostedt#  Go through the list of offsets to callers and write them to
4168feff1caSSteven Rostedt#  the output file in a format that can be read by an assembler.
4178feff1caSSteven Rostedt#
4188feff1caSSteven Rostedtsub update_funcs
4198feff1caSSteven Rostedt{
4206092858cSLi Hong    return unless ($ref_func and @offsets);
4218feff1caSSteven Rostedt
422c4b8ac2cSLi Hong    # Sanity check on weak function. A weak function may be overwritten by
423c4b8ac2cSLi Hong    # another function of the same name, making all these offsets incorrect.
4248feff1caSSteven Rostedt    if (defined $weak{$ref_func}) {
425c4b8ac2cSLi Hong	die "$inputfile: ERROR: referencing weak function" .
4268feff1caSSteven Rostedt	    " $ref_func for mcount\n";
4278feff1caSSteven Rostedt    }
4288feff1caSSteven Rostedt
4298feff1caSSteven Rostedt    # is this function static? If so, note this fact.
4308feff1caSSteven Rostedt    if (defined $locals{$ref_func}) {
4318feff1caSSteven Rostedt	$convert{$ref_func} = 1;
4328feff1caSSteven Rostedt    }
4338feff1caSSteven Rostedt
4348feff1caSSteven Rostedt    # Loop through all the mcount caller offsets and print a reference
4358feff1caSSteven Rostedt    # to the caller based from the ref_func.
4368feff1caSSteven Rostedt    if (!$opened) {
4378feff1caSSteven Rostedt	open(FILE, ">$mcount_s") || die "can't create $mcount_s\n";
4388feff1caSSteven Rostedt	$opened = 1;
439e58918abSJim Radford	print FILE "\t.section $mcount_section,\"a\",$section_type\n";
44042e007d0SSteven Rostedt	print FILE "\t.align $alignment\n" if (defined($alignment));
4418feff1caSSteven Rostedt    }
442dc4f8845SWolfram Sang    foreach my $cur_offset (@offsets) {
443dc4f8845SWolfram Sang	printf FILE "\t%s %s + %d\n", $type, $ref_func, $cur_offset - $offset;
4448feff1caSSteven Rostedt    }
4458feff1caSSteven Rostedt}
4468feff1caSSteven Rostedt
4478da3821bSSteven Rostedt#
4488da3821bSSteven Rostedt# Step 2: find the sections and mcount call sites
4498da3821bSSteven Rostedt#
45077a88274SMasahiro Yamadaopen(IN, "LC_ALL=C $objdump -hdr $inputfile|") || die "error running $objdump";
4518da3821bSSteven Rostedt
4528feff1caSSteven Rostedtmy $text;
4538feff1caSSteven Rostedt
454db24c7dcSLi Hong
455db24c7dcSLi Hong# read headers first
456b43f7093SSteven Rostedtmy $read_headers = 1;
457b43f7093SSteven Rostedt
4588da3821bSSteven Rostedtwhile (<IN>) {
459db24c7dcSLi Hong
460db24c7dcSLi Hong    if ($read_headers && /$mcount_section/) {
461db24c7dcSLi Hong	#
462db24c7dcSLi Hong	# Somehow the make process can execute this script on an
463db24c7dcSLi Hong	# object twice. If it does, we would duplicate the mcount
464db24c7dcSLi Hong	# section and it will cause the function tracer self test
465db24c7dcSLi Hong	# to fail. Check if the mcount section exists, and if it does,
466db24c7dcSLi Hong	# warn and exit.
467db24c7dcSLi Hong	#
468db24c7dcSLi Hong	print STDERR "ERROR: $mcount_section already in $inputfile\n" .
469db24c7dcSLi Hong	    "\tThis may be an indication that your build is corrupted.\n" .
470db24c7dcSLi Hong	    "\tDelete $inputfile and try again. If the same object file\n" .
471db24c7dcSLi Hong	    "\tstill causes an issue, then disable CONFIG_DYNAMIC_FTRACE.\n";
472db24c7dcSLi Hong	exit(-1);
473db24c7dcSLi Hong    }
474db24c7dcSLi Hong
4758da3821bSSteven Rostedt    # is it a section?
4768da3821bSSteven Rostedt    if (/$section_regex/) {
477b43f7093SSteven Rostedt	$read_headers = 0;
47834698bcbSSteven Rostedt
47934698bcbSSteven Rostedt	# Only record text sections that we know are safe
480dfaa9e2cSWolfram Sang	$read_function = defined($text_sections{$1});
4819c8e2f6dSJoe Lawrence	if (!$read_function) {
4829c8e2f6dSJoe Lawrence	    foreach my $prefix (keys %text_section_prefixes) {
4839c8e2f6dSJoe Lawrence		if (substr($1, 0, length $prefix) eq $prefix) {
4849c8e2f6dSJoe Lawrence		    $read_function = 1;
4859c8e2f6dSJoe Lawrence		    last;
4869c8e2f6dSJoe Lawrence		}
4879c8e2f6dSJoe Lawrence	    }
4889c8e2f6dSJoe Lawrence	}
4898feff1caSSteven Rostedt	# print out any recorded offsets
4906092858cSLi Hong	update_funcs();
4918feff1caSSteven Rostedt
4928feff1caSSteven Rostedt	# reset all markers and arrays
4938da3821bSSteven Rostedt	$text_found = 0;
4948feff1caSSteven Rostedt	undef($ref_func);
4958feff1caSSteven Rostedt	undef(@offsets);
4968feff1caSSteven Rostedt
4978da3821bSSteven Rostedt    # section found, now is this a start of a function?
4988da3821bSSteven Rostedt    } elsif ($read_function && /$function_regex/) {
4998da3821bSSteven Rostedt	$text_found = 1;
5008feff1caSSteven Rostedt	$text = $2;
5018feff1caSSteven Rostedt
5028feff1caSSteven Rostedt	# if this is either a local function or a weak function
5038feff1caSSteven Rostedt	# keep looking for functions that are global that
5048feff1caSSteven Rostedt	# we can use safely.
5058feff1caSSteven Rostedt	if (!defined($locals{$text}) && !defined($weak{$text})) {
5068feff1caSSteven Rostedt	    $ref_func = $text;
5078feff1caSSteven Rostedt	    $read_function = 0;
508bd171d5fSMatt Fleming	    $offset = hex $1;
5098feff1caSSteven Rostedt	} else {
5108feff1caSSteven Rostedt	    # if we already have a function, and this is weak, skip it
5113f6e968eSSteven Rostedt	    if (!defined($ref_func) && !defined($weak{$text}) &&
5123f6e968eSSteven Rostedt		 # PPC64 can have symbols that start with .L and
5133f6e968eSSteven Rostedt		 # gcc considers these special. Don't use them!
5143f6e968eSSteven Rostedt		 $text !~ /^\.L/) {
5158feff1caSSteven Rostedt		$ref_func = $text;
516bd171d5fSMatt Fleming		$offset = hex $1;
5178da3821bSSteven Rostedt	    }
5188da3821bSSteven Rostedt	}
5198feff1caSSteven Rostedt    }
5208feff1caSSteven Rostedt    # is this a call site to mcount? If so, record it to print later
5218feff1caSSteven Rostedt    if ($text_found && /$mcount_regex/) {
522465c6ccaSMike Frysinger	push(@offsets, (hex $1) + $mcount_adjust);
5238feff1caSSteven Rostedt    }
5248feff1caSSteven Rostedt}
5258feff1caSSteven Rostedt
5268feff1caSSteven Rostedt# dump out anymore offsets that may have been found
5276092858cSLi Hongupdate_funcs();
5288da3821bSSteven Rostedt
5298da3821bSSteven Rostedt# If we did not find any mcount callers, we are done (do nothing).
5308da3821bSSteven Rostedtif (!$opened) {
5318da3821bSSteven Rostedt    exit(0);
5328da3821bSSteven Rostedt}
5338da3821bSSteven Rostedt
5348da3821bSSteven Rostedtclose(FILE);
5358da3821bSSteven Rostedt
5368da3821bSSteven Rostedt#
5378da3821bSSteven Rostedt# Step 3: Compile the file that holds the list of call sites to mcount.
5388da3821bSSteven Rostedt#
5398da3821bSSteven Rostedt`$cc -o $mcount_o -c $mcount_s`;
5408da3821bSSteven Rostedt
5418da3821bSSteven Rostedtmy @converts = keys %convert;
5428da3821bSSteven Rostedt
5438da3821bSSteven Rostedt#
5448da3821bSSteven Rostedt# Step 4: Do we have sections that started with local functions?
5458da3821bSSteven Rostedt#
5468da3821bSSteven Rostedtif ($#converts >= 0) {
5478da3821bSSteven Rostedt    my $globallist = "";
5488da3821bSSteven Rostedt    my $locallist = "";
5498da3821bSSteven Rostedt
5508da3821bSSteven Rostedt    foreach my $con (@converts) {
5518da3821bSSteven Rostedt	$globallist .= " --globalize-symbol $con";
5528da3821bSSteven Rostedt	$locallist .= " --localize-symbol $con";
5538da3821bSSteven Rostedt    }
5548da3821bSSteven Rostedt
5558da3821bSSteven Rostedt    my $globalobj = $dirname . "/.tmp_gl_" . $filename;
5568da3821bSSteven Rostedt    my $globalmix = $dirname . "/.tmp_mx_" . $filename;
5578da3821bSSteven Rostedt
5588da3821bSSteven Rostedt    #
5598da3821bSSteven Rostedt    # Step 5: set up each local function as a global
5608da3821bSSteven Rostedt    #
5618da3821bSSteven Rostedt    `$objcopy $globallist $inputfile $globalobj`;
5628da3821bSSteven Rostedt
5638da3821bSSteven Rostedt    #
5648da3821bSSteven Rostedt    # Step 6: Link the global version to our list.
5658da3821bSSteven Rostedt    #
5668da3821bSSteven Rostedt    `$ld -r $globalobj $mcount_o -o $globalmix`;
5678da3821bSSteven Rostedt
5688da3821bSSteven Rostedt    #
5698da3821bSSteven Rostedt    # Step 7: Convert the local functions back into local symbols
5708da3821bSSteven Rostedt    #
5718da3821bSSteven Rostedt    `$objcopy $locallist $globalmix $inputfile`;
5728da3821bSSteven Rostedt
5738da3821bSSteven Rostedt    # Remove the temp files
5748da3821bSSteven Rostedt    `$rm $globalobj $globalmix`;
5758da3821bSSteven Rostedt
5768da3821bSSteven Rostedt} else {
5778da3821bSSteven Rostedt
5788da3821bSSteven Rostedt    my $mix = $dirname . "/.tmp_mx_" . $filename;
5798da3821bSSteven Rostedt
5808da3821bSSteven Rostedt    #
5818da3821bSSteven Rostedt    # Step 8: Link the object with our list of call sites object.
5828da3821bSSteven Rostedt    #
5838da3821bSSteven Rostedt    `$ld -r $inputfile $mcount_o -o $mix`;
5848da3821bSSteven Rostedt
5858da3821bSSteven Rostedt    #
5868da3821bSSteven Rostedt    # Step 9: Move the result back to the original object.
5878da3821bSSteven Rostedt    #
5888da3821bSSteven Rostedt    `$mv $mix $inputfile`;
5898da3821bSSteven Rostedt}
5908da3821bSSteven Rostedt
5918da3821bSSteven Rostedt# Clean up the temp files
5928da3821bSSteven Rostedt`$rm $mcount_o $mcount_s`;
5938da3821bSSteven Rostedt
5948da3821bSSteven Rostedtexit(0);
595b700fc3aSSteven Rostedt (VMware)
596b700fc3aSSteven Rostedt (VMware)# vim: softtabstop=4
597