| #!/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"; |
| } |
| } |