Skip to content

Commit aa7ada1

Browse files
authored
[Object] Beginnings of SFrame parser and dumper (llvm#147294)
This PR adds the SFrameParser class and uses it from llvm-readobj to dump the section contents. Currently, it only supports parsing the SFrame section header. Other parts of the section will be added in follow-up patches. llvm-readobj uses the same sframe flag syntax as GNU readelf, but I have not attempted match the output format of the tool. I'm starting with the "llvm" output format because it's easier to generate and lets us tweak the format to make it useful for testing the generation code. If needed, support for the GNU format could be added by overriding this functionality in the GNU ELF Dumper. For more information, see the [sframe specification](https://sourceware.org/binutils/wiki/sframe) and the related [RFC](https://discourse.llvm.org/t/rfc-adding-sframe-support-to-llvm/86900).
1 parent 84e689b commit aa7ada1

File tree

13 files changed

+420
-13
lines changed

13 files changed

+420
-13
lines changed

llvm/include/llvm/BinaryFormat/SFrame.h

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,36 @@
1515
#ifndef LLVM_BINARYFORMAT_SFRAME_H
1616
#define LLVM_BINARYFORMAT_SFRAME_H
1717

18+
#include "llvm/ADT/ArrayRef.h"
1819
#include "llvm/ADT/BitmaskEnum.h"
1920
#include "llvm/Support/DataTypes.h"
2021
#include "llvm/Support/Endian.h"
2122

22-
namespace llvm::sframe {
23+
namespace llvm {
24+
25+
template <typename T> struct EnumEntry;
26+
27+
namespace sframe {
2328

2429
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
2530

2631
constexpr uint16_t Magic = 0xdee2;
2732

2833
enum class Version : uint8_t {
29-
V1 = 1,
30-
V2 = 2,
34+
#define HANDLE_SFRAME_VERSION(CODE, NAME) NAME = CODE,
35+
#include "llvm/BinaryFormat/SFrameConstants.def"
3136
};
3237

3338
enum class Flags : uint8_t {
34-
FDESorted = 0x01,
35-
FramePointer = 0x02,
36-
FDEFuncStartPCRel = 0x04,
39+
#define HANDLE_SFRAME_FLAG(CODE, NAME) NAME = CODE,
40+
#include "llvm/BinaryFormat/SFrameConstants.def"
3741
V2AllFlags = FDESorted | FramePointer | FDEFuncStartPCRel,
3842
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/0xff),
3943
};
4044

4145
enum class ABI : uint8_t {
42-
AArch64EndianBig = 1,
43-
AArch64EndianLittle = 2,
44-
AMD64EndianLittle = 3,
46+
#define HANDLE_SFRAME_ABI(CODE, NAME) NAME = CODE,
47+
#include "llvm/BinaryFormat/SFrameConstants.def"
4548
};
4649

4750
/// SFrame FRE Types. Bits 0-3 of FuncDescEntry.Info.
@@ -160,6 +163,11 @@ template <endianness E> using FrameRowEntryAddr1 = FrameRowEntry<uint8_t, E>;
160163
template <endianness E> using FrameRowEntryAddr2 = FrameRowEntry<uint16_t, E>;
161164
template <endianness E> using FrameRowEntryAddr4 = FrameRowEntry<uint32_t, E>;
162165

163-
} // namespace llvm::sframe
166+
ArrayRef<EnumEntry<Version>> getVersions();
167+
ArrayRef<EnumEntry<Flags>> getFlags();
168+
ArrayRef<EnumEntry<ABI>> getABIs();
169+
170+
} // namespace sframe
171+
} // namespace llvm
164172

165173
#endif // LLVM_BINARYFORMAT_SFRAME_H
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===- SFrameConstants.def --------------------------------------*- 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+
#if !(defined(HANDLE_SFRAME_VERSION) || defined(HANDLE_SFRAME_FLAG) || \
10+
defined(HANDLE_SFRAME_ABI))
11+
#error "Missing HANDLE_SFRAME definition"
12+
#endif
13+
14+
#ifndef HANDLE_SFRAME_VERSION
15+
#define HANDLE_SFRAME_VERSION(CODE, NAME)
16+
#endif
17+
18+
#ifndef HANDLE_SFRAME_FLAG
19+
#define HANDLE_SFRAME_FLAG(CODE, NAME)
20+
#endif
21+
22+
#ifndef HANDLE_SFRAME_ABI
23+
#define HANDLE_SFRAME_ABI(CODE, NAME)
24+
#endif
25+
26+
HANDLE_SFRAME_VERSION(0x01, V1)
27+
HANDLE_SFRAME_VERSION(0x02, V2)
28+
29+
HANDLE_SFRAME_FLAG(0x01, FDESorted)
30+
HANDLE_SFRAME_FLAG(0x02, FramePointer)
31+
HANDLE_SFRAME_FLAG(0x04, FDEFuncStartPCRel)
32+
33+
HANDLE_SFRAME_ABI(0x01, AArch64EndianBig)
34+
HANDLE_SFRAME_ABI(0x02, AArch64EndianLittle)
35+
HANDLE_SFRAME_ABI(0x03, AMD64EndianLittle)
36+
37+
#undef HANDLE_SFRAME_VERSION
38+
#undef HANDLE_SFRAME_FLAG
39+
#undef HANDLE_SFRAME_ABI
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===- SFrameParser.h -------------------------------------------*- 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+
#ifndef LLVM_OBJECT_SFRAME_H
10+
#define LLVM_OBJECT_SFRAME_H
11+
12+
#include "llvm/ADT/ArrayRef.h"
13+
#include "llvm/BinaryFormat/SFrame.h"
14+
#include "llvm/Support/Error.h"
15+
#include <cstdint>
16+
17+
namespace llvm {
18+
namespace object {
19+
20+
template <endianness E> class SFrameParser {
21+
public:
22+
static Expected<SFrameParser> create(ArrayRef<uint8_t> Contents);
23+
24+
const sframe::Preamble<E> &getPreamble() const { return Header.Preamble; }
25+
const sframe::Header<E> &getHeader() const { return Header; }
26+
27+
bool usesFixedRAOffset() const {
28+
return getHeader().ABIArch == sframe::ABI::AMD64EndianLittle;
29+
}
30+
bool usesFixedFPOffset() const {
31+
return false; // Not used in any currently defined ABI.
32+
}
33+
34+
private:
35+
ArrayRef<uint8_t> Data;
36+
const sframe::Header<E> &Header;
37+
38+
SFrameParser(ArrayRef<uint8_t> Data, const sframe::Header<E> &Header)
39+
: Data(Data), Header(Header) {}
40+
};
41+
42+
extern template class SFrameParser<endianness::big>;
43+
extern template class SFrameParser<endianness::little>;
44+
45+
} // end namespace object
46+
} // end namespace llvm
47+
48+
#endif // LLVM_OBJECT_SFRAME_H

llvm/lib/BinaryFormat/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_llvm_component_library(LLVMBinaryFormat
1111
MsgPackDocumentYAML.cpp
1212
MsgPackReader.cpp
1313
MsgPackWriter.cpp
14+
SFrame.cpp
1415
Wasm.cpp
1516
XCOFF.cpp
1617

llvm/lib/BinaryFormat/SFrame.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===-- SFrame.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/BinaryFormat/SFrame.h"
10+
#include "llvm/Support/ScopedPrinter.h"
11+
12+
using namespace llvm;
13+
14+
ArrayRef<EnumEntry<sframe::Version>> sframe::getVersions() {
15+
static constexpr EnumEntry<Version> Versions[] = {
16+
#define HANDLE_SFRAME_VERSION(CODE, NAME) {#NAME, sframe::Version::NAME},
17+
#include "llvm/BinaryFormat/SFrameConstants.def"
18+
};
19+
20+
return ArrayRef(Versions);
21+
}
22+
23+
ArrayRef<EnumEntry<sframe::Flags>> sframe::getFlags() {
24+
static constexpr EnumEntry<sframe::Flags> Flags[] = {
25+
#define HANDLE_SFRAME_FLAG(CODE, NAME) {#NAME, sframe::Flags::NAME},
26+
#include "llvm/BinaryFormat/SFrameConstants.def"
27+
};
28+
return ArrayRef(Flags);
29+
}
30+
31+
ArrayRef<EnumEntry<sframe::ABI>> sframe::getABIs() {
32+
static constexpr EnumEntry<sframe::ABI> ABIs[] = {
33+
#define HANDLE_SFRAME_ABI(CODE, NAME) {#NAME, sframe::ABI::NAME},
34+
#include "llvm/BinaryFormat/SFrameConstants.def"
35+
};
36+
return ArrayRef(ABIs);
37+
}

llvm/lib/Object/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_llvm_component_library(LLVMObject
2525
OffloadBundle.cpp
2626
RecordStreamer.cpp
2727
RelocationResolver.cpp
28+
SFrameParser.cpp
2829
SymbolicFile.cpp
2930
SymbolSize.cpp
3031
TapiFile.cpp

llvm/lib/Object/SFrameParser.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//===- SFrameParser.cpp ---------------------------------------------------===//
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/Object/SFrameParser.h"
10+
#include "llvm/BinaryFormat/SFrame.h"
11+
#include "llvm/Object/Error.h"
12+
#include "llvm/Support/FormatVariadic.h"
13+
14+
using namespace llvm;
15+
using namespace llvm::object;
16+
17+
template <typename T>
18+
static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,
19+
uint64_t Offset) {
20+
static_assert(std::is_trivial_v<T>);
21+
if (Data.size() < Offset + sizeof(T)) {
22+
return createStringError(
23+
formatv("unexpected end of data at offset {0:x} while reading [{1:x}, "
24+
"{2:x})",
25+
Data.size(), Offset, Offset + sizeof(T))
26+
.str(),
27+
object_error::unexpected_eof);
28+
}
29+
return *reinterpret_cast<const T *>(Data.data() + Offset);
30+
}
31+
32+
template <endianness E>
33+
Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents) {
34+
Expected<const sframe::Preamble<E> &> Preamble =
35+
getDataSliceAs<sframe::Preamble<E>>(Contents, 0);
36+
if (!Preamble)
37+
return Preamble.takeError();
38+
39+
if (Preamble->Magic != sframe::Magic)
40+
return createError(
41+
formatv("invalid magic number ({0:x+4})", Preamble->Magic.value()));
42+
if (Preamble->Version != sframe::Version::V2)
43+
return createError(
44+
formatv("invalid/unsupported version number ({0})",
45+
static_cast<unsigned>(Preamble->Version.value())));
46+
47+
Expected<const sframe::Header<E> &> Header =
48+
getDataSliceAs<sframe::Header<E>>(Contents, 0);
49+
if (!Header)
50+
return Header.takeError();
51+
return SFrameParser(Contents, *Header);
52+
}
53+
54+
template class llvm::object::SFrameParser<endianness::big>;
55+
template class llvm::object::SFrameParser<endianness::little>;

0 commit comments

Comments
 (0)