@@ -646,11 +646,36 @@ ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const {
646646 return base () + Offset;
647647}
648648
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;
654679
655680 // This DenseMap maps the offset of each function (the location of the
656681 // 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,
660685 assert (RelaSec &&
661686 " Can't read a SHT_LLVM_BB_ADDR_MAP section in a relocatable "
662687 " 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);
664689 if (!Relas)
665690 return createError (" unable to read relocations for section " +
666- describe (* this , Sec) + " : " +
691+ describe (EF , Sec) + " : " +
667692 toString (Relas.takeError ()));
668- for (Elf_Rela Rela : *Relas)
693+ for (typename ELFFile<ELFT>:: Elf_Rela Rela : *Relas)
669694 FunctionOffsetTranslations[Rela.r_offset ] = Rela.r_addend ;
670695 }
671- Expected<ArrayRef<uint8_t >> ContentsOrErr = getSectionContents (Sec);
696+ Expected<ArrayRef<uint8_t >> ContentsOrErr = EF. getSectionContents (Sec);
672697 if (!ContentsOrErr)
673698 return ContentsOrErr.takeError ();
674699 ArrayRef<uint8_t > Content = *ContentsOrErr;
675- DataExtractor Data (Content, isLE (), ELFT::Is64Bits ? 8 : 4 );
700+ DataExtractor Data (Content, EF. isLE (), ELFT::Is64Bits ? 8 : 4 );
676701 std::vector<BBAddrMap> FunctionEntries;
677702
678703 DataExtractor::Cursor Cur (0 );
679704 Error ULEBSizeErr = Error::success ();
680705 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- };
699706
700707 uint8_t Version = 0 ;
708+ uint8_t Feature = 0 ;
709+ PGOAnalysisMap::Features FeatEnable{};
701710 while (!ULEBSizeErr && !MetadataDecodeErr && Cur &&
702711 Cur.tell () < Content.size ()) {
703712 if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
@@ -707,10 +716,24 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
707716 if (Version > 2 )
708717 return createError (" unsupported SHT_LLVM_BB_ADDR_MAP version: " +
709718 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)));
711733 }
712734 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));
714737 if (!Cur)
715738 return Cur.takeError ();
716739 if (IsRelocatable) {
@@ -719,20 +742,23 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
719742 if (FOTIterator == FunctionOffsetTranslations.end ()) {
720743 return createError (" failed to get relocation data for offset: " +
721744 Twine::utohexstr (SectionOffset) + " in section " +
722- describe (* this , Sec));
745+ describe (EF , Sec));
723746 }
724747 Address = FOTIterator->second ;
725748 }
726- uint32_t NumBlocks = ReadULEB128AsUInt32 ();
749+ uint32_t NumBlocks = readULEB128As<uint32_t >(Data, Cur, ULEBSizeErr);
750+
727751 std::vector<BBAddrMap::BBEntry> BBEntries;
728752 uint32_t PrevBBEndOffset = 0 ;
729753 for (uint32_t BlockIndex = 0 ;
730754 !MetadataDecodeErr && !ULEBSizeErr && Cur && (BlockIndex < NumBlocks);
731755 ++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);
736762 if (Version >= 1 ) {
737763 // Offset is calculated relative to the end of the previous BB.
738764 Offset += PrevBBEndOffset;
@@ -747,6 +773,44 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
747773 BBEntries.push_back ({ID, Offset, Size, *MetadataOrErr});
748774 }
749775 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+ }
750814 }
751815 // Either Cur is in the error state, or we have an error in ULEBSizeErr or
752816 // MetadataDecodeErr (but not both), but we join all errors here to be safe.
@@ -756,6 +820,18 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
756820 return FunctionEntries;
757821}
758822
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+
759835template <class ELFT >
760836Expected<
761837 MapVector<const typename ELFT::Shdr *, const typename ELFT::Shdr *>>
0 commit comments