^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) #!/usr/bin/env perl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) # SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) use File::Basename;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) use Math::BigInt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) use Getopt::Long;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) # Copyright 2008, Intel Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) # This file is part of the Linux kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) # Authors:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) # Arjan van de Ven <arjan@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) my $cross_compile = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) my $vmlinux_name = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) my $modulefile = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) # Get options
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) Getopt::Long::GetOptions(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) 'cross-compile|c=s' => \$cross_compile,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) 'module|m=s' => \$modulefile,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) 'help|h' => \&usage,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) ) || usage ();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) my $vmlinux_name = $ARGV[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) if (!defined($vmlinux_name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) my $kerver = `uname -r`;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) chomp($kerver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) $vmlinux_name = "/lib/modules/$kerver/build/vmlinux";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) print "No vmlinux specified, assuming $vmlinux_name\n";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) my $filename = $vmlinux_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) # Parse the oops to find the EIP value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) my $target = "0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) my $function;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) my $module = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) my $func_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) my $vmaoffset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) my %regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) sub parse_x86_regs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) my ($line) = @_;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if ($line =~ /EAX: ([0-9a-f]+) EBX: ([0-9a-f]+) ECX: ([0-9a-f]+) EDX: ([0-9a-f]+)/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) $regs{"%eax"} = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) $regs{"%ebx"} = $2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) $regs{"%ecx"} = $3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) $regs{"%edx"} = $4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if ($line =~ /ESI: ([0-9a-f]+) EDI: ([0-9a-f]+) EBP: ([0-9a-f]+) ESP: ([0-9a-f]+)/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) $regs{"%esi"} = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) $regs{"%edi"} = $2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) $regs{"%esp"} = $4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if ($line =~ /RAX: ([0-9a-f]+) RBX: ([0-9a-f]+) RCX: ([0-9a-f]+)/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) $regs{"%eax"} = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) $regs{"%ebx"} = $2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) $regs{"%ecx"} = $3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if ($line =~ /RDX: ([0-9a-f]+) RSI: ([0-9a-f]+) RDI: ([0-9a-f]+)/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) $regs{"%edx"} = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) $regs{"%esi"} = $2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) $regs{"%edi"} = $3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if ($line =~ /RBP: ([0-9a-f]+) R08: ([0-9a-f]+) R09: ([0-9a-f]+)/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) $regs{"%r08"} = $2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) $regs{"%r09"} = $3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if ($line =~ /R10: ([0-9a-f]+) R11: ([0-9a-f]+) R12: ([0-9a-f]+)/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) $regs{"%r10"} = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) $regs{"%r11"} = $2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) $regs{"%r12"} = $3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if ($line =~ /R13: ([0-9a-f]+) R14: ([0-9a-f]+) R15: ([0-9a-f]+)/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) $regs{"%r13"} = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) $regs{"%r14"} = $2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) $regs{"%r15"} = $3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) sub reg_name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) my ($reg) = @_;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) $reg =~ s/r(.)x/e\1x/;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) $reg =~ s/r(.)i/e\1i/;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) $reg =~ s/r(.)p/e\1p/;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return $reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) sub process_x86_regs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) my ($line, $cntr) = @_;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) my $str = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (length($line) < 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return ""; # not an asm istruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) # find the arguments to the instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if ($line =~ /([0-9a-zA-Z\,\%\(\)\-\+]+)$/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) $lastword = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) # we need to find the registers that get clobbered,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) # since their value is no longer relevant for previous
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) # instructions in the stream.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) $clobber = $lastword;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) # first, remove all memory operands, they're read only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) $clobber =~ s/\([a-z0-9\%\,]+\)//g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) # then, remove everything before the comma, thats the read part
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) $clobber =~ s/.*\,//g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) # if this is the instruction that faulted, we haven't actually done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) # the write yet... nothing is clobbered.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if ($cntr == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) $clobber = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) foreach $reg (keys(%regs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) my $clobberprime = reg_name($clobber);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) my $lastwordprime = reg_name($lastword);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) my $val = $regs{$reg};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if ($val =~ /^[0]+$/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) $val = "0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) $val =~ s/^0*//;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) # first check if we're clobbering this register; if we do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) # we print it with a =>, and then delete its value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if ($clobber =~ /$reg/ || $clobberprime =~ /$reg/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (length($val) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) $str = $str . " $reg => $val ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) $regs{$reg} = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) $val = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) # now check if we're reading this register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if ($lastword =~ /$reg/ || $lastwordprime =~ /$reg/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (length($val) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) $str = $str . " $reg = $val ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return $str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) # parse the oops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) while (<STDIN>) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) my $line = $_;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if ($line =~ /EIP: 0060:\[\<([a-z0-9]+)\>\]/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) $target = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if ($line =~ /RIP: 0010:\[\<([a-z0-9]+)\>\]/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) $target = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if ($line =~ /EIP is at ([a-zA-Z0-9\_]+)\+0x([0-9a-f]+)\/0x[a-f0-9]/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) $function = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) $func_offset = $2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if ($line =~ /RIP: 0010:\[\<[0-9a-f]+\>\] \[\<[0-9a-f]+\>\] ([a-zA-Z0-9\_]+)\+0x([0-9a-f]+)\/0x[a-f0-9]/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) $function = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) $func_offset = $2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) # check if it's a module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if ($line =~ /EIP is at ([a-zA-Z0-9\_]+)\+(0x[0-9a-f]+)\/0x[a-f0-9]+\W\[([a-zA-Z0-9\_\-]+)\]/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) $module = $3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if ($line =~ /RIP: 0010:\[\<[0-9a-f]+\>\] \[\<[0-9a-f]+\>\] ([a-zA-Z0-9\_]+)\+(0x[0-9a-f]+)\/0x[a-f0-9]+\W\[([a-zA-Z0-9\_\-]+)\]/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) $module = $3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) parse_x86_regs($line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) my $decodestart = Math::BigInt->from_hex("0x$target") - Math::BigInt->from_hex("0x$func_offset");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) my $decodestop = Math::BigInt->from_hex("0x$target") + 8192;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if ($target eq "0") {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) print "No oops found!\n";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) # if it's a module, we need to find the .ko file and calculate a load offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if ($module ne "") {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if ($modulefile eq "") {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) $modulefile = `modinfo -F filename $module`;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) chomp($modulefile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) $filename = $modulefile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if ($filename eq "") {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) print "Module .ko file for $module not found. Aborting\n";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) # ok so we found the module, now we need to calculate the vma offset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) open(FILE, $cross_compile."objdump -dS $filename |") || die "Cannot start objdump";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) while (<FILE>) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if ($_ =~ /^([0-9a-f]+) \<$function\>\:/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) my $fu = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) $vmaoffset = Math::BigInt->from_hex("0x$target") - Math::BigInt->from_hex("0x$fu") - Math::BigInt->from_hex("0x$func_offset");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) close(FILE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) my $counter = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) my $state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) my $center = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) my @lines;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) my @reglines;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) sub InRange {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) my ($address, $target) = @_;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) my $ad = "0x".$address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) my $ta = "0x".$target;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) my $delta = Math::BigInt->from_hex($ad) - Math::BigInt->from_hex($ta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (($delta > -4096) && ($delta < 4096)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) # first, parse the input into the lines array, but to keep size down,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) # we only do this for 4Kb around the sweet spot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) open(FILE, $cross_compile."objdump -dS --adjust-vma=$vmaoffset --start-address=$decodestart --stop-address=$decodestop $filename |") || die "Cannot start objdump";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) while (<FILE>) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) my $line = $_;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) chomp($line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if ($state == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if ($line =~ /^([a-f0-9]+)\:/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (InRange($1, $target)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) $state = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if ($state == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if ($line =~ /^([a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]+)\:/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) my $val = $1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (!InRange($val, $target)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if ($val eq $target) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) $center = $counter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) $lines[$counter] = $line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) $counter = $counter + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) close(FILE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if ($counter == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) print "No matching code found \n";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if ($center == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) print "No matching code found \n";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) my $start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) my $finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) my $codelines = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) my $binarylines = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) # now we go up and down in the array to find how much we want to print
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) $start = $center;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) while ($start > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) $start = $start - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) my $line = $lines[$start];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if ($line =~ /^([a-f0-9]+)\:/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) $binarylines = $binarylines + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) $codelines = $codelines + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if ($codelines > 10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if ($binarylines > 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) $finish = $center;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) $codelines = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) $binarylines = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) while ($finish < $counter) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) $finish = $finish + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) my $line = $lines[$finish];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if ($line =~ /^([a-f0-9]+)\:/) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) $binarylines = $binarylines + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) $codelines = $codelines + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if ($codelines > 10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if ($binarylines > 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) last;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) my $i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) # start annotating the registers in the asm.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) # this goes from the oopsing point back, so that the annotator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) # can track (opportunistically) which registers got written and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) # whos value no longer is relevant.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) $i = $center;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) while ($i >= $start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) $reglines[$i] = process_x86_regs($lines[$i], $center - $i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) $i = $i - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) $i = $start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) while ($i < $finish) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) my $line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if ($i == $center) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) $line = "*$lines[$i] ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) $line = " $lines[$i] ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) print $line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (defined($reglines[$i]) && length($reglines[$i]) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) my $c = 60 - length($line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) while ($c > 0) { print " "; $c = $c - 1; };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) print "| $reglines[$i]";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if ($i == $center) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) print "<--- faulting instruction";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) print "\n";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) $i = $i +1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) sub usage {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) print <<EOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) Usage:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) dmesg | perl $0 [OPTION] [VMLINUX]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) OPTION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) -c, --cross-compile CROSS_COMPILE Specify the prefix used for toolchain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) -m, --module MODULE_DIRNAME Specify the module filename.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) -h, --help Help.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) EOT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }