checkstack.pl 5.38 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#!/usr/bin/perl

#	Check the stack usage of functions
#
#	Copyright Joern Engel <joern@lazybastard.org>
#	Inspired by Linus Torvalds
#	Original idea maybe from Keith Owens
#	s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
#	Mips port by Juan Quintela <quintela@mandrakesoft.com>
#	IA64 port via Andreas Dilger
#	Arm port by Holger Schurig
#	sh64 port by Paul Mundt
#	Random bits by Matt Mackall <mpm@selenic.com>
#	M68k port by Geert Uytterhoeven and Andreas Schwab
#	AVR32 port by Haavard Skinnemoen (Atmel)
16
#	AArch64, PARISC ports by Kyle McMartin
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
#	sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk>
#
#	Usage:
#	objdump -d vmlinux | scripts/checkstack.pl [arch]
#
#	TODO :	Port to all architectures (one regex per arch)

use strict;

# check for arch
#
# $re is used for two matches:
# $& (whole re) matches the complete objdump line with the stack growth
# $1 (first bracket) matches the size of the stack growth
#
# $dre is similar, but for dynamic stack redutions:
# $& (whole re) matches the complete objdump line with the stack growth
# $1 (first bracket) matches the dynamic amount of the stack growth
#
# use anything else and feel the pain ;)
37
my (@stack, $re, $dre, $x, $xs, $funcre);
38 39 40 41 42 43 44 45 46
{
	my $arch = shift;
	if ($arch eq "") {
		$arch = `uname -m`;
		chomp($arch);
	}

	$x	= "[0-9a-f]";	# hex character
	$xs	= "[0-9a-f ]";	# hex character or space
47 48 49 50 51
	$funcre = qr/^$x* <(.*)>:$/;
	if ($arch eq 'aarch64') {
		#ffffffc0006325cc:       a9bb7bfd        stp     x29, x30, [sp,#-80]!
		$re = qr/^.*stp.*sp,\#-([0-9]{1,8})\]\!/o;
	} elsif ($arch eq 'arm') {
52 53 54 55 56 57
		#c0008ffc:	e24dd064	sub	sp, sp, #100	; 0x64
		$re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o;
	} elsif ($arch eq 'avr32') {
		#8000008a:       20 1d           sub sp,4
		#80000ca8:       fa cd 05 b0     sub sp,sp,1456
		$re = qr/^.*sub.*sp.*,([0-9]{1,8})/o;
58
	} elsif ($arch =~ /^x86(_64)?$/ || $arch =~ /^i[3456]86$/) {
59
		#c0105234:       81 ec ac 05 00 00       sub    $0x5ac,%esp
60 61 62 63
		# or
		#    2f60:    48 81 ec e8 05 00 00       sub    $0x5e8,%rsp
		$re = qr/^.*[as][du][db]    \$(0x$x{1,8}),\%(e|r)sp$/o;
		$dre = qr/^.*[as][du][db]    (%.*),\%(e|r)sp$/o;
64 65 66 67 68 69 70
	} elsif ($arch eq 'ia64') {
		#e0000000044011fc:       01 0f fc 8c     adds r12=-384,r12
		$re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
	} elsif ($arch eq 'm68k') {
		#    2b6c:       4e56 fb70       linkw %fp,#-1168
		#  1df770:       defc ffe4       addaw #-28,%sp
		$re = qr/.*(?:linkw %fp,|addaw )#-([0-9]{1,4})(?:,%sp)?$/o;
71 72 73 74
	} elsif ($arch eq 'metag') {
		#400026fc:       40 00 00 82     ADD       A0StP,A0StP,#0x8
		$re = qr/.*ADD.*A0StP,A0StP,\#(0x$x{1,8})/o;
		$funcre = qr/^$x* <[^\$](.*)>:$/;
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
	} elsif ($arch eq 'mips64') {
		#8800402c:       67bdfff0        daddiu  sp,sp,-16
		$re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
	} elsif ($arch eq 'mips') {
		#88003254:       27bdffe0        addiu   sp,sp,-32
		$re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
	} elsif ($arch eq 'parisc' || $arch eq 'parisc64') {
		$re = qr/.*ldo ($x{1,8})\(sp\),sp/o;
	} elsif ($arch eq 'ppc') {
		#c00029f4:       94 21 ff 30     stwu    r1,-208(r1)
		$re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o;
	} elsif ($arch eq 'ppc64') {
		#XXX
		$re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o;
	} elsif ($arch eq 'powerpc') {
		$re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o;
	} elsif ($arch =~ /^s390x?$/) {
		#   11160:       a7 fb ff 60             aghi   %r15,-160
		# or
		#  100092:	 e3 f0 ff c8 ff 71	 lay	 %r15,-56(%r15)
		$re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})
		      (?:\(\%r15\))?$/ox;
	} elsif ($arch =~ /^sh64$/) {
		#XXX: we only check for the immediate case presently,
		#     though we will want to check for the movi/sub
		#     pair for larger users. -- PFM.
		#a00048e0:       d4fc40f0        addi.l  r15,-240,r15
		$re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o;
	} elsif ($arch =~ /^blackfin$/) {
		#   0:   00 e8 38 01     LINK 0x4e0;
		$re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o;
	} elsif ($arch eq 'sparc' || $arch eq 'sparc64') {
		# f0019d10:       9d e3 bf 90     save  %sp, -112, %sp
		$re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o;
	} else {
		print("wrong or unknown architecture \"$arch\"\n");
		exit
	}
}

#
# main()
#
my ($func, $file, $lastslash);

while (my $line = <STDIN>) {
	if ($line =~ m/$funcre/) {
		$func = $1;
	}
	elsif ($line =~ m/(.*):\s*file format/) {
		$file = $1;
		$file =~ s/\.ko//;
		$lastslash = rindex($file, "/");
		if ($lastslash != -1) {
			$file = substr($file, $lastslash + 1);
		}
	}
	elsif ($line =~ m/$re/) {
		my $size = $1;
		$size = hex($size) if ($size =~ /^0x/);

		if ($size > 0xf0000000) {
			$size = - $size;
			$size += 0x80000000;
			$size += 0x80000000;
		}
		next if ($size > 0x10000000);

		next if $line !~ m/^($xs*)/;
		my $addr = $1;
		$addr =~ s/ /0/g;
		$addr = "0x$addr";

		my $intro = "$addr $func [$file]:";
		my $padlen = 56 - length($intro);
		while ($padlen > 0) {
			$intro .= '	';
			$padlen -= 8;
		}
		next if ($size < 100);
		push @stack, "$intro$size\n";
	}
	elsif (defined $dre && $line =~ m/$dre/) {
		my $size = "Dynamic ($1)";

		next if $line !~ m/^($xs*)/;
		my $addr = $1;
		$addr =~ s/ /0/g;
		$addr = "0x$addr";

		my $intro = "$addr $func [$file]:";
		my $padlen = 56 - length($intro);
		while ($padlen > 0) {
			$intro .= '	';
			$padlen -= 8;
		}
		push @stack, "$intro$size\n";
	}
}

# Sort output by size (last field)
print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack;