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
14using namespace llvm;
15using namespace gsym;
16
17void MergedFunctionsInfo::clear() { MergedFunctions.clear(); }
18
19llvm::Error MergedFunctionsInfo::encode(FileWriter &Out) const {
20 Out.writeU32(Value: MergedFunctions.size());
21 for (const auto &F : MergedFunctions) {
22 Out.writeU32(Value: 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(O&: Out, /*NoPadding =*/true);
27 if (!result)
28 return result.takeError();
29 const auto Length = Out.tell() - StartOffset;
30 Out.fixup32(Value: static_cast<uint32_t>(Length), Offset: StartOffset - 4);
31 }
32 return Error::success();
33}
34
35llvm::Expected<MergedFunctionsInfo>
36MergedFunctionsInfo::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(Data&: FuncData, BaseAddr);
45 if (!FI)
46 return FI.takeError();
47 MFI.MergedFunctions.push_back(x: std::move(*FI));
48 }
49
50 return MFI;
51}
52
53llvm::Expected<std::vector<DataExtractor>>
54MergedFunctionsInfo::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: Offset, length: 4))
60 return createStringError(
61 EC: std::errc::io_error,
62 Fmt: "unable to read the function count at offset 0x%8.8" PRIx64, Vals: Offset);
63
64 uint32_t Count = Data.getU32(offset_ptr: &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: Offset, length: 4))
69 return createStringError(
70 EC: std::errc::io_error,
71 Fmt: "unable to read size of function %u at offset 0x%8.8" PRIx64, Vals: i,
72 Vals: Offset);
73
74 uint32_t FnSize = Data.getU32(offset_ptr: &Offset);
75
76 // Ensure there is enough data for the function content.
77 if (!Data.isValidOffsetForDataOfSize(offset: Offset, length: FnSize))
78 return createStringError(
79 EC: std::errc::io_error,
80 Fmt: "function data is truncated for function %u at offset 0x%8.8" PRIx64
81 ", expected size %u",
82 Vals: i, Vals: Offset, Vals: FnSize);
83
84 // Extract the function data.
85 Results.emplace_back(args: Data.getData().substr(Start: Offset, N: FnSize),
86 args: Data.isLittleEndian(), args: Data.getAddressSize());
87
88 Offset += FnSize;
89 }
90 return Results;
91}
92
93bool operator==(const MergedFunctionsInfo &LHS,
94 const MergedFunctionsInfo &RHS) {
95 return LHS.MergedFunctions == RHS.MergedFunctions;
96}
97