1 //===- MergedFunctionsInfo.cpp ----------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/DebugInfo/GSYM/MergedFunctionsInfo.h" 10 #include "llvm/DebugInfo/GSYM/FileWriter.h" 11 #include "llvm/DebugInfo/GSYM/FunctionInfo.h" 12 #include "llvm/Support/DataExtractor.h" 13 14 using namespace llvm; 15 using namespace gsym; 16 17 void MergedFunctionsInfo::clear() { MergedFunctions.clear(); } 18 19 llvm::Error MergedFunctionsInfo::encode(FileWriter &Out) const { 20 Out.writeU32(MergedFunctions.size()); 21 for (const auto &F : MergedFunctions) { 22 Out.writeU32(0); 23 const auto StartOffset = Out.tell(); 24 // Encode the FunctionInfo with no padding so later we can just read them 25 // one after the other without knowing the offset in the stream for each. 26 llvm::Expected<uint64_t> result = F.encode(Out, /*NoPadding =*/true); 27 if (!result) 28 return result.takeError(); 29 const auto Length = Out.tell() - StartOffset; 30 Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4); 31 } 32 return Error::success(); 33 } 34 35 llvm::Expected<MergedFunctionsInfo> 36 MergedFunctionsInfo::decode(DataExtractor &Data, uint64_t BaseAddr) { 37 MergedFunctionsInfo MFI; 38 auto FuncExtractorsOrError = MFI.getFuncsDataExtractors(Data); 39 40 if (!FuncExtractorsOrError) 41 return FuncExtractorsOrError.takeError(); 42 43 for (DataExtractor &FuncData : *FuncExtractorsOrError) { 44 llvm::Expected<FunctionInfo> FI = FunctionInfo::decode(FuncData, BaseAddr); 45 if (!FI) 46 return FI.takeError(); 47 MFI.MergedFunctions.push_back(std::move(*FI)); 48 } 49 50 return MFI; 51 } 52 53 llvm::Expected<std::vector<DataExtractor>> 54 MergedFunctionsInfo::getFuncsDataExtractors(DataExtractor &Data) { 55 std::vector<DataExtractor> Results; 56 uint64_t Offset = 0; 57 58 // Ensure there is enough data to read the function count. 59 if (!Data.isValidOffsetForDataOfSize(Offset, 4)) 60 return createStringError( 61 std::errc::io_error, 62 "unable to read the function count at offset 0x%8.8" PRIx64, Offset); 63 64 uint32_t Count = Data.getU32(&Offset); 65 66 for (uint32_t i = 0; i < Count; ++i) { 67 // Ensure there is enough data to read the function size. 68 if (!Data.isValidOffsetForDataOfSize(Offset, 4)) 69 return createStringError( 70 std::errc::io_error, 71 "unable to read size of function %u at offset 0x%8.8" PRIx64, i, 72 Offset); 73 74 uint32_t FnSize = Data.getU32(&Offset); 75 76 // Ensure there is enough data for the function content. 77 if (!Data.isValidOffsetForDataOfSize(Offset, FnSize)) 78 return createStringError( 79 std::errc::io_error, 80 "function data is truncated for function %u at offset 0x%8.8" PRIx64 81 ", expected size %u", 82 i, Offset, FnSize); 83 84 // Extract the function data. 85 Results.emplace_back(Data.getData().substr(Offset, FnSize), 86 Data.isLittleEndian(), Data.getAddressSize()); 87 88 Offset += FnSize; 89 } 90 return Results; 91 } 92 93 bool operator==(const MergedFunctionsInfo &LHS, 94 const MergedFunctionsInfo &RHS) { 95 return LHS.MergedFunctions == RHS.MergedFunctions; 96 } 97