📄 run-leaks
字号:
#!/usr/bin/perl# Copyright (C) 2007 Apple Inc. All rights reserved.## Redistribution and use in source and binary forms, with or without# modification, are permitted provided that the following conditions# are met:## 1. Redistributions of source code must retain the above copyright# notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright# notice, this list of conditions and the following disclaimer in the# documentation and/or other materials provided with the distribution. # 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of# its contributors may be used to endorse or promote products derived# from this software without specific prior written permission. ## THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# Script to run the Mac OS X leaks tool with more expressive '-exclude' lists.use strict;use warnings;use File::Basename;use Getopt::Long;sub runLeaks($);sub parseLeaksOutput(\@);sub removeMatchingRecords(\@$\@);sub reportError($);sub main(){ # Read options. my $usage = "Usage: " . basename($0) . " [options] pid | executable name\n" . " --exclude-callstack regexp Exclude leaks whose call stacks match the regular expression 'regexp'.\n" . " --exclude-type regexp Exclude leaks whose data types match the regular expression 'regexp'.\n" . " --help Show this help message.\n"; my @callStacksToExclude = (); my @typesToExclude = (); my $help = 0; my $getOptionsResult = GetOptions( 'exclude-callstack:s' => \@callStacksToExclude, 'exclude-type:s' => \@typesToExclude, 'help' => \$help ); my $pidOrExecutableName = $ARGV[0]; if (!$getOptionsResult || $help) { print STDERR $usage; return 1; } if (!$pidOrExecutableName) { reportError("Missing argument: pid | executable."); print STDERR $usage; return 1; } # Run leaks tool. my $leaksOutput = runLeaks($pidOrExecutableName); if (!$leaksOutput) { return 1; } my $leakList = parseLeaksOutput(@$leaksOutput); if (!$leakList) { return 1; } # Filter output. my $leakCount = @$leakList; removeMatchingRecords(@$leakList, "callStack", @callStacksToExclude); removeMatchingRecords(@$leakList, "type", @typesToExclude); my $excludeCount = $leakCount - @$leakList; # Dump results. print $leaksOutput->[0]; print $leaksOutput->[1]; foreach my $leak (@$leakList) { print $leak->{"leaksOutput"}; } if ($excludeCount) { print "$excludeCount leaks excluded (not printed)\n"; } return 0;}exit(main());# Returns the output of the leaks tool in list form.sub runLeaks($){ my ($pidOrExecutableName) = @_; my @leaksOutput = `leaks $pidOrExecutableName`; if (!@leaksOutput) { reportError("Error running leaks tool."); return; } return \@leaksOutput;}# Returns a list of hash references with the keys { address, size, type, callStack, leaksOutput }sub parseLeaksOutput(\@){ my ($leaksOutput) = @_; # Format: # Process 00000: 1234 nodes malloced for 1234 KB # Process 00000: XX leaks for XXX total leaked bytes. # Leak: 0x00000000 size=1234 [instance of 'blah'] # 0x00000000 0x00000000 0x00000000 0x00000000 a..d.e.e # ... # Call stack: leak_caller() | leak() | malloc # # We treat every line except for Process 00000: and Leak: as optional my ($leakCount) = ($leaksOutput->[1] =~ /[[:blank:]]+([0-9]+)[[:blank:]]+leaks?/); if (!defined($leakCount)) { reportError("Could not parse leak count reported by leaks tool."); return; } my @leakList = (); for my $line (@$leaksOutput) { next if $line =~ /^Process/; next if $line =~ /^node buffer added/; if ($line =~ /^Leak: /) { my ($address) = ($line =~ /Leak: ([[:xdigit:]x]+)/); if (!defined($address)) { reportError("Could not parse Leak address."); return; } my ($size) = ($line =~ /size=([[:digit:]]+)/); if (!defined($size)) { reportError("Could not parse Leak size."); return; } my ($type) = ($line =~ /'([^']+)'/); #' if (!defined($type)) { $type = ""; # The leaks tool sometimes omits the type. } my %leak = ( "address" => $address, "size" => $size, "type" => $type, "callStack" => "", # The leaks tool sometimes omits the call stack. "leaksOutput" => $line ); push(@leakList, \%leak); } else { $leakList[$#leakList]->{"leaksOutput"} .= $line; if ($line =~ /Call stack:/) { $leakList[$#leakList]->{"callStack"} = $line; } } } if (@leakList != $leakCount) { my $parsedLeakCount = @leakList; reportError("Parsed leak count($parsedLeakCount) does not match leak count reported by leaks tool($leakCount)."); return; } return \@leakList;}sub removeMatchingRecords(\@$\@){ my ($recordList, $key, $regexpList) = @_; RECORD: for (my $i = 0; $i < @$recordList;) { my $record = $recordList->[$i]; foreach my $regexp (@$regexpList) { if ($record->{$key} =~ $regexp) { splice(@$recordList, $i, 1); next RECORD; } } $i++; }}sub reportError($){ my ($errorMessage) = @_; print STDERR basename($0) . ": $errorMessage\n";}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -