blob: 30a0fdfd2ce1651ad1573a0b2d7d324d860be2eb [file] [log] [blame]
yu.dongc33b3072024-08-21 23:14:49 -07001#!/usr/bin/perl
2#
3# Copyright Statement:
4# --------------------
5# This software is protected by Copyright and the information contained
6# herein is confidential. The software may not be copied and the information
7# contained herein may not be used or disclosed except with the written
8# permission of MediaTek Inc. (C) 2006
9#
10# BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
11# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
12# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
13# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
14# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
15# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
16# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
17# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
18# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
19# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
20# NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
21# SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
22#
23# BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
24# LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
25# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
26# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
27# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
28#
29# THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
30# WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
31# LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
32# RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
33# THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
34#
35#*****************************************************************************
36#*
37#* Filename:
38#* ---------
39#* ldsInfo.pm
40#*
41#* Project:
42#* --------
43#*
44#*
45#* Description:
46#* ------------
47#* This script is to parse LinkerScript
48#*
49#* Author:
50#* -------
51#* Qmei Yang (mtk03726)
52#*
53#****************************************************************************/
54#****************************************************************************
55# Included Modules
56#****************************************************************************
57use strict;
58BEGIN { push @INC, './pcore/tools/' } # add additional library path
59use CommonUtility;
60use sysGenUtility;
61#****************************************************************************
62# Constants
63#****************************************************************************
64package Region;
65use constant Base => 0;
66use constant MaxSize => 1;
67use constant Attribute => 2;
68use constant Offset => 3;
69
70package InfoIndex;
71use constant Base => 1;
72use constant MaxSize => 3;
73use constant Attribute => 4;
74use constant Offset => 2;
75
76package ldsInfo;
77#****************************************************************************
78# Global Variables
79#****************************************************************************
80#****************************************************************************
81# oo >>> Finished
82#****************************************************************************
83return 1;
84
85#****************************************************************************
86# ldsInfo Version
87#****************************************************************************
88sub ldsInfo_verno
89{
90 return " u0.02";
91 # u0.02 , 20160621 by Tero, Memory parsing modified
92 # u0.01 , 20150806 by carl, Avoid taking linker symbol with postfix "_LENGTH" as a section
93 # m0.11 , 20130605 by mei, Support to strip comments in MEMORY
94 # m0.10 , 20130503 by mei, Add GetMEMORYInfoByName()
95 # m0.09 , 20121125 by mei, Support ParseSECTIONS() to skip other kinds of ASSERT
96 # m0.08 , 20121029 by mei, Support more flexible MEMORY format
97 # m0.07 , 20121002 by mei, Support ORIGIN
98 # m0.06 , 20120921 by mei, Support parsing hidden execution regions(the regions aint shown in linker symbol)
99 # m0.05 , 20120724 by mei, Support parsing MaxSize by ASSERT in linker script
100 # m0.04 , 20120528 by mei, Support path and filename case sensitive on Linux
101 # m0.03 , 20120522 by mei, support sysgen2
102 # m0.02 , 20120513 by mei, support partially parsing Linker Script
103 # m0.01 , 20120504 by mei, initial version
104}
105
106sub ParseSECTIONS
107{
108 my $self = shift;
109 my ($strInput) = @_;
110 my @lines = split(/\n/, $strInput);
111 map {$self->parse_linker_symbol($_)} @lines;
112 my ($strPrvRegionName, $strPrvBase, $nOVERLAYLine) = (undef, undef, 0);
113 my @OVERLAY;
114 foreach my $strLine (@lines)
115 {
116 next if($strLine =~ /PROVIDE/);
117 if($strLine =~ /ASSERT/ and $strLine =~ /Sizes\s*of\s*(\S+)\s*exceed\s*(\w+)/ )
118 {
119 my ($strRegionName, $nMaxSize) = ($1, hex($2));
120 my $nIndex = $self->{ExeRegionLookUpTable}{$strRegionName};
121 $self->{ExeRegion}->{$nIndex}[3] = $nMaxSize;
122 }
123 elsif($strLine =~ /ASSERT/)
124 {
125 next;
126 }
127 elsif(($strLine =~ /(\S+)\s+(\S+)*\s*\(NOLOAD\)\s*\:(.*)/
128 or $strLine =~ /(\S+)\s+(\S+)*\s*\:(.*)/)
129 and $strLine !~ /OVERLAY/)
130 {
131 my ($strRegionName, $strBase, $strLast) = ($1, $2, $3);
132 if($strPrvRegionName eq "OVERLAY")
133 {
134 $self->parse_overlay(\@OVERLAY);
135 $nOVERLAYLine = 0;
136 @OVERLAY = ();
137 }
138 if($strBase =~ /ALIGN|\d+/)
139 {
140 my $nIndex = $self->{ExeRegionLookUpTable}{$strRegionName};
141 $self->{ExeRegion}->{$nIndex}[1] = $strBase;
142 $self->{ExeRegion}->{$nIndex}[2] = undef;
143 }
144 elsif($strBase =~ /ORIGIN\(\s*(\S+)\s*\)/)
145 {
146 my $nIndex = $self->{ExeRegionLookUpTable}{$strRegionName};
147 my $ORIGIN;
148 foreach my $aref (@{$self->{MEMORYInfo}})
149 {
150 if($1 eq $aref->[0])
151 {
152 $ORIGIN = $aref->[1];
153 last;
154 }
155 }
156 $self->{ExeRegion}->{$nIndex}[1] = $ORIGIN;
157 $self->{ExeRegion}->{$nIndex}[2] = undef;
158 }
159 else
160 { # used in set_hiddenERs()
161 $strRegionName =~ s/\///g;
162 my $nIndex = $self->{ExeRegionLookUpTable}{$strPrvRegionName};
163 $self->{HiddenExeRegion}->{$strRegionName} = [$nIndex, $strPrvRegionName];
164 }
165 if($strLast =~ /\{/)
166 {
167 $strLast =~ s/.*\{//;
168 $self->parse_input_section($strLast, $strRegionName);
169 }
170 $strPrvRegionName = $strRegionName;
171 }
172 elsif($strLine =~ /OVERLAY/ or ($nOVERLAYLine >0 and $strPrvRegionName eq "OVERLAY"))
173 {# parse overlay
174 $strPrvRegionName = "OVERLAY";
175 push(@OVERLAY, $strLine);
176 $nOVERLAYLine++ if($strLine =~ /OVERLAY/);
177 $nOVERLAYLine++ if($strLine =~/\{/);
178 $nOVERLAYLine-- if($strLine =~/\}/);
179 next;
180 }
181 elsif($strLine !~ /\=|\;/)
182 {# parse input section
183 $self->parse_input_section($strLine, $strPrvRegionName);
184 }
185 $self->parse_memory_view($strLine, $strPrvRegionName);
186 }
187 $self->set_hiddenERs();
188}
189sub parse_overlay #ParseSECTIONS
190{
191 my $self = shift;
192 my ($lines_aref) = @_;
193 my $strCurRegionName = undef;
194 my $strOVERLAYBase;
195 my @OverlayRegion;
196 foreach my $strLine (@$lines_aref)
197 {
198 if($strLine =~ /OVERLAY\s*(\S*)\s*:/)
199 {
200 $strOVERLAYBase = $1;
201 next;
202 }
203 elsif($strLine =~ /^\s*(\S+)\s*\{/ or ($strLine =~ /^\s*(\S+)/ and $strLine !~ /\{|\}|\*|\(|\)|\=|\;/))
204 {
205 my $strRegionName = $1;
206 $strRegionName =~ s/\s|\{|\}//g;
207 next if($strRegionName eq "");
208 $strCurRegionName = $strRegionName;
209 if(exists $self->{ExeRegionLookUpTable}{$strRegionName})
210 {
211 my $nIndex = $self->{ExeRegionLookUpTable}{$strRegionName};
212 $self->{ExeRegion}->{$nIndex}[1] = $strOVERLAYBase;
213 $self->{ExeRegion}->{$nIndex}[2] = undef;
214 $self->{ExeRegion}->{$nIndex}[4] = ["OVERLAY"];
215 push (@OverlayRegion, $strRegionName);
216 }
217 }
218 elsif($strLine =~ /\>/)
219 {
220 map{ $self->parse_memory_view($strLine, $_);}@OverlayRegion;
221 }
222 elsif($strLine !~ /\=|\;/ and defined $strCurRegionName)
223 {
224 $self->parse_input_section($strLine, $strCurRegionName);
225 }
226 }
227}
228sub parse_input_section #used by ParseSECTIONS and parse_overlay
229{
230 my $self = shift;
231 my ($strLine, $strRegionName)= @_;
232 $strLine =~ s/.*\{|\}.*//;
233
234 #remove empty string
235 my $temp = $strLine;
236 $temp =~ s/\s//g;
237 return if($temp eq "");
238
239 if($strLine =~ /\{*\s*(\S+)\s*\((.+)\)(\}*)/)
240 {
241 push(@{$self->{InputSection}{$strRegionName}}, "$1 ($2)");
242 }
243 elsif( $strLine !~/\;|\=/)
244 {
245 push(@{$self->{InputSection}{$strRegionName}}, $strLine);
246 }
247}
248sub parse_linker_symbol #used by ParseSECTIONS
249{
250 my $self = shift;
251 my ($strLine) = @_;
252
253 #DRDI/L2CACHE_LOCK/MCURO_HWRW etc. are dummy output sections, thus strip them.
254 my %dummySection = ( DRDI => 0,
255 L2CACHE_LOCK => 0,
256 MCURO_HWRW => 0,
257 DUMMY_END => 0,
258 KTEST => 0,
259 LOAD_VIEW_END => 0,
260 EXECUTION_VIEW_END => 0,
261 );
262
263 if( $strLine =~ /Image\$\$(\S+)\$\$ZI\$\$(\S+)\s*\=\s*(\S+|\.)\s*\;/ or
264 $strLine =~ /Image\$\$(\S+)\$\$(\S+)\s*\=\s*\s*(\S+|\.)\s*\;/)
265 {
266 my ($strRegionName, $strBase, $strOffset, $nMaxSize, @Attr) = ($1, undef, "+0x0", undef, ());
267 my ($strIndexName, $strInput) = ($2, $3);
268
269 return if ($strRegionName =~ /LENGTH/ or exists $dummySection{$strRegionName}); # should not add any LENGTH in section name
270 if($strIndexName =~ /Base/ and $strInput !~ /\s+|\./)
271 {
272 $strBase = $strInput;
273 $strOffset = undef;
274 }
275 if($strIndexName =~ /Length/ and $strInput =~ /\d+/)
276 {
277 $nMaxSize = hex($strInput) ;
278 }
279 if(!exists $self->{ExeRegionLookUpTable}{$strRegionName})
280 {
281 $self->{ExeRegion}->{++$self->{ExeRegionCount}} = [$strRegionName, $strBase, $strOffset, $nMaxSize, \@Attr];
282 $self->{ExeRegionLookUpTable}{$strRegionName} = $self->{ExeRegionCount};
283 }
284 else
285 {
286 if(defined $nMaxSize)
287 {
288 my $nIndex = $self->{ExeRegionLookUpTable}{$strRegionName};
289 $self->{ExeRegion}->{$nIndex}[3] = $nMaxSize;
290 }
291 }
292 }
293}
294sub parse_memory_view #used by ParseSECTIONS and parse_overlay
295{
296 my $self = shift;
297 my ($strLine, $strRegionName) = @_;
298 if($strLine =~ /\>\s*(\S+)\s*AT\s*\>\s*(\S+)/)
299 {
300 $self->{MemoryView}{$strRegionName} = [$1, $2];
301 }
302 elsif($strLine =~ /AT\s*\>\s*(\S+)/)
303 {
304 $self->{MemoryView}{$strRegionName} = ["", $1];
305 }
306 elsif($strLine =~ /\>\s*(\S+)/)
307 {
308 $self->{MemoryView}{$strRegionName} = [$1, ""];
309 }
310}
311sub set_hiddenERs
312{
313 my $self = shift;
314 foreach my $key (keys %{$self->{HiddenExeRegion}})
315 {
316 if(exists $self->{ExeRegionLookUpTable}->{$key})
317 {
318 delete $self->{HiddenExeRegion}->{$key};
319 }
320 }
321}
322
323sub ParseMEMORY
324{
325 my ($strMEMORY) = @_;
326 #strip comments
327 $strMEMORY =~s#/\*[^*]*\*+([^/*][^*]*\*+)*/|([^/"']*("[^"\\]*(\\[\d\D][^"\\]*)*"[^/"']*|'[^'\\]*(\\[\d\D][^'\\]*)*'[^/"']*|/+[^*/][^/"']*)*)#$2#g;
328 my @MemoryInfo;
329 my @lines = split(/\n/, $strMEMORY);
330 foreach my $line (@lines)
331 {
332 my ($strName, $strBase, $strLength) = &ParseMEMORYLine($line);
333 push @MemoryInfo, [$strName, $strBase, $strLength] if(defined $strName);
334 }
335 return \@MemoryInfo;
336}
337sub ParseMEMORYLine
338{
339 my ($strLine) = @_;
340 my ($strName, $strBase, $strLength) = (undef, undef, undef);
341 my @org = ("ORIGIN", "org", "o");
342 my @len = ("LENGTH", "len", "l");
343 my $bFind = 0;
344 foreach my $o (@org)
345 {
346 foreach my $l (@len)
347 {
348 if($strLine =~ /\s*(\S+)\s*:\s*$o\s*\=\s*(.+)\s*,\s*$l\s*\=\s*(.+)/)
349 {
350 ($strName, $strBase, $strLength) = ($1, $2, $3);
351 $bFind = 1; last;
352 } elsif ($strLine =~ /^\s*#/) {
353 $strName = $strLine;
354 }
355 }
356 last if($bFind==1);
357 }
358 return ($strName, $strBase, $strLength);
359}
360sub new
361{
362 my $class = shift;
363 my $self = {};
364 #default value
365 $self->{ldsPath} = undef;
366 $self->{MEMORY} = undef; #=string
367 $self->{SECTIONS} = undef; #=string
368 $self->{MEMORYInfo} = undef; #aref: [$strName, $strBase, $strLength]
369
370 $self->{ExeRegion} = {}; #%g_ExeRegion; (start from 1)
371 # nIndex => [$1=Region name, $2=strBaseAddress, $3=strOffset, $4=nMaxSize, $5=\@Attribute]
372 $self->{ExeRegionCount} = 0; #$g_ExeRegionCount = 0;
373 $self->{ExeRegionLookUpTable} = {}; #%g_ExeRegionLookUpTable; # RegionName -> Index
374 $self->{HiddenExeRegion} = {}; #%HiddenExeRegion = RegionName => [$nPrvERIndex, $strPrvERName];
375
376 $self->{MemoryView} = {}; # %g_MemoryView; (start from 1)
377 # $RegionName => [$ExecutionView, $LoadView];
378 $self->{InputSection} = {}; # $self->{InputSection}{$strRegionName} = @InputSections;
379 #$self->{EXCLUDE_FILE} = {}; # $self->{EXCLUDE_FILE}{$strInputSection} = @files;
380 bless $self, $class;
381 return $self;
382}
383
384sub ParseLinkerScript
385{
386 my $self = shift;
387 my ($ldsPath) = @_;
388 if(defined $ldsPath and -e $ldsPath)
389 {
390 open (FILE_HANDLE, "<$ldsPath") or &lds_die("$ldsPath: file error!", __FILE__, __LINE__);
391 my $strStart = undef;
392 while (<FILE_HANDLE>)
393 {
394 if(/^MEMORY/)
395 {
396 $strStart = "MEMORY";
397 }
398 elsif(/^SECTIONS/)
399 {
400 $strStart = "SECTIONS";
401 }
402 elsif(/^}/)
403 {
404 undef $strStart;
405 }
406 elsif($_ !~ /^{/ and defined $strStart)
407 {
408 $self->{$strStart} .= $_;
409 }
410 }
411 close FILE_HANDLE;
412 #strip comments
413 $self->{MEMORY} =~s#/\*[^*]*\*+([^/*][^*]*\*+)*/|([^/"']*("[^"\\]*(\\[\d\D][^"\\]*)*"[^/"']*|'[^'\\]*(\\[\d\D][^'\\]*)*'[^/"']*|/+[^*/][^/"']*)*)#$2#g;
414 $self->{SECTIONS} =~s#/\*[^*]*\*+([^/*][^*]*\*+)*/|([^/"']*("[^"\\]*(\\[\d\D][^"\\]*)*"[^/"']*|'[^'\\]*(\\[\d\D][^'\\]*)*'[^/"']*|/+[^*/][^/"']*)*)#$2#g;
415 $self->{MEMORYInfo} = &ParseMEMORY($self->{MEMORY});
416 &EvalMemory($self->{MEMORYInfo});
417 $self->ParseSECTIONS($self->{SECTIONS});
418 }
419 else
420 {
421 &lds_die("LinkerScript Path($ldsPath) doesn't exist", __FILE__, __LINE__);
422 }
423}
424
425sub EvalMemory
426{
427 my ($MEMORYInfo_aref) = @_;
428 foreach my $item (@$MEMORYInfo_aref)
429 {
430 my $nBase = eval($item->[1]);
431 my $nLen = eval($item->[2]);
432 $item->[1] = &CommonUtil::Dec2Hex($nBase);
433 $item->[2] = &CommonUtil::Dec2Hex($nLen);
434 }
435}
436
437sub GetMEMROYInfo
438{
439 my $self = shift;
440 return $self->{MEMORYInfo};
441}
442
443sub GetMEMORYInfoByName
444{
445 my $self = shift;
446 my ($strRegionName) = @_;
447 my ($strBase, $strLen) = (undef, undef);
448 my $MEMORYInfo_aref = $self->{MEMORYInfo};
449 foreach my $aref (@$MEMORYInfo_aref)
450 {
451 if($strRegionName eq $aref->[0])
452 {
453 $strBase = $aref->[1];
454 $strLen = $aref->[2];
455 last;
456 }
457 }
458 return ($strBase, $strLen);
459}
460
461sub ListMemoryView
462{
463 my $self = shift;
464 foreach my $item (keys %{$self->{MemoryView}})
465 {
466 print "[$item]\n";
467 map {print "$_ "}@{$self->{MemoryView}{$item}};
468 print "\n";
469 }
470}
471sub ListInputSections
472{
473 my $self = shift;
474 foreach my $item (keys %{$self->{InputSection}})
475 {
476 print "[$item]\n";
477 map {print "$_\n"}@{$self->{InputSection}{$item}};
478 print "\n\n";
479 }
480}
481
482#****************************************************************************
483# subroutine: GetAllExeRegion
484# input: x
485# output: an array reference of execution region
486#****************************************************************************
487sub GetAllExeRegion
488{
489 my $self = shift;
490 my @ExeRegions;
491 foreach my $i (1 .. $self->{ExeRegionCount})
492 {
493 push(@ExeRegions, $self->{ExeRegion}{$i}->[0]);
494 }
495 return \@ExeRegions;
496}
497#****************************************************************************
498# subroutine: GetAllHiddenExeRegion
499# purpose: To get hidden
500# input: x
501# output: an array reference of execution region
502#****************************************************************************
503sub GetAllHiddenExeRegion
504{
505 my $self = shift;
506 my $href = $self->{HiddenExeRegion};
507 my @ExeRegions = sort { $href->{$a}->[0] <=> $href->{$b}->[0]} keys %$href;
508 #map{print "[$_]".$href->{$_}->[0]."\n";} @ExeRegions;
509 return \@ExeRegions;
510}
511#****************************************************************************
512# subroutine: GetRegionInfo - Get Region information from ExecutionRegions
513# input: $strRegionName: Execution Name (Case sensitive)
514# $nOption= Region::Base, Region::MaxSize, Region::Attribute, Region::Offset
515# output: $strInfo may be base, maxsize, attribute, and offset
516#****************************************************************************
517sub GetRegionInfo
518{
519 my $self = shift;
520 my ($strRegionName, $nOption) = @_;
521 my $strInfo = undef;
522 my $Info_ref = $self->GetExeRegionInfo($strRegionName);
523
524 if(defined $Info_ref->[Region::Attribute])
525 {
526 if($nOption > Region::Offset || $nOption < Region::Base)
527 { # report error - $nOption must have a value
528 &lds_die("GetRegionInfo must have Option value($nOption)");
529 }
530 else
531 {
532 $strInfo = $Info_ref->[$nOption];
533 }
534 }
535 return $strInfo;
536}
537#****************************************************************************
538# subroutine: GetExeRegionInfo - Get Execution Region information
539# input: $strRegionName: Execution Name (Case sensitive)
540# output: an Array contains
541# [0]$strBase=Region Base address,
542# [1]$strMaxSize=Region MaxSize,
543# [2]$strAttribute=Attribute,
544# [3]$strOffset(undef= no offset , others=start with +0x.. or ALIGN)
545#****************************************************************************
546sub GetExeRegionInfo
547{
548 my $self = shift;
549 my ($strRegionName) = @_;
550 my ($strBase, $nMaxSize, $strAttribute, $strOffset) = (undef, undef, undef, undef);
551 my $nIndex = $self->{ExeRegionLookUpTable}{$strRegionName};
552 if(defined $nIndex)
553 {
554 $strOffset = $self->{ExeRegion}{$nIndex}->[2];
555 $strBase = $self->{ExeRegion}{$nIndex}->[1];
556 $nMaxSize = (defined $self->{ExeRegion}{$nIndex}->[3]) ? $self->{ExeRegion}{$nIndex}->[3] : 0xFFFFFFFF;
557 $strAttribute = $self->{ExeRegion}{$nIndex}->[4];
558 }
559 my @Info = ($strBase, &CommonUtil::Dec2Hex($nMaxSize), $strAttribute, $strOffset);
560 return \@Info;
561}
562
563#****************************************************************************
564# subroutine: lds_die
565# sample code: (message, __FILE__, __LINE__)
566# input: $error_msg, $file, $line_no
567#****************************************************************************
568sub lds_die
569{
570 my ($error_msg, $file, $line_no) = (@_);
571 &CommonUtil::error_handler($error_msg, $file, $line_no, 'ldsInfo');
572}