my $V = '0.1';
-if ($#ARGV != 10) {
- print "usage: $P arch bits objdump objcopy cc ld nm rm mv is_module inputfile\n";
+if ($#ARGV != 11) {
+ print "usage: $P arch endian bits objdump objcopy cc ld nm rm mv is_module inputfile\n";
print "version: $V\n";
exit(1);
}
-my ($arch, $bits, $objdump, $objcopy, $cc,
+my ($arch, $endian, $bits, $objdump, $objcopy, $cc,
$ld, $nm, $rm, $mv, $is_module, $inputfile) = @ARGV;
# This file refers to mcount and shouldn't be ftraced, so lets' ignore it
".text.unlikely" => 1,
);
-$objdump = "objdump" if ((length $objdump) == 0);
-$objcopy = "objcopy" if ((length $objcopy) == 0);
-$cc = "gcc" if ((length $cc) == 0);
-$ld = "ld" if ((length $ld) == 0);
-$nm = "nm" if ((length $nm) == 0);
-$rm = "rm" if ((length $rm) == 0);
-$mv = "mv" if ((length $mv) == 0);
+# Note: we are nice to C-programmers here, thus we skip the '||='-idiom.
+$objdump = 'objdump' if (!$objdump);
+$objcopy = 'objcopy' if (!$objcopy);
+$cc = 'gcc' if (!$cc);
+$ld = 'ld' if (!$ld);
+$nm = 'nm' if (!$nm);
+$rm = 'rm' if (!$rm);
+$mv = 'mv' if (!$mv);
#print STDERR "running: $P '$arch' '$objdump' '$objcopy' '$cc' '$ld' " .
# "'$nm' '$rm' '$mv' '$inputfile'\n";
}
}
-if ($arch eq "x86") {
+if ($arch =~ /(x86(_64)?)|(i386)/) {
if ($bits == 64) {
$arch = "x86_64";
} else {
$ld .= " -m elf64_sparc";
$cc .= " -m64";
$objcopy .= " -O elf64-sparc";
+} elsif ($arch eq "mips") {
+ # To enable module support, we need to enable the -mlong-calls option
+ # of gcc for module, after using this option, we can not get the real
+ # offset of the calling to _mcount, but the offset of the lui
+ # instruction or the addiu one. herein, we record the address of the
+ # first one, and then we can replace this instruction by a branch
+ # instruction to jump over the profiling function to filter the
+ # indicated functions, or swith back to the lui instruction to trace
+ # them, which means dynamic tracing.
+ #
+ # c: 3c030000 lui v1,0x0
+ # c: R_MIPS_HI16 _mcount
+ # c: R_MIPS_NONE *ABS*
+ # c: R_MIPS_NONE *ABS*
+ # 10: 64630000 daddiu v1,v1,0
+ # 10: R_MIPS_LO16 _mcount
+ # 10: R_MIPS_NONE *ABS*
+ # 10: R_MIPS_NONE *ABS*
+ # 14: 03e0082d move at,ra
+ # 18: 0060f809 jalr v1
+ #
+ # for the kernel:
+ #
+ # 10: 03e0082d move at,ra
+ # 14: 0c000000 jal 0 <loongson_halt>
+ # 14: R_MIPS_26 _mcount
+ # 14: R_MIPS_NONE *ABS*
+ # 14: R_MIPS_NONE *ABS*
+ # 18: 00020021 nop
+ if ($is_module eq "0") {
+ $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+ } else {
+ $mcount_regex = "^\\s*([0-9a-fA-F]+): R_MIPS_HI16\\s+_mcount\$";
+ }
+ $objdump .= " -Melf-trad".$endian."mips ";
+
+ if ($endian eq "big") {
+ $endian = " -EB ";
+ $ld .= " -melf".$bits."btsmip";
+ } else {
+ $endian = " -EL ";
+ $ld .= " -melf".$bits."ltsmip";
+ }
+
+ $cc .= " -mno-abicalls -fno-pic -mabi=" . $bits . $endian;
+ $ld .= $endian;
+
+ if ($bits == 64) {
+ $function_regex =
+ "^([0-9a-fA-F]+)\\s+<(.|[^\$]L.*?|\$[^L].*?|[^\$][^L].*?)>:";
+ $type = ".dword";
+ }
+} elsif ($arch eq "microblaze") {
+ # Microblaze calls '_mcount' instead of plain 'mcount'.
+ $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
} else {
die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
}
# Loop through all the mcount caller offsets and print a reference
# to the caller based from the ref_func.
- for (my $i=0; $i <= $#offsets; $i++) {
- if (!$opened) {
- open(FILE, ">$mcount_s") || die "can't create $mcount_s\n";
- $opened = 1;
- print FILE "\t.section $mcount_section,\"a\",$section_type\n";
- print FILE "\t.align $alignment\n" if (defined($alignment));
- }
- printf FILE "\t%s %s + %d\n", $type, $ref_func, $offsets[$i] - $offset;
+ if (!$opened) {
+ open(FILE, ">$mcount_s") || die "can't create $mcount_s\n";
+ $opened = 1;
+ print FILE "\t.section $mcount_section,\"a\",$section_type\n";
+ print FILE "\t.align $alignment\n" if (defined($alignment));
+ }
+ foreach my $cur_offset (@offsets) {
+ printf FILE "\t%s %s + %d\n", $type, $ref_func, $cur_offset - $offset;
}
}
$read_headers = 0;
# Only record text sections that we know are safe
- if (defined($text_sections{$1})) {
- $read_function = 1;
- } else {
- $read_function = 0;
- }
+ $read_function = defined($text_sections{$1});
# print out any recorded offsets
update_funcs();
}
# is this a call site to mcount? If so, record it to print later
if ($text_found && /$mcount_regex/) {
- $offsets[$#offsets + 1] = hex $1;
+ push(@offsets, hex $1);
}
}