MBA_Check.pl
14.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
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;
}