@@ -646,11 +646,36 @@ ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const {
646
646
return base () + Offset;
647
647
}
648
648
649
- template <class ELFT >
650
- Expected<std::vector<BBAddrMap>>
651
- ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
652
- const Elf_Shdr *RelaSec) const {
653
- bool IsRelocatable = getHeader ().e_type == ELF::ET_REL;
649
+ // Helper to extract and decode the next ULEB128 value as unsigned int.
650
+ // Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the unsigned
651
+ // int limit.
652
+ // Also returns zero if ULEBSizeErr is already in an error state.
653
+ // ULEBSizeErr is an out variable if an error occurs.
654
+ template <typename IntTy, std::enable_if_t <std::is_unsigned_v<IntTy>, int > = 0 >
655
+ static IntTy readULEB128As (DataExtractor &Data, DataExtractor::Cursor &Cur,
656
+ Error &ULEBSizeErr) {
657
+ // Bail out and do not extract data if ULEBSizeErr is already set.
658
+ if (ULEBSizeErr)
659
+ return 0 ;
660
+ uint64_t Offset = Cur.tell ();
661
+ uint64_t Value = Data.getULEB128 (Cur);
662
+ if (Value > std::numeric_limits<IntTy>::max ()) {
663
+ ULEBSizeErr = createError (" ULEB128 value at offset 0x" +
664
+ Twine::utohexstr (Offset) + " exceeds UINT" +
665
+ Twine (std::numeric_limits<IntTy>::digits) +
666
+ " _MAX (0x" + Twine::utohexstr (Value) + " )" );
667
+ return 0 ;
668
+ }
669
+ return static_cast <IntTy>(Value);
670
+ }
671
+
672
+ template <typename ELFT>
673
+ static Expected<std::vector<BBAddrMap>>
674
+ decodeBBAddrMapImpl (const ELFFile<ELFT> &EF,
675
+ const typename ELFFile<ELFT>::Elf_Shdr &Sec,
676
+ const typename ELFFile<ELFT>::Elf_Shdr *RelaSec,
677
+ std::vector<PGOAnalysisMap> *PGOAnalyses) {
678
+ bool IsRelocatable = EF.getHeader ().e_type == ELF::ET_REL;
654
679
655
680
// This DenseMap maps the offset of each function (the location of the
656
681
// reference to the function in the SHT_LLVM_BB_ADDR_MAP section) to the
@@ -660,44 +685,28 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
660
685
assert (RelaSec &&
661
686
" Can't read a SHT_LLVM_BB_ADDR_MAP section in a relocatable "
662
687
" object file without providing a relocation section." );
663
- Expected<Elf_Rela_Range> Relas = this -> relas (*RelaSec);
688
+ Expected<typename ELFFile<ELFT>:: Elf_Rela_Range> Relas = EF. relas (*RelaSec);
664
689
if (!Relas)
665
690
return createError (" unable to read relocations for section " +
666
- describe (* this , Sec) + " : " +
691
+ describe (EF , Sec) + " : " +
667
692
toString (Relas.takeError ()));
668
- for (Elf_Rela Rela : *Relas)
693
+ for (typename ELFFile<ELFT>:: Elf_Rela Rela : *Relas)
669
694
FunctionOffsetTranslations[Rela.r_offset ] = Rela.r_addend ;
670
695
}
671
- Expected<ArrayRef<uint8_t >> ContentsOrErr = getSectionContents (Sec);
696
+ Expected<ArrayRef<uint8_t >> ContentsOrErr = EF. getSectionContents (Sec);
672
697
if (!ContentsOrErr)
673
698
return ContentsOrErr.takeError ();
674
699
ArrayRef<uint8_t > Content = *ContentsOrErr;
675
- DataExtractor Data (Content, isLE (), ELFT::Is64Bits ? 8 : 4 );
700
+ DataExtractor Data (Content, EF. isLE (), ELFT::Is64Bits ? 8 : 4 );
676
701
std::vector<BBAddrMap> FunctionEntries;
677
702
678
703
DataExtractor::Cursor Cur (0 );
679
704
Error ULEBSizeErr = Error::success ();
680
705
Error MetadataDecodeErr = Error::success ();
681
- // Helper to extract and decode the next ULEB128 value as uint32_t.
682
- // Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the uint32_t
683
- // limit.
684
- // Also returns zero if ULEBSizeErr is already in an error state.
685
- auto ReadULEB128AsUInt32 = [&Data, &Cur, &ULEBSizeErr]() -> uint32_t {
686
- // Bail out and do not extract data if ULEBSizeErr is already set.
687
- if (ULEBSizeErr)
688
- return 0 ;
689
- uint64_t Offset = Cur.tell ();
690
- uint64_t Value = Data.getULEB128 (Cur);
691
- if (Value > UINT32_MAX) {
692
- ULEBSizeErr = createError (
693
- " ULEB128 value at offset 0x" + Twine::utohexstr (Offset) +
694
- " exceeds UINT32_MAX (0x" + Twine::utohexstr (Value) + " )" );
695
- return 0 ;
696
- }
697
- return static_cast <uint32_t >(Value);
698
- };
699
706
700
707
uint8_t Version = 0 ;
708
+ uint8_t Feature = 0 ;
709
+ PGOAnalysisMap::Features FeatEnable{};
701
710
while (!ULEBSizeErr && !MetadataDecodeErr && Cur &&
702
711
Cur.tell () < Content.size ()) {
703
712
if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
@@ -707,10 +716,24 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
707
716
if (Version > 2 )
708
717
return createError (" unsupported SHT_LLVM_BB_ADDR_MAP version: " +
709
718
Twine (static_cast <int >(Version)));
710
- Data.getU8 (Cur); // Feature byte
719
+ Feature = Data.getU8 (Cur); // Feature byte
720
+ if (!Cur)
721
+ break ;
722
+ auto FeatEnableOrErr = PGOAnalysisMap::Features::decode (Feature);
723
+ if (!FeatEnableOrErr)
724
+ return FeatEnableOrErr.takeError ();
725
+ FeatEnable =
726
+ FeatEnableOrErr ? *FeatEnableOrErr : PGOAnalysisMap::Features{};
727
+ if (Feature != 0 && Version < 2 && Cur)
728
+ return createError (
729
+ " version should be >= 2 for SHT_LLVM_BB_ADDR_MAP when "
730
+ " PGO features are enabled: version = " +
731
+ Twine (static_cast <int >(Version)) +
732
+ " feature = " + Twine (static_cast <int >(Feature)));
711
733
}
712
734
uint64_t SectionOffset = Cur.tell ();
713
- uintX_t Address = static_cast <uintX_t>(Data.getAddress (Cur));
735
+ auto Address =
736
+ static_cast <typename ELFFile<ELFT>::uintX_t>(Data.getAddress (Cur));
714
737
if (!Cur)
715
738
return Cur.takeError ();
716
739
if (IsRelocatable) {
@@ -719,20 +742,23 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
719
742
if (FOTIterator == FunctionOffsetTranslations.end ()) {
720
743
return createError (" failed to get relocation data for offset: " +
721
744
Twine::utohexstr (SectionOffset) + " in section " +
722
- describe (* this , Sec));
745
+ describe (EF , Sec));
723
746
}
724
747
Address = FOTIterator->second ;
725
748
}
726
- uint32_t NumBlocks = ReadULEB128AsUInt32 ();
749
+ uint32_t NumBlocks = readULEB128As<uint32_t >(Data, Cur, ULEBSizeErr);
750
+
727
751
std::vector<BBAddrMap::BBEntry> BBEntries;
728
752
uint32_t PrevBBEndOffset = 0 ;
729
753
for (uint32_t BlockIndex = 0 ;
730
754
!MetadataDecodeErr && !ULEBSizeErr && Cur && (BlockIndex < NumBlocks);
731
755
++BlockIndex) {
732
- uint32_t ID = Version >= 2 ? ReadULEB128AsUInt32 () : BlockIndex;
733
- uint32_t Offset = ReadULEB128AsUInt32 ();
734
- uint32_t Size = ReadULEB128AsUInt32 ();
735
- uint32_t MD = ReadULEB128AsUInt32 ();
756
+ uint32_t ID = Version >= 2
757
+ ? readULEB128As<uint32_t >(Data, Cur, ULEBSizeErr)
758
+ : BlockIndex;
759
+ uint32_t Offset = readULEB128As<uint32_t >(Data, Cur, ULEBSizeErr);
760
+ uint32_t Size = readULEB128As<uint32_t >(Data, Cur, ULEBSizeErr);
761
+ uint32_t MD = readULEB128As<uint32_t >(Data, Cur, ULEBSizeErr);
736
762
if (Version >= 1 ) {
737
763
// Offset is calculated relative to the end of the previous BB.
738
764
Offset += PrevBBEndOffset;
@@ -747,6 +773,44 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
747
773
BBEntries.push_back ({ID, Offset, Size, *MetadataOrErr});
748
774
}
749
775
FunctionEntries.emplace_back (Address, std::move (BBEntries));
776
+
777
+ if (FeatEnable.FuncEntryCount || FeatEnable.BBFreq || FeatEnable.BrProb ) {
778
+ // Function entry count
779
+ uint64_t FuncEntryCount =
780
+ FeatEnable.FuncEntryCount
781
+ ? readULEB128As<uint64_t >(Data, Cur, ULEBSizeErr)
782
+ : 0 ;
783
+
784
+ std::vector<PGOAnalysisMap::PGOBBEntry> PGOBBEntries;
785
+ for (uint32_t BlockIndex = 0 ; !MetadataDecodeErr && !ULEBSizeErr && Cur &&
786
+ (BlockIndex < NumBlocks);
787
+ ++BlockIndex) {
788
+ // Block frequency
789
+ uint64_t BBF = FeatEnable.BBFreq
790
+ ? readULEB128As<uint64_t >(Data, Cur, ULEBSizeErr)
791
+ : 0 ;
792
+
793
+ // Branch probability
794
+ llvm::SmallVector<PGOAnalysisMap::PGOBBEntry::SuccessorEntry, 2 >
795
+ Successors;
796
+ if (FeatEnable.BrProb ) {
797
+ auto SuccCount = readULEB128As<uint64_t >(Data, Cur, ULEBSizeErr);
798
+ for (uint64_t I = 0 ; I < SuccCount; ++I) {
799
+ uint32_t BBID = readULEB128As<uint32_t >(Data, Cur, ULEBSizeErr);
800
+ uint32_t BrProb = readULEB128As<uint32_t >(Data, Cur, ULEBSizeErr);
801
+ if (PGOAnalyses)
802
+ Successors.push_back ({BBID, BranchProbability::getRaw (BrProb)});
803
+ }
804
+ }
805
+
806
+ if (PGOAnalyses)
807
+ PGOBBEntries.push_back ({BlockFrequency (BBF), std::move (Successors)});
808
+ }
809
+
810
+ if (PGOAnalyses)
811
+ PGOAnalyses->push_back (
812
+ {FuncEntryCount, std::move (PGOBBEntries), FeatEnable});
813
+ }
750
814
}
751
815
// Either Cur is in the error state, or we have an error in ULEBSizeErr or
752
816
// MetadataDecodeErr (but not both), but we join all errors here to be safe.
@@ -756,6 +820,18 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
756
820
return FunctionEntries;
757
821
}
758
822
823
+ template <class ELFT >
824
+ Expected<std::vector<BBAddrMap>>
825
+ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, const Elf_Shdr *RelaSec,
826
+ std::vector<PGOAnalysisMap> *PGOAnalyses) const {
827
+ size_t OriginalPGOSize = PGOAnalyses ? PGOAnalyses->size () : 0 ;
828
+ auto AddrMapsOrErr = decodeBBAddrMapImpl (*this , Sec, RelaSec, PGOAnalyses);
829
+ // remove new analyses when an error occurs
830
+ if (!AddrMapsOrErr && PGOAnalyses)
831
+ PGOAnalyses->resize (OriginalPGOSize);
832
+ return std::move (AddrMapsOrErr);
833
+ }
834
+
759
835
template <class ELFT >
760
836
Expected<
761
837
MapVector<const typename ELFT::Shdr *, const typename ELFT::Shdr *>>
0 commit comments