-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[Object] Parsing and dumping of SFrame Frame Row Entries #151301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,14 +32,25 @@ getDataSlice(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Size) { | |
} | ||
|
||
template <typename T> | ||
static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data, | ||
uint64_t Offset) { | ||
static Expected<ArrayRef<T>> | ||
getDataSliceAsArrayOf(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Count) { | ||
static_assert(std::is_trivial_v<T>); | ||
Expected<ArrayRef<uint8_t>> Slice = getDataSlice(Data, Offset, sizeof(T)); | ||
Expected<ArrayRef<uint8_t>> Slice = | ||
getDataSlice(Data, Offset, sizeof(T) * Count); | ||
if (!Slice) | ||
return Slice.takeError(); | ||
|
||
return *reinterpret_cast<const T *>(Slice->data()); | ||
return ArrayRef(reinterpret_cast<const T *>(Slice->data()), Count); | ||
} | ||
|
||
template <typename T> | ||
static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data, | ||
uint64_t Offset) { | ||
Expected<ArrayRef<T>> Array = getDataSliceAsArrayOf<T>(Data, Offset, 1); | ||
if (!Array) | ||
return Array.takeError(); | ||
|
||
return Array->front(); | ||
} | ||
|
||
template <endianness E> | ||
|
@@ -100,6 +111,116 @@ uint64_t SFrameParser<E>::getAbsoluteStartAddress( | |
return Result; | ||
} | ||
|
||
template <typename EndianT> | ||
static Error readArray(ArrayRef<uint8_t> Data, uint64_t Count, uint64_t &Offset, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this returning an |
||
SmallVectorImpl<int32_t> &Vec) { | ||
Expected<ArrayRef<EndianT>> RawArray = | ||
getDataSliceAsArrayOf<EndianT>(Data, Offset, Count); | ||
if (!RawArray) | ||
return RawArray.takeError(); | ||
Offset += Count * sizeof(EndianT); | ||
Vec.resize(Count); | ||
llvm::copy(*RawArray, Vec.begin()); | ||
return Error::success(); | ||
} | ||
|
||
template <typename T, endianness E> | ||
static Error readFRE(ArrayRef<uint8_t> Data, uint64_t &Offset, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question. |
||
typename SFrameParser<E>::FrameRowEntry &FRE) { | ||
Expected<sframe::FrameRowEntry<T, E>> RawFRE = | ||
getDataSliceAs<sframe::FrameRowEntry<T, E>>(Data, Offset); | ||
if (!RawFRE) | ||
return RawFRE.takeError(); | ||
|
||
Offset += sizeof(*RawFRE); | ||
FRE.StartAddress = RawFRE->StartAddress; | ||
FRE.Info.Info = RawFRE->Info.Info; | ||
|
||
switch (FRE.Info.getOffsetSize()) { | ||
case sframe::FREOffset::B1: | ||
return readArray<sframe::detail::packed<int8_t, E>>( | ||
Data, FRE.Info.getOffsetCount(), Offset, FRE.Offsets); | ||
case sframe::FREOffset::B2: | ||
return readArray<sframe::detail::packed<int16_t, E>>( | ||
Data, FRE.Info.getOffsetCount(), Offset, FRE.Offsets); | ||
case sframe::FREOffset::B4: | ||
return readArray<sframe::detail::packed<int32_t, E>>( | ||
Data, FRE.Info.getOffsetCount(), Offset, FRE.Offsets); | ||
default: | ||
return createError("unsupported/unknown offset size"); | ||
} | ||
} | ||
|
||
template <endianness E> Error SFrameParser<E>::FallibleFREIterator::inc() { | ||
if (++Idx == Size) | ||
return Error::success(); | ||
|
||
switch (FREType) { | ||
case sframe::FREType::Addr1: | ||
return readFRE<uint8_t, E>(Data, Offset, FRE); | ||
case sframe::FREType::Addr2: | ||
return readFRE<uint16_t, E>(Data, Offset, FRE); | ||
case sframe::FREType::Addr4: | ||
return readFRE<uint32_t, E>(Data, Offset, FRE); | ||
default: | ||
return createError("invalid/unsupported FRE type"); | ||
} | ||
} | ||
|
||
template <endianness E> | ||
iterator_range<typename SFrameParser<E>::fre_iterator> | ||
SFrameParser<E>::fres(const sframe::FuncDescEntry<E> &FDE, Error &Err) const { | ||
uint64_t Offset = getFREBase() + FDE.StartFREOff; | ||
fre_iterator BeforeBegin = make_fallible_itr( | ||
FallibleFREIterator(Data, FDE.getFREType(), -1, FDE.NumFREs, Offset), | ||
Err); | ||
fre_iterator End = make_fallible_end( | ||
FallibleFREIterator(Data, FDE.getFREType(), FDE.NumFREs, FDE.NumFREs, | ||
/*Offset=*/0)); | ||
return {++BeforeBegin, End}; | ||
} | ||
|
||
static std::optional<int32_t> getOffset(ArrayRef<int32_t> Offsets, size_t Idx) { | ||
if (Offsets.size() > Idx) | ||
return Offsets[Idx]; | ||
return std::nullopt; | ||
} | ||
|
||
template <endianness E> | ||
std::optional<int32_t> | ||
SFrameParser<E>::getCFAOffset(const FrameRowEntry &FRE) const { | ||
return getOffset(FRE.Offsets, 0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little concerned about this and the similar code in the following blocks, mostly because future ABIs/architectures won't necessarily have the same meanings for the different offsets. It's probably sufficient for now to add a comment or two highlighting that all supported ABIs use the specified offset. |
||
} | ||
|
||
template <endianness E> | ||
std::optional<int32_t> | ||
SFrameParser<E>::getRAOffset(const FrameRowEntry &FRE) const { | ||
if (usesFixedRAOffset()) | ||
return Header.CFAFixedRAOffset; | ||
return getOffset(FRE.Offsets, 1); | ||
} | ||
|
||
template <endianness E> | ||
std::optional<int32_t> | ||
SFrameParser<E>::getFPOffset(const FrameRowEntry &FRE) const { | ||
if (usesFixedFPOffset()) | ||
return Header.CFAFixedFPOffset; | ||
return getOffset(FRE.Offsets, usesFixedRAOffset() ? 1 : 2); | ||
} | ||
|
||
template <endianness E> | ||
ArrayRef<int32_t> | ||
SFrameParser<E>::getExtraOffsets(const FrameRowEntry &FRE) const { | ||
size_t UsedOffsets = 1; // CFA | ||
if (!usesFixedRAOffset()) | ||
++UsedOffsets; | ||
if (!usesFixedFPOffset()) | ||
++UsedOffsets; | ||
if (FRE.Offsets.size() > UsedOffsets) | ||
return ArrayRef(FRE.Offsets).drop_front(UsedOffsets); | ||
return {}; | ||
} | ||
|
||
template class LLVM_EXPORT_TEMPLATE llvm::object::SFrameParser<endianness::big>; | ||
template class LLVM_EXPORT_TEMPLATE | ||
llvm::object::SFrameParser<endianness::little>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm probably missing something, but why not just have the static local exposed as a constant without the function wrapper?