blob: 5d81585f4181a7ff4afa49a16efe763a2695a77a [file] [log] [blame]
rjw6c1fd8f2022-11-30 14:33:01 +08001#!/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) 2018
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#* AutoAdjustInputSection.pl
40#*
41#* Project:
42#* --------
43#*
44#*
45#* Description:
46#* ------------
47#* This scripts is used to parse the configuration of Auto-Placement symbols with order.
48#*
49#* Author:
50#* -------
51#* Yao Liu (mtk15073)
52#*
53#****************************************************************************/
54
55use strict;
56use warnings;
57
58BEGIN { push @INC , './tools/' } # add additional library path
59use FileInfoParser;
60use CommonUtility;
61use File::Basename;
62use File::Spec;
63use Data::Dumper;
64use constant {
65 LOG => 0,
66 WARNING => 1,
67 FATAL => 2,
68};
69
70my ($ToolChainBase, $LDSFileName, $Tempdir) = (@ARGV);
71&msg_handler(LOG, "Input file: $ToolChainBase, $LDSFileName, $Tempdir\n");
72
73my ($Readelf, $AR);
74my ($Project, $Flavor);
75my ($LibPath1Prefix, $LibPath2Prefix);
76my $tempInputFolder;
77&GetEnvInfo();
78
79#record all the used lib and obj
80my %libObjHash;
81#extract the info of all symbols of a .obj
82my %SymLogInfoHash;
83#extract the info of all sections of a .obj
84my %SecLogInfoHash;
85#Enable/disable local test, 0: disable, 1: enable
86my $local_test = 0;
87#record all official config info
88my %Official_Config;
89#record all local config info
90my %Local_Config;
91#record all section ID
92my %SectionIDHash;
93#record the order of section ID
94my @SectionOrder;
95
96my $official_config = $Tempdir."~official_config.ldf";
97my $local_config = $Tempdir."~local_config.ldf";
98&msg_handler(FATAL, "official/local config file do not exist!\n") if(!-e $official_config && !-e $local_config);
99
100&ParseConfigFile($official_config);
101&ParseConfigFile($local_config) if($local_test);
102
103&ParseLibObj();
104
105&CheckUserConfiguration();
106
107&UpdateLDS($LDSFileName);
108
109&CleanTempFiles();
110
111
112exit 0;
113
114sub GetEnvInfo
115{
116 $AR = $ToolChainBase."ar";
117 $Readelf = $ToolChainBase."readelf";
118
119 &msg_handler(FATAL, "GCC tool does not exist", __LINE__) unless(-e $Readelf and -e $AR);
120
121 my $RelPath = File::Basename::dirname($LDSFileName);
122 my $AbsPath = File::Spec->rel2abs($RelPath);
123
124 if($AbsPath =~ m|/mcu/build/(\w+)/(\w+)/|) {
125 ($Project, $Flavor) = ($1, $2);
126 }else {
127 &msg_handler(FATAL, "Fail to get project and flavor", __LINE__);
128 }
129
130 $LibPath1Prefix = "./mtk_rel/$Project/$Flavor/TARGET/lib/";
131 $LibPath2Prefix = "./build/$Project/$Flavor/bin/lib/";
132
133 $tempInputFolder = $Tempdir . "CustomInputSection";
134 system("rm -rf $tempInputFolder") if(-e $tempInputFolder);
135 system("mkdir -p $tempInputFolder");
136 $? == 0 or &msg_handler(FATAL, "Making $tempInputFolder failed $?", __LINE__);
137}
138
139sub ParseConfigFile
140{
141 my ($ConfigFile) = (@_);
142 my $FileName = $ConfigFile;
143
144 open CFG, "$ConfigFile" or &msg_handler(FATAL, "Can not open $ConfigFile!", __LINE__);
145 local $/ = undef;
146 my $tempOutput = <CFG>;
147 close CFG;
148
149 my ($SubSection, $bFlag, $sFlag) = (undef, 0, 0);
150 my @TotalSecArray;
151 my $BreakRegExp = "[\\*]{20}\\s[<]\\sGROUP\\s*CFG\\s[>]\\s[\\*]{20}";
152
153 #split entire config file into several configuration groups.
154 foreach my $line (split /\n/, $tempOutput) {
155 if($bFlag == 0) {
156 $bFlag = 1 if(($line =~ m/^\[Symbol\]\s+\[Obj\]\s+\[Lib\]$/));
157 next;
158 }
159 next if($line =~ m/^\s*$/);
160
161 if($line =~ m/^\s*$BreakRegExp\s*$/) {
162 $sFlag = 1;
163 if(defined $SubSection) {
164 push @TotalSecArray, $SubSection;
165 undef $SubSection;
166 }
167 next;
168 }
169 $SubSection .= $line."\n" if($sFlag == 1);
170 }
171 push @TotalSecArray, $SubSection if(defined $SubSection);
172
173 my %unique;
174 foreach my $content (@TotalSecArray) {
175 my @tempArray = split /\n/, $content;
176 my ($Section_ID, $name_flag, $size_flag);
177 foreach my $line (@tempArray) {
178 if($line =~ /^Section ID\s*:\s*(.*)$/) {
179 $Section_ID = $1;
180 if (! $Section_ID =~ /L2CACHE_LOCK_RO_SECTION_\w+/) {
181 my $msg = "Illegal Line Format: $line";
182 &msg_handler(FATAL, "Illegal Line Format: $line", __LINE__, $FileName);
183 next;
184 }
185 &msg_handler(FATAL, "The section ID $Section_ID has been defined in config file!\n", __LINE__) if(exists $SectionIDHash{$Section_ID});
186 $SectionIDHash{$Section_ID} = 0;
187 $name_flag = 1;
188 next;
189 } elsif($line =~ /^Reserved size\s*:\s*(.*)$/ && $name_flag == 1) {
190 $Official_Config{$Section_ID}{"size"} = $1 if($ConfigFile eq $official_config);
191 $Local_Config{$Section_ID}{"size"} = $1 if($ConfigFile eq $local_config);
192 push @SectionOrder, $Section_ID;
193 $size_flag = 1;
194 next;
195 } elsif(!($name_flag == 1 && $size_flag == 1)) {
196 &msg_handler(FATAL, "Wrong config format in $Section_ID!", __LINE__, $FileName);
197 }
198
199 if($line =~ m/^(\S+)\s+(\S+)\s+(\S+)\s*$/ && ($ConfigFile eq $official_config)) {
200 if(exists $unique{$1.":".$2.":".$3}) {
201 &msg_handler(FATAL, "[Duplicated Lines]: $line", __LINE__, $FileName);
202 next;
203 } else {
204 $Official_Config{$Section_ID}{$1.":".$2.":".$3}{"symbol_name"} = $1;
205 $Official_Config{$Section_ID}{$1.":".$2.":".$3}{"obj"} = $2;
206 $Official_Config{$Section_ID}{$1.":".$2.":".$3}{"lib"} = $3;
207 $unique{$1.":".$2.":".$3} = 0;
208 $libObjHash{$3}{$2} = 0;
209 }
210 }
211 }
212 }
213}
214
215sub ParseLibObj
216{
217 foreach my $lib (keys %libObjHash) {
218 my $LibPath1 = $LibPath1Prefix . $lib;
219 my $LibPath2 = $LibPath2Prefix . $lib;
220 my $LibPath = (-e $LibPath1) ? $LibPath1 : $LibPath2;
221 if(!-e $LibPath) {
222 delete $libObjHash{$lib};
223 next;
224 }
225
226 my @ObjArray = keys %{$libObjHash{$lib}};
227 foreach my $obj (@ObjArray) {
228 my $ExtractObj = $Tempdir . "CustomInputSection/" . $lib . $obj;
229 my $SymLog = $ExtractObj . "." . "symbols.log";
230 my $SecLog = $ExtractObj . "." . "sections.log";
231
232 next if(-f $SymLog && -f $SecLog); #have been parsed before.
233
234 #extract the obj from lib
235 system("$AR -x $LibPath $obj 2> /dev/null");
236 unless(-f $obj) {
237 delete $libObjHash{$lib}{$obj};
238 next;
239 }
240
241 #move the obj to certain folder
242 system("mv $obj $ExtractObj");
243 $? == 0 or &msg_handler(FATAL, "$ExtractObj moving failed", __LINE__);
244
245 #generate SYM log
246 system("$Readelf --syms -W $ExtractObj > $SymLog");
247 $? == 0 or &msg_handler(FATAL, "Generating $SymLog failed", __LINE__);
248
249 #generate SECTION log
250 system("$Readelf -S -W $ExtractObj > $SecLog");
251 $? == 0 or &msg_handler(FATAL, "Generating $SecLog failed", __LINE__);
252
253 &ParseSymAndSecLog($SymLog, $SecLog, $lib, $obj);
254 }
255 }
256}
257
258sub ParseSymAndSecLog
259{
260 my ($tempSymLog, $tempSecLog, $tempLib, $tempObj) = (@_);
261 my $key = $tempLib . $tempObj;
262
263 open SYM_LOG, "< $tempSymLog" or &msg_handler(FATAL, "Fail to open $tempSymLog", __LINE__);
264 while(my $line = <SYM_LOG>) {
265 # 17: 00000024 40 FUNC LOCAL DEFAULT [MIPS16] 9 ev_cmp_f
266 if($line =~ m/^\s*\d+\s*:\s*\S+\s+(\d+).*\s+(\d+)\s+(\w+)$/) {
267 my ($Symbol, $index, $size) = ($3, $2, $1);
268 $SymLogInfoHash{$key}{$Symbol}{'index'} = $index;
269 $SymLogInfoHash{$key}{$Symbol}{'size'} = $size;
270 }
271 }
272 close SYM_LOG;
273
274 open SEC_LOG, "< $tempSecLog" or &msg_handler(FATAL, "Fail to open $tempSecLog", __LINE__);
275 while(my $line = <SEC_LOG>) {
276 # [22] .text.evshed_give PROGBITS 00000000 000bbc 00002c 00 AX 0 0 4
277 if($line =~ m/^\s*\[\s*(\d+)\s*\]\s+(\S+)\s+/) {
278 my ($index, $Section) = ($1, $2);
279 if($Section =~ m/^(\.?\w+)\.\w+$/) {
280 $SecLogInfoHash{$key}{$index}{'type'} = $1;
281 $SecLogInfoHash{$key}{$index}{'valid'} = 'false';
282 }elsif($Section =~ m/^[^\.]*$/) {
283 $SecLogInfoHash{$key}{$index}{'type'} = $Section;
284 $SecLogInfoHash{$key}{$index}{'valid'} = 'true';
285 }
286 }
287 }
288 close SEC_LOG;
289}
290
291sub CheckUserConfiguration
292{
293 foreach my $id (keys %Official_Config) {
294 foreach my $item (keys %{$Official_Config{$id}}) {
295 next if($item eq "size");
296 my $symbol_name = $Official_Config{$id}{$item}{"symbol_name"};
297 my $obj = $Official_Config{$id}{$item}{"obj"};
298 my $lib = $Official_Config{$id}{$item}{"lib"};
299 my $SymNameInObj;
300
301 if(not exists $libObjHash{$lib}) { #lib does not exist
302 my $tips = "$lib does not exist.";
303 &msg_handler(FATAL, "$symbol_name not found in Group" . "[$id]" . ": $tips", __LINE__);
304 next;
305 }elsif(not exists $libObjHash{$lib}{$obj}) { #obj can't be found in lib
306 my $tips = "$symbol_name not exists in $obj.";
307 &msg_handler(FATAL, "$symbol_name not found in Group" . "[$id]" . ": $tips", __LINE__);
308 next;
309 }elsif(not exists $SymLogInfoHash{$lib.$obj}) { #the symbol not exists
310 my $tips = "If your symbol type is C++, please use the full name in MAP/SYM, such as [ipfcore_task_init] -> [_Z17ipfcore_task_initv]";
311 &msg_handler(FATAL, "$symbol_name can't be found in Group" . "[$id]" . ", $tips", __LINE__);
312 next;
313 }
314 my $index = $SymLogInfoHash{$lib.$obj}{$symbol_name}{"index"};
315 if(not exists $SecLogInfoHash{$lib.$obj}{$index}) {
316 &msg_handler(FATAL, "Can not find the input section of $symbol_name in [$id]!", __LINE__);
317 next;
318 }elsif(not $SecLogInfoHash{$lib.$obj}{$index}{'type'} eq $id) {
319 &msg_handler(FATAL, "$symbol_name is not used $id to define. Please check!", __LINE__);
320 next;
321 }
322 }
323 }
324}
325
326sub UpdateLDS
327{
328 my ($LDSFile) = (@_);
329 my ($output, $assert, $flag) = (undef, "", 0);
330 open LDS, "< $LDSFile" or &msg_handler(FATAL, "Fail to open $LDSFile", __LINE__);
331
332 while(my $line = <LDS>) {
333 if($line =~ /^(\s+)Image\$\$CACHED_EXTSRAM_L2CACHE_LOCK_RO\$\$Base = \. ;/) {
334 my $prefix = $1;
335 $output .= $line;
336 foreach my $section (@SectionOrder){
337 my $template = <<"__TEMPLATE";
338$prefix. = ALIGN(64);
339$prefix$section\$\$Base = .;
340$prefix* ($section)
341$prefix. = ALIGN(64);
342$prefix$section\$\$Limit = .;
343$prefix$section\$\$Length = ABSOLUTE($section\$\$Limit - $section\$\$Base);
344
345__TEMPLATE
346 $output .= $template;
347 my $setting_size;
348 if(exists $Official_Config{$section}){
349 $setting_size = $Official_Config{$section}{"size"};
350 }elsif(exists $Local_Config{$section}){
351 $setting_size = $Local_Config{$section}{"size"};
352 }else{
353 &msg_handler(FATAL, "The section $section is not defined in config file!", __LINE__);
354 }
355 $assert .= " ASSERT( $section\$\$Length <= $setting_size,\"$section exceeds the setting size!\")\n";
356 }
357 }elsif($line =~ /^(\s+)ASSERT\(/ && $flag == 0) {
358 $output .= $assert;
359 $output .= $line;
360 $flag = 1;
361 }else{
362 $output .= $line;
363 }
364 }
365 close LDS;
366
367 open LDS, "> $LDSFile" or &msg_handler(FATAL, "Fail to open $LDSFile", __LINE__);
368 print LDS $output;
369 close LDS;
370
371 &msg_handler(LOG, "\nLDS is updated successfully ^O^, please check $LDSFileName.", __LINE__);
372}
373
374sub CleanTempFiles
375{
376 system("rm -rf $tempInputFolder");
377 $? == 0 or &msg_handler(FATAL, "Deleting $tempInputFolder failed $?", __LINE__);
378}
379
380sub msg_handler
381{
382 my ($type, $msg, $line_no) = (@_);
383 my $prompt_prefix;
384 if($type == LOG) {
385 print $msg . "\n";
386 }
387 elsif($type == WARNING) {
388 $prompt_prefix = ">> AAIS Warning : ";
389 print $prompt_prefix . $msg . "\n";
390 }
391 elsif($type == FATAL) {
392 $prompt_prefix = ">> *** AAIS Fatal : ";
393 my $location = "[at line $line_no] ";
394 die $prompt_prefix . $location . $msg . "\n";
395 }
396}