Skip to content

Commit 0d71f2a

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 ee9b84f commit 0d71f2a

File tree

13 files changed

+393
-13
lines changed

13 files changed

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

0 commit comments

Comments
 (0)