Back to home page

LXR

 
 

    


0001 #!/usr/bin/perl
0002 
0003 #   Check the stack usage of functions
0004 #
0005 #   Copyright Joern Engel <joern@lazybastard.org>
0006 #   Inspired by Linus Torvalds
0007 #   Original idea maybe from Keith Owens
0008 #   s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
0009 #   Mips port by Juan Quintela <quintela@mandrakesoft.com>
0010 #   IA64 port via Andreas Dilger
0011 #   Arm port by Holger Schurig
0012 #   sh64 port by Paul Mundt
0013 #   Random bits by Matt Mackall <mpm@selenic.com>
0014 #   M68k port by Geert Uytterhoeven and Andreas Schwab
0015 #   AVR32 port by Haavard Skinnemoen (Atmel)
0016 #   AArch64, PARISC ports by Kyle McMartin
0017 #   sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk>
0018 #
0019 #   Usage:
0020 #   objdump -d vmlinux | scripts/checkstack.pl [arch]
0021 #
0022 #   TODO :  Port to all architectures (one regex per arch)
0023 
0024 use strict;
0025 
0026 # check for arch
0027 #
0028 # $re is used for two matches:
0029 # $& (whole re) matches the complete objdump line with the stack growth
0030 # $1 (first bracket) matches the size of the stack growth
0031 #
0032 # $dre is similar, but for dynamic stack redutions:
0033 # $& (whole re) matches the complete objdump line with the stack growth
0034 # $1 (first bracket) matches the dynamic amount of the stack growth
0035 #
0036 # use anything else and feel the pain ;)
0037 my (@stack, $re, $dre, $x, $xs, $funcre);
0038 {
0039     my $arch = shift;
0040     if ($arch eq "") {
0041         $arch = `uname -m`;
0042         chomp($arch);
0043     }
0044 
0045     $x  = "[0-9a-f]";   # hex character
0046     $xs = "[0-9a-f ]";  # hex character or space
0047     $funcre = qr/^$x* <(.*)>:$/;
0048     if ($arch eq 'aarch64') {
0049         #ffffffc0006325cc:       a9bb7bfd        stp     x29, x30, [sp,#-80]!
0050         $re = qr/^.*stp.*sp,\#-([0-9]{1,8})\]\!/o;
0051     } elsif ($arch eq 'arm') {
0052         #c0008ffc:  e24dd064    sub sp, sp, #100    ; 0x64
0053         $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o;
0054     } elsif ($arch eq 'avr32') {
0055         #8000008a:       20 1d           sub sp,4
0056         #80000ca8:       fa cd 05 b0     sub sp,sp,1456
0057         $re = qr/^.*sub.*sp.*,([0-9]{1,8})/o;
0058     } elsif ($arch =~ /^x86(_64)?$/ || $arch =~ /^i[3456]86$/) {
0059         #c0105234:       81 ec ac 05 00 00       sub    $0x5ac,%esp
0060         # or
0061         #    2f60:    48 81 ec e8 05 00 00       sub    $0x5e8,%rsp
0062         $re = qr/^.*[as][du][db]    \$(0x$x{1,8}),\%(e|r)sp$/o;
0063         $dre = qr/^.*[as][du][db]    (%.*),\%(e|r)sp$/o;
0064     } elsif ($arch eq 'ia64') {
0065         #e0000000044011fc:       01 0f fc 8c     adds r12=-384,r12
0066         $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
0067     } elsif ($arch eq 'm68k') {
0068         #    2b6c:       4e56 fb70       linkw %fp,#-1168
0069         #  1df770:       defc ffe4       addaw #-28,%sp
0070         $re = qr/.*(?:linkw %fp,|addaw )#-([0-9]{1,4})(?:,%sp)?$/o;
0071     } elsif ($arch eq 'metag') {
0072         #400026fc:       40 00 00 82     ADD       A0StP,A0StP,#0x8
0073         $re = qr/.*ADD.*A0StP,A0StP,\#(0x$x{1,8})/o;
0074         $funcre = qr/^$x* <[^\$](.*)>:$/;
0075     } elsif ($arch eq 'mips64') {
0076         #8800402c:       67bdfff0        daddiu  sp,sp,-16
0077         $re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
0078     } elsif ($arch eq 'mips') {
0079         #88003254:       27bdffe0        addiu   sp,sp,-32
0080         $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
0081     } elsif ($arch eq 'parisc' || $arch eq 'parisc64') {
0082         $re = qr/.*ldo ($x{1,8})\(sp\),sp/o;
0083     } elsif ($arch eq 'ppc') {
0084         #c00029f4:       94 21 ff 30     stwu    r1,-208(r1)
0085         $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o;
0086     } elsif ($arch eq 'ppc64') {
0087         #XXX
0088         $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o;
0089     } elsif ($arch eq 'powerpc') {
0090         $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o;
0091     } elsif ($arch =~ /^s390x?$/) {
0092         #   11160:       a7 fb ff 60             aghi   %r15,-160
0093         # or
0094         #  100092:   e3 f0 ff c8 ff 71   lay     %r15,-56(%r15)
0095         $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})
0096               (?:\(\%r15\))?$/ox;
0097     } elsif ($arch =~ /^sh64$/) {
0098         #XXX: we only check for the immediate case presently,
0099         #     though we will want to check for the movi/sub
0100         #     pair for larger users. -- PFM.
0101         #a00048e0:       d4fc40f0        addi.l  r15,-240,r15
0102         $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o;
0103     } elsif ($arch =~ /^blackfin$/) {
0104         #   0:   00 e8 38 01     LINK 0x4e0;
0105         $re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o;
0106     } elsif ($arch eq 'sparc' || $arch eq 'sparc64') {
0107         # f0019d10:       9d e3 bf 90     save  %sp, -112, %sp
0108         $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o;
0109     } else {
0110         print("wrong or unknown architecture \"$arch\"\n");
0111         exit
0112     }
0113 }
0114 
0115 #
0116 # main()
0117 #
0118 my ($func, $file, $lastslash);
0119 
0120 while (my $line = <STDIN>) {
0121     if ($line =~ m/$funcre/) {
0122         $func = $1;
0123     }
0124     elsif ($line =~ m/(.*):\s*file format/) {
0125         $file = $1;
0126         $file =~ s/\.ko//;
0127         $lastslash = rindex($file, "/");
0128         if ($lastslash != -1) {
0129             $file = substr($file, $lastslash + 1);
0130         }
0131     }
0132     elsif ($line =~ m/$re/) {
0133         my $size = $1;
0134         $size = hex($size) if ($size =~ /^0x/);
0135 
0136         if ($size > 0xf0000000) {
0137             $size = - $size;
0138             $size += 0x80000000;
0139             $size += 0x80000000;
0140         }
0141         next if ($size > 0x10000000);
0142 
0143         next if $line !~ m/^($xs*)/;
0144         my $addr = $1;
0145         $addr =~ s/ /0/g;
0146         $addr = "0x$addr";
0147 
0148         my $intro = "$addr $func [$file]:";
0149         my $padlen = 56 - length($intro);
0150         while ($padlen > 0) {
0151             $intro .= ' ';
0152             $padlen -= 8;
0153         }
0154         next if ($size < 100);
0155         push @stack, "$intro$size\n";
0156     }
0157     elsif (defined $dre && $line =~ m/$dre/) {
0158         my $size = "Dynamic ($1)";
0159 
0160         next if $line !~ m/^($xs*)/;
0161         my $addr = $1;
0162         $addr =~ s/ /0/g;
0163         $addr = "0x$addr";
0164 
0165         my $intro = "$addr $func [$file]:";
0166         my $padlen = 56 - length($intro);
0167         while ($padlen > 0) {
0168             $intro .= ' ';
0169             $padlen -= 8;
0170         }
0171         push @stack, "$intro$size\n";
0172     }
0173 }
0174 
0175 # Sort output by size (last field)
0176 print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack;