Skip to content

Commit dbd9afd

Browse files
committed
[Object] Beginnings of SFrame parser and dumper
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.
1 parent 94d75cc commit dbd9afd

File tree

13 files changed

+384
-12
lines changed

13 files changed

+384
-12
lines changed

llvm/include/llvm/BinaryFormat/SFrame.h

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,35 @@
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,
39+
#define HANDLE_SFRAME_FLAG(CODE, NAME) NAME = CODE,
40+
#include "llvm/BinaryFormat/SFrameConstants.def"
3641
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/0xff),
3742
};
3843

3944
enum class ABI : uint8_t {
40-
AArch64EndianBig = 1,
41-
AArch64EndianLittle = 2,
42-
AMD64EndianLittle = 3,
45+
#define HANDLE_SFRAME_ABI(CODE, NAME) NAME = CODE,
46+
#include "llvm/BinaryFormat/SFrameConstants.def"
4347
};
4448

4549
/// SFrame FRE Types. Bits 0-3 of FuncDescEntry.Info.
@@ -158,6 +162,11 @@ template <endianness E> using FrameRowEntryAddr1 = FrameRowEntry<uint8_t, E>;
158162
template <endianness E> using FrameRowEntryAddr2 = FrameRowEntry<uint16_t, E>;
159163
template <endianness E> using FrameRowEntryAddr4 = FrameRowEntry<uint32_t, E>;
160164

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

163172
#endif // LLVM_BINARYFORMAT_SFRAME_H
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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+
32+
HANDLE_SFRAME_ABI(0x01, AArch64EndianBig)
33+
HANDLE_SFRAME_ABI(0x02, AArch64EndianLittle)
34+
HANDLE_SFRAME_ABI(0x03, AMD64EndianLittle)
35+
36+
#undef HANDLE_SFRAME_VERSION
37+
#undef HANDLE_SFRAME_FLAG
38+
#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: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 make_error<GenericBinaryError>(
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 make_error<GenericBinaryError>("invalid magic number",
41+
object_error::parse_failed);
42+
}
43+
if (Preamble->Version != sframe::Version::V2) {
44+
return make_error<GenericBinaryError>("invalid/unsupported version number",
45+
object_error::parse_failed);
46+
}
47+
48+
Expected<const sframe::Header<E> &> Header =
49+
getDataSliceAs<sframe::Header<E>>(Contents, 0);
50+
if (!Header)
51+
return Header.takeError();
52+
return SFrameParser(Contents, *Header);
53+
}
54+
55+
template class llvm::object::SFrameParser<endianness::big>;
56+
template class llvm::object::SFrameParser<endianness::little>;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
## Check parsing and dumping of the SFrame header.
2+
# RUN: yaml2obj --docnum=1 %s -o %t.1
3+
# RUN: llvm-readobj --sframe=.sframe_1b --sframe=.sframe_bad_magic \
4+
# RUN: --sframe=.sframe_bad_version --sframe=.sframe_6b \
5+
# RUN: --sframe=.sframe_header %t.1 2>&1 | FileCheck %s --check-prefix=CASE1
6+
7+
## Check big-endian support and the handling of --sframe argument default.
8+
# RUN: yaml2obj --docnum=2 %s -o %t.2
9+
# RUN: llvm-readobj --sframe %t.2 2>&1 | FileCheck %s --check-prefix=CASE2
10+
11+
--- !ELF
12+
FileHeader:
13+
Class: ELFCLASS64
14+
Data: ELFDATA2LSB
15+
Type: ET_EXEC
16+
Machine: EM_X86_64
17+
Sections:
18+
- Name: .sframe_1b
19+
Type: SHT_PROGBITS
20+
Flags: [ SHF_ALLOC ]
21+
ContentArray: [ 0x00 ]
22+
# CASE1-LABEL: Contents of SFrame section '.sframe_1b':
23+
# CASE1: warning: {{.*}}: unexpected end of data at offset 0x1 while reading [0x0, 0x4)
24+
25+
- Name: .sframe_bad_magic
26+
Type: SHT_PROGBITS
27+
Flags: [ SHF_ALLOC ]
28+
ContentArray: [ 0xde, 0xad, 0xbe, 0xef]
29+
# CASE1-LABEL: Contents of SFrame section '.sframe_bad_magic':
30+
# CASE1: warning: {{.*}}: invalid magic number
31+
32+
- Name: .sframe_bad_version
33+
Type: SHT_PROGBITS
34+
Flags: [ SHF_ALLOC ]
35+
ContentArray: [
36+
0xe2, 0xde, 0x01, 0x00 # Preamble (magic, version, flags)
37+
]
38+
# CASE1-LABEL: Contents of SFrame section '.sframe_bad_version':
39+
# CASE1: warning: {{.*}}: invalid/unsupported version number
40+
41+
- Name: .sframe_6b
42+
Type: SHT_PROGBITS
43+
Flags: [ SHF_ALLOC ]
44+
ContentArray: [
45+
0xe2, 0xde, 0x02, 0x00, # Preamble (magic, version, flags)
46+
0x01, 0x02
47+
]
48+
49+
# CASE1-LABEL: Contents of SFrame section '.sframe_6b':
50+
# CASE1: warning: {{.*}}: unexpected end of data at offset 0x6 while reading [0x0, 0x1c)
51+
52+
- Name: .sframe_header
53+
Type: SHT_PROGBITS
54+
Flags: [ SHF_ALLOC ]
55+
ContentArray: [
56+
0xe2, 0xde, 0x02, 0x00, # Preamble (magic, version, flags)
57+
# Header:
58+
0x03, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
59+
0x01, 0x00, 0x00, 0x00, # Number of FDEs
60+
0x10, 0x00, 0x00, 0x00, # Number of FREs
61+
0x00, 0x10, 0x00, 0x00, # FRE length
62+
0x04, 0x00, 0x00, 0x00, # FDE offset
63+
0x00, 0x01, 0x00, 0x00, # FRE offset
64+
]
65+
# CASE1-LABEL: Contents of SFrame section '.sframe_header':
66+
# CASE1: Header {
67+
# CASE1-NEXT: Magic: 0xDEE2
68+
# CASE1-NEXT: Version: V2 (0x2)
69+
# CASE1-NEXT: Flags [ (0x0)
70+
# CASE1-NEXT: ]
71+
# CASE1-NEXT: ABI: AMD64EndianLittle (0x3)
72+
# CASE1-NEXT: CFA fixed RA offset: 71
73+
# CASE1-NEXT: CFA fixed FP offset (unused): 66
74+
# CASE1-NEXT: Auxiliary header length: 0
75+
# CASE1-NEXT: Num FDEs: 1
76+
# CASE1-NEXT: Num FREs: 16
77+
# CASE1-NEXT: FRE subsection length: 4096
78+
# CASE1-NEXT: FDE subsection offset: 4
79+
# CASE1-NEXT: FRE subsection offset: 256
80+
# CASE1-NEXT: }
81+
82+
--- !ELF
83+
FileHeader:
84+
Class: ELFCLASS64
85+
Data: ELFDATA2MSB
86+
Type: ET_EXEC
87+
Machine: EM_AARCH64
88+
Sections:
89+
- Name: .sframe
90+
Type: SHT_PROGBITS
91+
Flags: [ SHF_ALLOC ]
92+
ContentArray: [
93+
0xde, 0xe2, 0x02, 0x01, # Preamble (magic, version, flags)
94+
# Header:
95+
0x01, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
96+
0x00, 0x00, 0x00, 0x01, # Number of FDEs
97+
0x00, 0x00, 0x00, 0x10, # Number of FREs
98+
0x00, 0x00, 0x10, 0x00, # FRE length
99+
0x00, 0x00, 0x00, 0x04, # FDE offset
100+
0x00, 0x00, 0x01, 0x00, # FRE offset
101+
]
102+
# CASE2-LABEL: Contents of SFrame section '.sframe':
103+
# CASE2: Header {
104+
# CASE2-NEXT: Magic: 0xDEE2
105+
# CASE2-NEXT: Version: V2 (0x2)
106+
# CASE2-NEXT: Flags [ (0x1)
107+
# CASE2-NEXT: FDESorted (0x1)
108+
# CASE2-NEXT: ]
109+
# CASE2-NEXT: ABI: AArch64EndianBig (0x1)
110+
# CASE2-NEXT: CFA fixed RA offset (unused): 71
111+
# CASE2-NEXT: CFA fixed FP offset (unused): 66
112+
# CASE2-NEXT: Auxiliary header length: 0
113+
# CASE2-NEXT: Num FDEs: 1
114+
# CASE2-NEXT: Num FREs: 16
115+
# CASE2-NEXT: FRE subsection length: 4096
116+
# CASE2-NEXT: FDE subsection offset: 4
117+
# CASE2-NEXT: FRE subsection offset: 256
118+
# CASE2-NEXT: }

0 commit comments

Comments
 (0)