| #!/usr/bin/perl | 
 | # | 
 | #  Copyright Statement: | 
 | #  -------------------- | 
 | #  This software is protected by Copyright and the information contained | 
 | #  herein is confidential. The software may not be copied and the information | 
 | #  contained herein may not be used or disclosed except with the written | 
 | #  permission of MediaTek Inc. (C) 2018 | 
 | # | 
 | #  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES | 
 | #  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") | 
 | #  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON | 
 | #  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, | 
 | #  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF | 
 | #  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. | 
 | #  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE | 
 | #  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR | 
 | #  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH | 
 | #  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO | 
 | #  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S | 
 | #  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. | 
 | # | 
 | #  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE | 
 | #  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, | 
 | #  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, | 
 | #  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO | 
 | #  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. | 
 | # | 
 | #  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE | 
 | #  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF | 
 | #  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND | 
 | #  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER | 
 | #  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). | 
 | # | 
 | #***************************************************************************** | 
 | #* | 
 | #* Filename: | 
 | #* --------- | 
 | #*   AutoAdjustInputSection.pl | 
 | #* | 
 | #* Project: | 
 | #* -------- | 
 | #* | 
 | #* | 
 | #* Description: | 
 | #* ------------ | 
 | #*   This scripts is used to parse the configuration of Auto-Placement symbols with order. | 
 | #* | 
 | #* Author: | 
 | #* ------- | 
 | #*   Yao Liu (mtk15073) | 
 | #* | 
 | #****************************************************************************/ | 
 |  | 
 | use strict; | 
 | use warnings; | 
 |  | 
 | BEGIN { push @INC , './tools/' }  # add additional library path | 
 | use FileInfoParser; | 
 | use CommonUtility; | 
 | use File::Basename; | 
 | use File::Spec; | 
 | use Data::Dumper; | 
 | use constant { | 
 |     LOG        => 0, | 
 |     WARNING    => 1, | 
 |     FATAL      => 2, | 
 | }; | 
 |  | 
 | my ($ToolChainBase, $LDSFileName, $Tempdir) = (@ARGV); | 
 | &msg_handler(LOG, "Input file: $ToolChainBase, $LDSFileName, $Tempdir\n"); | 
 |  | 
 | my ($Readelf, $AR); | 
 | my ($Project, $Flavor); | 
 | my ($LibPath1Prefix, $LibPath2Prefix); | 
 | my $tempInputFolder; | 
 | &GetEnvInfo(); | 
 |  | 
 | #record all the used lib and obj | 
 | my %libObjHash; | 
 | #extract the info of all symbols of a .obj | 
 | my %SymLogInfoHash; | 
 | #extract the info of all sections of a .obj | 
 | my %SecLogInfoHash; | 
 | #Enable/disable local test, 0: disable, 1: enable | 
 | my $local_test = 0; | 
 | #record all official config info | 
 | my %Official_Config; | 
 | #record all local config info | 
 | my %Local_Config; | 
 | #record all section ID | 
 | my %SectionIDHash; | 
 | #record the order of section ID | 
 | my @SectionOrder; | 
 |  | 
 | my $official_config = $Tempdir."~official_config.ldf"; | 
 | my $local_config = $Tempdir."~local_config.ldf"; | 
 | &msg_handler(FATAL, "official/local config file do not exist!\n") if(!-e $official_config && !-e $local_config); | 
 |  | 
 | &ParseConfigFile($official_config); | 
 | &ParseConfigFile($local_config) if($local_test); | 
 |  | 
 | &ParseLibObj(); | 
 |  | 
 | &CheckUserConfiguration(); | 
 |  | 
 | &UpdateLDS($LDSFileName); | 
 |  | 
 | &CleanTempFiles(); | 
 |  | 
 |  | 
 | exit 0; | 
 |  | 
 | sub GetEnvInfo | 
 | { | 
 |     $AR      = $ToolChainBase."ar"; | 
 |     $Readelf = $ToolChainBase."readelf"; | 
 |  | 
 |     &msg_handler(FATAL, "GCC tool does not exist", __LINE__) unless(-e $Readelf and -e $AR); | 
 |  | 
 |     my $RelPath = File::Basename::dirname($LDSFileName); | 
 |     my $AbsPath = File::Spec->rel2abs($RelPath); | 
 |  | 
 |     if($AbsPath =~ m|/mcu/build/(\w+)/(\w+)/|) { | 
 |         ($Project, $Flavor) = ($1, $2); | 
 |     }else { | 
 |         &msg_handler(FATAL, "Fail to get project and flavor", __LINE__); | 
 |     } | 
 |  | 
 |     $LibPath1Prefix = "./mtk_rel/$Project/$Flavor/TARGET/lib/"; | 
 |     $LibPath2Prefix = "./build/$Project/$Flavor/bin/lib/"; | 
 |  | 
 |     $tempInputFolder = $Tempdir . "CustomInputSection"; | 
 |     system("rm -rf $tempInputFolder") if(-e $tempInputFolder); | 
 |     system("mkdir -p $tempInputFolder"); | 
 |     $? == 0 or &msg_handler(FATAL, "Making $tempInputFolder failed $?", __LINE__); | 
 | } | 
 |  | 
 | sub ParseConfigFile | 
 | { | 
 |     my ($ConfigFile) = (@_); | 
 |     my $FileName = $ConfigFile; | 
 |  | 
 |     open CFG, "$ConfigFile" or &msg_handler(FATAL, "Can not open $ConfigFile!", __LINE__); | 
 |     local $/ = undef; | 
 |     my $tempOutput = <CFG>; | 
 |     close CFG; | 
 |  | 
 |     my ($SubSection, $bFlag, $sFlag) = (undef, 0, 0); | 
 |     my @TotalSecArray; | 
 |     my $BreakRegExp = "[\\*]{20}\\s[<]\\sGROUP\\s*CFG\\s[>]\\s[\\*]{20}"; | 
 |  | 
 |     #split entire config file into several configuration groups. | 
 |     foreach my $line (split /\n/, $tempOutput) { | 
 |         if($bFlag == 0) { | 
 |             $bFlag = 1 if(($line =~ m/^\[Symbol\]\s+\[Obj\]\s+\[Lib\]$/)); | 
 |             next; | 
 |         } | 
 |         next if($line =~ m/^\s*$/); | 
 |  | 
 |         if($line =~ m/^\s*$BreakRegExp\s*$/) { | 
 |             $sFlag = 1; | 
 |             if(defined $SubSection) { | 
 |                 push @TotalSecArray, $SubSection; | 
 |                 undef $SubSection; | 
 |             } | 
 |             next; | 
 |         } | 
 |         $SubSection .= $line."\n" if($sFlag == 1); | 
 |     } | 
 |     push @TotalSecArray, $SubSection if(defined $SubSection); | 
 |  | 
 |     my %unique; | 
 |     foreach my $content (@TotalSecArray) { | 
 |         my @tempArray = split /\n/, $content; | 
 |         my ($Section_ID, $name_flag, $size_flag); | 
 |         foreach my $line (@tempArray) { | 
 |             if($line =~ /^Section ID\s*:\s*(.*)$/) { | 
 |                 $Section_ID = $1; | 
 |                 if (! $Section_ID =~ /L2CACHE_LOCK_RO_SECTION_\w+/) { | 
 |                     my $msg = "Illegal Line Format: $line"; | 
 |                     &msg_handler(FATAL, "Illegal Line Format: $line", __LINE__, $FileName); | 
 |                     next; | 
 |                 } | 
 |                 &msg_handler(FATAL, "The section ID $Section_ID has been defined in config file!\n", __LINE__) if(exists $SectionIDHash{$Section_ID}); | 
 |                 $SectionIDHash{$Section_ID} = 0; | 
 |                 $name_flag = 1; | 
 |                 next; | 
 |             } elsif($line =~ /^Reserved size\s*:\s*(.*)$/ && $name_flag == 1) { | 
 |                 $Official_Config{$Section_ID}{"size"} = $1 if($ConfigFile eq $official_config); | 
 |                 $Local_Config{$Section_ID}{"size"} = $1 if($ConfigFile eq $local_config); | 
 |                 push @SectionOrder, $Section_ID; | 
 |                 $size_flag = 1; | 
 |                 next; | 
 |             } elsif(!($name_flag == 1 && $size_flag == 1)) { | 
 |                 &msg_handler(FATAL, "Wrong config format in $Section_ID!", __LINE__, $FileName); | 
 |             } | 
 |        | 
 |             if($line =~ m/^(\S+)\s+(\S+)\s+(\S+)\s*$/ && ($ConfigFile eq $official_config)) { | 
 |                 if(exists $unique{$1.":".$2.":".$3}) { | 
 |                     &msg_handler(FATAL, "[Duplicated Lines]: $line", __LINE__, $FileName); | 
 |                     next; | 
 |                 } else { | 
 |                     $Official_Config{$Section_ID}{$1.":".$2.":".$3}{"symbol_name"} = $1; | 
 |                     $Official_Config{$Section_ID}{$1.":".$2.":".$3}{"obj"} = $2; | 
 |                     $Official_Config{$Section_ID}{$1.":".$2.":".$3}{"lib"} = $3; | 
 |                     $unique{$1.":".$2.":".$3} = 0; | 
 |                     $libObjHash{$3}{$2} = 0; | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | sub ParseLibObj | 
 | { | 
 |     foreach my $lib (keys %libObjHash) { | 
 |         my $LibPath1 = $LibPath1Prefix . $lib; | 
 |         my $LibPath2 = $LibPath2Prefix . $lib; | 
 |         my $LibPath = (-e $LibPath1) ? $LibPath1 : $LibPath2; | 
 |         if(!-e $LibPath) { | 
 |             delete $libObjHash{$lib}; | 
 |             next; | 
 |         } | 
 |  | 
 |         my @ObjArray = keys %{$libObjHash{$lib}}; | 
 |         foreach my $obj (@ObjArray) { | 
 |             my $ExtractObj = $Tempdir . "CustomInputSection/" . $lib . $obj; | 
 |             my $SymLog = $ExtractObj . "." . "symbols.log"; | 
 |             my $SecLog = $ExtractObj . "." . "sections.log"; | 
 |  | 
 |             next if(-f $SymLog && -f $SecLog); #have been parsed before. | 
 |  | 
 |             #extract the obj from lib | 
 |             system("$AR -x $LibPath $obj 2> /dev/null"); | 
 |             unless(-f $obj) { | 
 |                 delete $libObjHash{$lib}{$obj}; | 
 |                 next; | 
 |             } | 
 |  | 
 |             #move the obj to certain folder | 
 |             system("mv $obj $ExtractObj"); | 
 |             $? == 0 or &msg_handler(FATAL, "$ExtractObj moving failed", __LINE__); | 
 |  | 
 |             #generate SYM log | 
 |             system("$Readelf --syms -W $ExtractObj > $SymLog"); | 
 |             $? == 0 or &msg_handler(FATAL, "Generating $SymLog failed", __LINE__); | 
 |  | 
 |             #generate SECTION log | 
 |             system("$Readelf -S -W $ExtractObj > $SecLog"); | 
 |             $? == 0 or &msg_handler(FATAL, "Generating $SecLog failed", __LINE__); | 
 |  | 
 |             &ParseSymAndSecLog($SymLog, $SecLog, $lib, $obj); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | sub ParseSymAndSecLog | 
 | { | 
 |     my ($tempSymLog, $tempSecLog, $tempLib, $tempObj) = (@_); | 
 |     my $key = $tempLib . $tempObj; | 
 |  | 
 |     open SYM_LOG, "< $tempSymLog" or &msg_handler(FATAL, "Fail to open $tempSymLog", __LINE__); | 
 |     while(my $line = <SYM_LOG>) { | 
 |         #    17: 00000024    40 FUNC    LOCAL  DEFAULT [MIPS16]     9 ev_cmp_f | 
 |         if($line =~ m/^\s*\d+\s*:\s*\S+\s+(\d+).*\s+(\d+)\s+(\w+)$/) { | 
 |             my ($Symbol, $index, $size) = ($3, $2, $1); | 
 |             $SymLogInfoHash{$key}{$Symbol}{'index'} = $index; | 
 |             $SymLogInfoHash{$key}{$Symbol}{'size'}  = $size; | 
 |         } | 
 |     } | 
 |     close SYM_LOG; | 
 |  | 
 |     open SEC_LOG, "< $tempSecLog" or &msg_handler(FATAL, "Fail to open $tempSecLog", __LINE__); | 
 |     while(my $line = <SEC_LOG>) { | 
 |         #  [22] .text.evshed_give PROGBITS        00000000 000bbc 00002c 00  AX  0   0  4 | 
 |         if($line =~ m/^\s*\[\s*(\d+)\s*\]\s+(\S+)\s+/) { | 
 |             my ($index, $Section) = ($1, $2); | 
 |             if($Section =~ m/^(\.?\w+)\.\w+$/) { | 
 |                 $SecLogInfoHash{$key}{$index}{'type'}  = $1; | 
 |                 $SecLogInfoHash{$key}{$index}{'valid'} = 'false'; | 
 |             }elsif($Section =~ m/^[^\.]*$/) { | 
 |                 $SecLogInfoHash{$key}{$index}{'type'}  = $Section; | 
 |                 $SecLogInfoHash{$key}{$index}{'valid'} = 'true'; | 
 |             } | 
 |         } | 
 |     } | 
 |     close SEC_LOG; | 
 | } | 
 |  | 
 | sub CheckUserConfiguration | 
 | { | 
 |     foreach my $id (keys %Official_Config) { | 
 |         foreach my $item (keys %{$Official_Config{$id}}) { | 
 |             next if($item eq "size"); | 
 |             my $symbol_name = $Official_Config{$id}{$item}{"symbol_name"}; | 
 |             my $obj = $Official_Config{$id}{$item}{"obj"}; | 
 |             my $lib = $Official_Config{$id}{$item}{"lib"}; | 
 |             my $SymNameInObj; | 
 |              | 
 |             if(not exists $libObjHash{$lib}) { #lib does not exist | 
 |                 my $tips = "$lib does not exist."; | 
 |                 &msg_handler(FATAL, "$symbol_name not found in Group" . "[$id]" . ": $tips", __LINE__); | 
 |                 next; | 
 |             }elsif(not exists $libObjHash{$lib}{$obj}) { #obj can't be found in lib | 
 |                 my $tips = "$symbol_name not exists in $obj."; | 
 |                 &msg_handler(FATAL, "$symbol_name not found in Group" . "[$id]" . ": $tips", __LINE__); | 
 |                 next; | 
 |             }elsif(not exists $SymLogInfoHash{$lib.$obj}) { #the symbol not exists | 
 |                 my $tips = "If your symbol type is C++, please use the full name in MAP/SYM, such as [ipfcore_task_init] -> [_Z17ipfcore_task_initv]"; | 
 |                 &msg_handler(FATAL, "$symbol_name can't be found in Group" . "[$id]" . ", $tips", __LINE__); | 
 |                 next; | 
 |             } | 
 |             my $index = $SymLogInfoHash{$lib.$obj}{$symbol_name}{"index"}; | 
 |             if(not exists $SecLogInfoHash{$lib.$obj}{$index}) { | 
 |                 &msg_handler(FATAL, "Can not find the input section of $symbol_name in [$id]!", __LINE__); | 
 |                 next; | 
 |             }elsif(not $SecLogInfoHash{$lib.$obj}{$index}{'type'} eq $id) { | 
 |                 &msg_handler(FATAL, "$symbol_name is not used $id to define. Please check!", __LINE__); | 
 |                 next; | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | sub UpdateLDS | 
 | { | 
 |     my ($LDSFile) = (@_); | 
 |     my ($output, $assert, $flag) = (undef, "", 0); | 
 |     open LDS, "< $LDSFile" or &msg_handler(FATAL, "Fail to open $LDSFile", __LINE__); | 
 |  | 
 |     while(my $line = <LDS>) { | 
 |         if($line =~ /^(\s+)Image\$\$CACHED_EXTSRAM_L2CACHE_LOCK_RO\$\$Base = \. ;/) { | 
 |             my $prefix = $1; | 
 |             $output .= $line; | 
 |             foreach my $section (@SectionOrder){ | 
 |                 my $template = <<"__TEMPLATE"; | 
 | $prefix. = ALIGN(64); | 
 | $prefix$section\$\$Base = .; | 
 | $prefix* ($section) | 
 | $prefix. = ALIGN(64); | 
 | $prefix$section\$\$Limit = .; | 
 | $prefix$section\$\$Length = ABSOLUTE($section\$\$Limit - $section\$\$Base); | 
 |  | 
 | __TEMPLATE | 
 |                 $output .= $template; | 
 |                 my $setting_size; | 
 |                 if(exists $Official_Config{$section}){ | 
 |                     $setting_size = $Official_Config{$section}{"size"}; | 
 |                 }elsif(exists $Local_Config{$section}){ | 
 |                     $setting_size = $Local_Config{$section}{"size"}; | 
 |                 }else{ | 
 |                     &msg_handler(FATAL, "The section $section is not defined in config file!", __LINE__); | 
 |                 } | 
 |                 $assert .= "    ASSERT( $section\$\$Length <= $setting_size,\"$section exceeds the setting size!\")\n"; | 
 |             } | 
 |         }elsif($line =~ /^(\s+)ASSERT\(/ && $flag == 0) { | 
 |             $output .= $assert; | 
 |             $output .= $line; | 
 |             $flag = 1; | 
 |         }else{ | 
 |             $output .= $line; | 
 |         } | 
 |     } | 
 |     close LDS; | 
 |  | 
 |     open LDS, "> $LDSFile" or &msg_handler(FATAL, "Fail to open $LDSFile", __LINE__); | 
 |     print LDS $output; | 
 |     close LDS; | 
 |  | 
 |     &msg_handler(LOG, "\nLDS is updated successfully ^O^, please check $LDSFileName.", __LINE__); | 
 | } | 
 |  | 
 | sub CleanTempFiles | 
 | { | 
 |     system("rm -rf $tempInputFolder"); | 
 |     $? == 0 or &msg_handler(FATAL, "Deleting $tempInputFolder failed $?", __LINE__); | 
 | } | 
 |  | 
 | sub msg_handler | 
 | { | 
 |     my ($type, $msg, $line_no) = (@_); | 
 |     my $prompt_prefix; | 
 |     if($type == LOG) { | 
 |         print $msg . "\n"; | 
 |     } | 
 |     elsif($type == WARNING) { | 
 |         $prompt_prefix = ">> AAIS Warning : "; | 
 |         print $prompt_prefix . $msg . "\n"; | 
 |     } | 
 |     elsif($type == FATAL) { | 
 |         $prompt_prefix = ">> *** AAIS Fatal : "; | 
 |         my $location = "[at line $line_no] "; | 
 |         die $prompt_prefix . $location . $msg . "\n"; | 
 |     } | 
 | } |