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