blob: fdfe5cc245c546c5c5c97a90a947ad8f9e761fa9 [file] [log] [blame]
use strict;
use warnings;
#*--------------------------------------------------------------------------*
#* Global variables
#*--------------------------------------------------------------------------*
my $LISFILE = $ARGV[0];
my $DBGFILE = $ARGV[1];
my %lang_pack_set;
my %cust_pack_set;
my %jump_table_set;
my %lib_set;
my %symbol_set;
my %symbol_startaddr_set;
my %symbol_endaddr_set;
my %filesrange_set;
my (@ref_sec, @dec_sec, @dec_region, @content, @total); # referencing obj, referencing function, declaration obj, declaraion region, referenced content
my ($initialtime, $finishtime, $exectime);
my $output = "";
#*--------------------------------------------------------------------------*
#* Code Body
#*--------------------------------------------------------------------------*
warn "
==============================================================================
[Program] MBA_Check.pl
[Version] V2.0
[Date] 2011-12-01
[Author] yikuan.huang\@mediatek.com Timon.Lu\@mediatek.com
[Copyright] Copyright (C) 2011 MediaTek Incorporation. All Rights Reserved.
==============================================================================
";
$initialtime = time();
# parse the dbg file
parsedbgfile();
# parse the lis file
parselisfile();
# check the reference chain
getFalseReference();
# output result to file
writeOutput();
$finishtime = time();
$exectime = $finishtime - $initialtime;
print "Total execution time: ".$exectime." seconds\n";
#****************************************************************************
# FUNCTION
# parsedbgfile
# DESCRIPTION
# This function parse DBG info file
# if you need to know detail, please refer to DBG file format
#****************************************************************************
sub parsedbgfile{
my $dbgfilesize = -s $ARGV[1];
my ($mainversion, $subversion, $projectname, $hwversion, $swversion, $buildtime, $symtableoffset, $filetableoffset);
my $symtablelength;
my ($buf, $data, $n);
my @contents;
#-------------------------------------------------------------
die "$DBGFILE does not exist!\n" if (!-e $DBGFILE);
open (DBG_FILE_HANDLE, "<$DBGFILE") or die "Fail to open $DBGFILE\n";
binmode DBG_FILE_HANDLE;
#-------------------------------------------------------------
$n = sysread (DBG_FILE_HANDLE, $data, $dbgfilesize);
#------------------------parse header --------------------------
if($data =~ /CATI(.{4})(.{4})([\w\s\x2E\x3A\x2F\x5F]+)\x00([\w\s\x2E\x3A\x2F\x5F]+)\x00([\w\s\x2E\x3A\x2F\x5F]+)\x00([\w\s\x2E\x3A\x2F\x5F]+)\x00(.{4})(.{4})([\s\S]*)/){
#mainversion of debug info
$mainversion = unpack('V', $1);
#subversion of debug info
$subversion = unpack('V', $2);
#project name of debug info
$projectname = $3;
#HW version of debug info
$hwversion = $4;
#SW version of debug info
$swversion = $5;
#build time of debug info which will be generated after building binary
$buildtime = $6;
#symtable offset of debug info which is append after debug info header (mainversion...etc)
$symtableoffset = unpack('V', $7);
#filetable offset of debug info which is append after symtable.
$filetableoffset = unpack('V', $8);
#debug info version match
if(($mainversion != 1) || ($subversion != 0)){
die "debug info file version is incorrect! VER_MAIN: ".$mainversion.", VER_SUB: ".$subversion."\n";
}
#get symbol table length
$symtablelength = $filetableoffset - $symtableoffset;
#truncate symbol table
$data = substr($9, 0, $symtablelength);
my $count = 3;
my $symbol;
#split symbol table by its format. name->null string->4 bytes for start addr->4 bytes for end addr ...repeat
my @symbols = split(/([\w:()]+).(.{4})(.{4})/, $data);
foreach my $val (@symbols) {
if(($count % 4 ) == 0){
#print length($val)." ".$val."\n";
$symbol = $val;
$symbol_set{$symbol} = $symbol;
}
elsif(($count % 4 ) == 1){
#print length($val)." ".unpack('V', $val)."\n";
$symbol_startaddr_set{$symbol} = unpack('V', $val);
}
elsif(($count % 4 ) == 2){
#print length($val)." ".unpack('V', $val)."\n";
$symbol_endaddr_set{$symbol} = unpack('V', $val);
}
$count++;
}
#truncate file table
$data = substr($9, $symtablelength+1);
$count = 1;
my $file_name="";
#split file table by its format. name->null string->4 bytes for number of addr range pair-> 4 bytes for
#pair one start addr->4 bytes for pair one end addr->......pair loop
#my @files = split(/([\w\x2F]+\x2F[\w]+).[c|cpp]\x00/, $data);
my @files = split(/\w+\x2F([\w]+).[c|cpp]\x00/, $data);
foreach my $val (@files) {
if($count % 2 == 0){
$file_name = $val;
#print $file_name."\n";
}
elsif($count % 2 == 1){
@contents = unpack("V*", $val);
$filesrange_set{$file_name} = [@contents];
}
$count++;
}
}
else{
}
close(DBG_FILE_HANDLE);
}
#****************************************************************************
# FUNCTION
# parselisfile
# DESCRIPTION
# This function parse LIS file
#****************************************************************************
sub parselisfile{
my ($i, $ref_count);
my $loadregionswitch = 0;
my $langpackswitch = 0;
my $custpackswitch = 0;
my $jumptableswitch = 0;
$i = 0;
die "$LISFILE does not exist!\n" if (!-e $LISFILE);
open (FILE_HANDLE, "<$LISFILE") or die "Fail to open $LISFILE\n";
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_sec[$i] = $2.$1; # AAA
$dec_sec[$i] = $4.$3; # BBB
$total[$i] = $_;
$i++; # should be indexed with the same $i
}
if (/Memory Map of the image/){
$loadregionswitch = 1;
}
if (/Image component sizes/){
$loadregionswitch = 0;
}
# turn on the switch if meet Load Region LANG_PACK_ROM
if (/Execution Region LANG_PACK_ROM_CONTENT/){
$langpackswitch = 1;
}
else{
# turn off the switch if meet another Load Region
if (/Execution Region/){
$langpackswitch = 0;
}
}
# turn on the switch if meet Load Region CUSTPACK_ROM
if (/Execution Region CUSTPACK_ROM_CONTENT/){
$custpackswitch = 1;
}
else{
# turn off the switch if meet another Load Region
if (/Execution Region/){
$custpackswitch = 0;
}
}
# turn on the switch if meet Load Region JUMP_TABLE
if (/Load Region JUMP_TABLE/){
$jumptableswitch = 1;
}
else{
# turn off the switch if meet another Load Region
if (/Execution Region/){
$jumptableswitch = 0;
}
}
# parse the lang pack section
if ($langpackswitch == 1){
if(/\s*0x\S*\s*\S*\s*\S*\s*\S*\s*\S*\s*(\S*)\s*(\w*)/){
unless(trim($1.$2) eq ""){
#print $2.$1."\n";
$lang_pack_set{$1.$2}=$1.$2;
}
}
}
# parse the cust pack section
if ($custpackswitch == 1){
if(/\s*0x\S*\s*\S*\s*\S*\s*\S*\s*\S*\s*(\S*)\s*(\w*)/){
unless(trim($1.$2) eq ""){
$cust_pack_set{$1.$2}=$1.$2;
}
}
}
# parse the jump table section
if ($jumptableswitch == 1){
if(/\s*0x\S*\s*\S*\s*\S*\s*\S*\s*\S*\s*(\S*)\s*(\w*)/){
unless(trim($1.$2) eq ""){
#print $2.$1."\n";
$jump_table_set{$1.$2}=$1.$2;
}
}
}
if ($loadregionswitch == 1){
#parse function
if(/\s*0x\S*\s*\S*\s*\S*\s*\S*\s*\S*\s*(\S*)\s*(\S*)/){
my $section = $1;
my $objandLib = $2;
if($objandLib =~ /(\S*)\.o.*\((\S*)\)/){ #$2 = library name
$lib_set{$section.$1} = $2;
#print "$section -> $1 -> $2 \n";
}
}
}
}
close FILE_HANDLE or die "Fail to close $LISFILE\n";
}
#****************************************************************************
# FUNCTION
# replaceFileName
# DESCRIPTION
# this function use the result of parsedbgfile to get real file name!
#
#****************************************************************************
sub replaceFileName{
my $filename = "";
my $libname = "";
my ($fromfunctionaddr, $tofunctionaddr, $fromfilename, $tofilename);
if($_[0] =~ /(\S+)\..*[\(\.]+(\w+)\)\srefers\sto\s(\S+)\..*[\(\.]+(\w+)\)\sfor\s(\S+)\s*/){
$fromfunctionaddr = $symbol_startaddr_set{$2}; # $2 = from function address
$tofunctionaddr = $symbol_startaddr_set{$4}; # $4 = to function address
# those two line are used to prevent warning msg.
$fromfunctionaddr = defined $fromfunctionaddr ? $fromfunctionaddr : 0;
$tofunctionaddr = defined $tofunctionaddr ? $tofunctionaddr : 0;
# look for file name by function address
for $filename (keys %filesrange_set){
if(length($filename) != 0){
for(my $i = 1; $i < ($filesrange_set{$filename}[0]*2+1); $i+=2){
if($fromfunctionaddr != 0 && $fromfunctionaddr >= $filesrange_set{$filename}[$i] && $fromfunctionaddr <= $filesrange_set{$filename}[$i+1]){
$fromfilename = $filename;
$_[0] =~ s/$1/$fromfilename/g;
}
if($tofunctionaddr != 0 && $tofunctionaddr >= $filesrange_set{$filename}[$i] && $tofunctionaddr <= $filesrange_set{$filename}[$i+1]){
$tofilename = $filename;
$_[0] =~ s/$3/$tofilename/g;
}
}
}
}
}
# those two line are used to prevent warning msg.
$fromfilename = defined $fromfilename ? $fromfilename : "";
$tofilename = defined $tofilename ? $tofilename : "";
$libname = $lib_set{$_[1]};
$libname = defined $libname ? $libname : "";
if(length($fromfilename) != 0){
$_[0] = "Warnning : $fromfilename.obj ($libname) \n ".$_[0];
}
else{
$_[0] = "Warnning : $1.obj ($libname) \n ".$_[0];
}
}
#****************************************************************************
# FUNCTION
# getFalseReference
# DESCRIPTION
# Check the function reference
#****************************************************************************
sub getFalseReference{
for (my $i = 0;$i<@ref_sec;$i++) {
my $from_sec = $ref_sec[$i];
my $to_sec = $dec_sec[$i];
my $line = $total[$i];
# hard code to skip function InitializeResourceVariables and StandaloneResValidation
if(($from_sec =~ /resource_custpack_jtbl.*/) || ($from_sec =~ /resource_lang_pack_jtbl.*/)){
next;
}
# check if lang not refer to lang
if(isLangPack($from_sec) eq "true"){
unless(isLangPack($to_sec) eq "true"){
replaceFileName($line, $from_sec);
$output = $output.$line."Recommend Correction ---> Cannot Cross Reference Out of Lang Pack Content, Please Move RO-CODE out of RESB or Revise Data Structure\n\n";
}
}
# check if cust not refer to cust
if(isCustPack($from_sec) eq "true"){
unless(isCustPack($to_sec) eq "true"){
replaceFileName($line, $from_sec);
$output = $output.$line."Recommend Correction ---> Cannot Cross Reference Out of Cust Pack Content, Please Move RO-CODE out of RESB or Revise Data Structure\n\n";
}
}
# check if jtb not refer to lang or cust
if(isJumpTable($from_sec) eq "true"){
unless((isLangPack($to_sec) eq "true")||(isCustPack($to_sec) eq "true")){
replaceFileName($line, $from_sec);
$output = $output.$line."Recommend Correction ---> Critial Probelm, Please Reach System Service To Help You\n\n";
}
}
# check if not lang or jtb refer to lang
if(isLangPack($to_sec) eq "true"){
unless((isLangPack($from_sec) eq "true")||(isJumpTable($from_sec) eq "true")){
replaceFileName($line, $from_sec);
$output = $output.$line."Recommend Correction ---> Cannot Directly Reference To Lang Pack Content, Lookup JumpTable First\n\n";
}
}
# check if not cust or jtb refer to cust
if(isCustPack($to_sec) eq "true"){
unless((isCustPack($from_sec) eq "true")||(isJumpTable($from_sec) eq "true")){
replaceFileName($line, $from_sec);
$output = $output.$line."Recommend Correction ---> Cannot Directly Reference To Cust Pack Content, Lookup JumpTable First\n\n";
}
}
# check if lang or cust refer to jtb
if(isJumpTable($to_sec) eq "true"){
if((isLangPack($from_sec) eq "true")||(isCustPack($from_sec) eq "true")){
replaceFileName($line, $from_sec);
$output = $output.$line."Recommend Correction ---> Cannot Reverse Reference From RESB to Jump Table, Please Revise Data Structure\n\n";
}
}
}
}
#****************************************************************************
# FUNCTION
# isLangPack
# DESCRIPTION
# Check the obj if exist in Lang Pack region
#****************************************************************************
sub isLangPack(){
my $result = "false";
my $obj = $_[0];
while ( my ($key, $value) = each(%lang_pack_set) ) {
my $target = $key;
if($obj eq $target){
$result = "true";
}
}
return $result;
}
#****************************************************************************
# FUNCTION
# isCustPack
# DESCRIPTION
# Check the obj if exist in Cust Pack region
#****************************************************************************
sub isCustPack(){
my $result = "false";
my $obj = $_[0];
while ( my ($key, $value) = each(%cust_pack_set) ) {
my $target = $key;
if($obj eq $target){
$result = "true";
}
}
return $result;
}
#****************************************************************************
# FUNCTION
# isJumpTable
# DESCRIPTION
# Check the obj if exist in Jump Table region
#****************************************************************************
sub isJumpTable(){
my $result = "false";
my $obj = $_[0];
while ( my ($key, $value) = each(%jump_table_set) ) {
my $target = $key;
if($obj eq $target){
$result = "true";
}
}
return $result;
}
#****************************************************************************
# FUNCTION
# writeOutput
# DESCRIPTION
# Output the result to file
#****************************************************************************
sub writeOutput{
# set the name of output file
my @part = split /\\/, $LISFILE;
my $outputFile = $part[-1];
$outputFile =~ s/lis/txt/;
#write result to file
open(RESULT,">$outputFile") || die "File open error!\n";
print RESULT $output;
close(RESULT)
}
#****************************************************************************
# FUNCTION
# trim
# DESCRIPTION
# Trim the space in front and back of string
#****************************************************************************
sub trim($)
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}