#*--------------------------------------------------------------------------* | |
#* Global variables | |
#*--------------------------------------------------------------------------* | |
my $LISFILE = $ARGV[0]; | |
my $rootdir = @ARGV[1]; | |
my $mcudir = @ARGV[2]; | |
my $branch = @ARGV[3]; | |
my @filearray; | |
my @disarray; | |
my @unusedroarray; | |
my @resultarray; | |
my @symbolarray; | |
my $printmode = "dec"; | |
my $outputfilename; | |
my $unusedfilename; | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
$initialtime = time(); | |
warn " | |
============================================================================== | |
[Program] ROParser.pl | |
[Version] V3.0 | |
[Date] 2008-04-09 | |
[Author] yikuan.huang\@mediatek.com | |
[Copyright] Copyright (C) 2008 MediaTek Incorporation. All Rights Reserved. | |
============================================================================== | |
"; | |
unless(defined($branch)){ | |
usage(); | |
} | |
startview($branch); | |
determinefilename(); | |
print "start to parse LIS file......\n"; | |
parselisfile(); | |
print "finish parsing LIS file......\n"; | |
print "start to disassemble...\n"; | |
traversefile($rootdir); | |
disassemble(); | |
print "finish disassembling!\n"; | |
print "start to get unusedRO...\n"; | |
getunusedRO(); | |
print "finish getting unusedRO...\n"; | |
print "start to parse dis file...\n"; | |
parsedisfile(); | |
print "finish parsing dis file...\n"; | |
print "start to dump resule to files...\n"; | |
dump_resulte_to_file(); | |
print "finish dumping resule to files!\n"; | |
$finishtime = time(); | |
$exectime = $finishtime - $initialtime; | |
print "Total execution time: ".$exectime." seconds\n"; | |
#**************************************************************************** | |
# FUNCTION | |
# determinefilename | |
# DESCRIPTION | |
# This function determine the name of output file | |
#**************************************************************************** | |
sub determinefilename{ | |
@filepart = split /\\/,$LISFILE; | |
$outputfilename = $filepart[-1]; | |
$unusedfilename = $filepart[-1]; | |
if($filepart[-1] =~ /(\S+)lis/){ | |
$outputfilename = $1; | |
} | |
$unusedfilename = $outputfilename; | |
$outputfilename = $outputfilename."txt"; | |
$unusedfilename =~ s/\.//; | |
$unusedfilename = $unusedfilename."unusedRO.txt"; | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# parselisfile | |
# DESCRIPTION | |
# This function parse LIS file | |
#**************************************************************************** | |
sub parselisfile{ | |
#**************************************************************************** | |
# Parse LIS file content | |
#**************************************************************************** | |
my (@ref_obj, @ref_func, @dec_obj, @dec_region, @content , @symbol); # referencing obj, referencing function, declaration obj, declaraion region, referenced content | |
my ($i, $ref_count ,$j, $switch); | |
die "$LISFILE does not exist!\n" if (!-e $LISFILE); | |
open (FILE_HANDLE, "<$LISFILE") or die "Fail to open $LISFILE\n"; | |
$i = 0; | |
$j = 0; | |
$switch = 0; | |
while (<FILE_HANDLE>) { | |
if (/(\S+)\((\S+)\)\srefers\sto\s(\S+)\((\S+)\)\sfor\s(\S+)\s*/) { # AAA.obj(i.func/pragma) refers to BBB.obj(i.func/pragma/region) for content | |
$ref_obj[$i] = $1; # AAA | |
$ref_func[$i] = $2; # i.func/pragma | |
$dec_obj[$i] = $3; # BBB | |
$dec_region[$i] = $4; # i.func/pragma/region | |
$content[$i] = $5; # content | |
$i++; # should be indexed with the same $i | |
} | |
if (/Local Symbols/){ | |
$switch = 1; | |
} | |
if (/================================================================================/){ | |
$switch = 0; | |
} | |
if ($switch == 1){ | |
$_ = trim($_); | |
if(/(\S+)(\s*)(\S+)(\s*)(\S+)(\s*)(\S+)(\s*)(\S+)/){ | |
$symbol[$j] = $1; | |
$j++; | |
} | |
} | |
} | |
$ref_count = $i; | |
close FILE_HANDLE or die "Fail to close $LISFILE\n"; | |
@symbol = reverse sort @symbol; | |
#**************************************************************************** | |
# Further parse the reference table to find constdata | |
#**************************************************************************** | |
my $ref_data; | |
my %constdata; | |
$i = 0; | |
foreach $ref_data (@content) { | |
if ($ref_data eq ".constdata\$1") { # AAA.obj(i.func/pragma) refers to BBB.obj(i.func/pragma/region) for .constdata$1 | |
$constdata{$i} = $ref_data; # constdata{$i} = .constdata$1, $i is the index of constdata references | |
} | |
$i++; | |
} | |
#**************************************************************************** | |
# Find unused RO data | |
#**************************************************************************** | |
my (%unused_RO_func, %unused_RO_pragma); | |
$i = 0; | |
while ($i < $ref_count) { | |
if (defined $constdata{$i}) { | |
my $is_In_Symbol_Table = 0; | |
my $funcname = $ref_func[$i]; | |
foreach (@symbol){ | |
my $tablefuncname = $_; | |
if($funcname eq $tablefuncname){ | |
$is_In_Symbol_Table = 1; | |
last; | |
} | |
if($funcname gt $tablefuncname){ | |
$is_In_Symbol_Table = 0; | |
last; | |
} | |
} | |
if ($is_In_Symbol_Table == 0) { | |
if ($ref_func[$i] =~ /i.(\S+)/) { # function case | |
$unused_RO_func{$ref_func[$i]} = $ref_obj[$i]; | |
} | |
else{ | |
$unused_RO_pragma{$ref_func[$i]} = $ref_obj[$i]; | |
} | |
#print $ref_func[$i]."...".$ref_obj[$i]."\n"; | |
} | |
} | |
$i++; | |
} | |
#**************************************************************************** | |
# Output unreferenced functions that contain unused RO data | |
#**************************************************************************** | |
open (FILE_HANDLE, ">$unusedfilename") or die "Fail to open $unusedfilename\n"; | |
my $ref_data; | |
print FILE_HANDLE "Unreferenced functions that contain unused RO data: \n"; | |
foreach $ref_data (sort {$unused_RO_func{$a} cmp $unused_RO_func{$b}} keys %unused_RO_func) { | |
print FILE_HANDLE "$ref_data ($unused_RO_func{$ref_data})\n"; | |
} | |
print FILE_HANDLE "\nOther pragmas that contains unreferenced functions with RO data: \n"; | |
foreach $ref_data (sort {$unused_RO_pragma{$a} cmp $unused_RO_pragma{$b}} keys %unused_RO_pragma) { | |
print FILE_HANDLE "$ref_data ($unused_RO_pragma{$ref_data})\n"; | |
} | |
close FILE_HANDLE or die "Fail to close output.txt\n"; | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# dump_resulte_to_file | |
# DESCRIPTION | |
# This function dumps the result of RO parser to file(result.txt) | |
#**************************************************************************** | |
sub dump_resulte_to_file{ | |
#*--------------------------------------------------------------------------* | |
#* Local variables | |
#*--------------------------------------------------------------------------* | |
$resultfuncname; | |
$resultobjname; | |
$resultconstantstring; | |
$resultstringsize; | |
$resultconstantdata; | |
$resultdatasize; | |
$resultfilepath; | |
$resultowner; | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
%ownerhash; | |
open(RESULT,">$outputfilename") || die "File open error!\n"; | |
# Set the data format | |
format RESULT = | |
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<< @<<<<<<<<<< | |
$resultfuncname,$resultobjname,$resultconstantstring,$resultstringsize,$resultconstantdata,$resultdatasize,$resultowner | |
. | |
foreach (@resultarray){ | |
my $resulthash = $_; | |
$resultfuncname = $resulthash->{"funcname"}; | |
$resultobjname = $resulthash->{"objname"}; | |
$resultconstantstring = $resulthash->{"constantstring"}; | |
$resultstringsize = $resulthash->{"stringsize"}; | |
$resultconstantdata = $resulthash->{"constantdata"}; | |
$resultdatasize = $resulthash->{"datasize"}; | |
$resultfilepath = get_objpath_by_objname($resultobjname); | |
if(defined $ownerhash{$resultfilepath}){ | |
} | |
else{ | |
$ownerhash{$resultfilepath} = getOwner($resultfilepath); | |
} | |
$resultowner = $ownerhash{$resultfilepath}; | |
if($printmode eq "dec"){ | |
if($resultstringsize =~ /0x(\w+)/){ | |
$resultstringsize = hex($1); | |
} | |
if($resultdatasize =~ /0x(\w+)/){ | |
$resultdatasize = hex($1); | |
} | |
} | |
#print $resultfuncname." ".$resultobjname." ".$resultconstantstring." ".$resultstringsize." ".$resultconstantdata." ".$resultdatasize."\n"; | |
write(RESULT); | |
} | |
close(RESULT); | |
#delete unusedRO file | |
#unlink($unusedfilename); | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# check_global_table | |
# DESCRIPTION | |
# This function check whether the offset is in the global symbol table | |
#**************************************************************************** | |
sub check_global_table(){ | |
$_ = $_[0]; | |
s/0x//; | |
my $offset = hex($_); | |
my $objname = $_[1]; | |
my $result = "0"; | |
#print $offset." ... ".$objname."\n"; | |
foreach (@symbolarray){ | |
my $symbolhash = $_; | |
$symbolojbname = $symbolhash->{"objname"}; | |
$symbolname = $symbolhash->{"symbolname"}; | |
$symbolvalue = $symbolhash->{"symbolvalue"}; | |
$symbolsize = $symbolhash->{"symbolsize"}; | |
$symbolstart = $symbolhash->{"symbolstart"}; | |
$symbolend = $symbolhash->{"symbolend"}; | |
if($symbolojbname eq $objname){ | |
if(($offset>=$symbolstart) && ( $offset<$symbolend)){ | |
$result = $symbolname.":".$symbolsize; | |
last; | |
} | |
} | |
} | |
return $result; | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# parsedisfile | |
# DESCRIPTION | |
# This function parse the dis file which appears in @unusedroarray , and create the result | |
#**************************************************************************** | |
sub parsedisfile(){ | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
foreach (@unusedroarray){ | |
my $gethash = $_; | |
my $getobjname = $gethash->{"objname"}; | |
my $getfuncname = $gethash->{"funcname"}; | |
my $getdisfilepath = $gethash->{"disfilepath"}; | |
my $firstaddress; | |
my $offset; | |
my $constdatasecnum; | |
if(defined($getdisfilepath)){ | |
@symbolarray = (); | |
open(FILE,"<$getdisfilepath") || die "File open error - $getdisfilepath!\n"; | |
@data = <FILE>; | |
my $funcswitch = 0; | |
my $getoffset = 0; | |
my $findconstdatasec = 0; | |
my $constdataswitch = 0; | |
my $hasvalue = 0; | |
my $thisoffset; | |
my $targetoffset; | |
my $hasequal = 0; | |
my @blockarray; | |
my @indexarray; | |
my @firstaddressarray; | |
my $index = 0; | |
my $targetindex = 0; | |
my $maxlength = 16; | |
my $hasglobal = 0; | |
#&parse_for_global_symbol_table(@data); | |
my $currentsecnum; #store section number temporarily | |
my @secnum; #store section number in one dis file | |
#**************************************************************************** | |
# 1 >>> First round : scan the dis file, and get all the section number which has .constdata | |
# For example, ** Section #10 | |
# | |
# Name : .constdata | |
# We find the ".constdata", and get it's previous section number - 10 | |
# Store all the section number into @secnum | |
#**************************************************************************** | |
foreach(@data){ | |
# Find each section number, and record it in the $currentsecnum | |
if($_ =~ /\*\* Section #(\d+)/){ | |
$currentsecnum = $1; | |
} | |
# Find the .constdata, record the previous section number into @secnum | |
if(index($_,"Name : .constdata")>=0){ | |
push @secnum, $currentsecnum; | |
} | |
} | |
#**************************************************************************** | |
# 2 >>> Second round : scan the dis file, get the data row from the symbol table | |
# For example, | |
# Symbol table .symtab (121 symbols, 112 local) | |
# Symbol Name Value Bind Sec Type Size | |
# ======================================================================== | |
# 1 $t 0x00000000 Lc 5 Code | |
# ................................ | |
# ======================================================================== | |
# | |
# We find "Symbol table" first, and record the data between two "=======" lines | |
#**************************************************************************** | |
$isSym = 0; | |
$switch = 0; | |
foreach(@data){ | |
# Find the symbol table | |
if(index($_,"Symbol table .symtab")>=0){ | |
$isSym = 1; | |
next; | |
} | |
if((index($_,"=================")>=0)&&($isSym eq 1)){ | |
$switch = 1; | |
$isSym = 0; | |
next; | |
} | |
if((index($_,"==================")>=0)&&($isSym eq 0)){ | |
$switch = 0; | |
next; | |
} | |
if($switch eq 1){ | |
my %symbolhash; | |
#if it has 7 values | |
if(/\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/){ | |
#print $1."\n".$2."\n".$3."\n".$4."\n".$5."\n".$6."\n".$7."\n"; | |
#print "\n"; | |
if(matchsecnum($5,@secnum) eq 1){ | |
%symbolhash ={}; | |
$symbolhash{"objname"}= $getobjname; | |
$symbolhash{"symbolname"}= $2; | |
$symbolhash{"symbolvalue"}= $3; | |
$symbolhash{"symbolsize"}= $7; | |
if(index($symbolhash{"symbolsize"},"0x")>=0){ | |
$_ = $symbolhash{"symbolvalue"}; | |
s/0x//; | |
$symbolhash{"symbolstart"} = hex($_); | |
$_ = $symbolhash{"symbolsize"}; | |
s/0x//; | |
$symbolhash{"symbolend"} = $symbolhash{"symbolstart"} + hex($_); | |
push @symbolarray, \%symbolhash; | |
} | |
} | |
next; | |
} | |
#if it has 6 values | |
elsif(/\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/){ | |
#print $1."\n".$2."\n".$3."\n".$4."\n".$5."\n".$6."\n"; | |
#print "\n"; | |
if(matchsecnum($5,@secnum) eq 1){ | |
%symbolhash ={}; | |
$symbolhash{"objname"}= $getobjname; | |
$symbolhash{"symbolname"}= $2; | |
$symbolhash{"symbolvalue"}= $3; | |
} | |
next; | |
} | |
# across two line!! | |
else{ | |
# second line: 5 values | |
if(/\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/){ | |
#print $1."\n".$2."\n".$3."\n".$4."\n".$5."\n"; | |
if(matchsecnum($3,@secnum) eq 1){ | |
$symbolhash{"objname"}= $getobjname; | |
$symbolhash{"symbolvalue"}= $1; | |
$symbolhash{"symbolsize"}= $5; | |
if(index($symbolhash{"symbolsize"},"0x")>=0){ | |
$_ = $symbolhash{"symbolvalue"}; | |
s/0x//; | |
$symbolhash{"symbolstart"} = hex($_); | |
$_ = $symbolhash{"symbolsize"}; | |
s/0x//; | |
$symbolhash{"symbolend"} = $symbolhash{"symbolstart"} + hex($_); | |
push @symbolarray, \%symbolhash; | |
} | |
%symbolhash ={}; | |
} | |
next; | |
} | |
# second line: 4 values | |
if(/\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/){ | |
#print $1."\n".$2."\n".$3."\n".$4."\n"; | |
if(matchsecnum($3,@secnum) eq 1){ | |
$symbolhash{"objname"}= $getobjname; | |
$symbolhash{"symbolvalue"}= $1; | |
if(index($symbolhash{"symbolsize"},"0x")>=0){ | |
$_ = $symbolhash{"symbolvalue"}; | |
s/0x//; | |
$symbolhash{"symbolstart"} = hex($_); | |
$_ = $symbolhash{"symbolsize"}; | |
s/0x//; | |
$symbolhash{"symbolend"} = $symbolhash{"symbolstart"} + hex($_); | |
push @symbolarray, \%symbolhash; | |
} | |
%symbolhash ={}; | |
} | |
next; | |
} | |
# first line: 2 values | |
if(/\s+(\S+)\s+(\S+)/){ | |
#print $1."\n".$2."\n"; | |
$symbolhash{"symbolname"}= $2; | |
next | |
} | |
} | |
} | |
} | |
foreach(@data){ | |
# open the section | |
if($_ =~ /Name : i.$getfuncname\n/){ | |
$funcswitch = 1; | |
$findconstdatasec = 1; | |
next; | |
} | |
if($_ =~ /Name : $getfuncname\n/){ | |
$funcswitch = 1; | |
$findconstdatasec = 1; | |
next; | |
} | |
if(($funcswitch == 1)&&($_ =~ /.constdata$1/)){ | |
# if the address has 4 digits | |
$isExist = "false"; | |
if($_ =~ /= 0x(\w\w\w\w)]/){ | |
$firstaddress = $1; | |
foreach $address(@firstaddressarray){ | |
if($address eq $firstaddress){ | |
$isExist = "true"; | |
} | |
} | |
if($isExist eq "false"){ | |
push @firstaddressarray, $firstaddress; | |
} | |
next; | |
} | |
# if the address has 3 digits | |
if($_ =~ /= 0x(\w\w\w)]/){ | |
$firstaddress = $1; | |
foreach $address(@firstaddressarray){ | |
if($address eq $firstaddress){ | |
$isExist = "true"; | |
} | |
} | |
if($isExist eq "false"){ | |
push @firstaddressarray, $firstaddress; | |
} | |
next; | |
} | |
# if the address has 2 digits | |
if($_ =~ /= 0x(\w\w)]/){ | |
$firstaddress = $1; | |
foreach $address(@firstaddressarray){ | |
if($address eq $firstaddress){ | |
$isExist = "true"; | |
} | |
} | |
if($isExist eq "false"){ | |
push @firstaddressarray, $firstaddress; | |
} | |
next; | |
} | |
# if the address has 1 digits | |
if($_ =~ /= 0x(\w)]/){ | |
$firstaddress = $1; | |
foreach $address(@firstaddressarray){ | |
if($address eq $firstaddress){ | |
$isExist = "true"; | |
} | |
} | |
if($isExist eq "false"){ | |
push @firstaddressarray, $firstaddress; | |
} | |
next; | |
} | |
} | |
# close the section | |
if(($funcswitch == 1)&&index($_,"====================================") >= 0){ | |
$funcswitch = 0; | |
} | |
} | |
#print $getdisfilepath."\n"; | |
#print @firstaddressarray."\n"; | |
foreach(@firstaddressarray){ | |
$firstaddress = $_; | |
$stringlength = 0; | |
$stringresult = ""; | |
foreach(@data){ | |
# open the section | |
if($_ =~ /Name : i.$getfuncname\n/){ | |
$funcswitch = 1; | |
$findconstdatasec = 1; | |
next; | |
} | |
if($_ =~ /Name : $getfuncname\n/){ | |
$funcswitch = 1; | |
$findconstdatasec = 1; | |
next; | |
} | |
if(($funcswitch == 1)&&($firstaddress ne "")&&($_ =~ /0x0+$firstaddress:/)){ | |
my @linearray = split; | |
if($linearray[1] =~ /00(\S+)/){ | |
$offset = "0x".$1; | |
$getoffset = 1; | |
# check whether the offset is in the global symbol table | |
$returndata = &check_global_table($offset,$getobjname); | |
unless($returndata eq "0"){ | |
my %resulthash ={}; | |
$resulthash{"funcname"}= $getfuncname; | |
$resulthash{"objname"}= $getobjname; | |
if($returndata =~ /(\S+):(\S+)/){ | |
$resulthash{"constantdata"} = $1; | |
$resulthash{"datasize"}= $2; | |
} | |
push @resultarray, \%resulthash; | |
$hasglobal = 1; | |
last; | |
} | |
next; | |
} | |
} | |
# close the section | |
if(($funcswitch == 1)&&index($_,"====================================") >= 0){ | |
$funcswitch = 0; | |
} | |
# find the section number of .constdata | |
if(($findconstdatasec == 1)&&(index($_,".constdata$1")>=0)){ | |
if(/#(\d+) '.constdata'/){ | |
$constdatasecnum = $1; | |
$findconstdatasec = 0; | |
next; | |
} | |
} | |
# find .constdata block | |
if(($getoffset==1)&&($_ =~ /\*\* Section #${constdatasecnum}$/)){ | |
$constdataswitch = 1; | |
#$getoffset == 0; | |
next; | |
} | |
# find the string in the .constdata block | |
if(($constdataswitch == 1)&&($_ =~ /0x(\S+):/)){ | |
# if match the offset | |
if(index($_,$offset.":")>=0){ | |
$hasequal = 1; | |
$targetindex = $index; | |
} | |
push @indexarray,$index; | |
push @blockarray,trim($_); | |
$index++; | |
} | |
if(($constdataswitch == 1)&&(index($_,"====================================") >= 0)){ | |
$constdataswitch = 0; | |
} | |
} | |
if($hasglobal == 1){ | |
next; | |
} | |
if($getoffset == 0){ | |
$resulthash{"funcname"}= $getfuncname; | |
$resulthash{"objname"}= "(".$getobjname.")"; | |
push @resultarray, \%resulthash; | |
next; | |
} | |
# start to parse the block data | |
# if find the offset match the target offset | |
if($hasequal == 1){ | |
$line = trim($blockarray[$targetindex]); | |
$moreswitch = 1; | |
#$stringlength = 0; | |
while($moreswitch == 1){ | |
@stringarray = split /\s+/,$line; | |
# remove the first and last item | |
shift(@stringarray); | |
pop(@stringarray); | |
$thislength = 0; | |
if(scalar(@stringarray) == 0){ | |
$moreswitch = 0; | |
} | |
foreach $hexvalue(@stringarray){ | |
if(is_ascii($hexvalue)){ | |
$thislength++; | |
if($thislength <= $maxlength){ | |
$stringresult = $stringresult.hex_to_ascii($hexvalue); | |
} | |
# need to consider next line | |
if($thislength == $maxlength){ | |
$targetindex = $targetindex + 1; | |
if($targetindex < scalar(@blockarray)){ | |
$line = trim($blockarray[$targetindex]); | |
$stringlength += $thislength; | |
} | |
} | |
} | |
else{ | |
if(($hexvalue eq "00")&&($stringlength != 0)){ | |
$stringlength += 1; | |
} | |
$stringlength += $thislength; | |
$moreswitch = 0; | |
last; | |
} | |
} | |
} | |
# save the result | |
my %resulthash ={}; | |
if($stringlength > 0){ | |
$resulthash{"funcname"}= $getfuncname; | |
$resulthash{"objname"}= $getobjname; | |
$resulthash{"constantstring"} = $stringresult; | |
$resulthash{"stringsize"}= "0x".dec2hex($stringlength); | |
} | |
else{ | |
$resulthash{"funcname"}= "(".$getfuncname.")"; | |
$resulthash{"objname"}= $getobjname; | |
} | |
push @resultarray, \%resulthash; | |
} | |
# if no offset match the target offset | |
else{ | |
my $findbetween = 0; | |
for($i=0;$i<@blockarray;$i++){ | |
$line = trim($blockarray[$i]); | |
$nextarget = $i; | |
@stringarray = split /\s+/,$line; | |
# get the offset value of this line | |
$_ = shift(@stringarray); | |
s/0x//; | |
$thisoffset = hex($_); | |
# get the offset value of next line | |
$nextoffset = 0; | |
if($i != (@blockarray-1)){ | |
@temparray = split /\s+/,trim($blockarray[$i+1]); | |
$_ = shift(@temparray); | |
s/0x//; | |
$nextoffset = hex($_); | |
} | |
# get the target offset | |
$_ = $offset; | |
s/0x//; | |
$targetoffset = hex($_); | |
$difference = $targetoffset - $thisoffset; | |
if(($targetoffset > $thisoffset)&&($targetoffset < $nextoffset)){ | |
$findbetween = 1; | |
$moreswitch = 0; | |
#$stringlength = 0; | |
@stringarray = split /\s+/,$line; | |
# remove the first and last item | |
shift(@stringarray); | |
pop(@stringarray); | |
# remove the first different items | |
for($j=0;$j<$difference;$j++){ | |
shift(@stringarray); | |
} | |
$thislength = 0; | |
$moreswitch = 0; | |
foreach $hexvalue(@stringarray){ | |
if(is_ascii($hexvalue)){ | |
$thislength++; | |
if($thislength <= ($maxlength-$difference)){ | |
$stringresult = $stringresult.hex_to_ascii($hexvalue); | |
} | |
# need to consider next line | |
if($thislength == ($maxlength-$difference)){ | |
$nextarget = $nextarget + 1; | |
if($nextarget < scalar(@blockarray)){ | |
$line = trim($blockarray[$nextarget]); | |
$moreswitch = 1; | |
$stringlength += $thislength; | |
} | |
} | |
} | |
else{ | |
if(($hexvalue eq "00")&&($stringlength != 0)){ | |
$stringlength += 1; | |
} | |
$stringlength += $thislength; | |
$moreswitch = 0; | |
last; | |
} | |
} | |
while($moreswitch == 1){ | |
@stringarray = split /\s+/,$line; | |
# remove the first and last item | |
shift(@stringarray); | |
pop(@stringarray); | |
$thislength = 0; | |
if(scalar(@stringarray) == 0){ | |
$moreswitch = 0; | |
} | |
foreach $hexvalue(@stringarray){ | |
if(is_ascii($hexvalue)){ | |
$thislength++; | |
if($thislength <= $maxlength){ | |
$stringresult = $stringresult.hex_to_ascii($hexvalue); | |
} | |
# need to consider next line | |
if($thislength == $maxlength){ | |
$nextarget = $nextarget + 1; | |
if($nextarget < @blockarray){ | |
$line = trim($blockarray[$nextarget]); | |
$stringlength += $thislength; | |
} | |
} | |
} | |
else{ | |
if(($hexvalue eq "00")&&($stringlength != 0)){ | |
$stringlength += 1; | |
} | |
$stringlength += $thislength; | |
$moreswitch = 0; | |
last; | |
} | |
} | |
} | |
# save the result | |
my %resulthash ={}; | |
if($stringlength > 0){ | |
$resulthash{"funcname"}= $getfuncname; | |
$resulthash{"objname"}= $getobjname; | |
$resulthash{"constantstring"} = $stringresult; | |
$resulthash{"stringsize"}= "0x".dec2hex($stringlength); | |
} | |
else{ | |
$resulthash{"funcname"}= "(".$getfuncname.")"; | |
$resulthash{"objname"}= $getobjname; | |
} | |
push @resultarray, \%resulthash; | |
last; | |
} | |
} | |
# if no offset is between two offsets | |
if($findbetween == 0){ | |
if($#blockarray != -1){ | |
$line = trim($blockarray[$#blockarray]); | |
@stringarray = split /\s+/,$line; | |
# get the offset value of this line | |
$_ = shift(@stringarray); | |
s/0x//; | |
$thisoffset = hex($_); | |
# get the target offset | |
$_ = $offset; | |
s/0x//; | |
$targetoffset = hex($_); | |
# calculate the difference | |
$difference = $targetoffset - $thisoffset; | |
# remove the first and last item | |
shift(@stringarray); | |
pop(@stringarray); | |
# remove the first different items | |
for($j=0;$j<$difference;$j++){ | |
shift(@stringarray); | |
} | |
foreach $hexvalue(@stringarray){ | |
if(is_ascii($hexvalue)){ | |
$stringlength++; | |
if($stringlength <= ($maxlength-$difference)){ | |
$stringresult = $stringresult.hex_to_ascii($hexvalue); | |
} | |
} | |
} | |
# save the result | |
my %resulthash ={}; | |
if($stringlength > 0){ | |
$resulthash{"funcname"}= $getfuncname; | |
$resulthash{"objname"}= $getobjname; | |
$resulthash{"constantstring"} = $stringresult; | |
$resulthash{"stringsize"}= "0x".dec2hex($stringlength); | |
} | |
else{ | |
$resulthash{"funcname"}= "(".$getfuncname.")"; | |
$resulthash{"objname"}= $getobjname; | |
} | |
push @resultarray, \%resulthash; | |
} | |
} | |
} | |
} #close for firstaddressarray | |
close(FILE); | |
} | |
} | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# getunusedRO | |
# DESCRIPTION | |
# Parse unusedRO.txt, and get the function name and obj filename | |
#**************************************************************************** | |
sub getunusedRO{ | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
open(FILE,"<$unusedfilename") || die "File open error!\n"; | |
@data = <FILE>; | |
foreach(@data){ | |
#skip the line that contains : | |
if(index($_,":") >= 0){ | |
next; | |
} | |
# Find each section number, and record it in the $currentsecnum | |
if($_ =~ /(\S+)\s\((\S+)\)/){ | |
#print $1." ".$2."\n"; | |
my %unusedrohash ={}; | |
$unusedrohash{"funcname"}= $1; | |
$unusedrohash{"objname"}= $2; | |
$unusedrohash{"disfilepath"} = get_dispath_by_objname($2); | |
push @unusedroarray, \%unusedrohash; | |
} | |
} | |
close(FILE); | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# get_dispath_by_objname | |
# DESCRIPTION | |
# Find the corresponding disfile by obj name | |
#**************************************************************************** | |
sub get_dispath_by_objname(){ | |
#*--------------------------------------------------------------------------* | |
#* Local variables | |
#*--------------------------------------------------------------------------* | |
my $objname = $_[0]; | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
foreach (@disarray){ | |
my $gethash = $_; | |
my $getobjname = $gethash->{"objname"}; | |
my $getdisfilepath = $gethash->{"disfilepath"}; | |
#if($objname =~ /(\S+).o$/){ | |
# $objname = $1.".obj"; | |
#} | |
if($getobjname eq $objname){ | |
return $getdisfilepath; | |
} | |
} | |
return undef; | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# get_objpath_by_objname | |
# DESCRIPTION | |
# Find the corresponding objfile by obj name | |
#**************************************************************************** | |
sub get_objpath_by_objname(){ | |
#*--------------------------------------------------------------------------* | |
#* Local variables | |
#*--------------------------------------------------------------------------* | |
my $objname = $_[0]; | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
foreach (@disarray){ | |
my $gethash = $_; | |
my $getobjname = $gethash->{"objname"}; | |
my $getobjfilepath = $gethash->{"objfilepath"}; | |
#if($objname =~ /(\S+).o$/){ | |
# $objname = $1.".obj"; | |
#} | |
if($getobjname eq $objname){ | |
return $getobjfilepath; | |
} | |
} | |
return undef; | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# dimp_symboltable_to_file | |
# DESCRIPTION | |
# This function dumps the the data of symbolarray to file(symboltable.txt) | |
#**************************************************************************** | |
sub dump_symboltable_to_file{ | |
#*--------------------------------------------------------------------------* | |
#* Local variables | |
#*--------------------------------------------------------------------------* | |
my $disfilename; | |
my $symbolname; | |
my $symbolvalue; | |
my $symbolsize; | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
open(FILE,">symboltable.txt") || die "File open error!\n"; | |
# Set the data format | |
format FILE = | |
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<< | |
$disfilename,$symbolname, $symbolvalue,$symbolsize | |
. | |
foreach (@symbolarray){ | |
my $symbolhash = $_; | |
$disfilename = $symbolhash->{"objname"}; | |
$symbolname = $symbolhash->{"symbolname"}; | |
$symbolvalue = $symbolhash->{"symbolvalue"}; | |
$symbolsize = $symbolhash->{"symbolsize"}; | |
# Remove the empty line | |
unless($symbolname eq ""){ | |
write(FILE); | |
} | |
} | |
close(FILE); | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# matchsecnum | |
# DESCRIPTION | |
# This function determine whether the section number is in the secnum array | |
# PARAMETERS | |
# $secnum section number | |
# @secnumarray section number array | |
# RETURNS | |
# result return 1 for success; return 0 for fail | |
#**************************************************************************** | |
sub matchsecnum{ | |
#*--------------------------------------------------------------------------* | |
#* Local variables | |
#*--------------------------------------------------------------------------* | |
my $result = 0; | |
my $secnum = $_[0]; | |
my @secnumarray = $_[1]; | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
foreach (@secnumarray){ | |
if($secnum == $_){ | |
$result = 1; | |
return $result; | |
} | |
} | |
return $result; | |
} | |
sub trim($) | |
{ | |
my $string = shift; | |
$string =~ s/^\s+//; | |
$string =~ s/\s+$//; | |
return $string; | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# disassemble | |
# DESCRIPTION | |
# This function disassemble all the obj files in the root directory | |
#**************************************************************************** | |
sub disassemble{ | |
foreach (@filearray){ | |
#*--------------------------------------------------------------------------* | |
#* Local variables | |
#*--------------------------------------------------------------------------* | |
my $myhash = $_; | |
my $filename = $myhash->{"filename"}; | |
my $filepath = $myhash->{"filepath"}; | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
$_ = $filename; | |
s/.obj/.dis/; | |
my $newfilename = $_; | |
$_ = $filepath; | |
s/$filename/$newfilename/; | |
#Start to Disassemble (obj=>dis) | |
#If the dis file doesn't exist, disassemble the obj file | |
unless(-e $_){ | |
#system("start C:\\Progra~1\\ARM\\ADSv1_2\\Bin\\fromelf -cdrstvz ".$myhash->{"filepath"}.">".$_); | |
system("C:\\Progra~1\\ARM\\ADSv1_2\\Bin\\fromelf -cdrstvz ".$myhash->{"filepath"}.">".$_); | |
print "C:\\Progra~1\\ARM\\ADSv1_2\\Bin\\fromelf -cdrstvz ".$myhash->{"filepath"}.">".$_."\n"; | |
#sleep(1); | |
} | |
my %filehash ={}; | |
$filehash{"objname"}= $filename; | |
$filehash{"objfilepath"}= $filepath; | |
$filehash{"disfilepath"}= $_; | |
push @disarray, \%filehash; | |
} | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# traversefile | |
# DESCRIPTION | |
# This function scan the root directory , find all the obj files | |
# PARAMETERS | |
# #sub_DIR root directory | |
#**************************************************************************** | |
sub traversefile{ | |
#*--------------------------------------------------------------------------* | |
#* Local variables | |
#*--------------------------------------------------------------------------* | |
my $sub_DIR_id ; | |
my $sub_DIR ; | |
my $sub_SRC_FILE; | |
my @dirarray; | |
my $i; | |
my $count=0; | |
my $newdir; | |
$sub_DIR = $_[0]; # root directory | |
#*--------------------------------------------------------------------------* | |
#* Code Body | |
#*--------------------------------------------------------------------------* | |
#if $sub_DIR is a directory | |
if(-d ($sub_DIR)){ | |
opendir(sub_DIR_id, $sub_DIR) or die " cannot open directory :($sub_DIR)\n"; | |
while ( defined ($sub_SRC_FILE = readdir(sub_DIR_id)) ) | |
{ | |
#exclude . and .. | |
if (($sub_SRC_FILE ne "\.") && ($sub_SRC_FILE ne "\.\.")) | |
{ | |
my $path = $sub_DIR."\\".$sub_SRC_FILE; | |
unless(-d ($path)){ | |
$_ = $path; | |
#Only count obj file | |
if(/.obj$/i){ | |
my %filehash ={}; | |
$filehash{"filename"}= $sub_SRC_FILE; | |
$filehash{"filepath"}= $path; | |
push @filearray, \%filehash; | |
} | |
} | |
@dirarray[$count]=$sub_DIR."\\".$sub_SRC_FILE; | |
$count++; | |
} | |
} | |
for($i=0;$i<$count;$i++){ | |
$newdir = @dirarray[$i]; | |
traversefile($newdir); | |
} | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# hex_to_ascii | |
# DESCRIPTION | |
# This function convert each two-digit hex number back to an ASCII character | |
#**************************************************************************** | |
sub hex_to_ascii ($){ | |
(my $str = shift) =~ s/([a-fA-F0-9]{2})/chr(hex $1)/eg; | |
return $str; | |
} | |
#**************************************************************************** | |
# FUNCTION | |
# is_ascii | |
# DESCRIPTION | |
# This function check whether the param is a ascii code | |
#**************************************************************************** | |
sub is_ascii($){ | |
$param = hex_to_ascii($_[0]); | |
$asciinum = ord($param); | |
if((($asciinum>=32)&&($asciinum<=126))||($asciinum==10)){ | |
return 1; | |
} | |
else{ | |
return 0; | |
} | |
} | |
sub dec2hex { | |
# parameter passed to | |
# the subfunction | |
my $decnum = $_[0]; | |
# the final hex number | |
my $hexnum; | |
my $tempval; | |
while ($decnum != 0) { | |
# get the remainder (modulus function) | |
# by dividing by 16 | |
$tempval = $decnum % 16; | |
# convert to the appropriate letter | |
# if the value is greater than 9 | |
if ($tempval > 9) { | |
$tempval = chr($tempval + 55); | |
} | |
# 'concatenate' the number to | |
# what we have so far in what will | |
# be the final variable | |
$hexnum = $tempval . $hexnum ; | |
# new actually divide by 16, and | |
# keep the integer value of the | |
# answer | |
$decnum = int($decnum / 16); | |
# if we cant divide by 16, this is the | |
# last step | |
if ($decnum < 16) { | |
# convert to letters again.. | |
if ($decnum > 9) { | |
$decnum = chr($decnum + 55); | |
} | |
# add this onto the final answer.. | |
# reset decnum variable to zero so loop | |
# will exit | |
$hexnum = $decnum . $hexnum; | |
$decnum = 0 | |
} | |
} | |
return $hexnum; | |
} # end sub | |
} | |
sub getOwner(){ | |
$cc_mcu_path = "M:\\".$branch."_int\\MAUI_SW\\mcu"; | |
$fullfilepath = shift @_; | |
@part = split /\\/,$fullfilepath; | |
$obj_parse = $part[-1]; | |
$lib_parse = $part[-2].".lib"; | |
$owner = ""; | |
$filepath = getfilepath($lib_parse,$obj_parse,$mcudir); | |
if($mcudir eq ".\\"){ | |
$_ = $filepath; | |
s/.\\/\\/; | |
$cc_mcu_path = $cc_mcu_path.$_; | |
} | |
else{ | |
if($filepath =~ /(\S+)mcu(\S+)/){ | |
$cc_mcu_path = $cc_mcu_path.$2; | |
} | |
} | |
if (!-e ){ | |
$new_cc_mcu_path = $cc_mcu_path."pp"; | |
if (-e $new_cc_mcu_path){ | |
$cc_mcu_path = $new_cc_mcu_path; | |
} | |
} | |
$owner = get_owner_from_CC_server($cc_mcu_path); | |
return $owner; | |
} | |
sub getfilepath | |
{ | |
my ($mcu_path, $lis_path); | |
$lib_file = shift @_; | |
$obj_file = shift @_; | |
$mcu_path = shift @_; | |
my ($lib_tmp, $obj_tmp); | |
### get lis file path | |
$lib_file =~ /(.*).lib/; | |
$lib_tmp = $1; | |
# search source file path for object file | |
# query from lis file | |
if ((lc($lib_file) eq "conn_app.lib")||(lc($lib_file) eq "inet_app.lib")||(lc($lib_file) eq "mmi_app.lib")||(lc($lib_file) eq "mmi_framework.lib")||(lc($lib_file) eq "media_app.lib")) ## find file path in the official release code base | |
{ | |
$lis_path = $mcu_path . "make\\plutommi\\$lib_tmp\\$lib_tmp.lis"; | |
} | |
else | |
{ | |
$lis_path = $mcu_path . "make\\$lib_tmp\\$lib_tmp.lis"; | |
} | |
### get c file path | |
$obj_file =~ /(.*).obj/; | |
$obj_tmp = $1; | |
my $c_file = "$obj_tmp" . ".c"; | |
my $success = open (LIS_FILE, "<$lis_path") or warn "cannot open $lis_path\n"; | |
if($success) | |
{ | |
# read whole file | |
my $backup = $/; | |
undef $/; | |
my $reading = <LIS_FILE>; | |
$/ = $backup; | |
if ($reading =~ /(.*\\)$c_file/i) | |
{ | |
#print "HIT2: $1\n"; | |
$c_file = $mcu_path. $1 . $c_file; | |
#print "C_FILE: $c_file\n"; | |
} | |
else | |
{ | |
print "Assert: $c_file is NOT MATCHED in $lis_path !\n"; | |
} | |
} | |
return $c_file; | |
} | |
#**************************************************************************** | |
# Get owner of the source of a label from CC server | |
# Support when file is merged from subsidiary branch | |
#**************************************************************************** | |
sub get_owner_from_CC_server | |
{ | |
my ($src) = @_; | |
my $result; | |
my $CQ_owner; | |
my $cmd1; | |
my $tmp3; | |
my $tmp4; | |
my $tmp5; | |
my $cmd2=(); | |
if($src=~/(.+)\\(.+)/g ) | |
{ | |
$tmp3=$1; | |
$tmp4=$2; | |
my $file_name; | |
$tmp5="M: & cd ".$tmp3." & "; | |
$tmp4=~s/\./\\\./; | |
if(!(-d $tmp3)) | |
{ | |
$CQ_owner="ccadmin"; | |
return $CQ_owner; | |
} | |
#opendir (TMP3_DIR, $tmp3) or die "can't open directory $tmp3: $!"; | |
opendir (TMP3_DIR, $tmp3); | |
while ( defined ($file_name = readdir(TMP3_DIR)) ) | |
{ | |
if ($file_name=~/^$tmp4$/i) | |
{ | |
$tmp4=$file_name; | |
last; | |
} | |
} | |
closedir TMP3_DIR; | |
$cmd2=(); | |
$cmd2=$tmp5.'cleartool describe -fmt "Onwer: %Lu\nActivity: %[activity]p\n"'." ".$tmp4; | |
$result=`$cmd2`; | |
} | |
if($result=~/Onwer: (.+)\.Domain Users/i) | |
{ | |
$CQ_owner=$1; | |
if($CQ_owner=~/ccadmin/i) | |
{ | |
$cmd2=(); | |
$cmd2=$tmp5."cleartool describe ".$tmp4."\|find \"Merge\""; | |
$result=`$cmd2`; | |
if($result=~/Merge <- ([^\s]+)/i) | |
{ | |
$tmp4=$1; | |
$cmd2='cleartool describe -fmt "Onwer: %Lu\nActivity: %[activity]p\n"'." ".$tmp4; | |
$result=`$cmd2`; | |
if($result=~/Onwer: (.+)\.Domain Users/i) | |
{ | |
$CQ_owner=$1; | |
#print "Merge file owner:$CQ_owner \n"; | |
} | |
} | |
} | |
} | |
return $CQ_owner; | |
} # sub get_owner_from_CC_server | |
sub usage | |
{ | |
print "perl ROParser.pl <LIS filepath> <obj root path> <mcu path> <branch>\n"; | |
exit(0); | |
} | |
sub startview(){ | |
$view = $branch."_int"; | |
$result = `cleartool startview $view 2>&1`; | |
print $result; | |
if($result =~ /cleartool: Error:/){ | |
exit(0); | |
} | |
} |