1 //===- InlineInfo.cpp -------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/DebugInfo/GSYM/FileEntry.h"
11 #include "llvm/DebugInfo/GSYM/FileWriter.h"
12 #include "llvm/DebugInfo/GSYM/InlineInfo.h"
13 #include "llvm/Support/DataExtractor.h"
21 raw_ostream
&llvm::gsym::operator<<(raw_ostream
&OS
, const InlineInfo
&II
) {
25 for (auto Range
: II
.Ranges
) {
32 OS
<< " Name = " << HEX32(II
.Name
) << ", CallFile = " << II
.CallFile
33 << ", CallLine = " << II
.CallFile
<< '\n';
34 for (const auto &Child
: II
.Children
)
39 static bool getInlineStackHelper(const InlineInfo
&II
, uint64_t Addr
,
40 std::vector
<const InlineInfo
*> &InlineStack
) {
41 if (II
.Ranges
.contains(Addr
)) {
42 // If this is the top level that represents the concrete function,
43 // there will be no name and we shoud clear the inline stack. Otherwise
44 // we have found an inline call stack that we need to insert.
46 InlineStack
.insert(InlineStack
.begin(), &II
);
47 for (const auto &Child
: II
.Children
) {
48 if (::getInlineStackHelper(Child
, Addr
, InlineStack
))
51 return !InlineStack
.empty();
56 llvm::Optional
<InlineInfo::InlineArray
> InlineInfo::getInlineStack(uint64_t Addr
) const {
58 if (getInlineStackHelper(*this, Addr
, Result
))
63 /// Decode an InlineInfo in Data at the specified offset.
65 /// A local helper function to decode InlineInfo objects. This function is
66 /// called recursively when parsing child InlineInfo objects.
68 /// \param Data The data extractor to decode from.
69 /// \param Offset The offset within \a Data to decode from.
70 /// \param BaseAddr The base address to use when decoding address ranges.
71 /// \returns An InlineInfo or an error describing the issue that was
72 /// encountered during decoding.
73 static llvm::Expected
<InlineInfo
> decode(DataExtractor
&Data
, uint64_t &Offset
,
76 if (!Data
.isValidOffset(Offset
))
77 return createStringError(std::errc::io_error
,
78 "0x%8.8" PRIx64
": missing InlineInfo address ranges data", Offset
);
79 Inline
.Ranges
.decode(Data
, BaseAddr
, Offset
);
80 if (Inline
.Ranges
.empty())
82 if (!Data
.isValidOffsetForDataOfSize(Offset
, 1))
83 return createStringError(std::errc::io_error
,
84 "0x%8.8" PRIx64
": missing InlineInfo uint8_t indicating children",
86 bool HasChildren
= Data
.getU8(&Offset
) != 0;
87 if (!Data
.isValidOffsetForDataOfSize(Offset
, 4))
88 return createStringError(std::errc::io_error
,
89 "0x%8.8" PRIx64
": missing InlineInfo uint32_t for name", Offset
);
90 Inline
.Name
= Data
.getU32(&Offset
);
91 if (!Data
.isValidOffset(Offset
))
92 return createStringError(std::errc::io_error
,
93 "0x%8.8" PRIx64
": missing ULEB128 for InlineInfo call file", Offset
);
94 Inline
.CallFile
= (uint32_t)Data
.getULEB128(&Offset
);
95 if (!Data
.isValidOffset(Offset
))
96 return createStringError(std::errc::io_error
,
97 "0x%8.8" PRIx64
": missing ULEB128 for InlineInfo call line", Offset
);
98 Inline
.CallLine
= (uint32_t)Data
.getULEB128(&Offset
);
100 // Child address ranges are encoded relative to the first address in the
101 // parent InlineInfo object.
102 const auto ChildBaseAddr
= Inline
.Ranges
[0].Start
;
104 llvm::Expected
<InlineInfo
> Child
= decode(Data
, Offset
, ChildBaseAddr
);
106 return Child
.takeError();
107 // InlineInfo with empty Ranges termintes a child sibling chain.
108 if (Child
.get().Ranges
.empty())
110 Inline
.Children
.emplace_back(std::move(*Child
));
116 llvm::Expected
<InlineInfo
> InlineInfo::decode(DataExtractor
&Data
,
119 return ::decode(Data
, Offset
, BaseAddr
);
122 llvm::Error
InlineInfo::encode(FileWriter
&O
, uint64_t BaseAddr
) const {
123 // Users must verify the InlineInfo is valid prior to calling this funtion.
124 // We don't want to emit any InlineInfo objects if they are not valid since
125 // it will waste space in the GSYM file.
127 return createStringError(std::errc::invalid_argument
,
128 "attempted to encode invalid InlineInfo object");
129 Ranges
.encode(O
, BaseAddr
);
130 bool HasChildren
= !Children
.empty();
131 O
.writeU8(HasChildren
);
133 O
.writeULEB(CallFile
);
134 O
.writeULEB(CallLine
);
136 // Child address ranges are encoded as relative to the first
137 // address in the Ranges for this object. This keeps the offsets
138 // small and allows for efficient encoding using ULEB offsets.
139 const uint64_t ChildBaseAddr
= Ranges
[0].Start
;
140 for (const auto &Child
: Children
) {
141 // Make sure all child address ranges are contained in the parent address
143 for (const auto &ChildRange
: Child
.Ranges
) {
144 if (!Ranges
.contains(ChildRange
))
145 return createStringError(std::errc::invalid_argument
,
146 "child range not contained in parent");
148 llvm::Error Err
= Child
.encode(O
, ChildBaseAddr
);
153 // Terminate child sibling chain by emitting a zero. This zero will cause
154 // the decodeAll() function above to return false and stop the decoding
155 // of child InlineInfo objects that are siblings.
158 return Error::success();