Skip to content

Commit d5385eb

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 fbd23f8 commit d5385eb

File tree

12 files changed

+388
-7
lines changed

12 files changed

+388
-7
lines changed

llvm/include/llvm/BinaryFormat/SFrame.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,31 @@
2020

2121
#include "llvm/Support/Compiler.h"
2222
#include "llvm/Support/DataTypes.h"
23+
#include "llvm/ADT/ArrayRef.h"
2324

2425
namespace llvm {
2526

27+
template <typename T> struct EnumEntry;
28+
2629
namespace sframe {
2730

2831
constexpr uint16_t SFRAME_MAGIC = 0xDEE2;
2932

3033
enum : uint8_t {
31-
SFRAME_VERSION_1 = 1,
32-
SFRAME_VERSION_2 = 2,
34+
#define HANDLE_SFRAME_VERSION(CODE, NAME) SFRAME_##NAME = CODE,
35+
#include "llvm/BinaryFormat/SFrameConstants.def"
3336
};
3437

3538
/// sframe_preable.sfp_flags flags.
3639
enum : uint8_t {
37-
SFRAME_F_FDE_SORTED = 0x1,
38-
SFRAME_F_FRAME_POINTER = 0x2,
40+
#define HANDLE_SFRAME_HEADER_FLAG(CODE, NAME) SFRAME_F_##NAME = CODE,
41+
#include "llvm/BinaryFormat/SFrameConstants.def"
3942
};
4043

4144
/// Possible values for sframe_header.sfh_abi_arch.
4245
enum : uint8_t {
43-
SFRAME_ABI_AARCH64_ENDIAN_BIG = 1,
44-
SFRAME_ABI_AARCH64_ENDIAN_LITTLE = 2,
45-
SFRAME_ABI_AMD64_ENDIAN_LITTLE = 3
46+
#define HANDLE_SFRAME_ABI(CODE, NAME) SFRAME_ABI_##NAME = CODE,
47+
#include "llvm/BinaryFormat/SFrameConstants.def"
4648
};
4749

4850
/// SFrame FRE Types. Bits 0-3 of sframe_func_desc_entry.sfde_func_info.
@@ -159,6 +161,10 @@ struct sframe_frame_row_entry_addr4 {
159161

160162
LLVM_PACKED_END
161163

164+
ArrayRef<EnumEntry<uint8_t>> getVersions();
165+
ArrayRef<EnumEntry<uint8_t>> getHeaderFlags();
166+
ArrayRef<EnumEntry<uint8_t>> getABIs();
167+
162168
} // namespace sframe
163169
} // namespace llvm
164170

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_HEADER_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_HEADER_FLAG
19+
#define HANDLE_SFRAME_HEADER_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, VERSION_1)
27+
HANDLE_SFRAME_VERSION(0x02, VERSION_2)
28+
29+
HANDLE_SFRAME_HEADER_FLAG(0x01, FDE_SORTED)
30+
HANDLE_SFRAME_HEADER_FLAG(0x02, FRAME_POINTER)
31+
32+
HANDLE_SFRAME_ABI(0x01, AARCH64_ENDIAN_BIG)
33+
HANDLE_SFRAME_ABI(0x02, AARCH64_ENDIAN_LITTLE)
34+
HANDLE_SFRAME_ABI(0x03, AMD64_ENDIAN_LITTLE)
35+
36+
#undef HANDLE_SFRAME_VERSION
37+
#undef HANDLE_SFRAME_HEADER_FLAG
38+
#undef HANDLE_SFRAME_ABI
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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/BinaryFormat/SFrame.h"
13+
#include "llvm/Support/DataExtractor.h"
14+
#include "llvm/Support/Error.h"
15+
#include <cstdint>
16+
17+
namespace llvm {
18+
namespace object {
19+
20+
class SFrameParser {
21+
public:
22+
static Expected<SFrameParser> create(ArrayRef<uint8_t> Contents);
23+
24+
const sframe::sframe_preamble &getPreamble() const {
25+
return Header.sfh_preamble;
26+
}
27+
const sframe::sframe_header &getHeader() const { return Header; }
28+
29+
bool usesFixedRAOffset() const {
30+
return Header.sfh_abi_arch == sframe::SFRAME_ABI_AMD64_ENDIAN_LITTLE;
31+
}
32+
bool usesFixedFPOffset() const {
33+
return false; // Not used in any currently defined ABI.
34+
}
35+
36+
private:
37+
DataExtractor Data;
38+
sframe::sframe_header Header;
39+
40+
SFrameParser(DataExtractor Data, sframe::sframe_header Header)
41+
: Data(Data), Header(Header) {}
42+
};
43+
44+
} // end namespace object
45+
} // end namespace llvm
46+
47+
#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: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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<uint8_t>> sframe::getVersions() {
15+
static constexpr EnumEntry<uint8_t> Versions[] = {
16+
#define HANDLE_SFRAME_VERSION(CODE, NAME) \
17+
{"SFRAME_" #NAME, sframe::SFRAME_##NAME},
18+
#include "llvm/BinaryFormat/SFrameConstants.def"
19+
};
20+
21+
return ArrayRef(Versions);
22+
}
23+
24+
ArrayRef<EnumEntry<uint8_t>> sframe::getHeaderFlags() {
25+
static constexpr EnumEntry<uint8_t> Flags[] = {
26+
#define HANDLE_SFRAME_HEADER_FLAG(CODE, NAME) \
27+
{"SFRAME_F_" #NAME, sframe::SFRAME_F_##NAME},
28+
#include "llvm/BinaryFormat/SFrameConstants.def"
29+
};
30+
return ArrayRef(Flags);
31+
}
32+
33+
ArrayRef<EnumEntry<uint8_t>> sframe::getABIs() {
34+
static constexpr EnumEntry<uint8_t> ABIs[] = {
35+
#define HANDLE_SFRAME_ABI(CODE, NAME) \
36+
{"SFRAME_ABI_" #NAME, sframe::SFRAME_ABI_##NAME},
37+
#include "llvm/BinaryFormat/SFrameConstants.def"
38+
};
39+
return ArrayRef(ABIs);
40+
}

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: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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/Object/Error.h"
11+
12+
using namespace llvm;
13+
using namespace llvm::object;
14+
using namespace llvm::sframe;
15+
16+
Expected<SFrameParser> SFrameParser::create(ArrayRef<uint8_t> Contents) {
17+
sframe_header Header;
18+
sframe_preamble &Preamble = Header.sfh_preamble;
19+
20+
// IsLittleEndian will be swapped if needed, AddressSize is unused.
21+
DataExtractor Data(Contents, /*IsLittleEndian=*/true, /*AddressSize=*/0);
22+
DataExtractor::Cursor Cursor(0);
23+
Preamble.sfp_magic = Data.getU16(Cursor);
24+
if (!Cursor)
25+
return Cursor.takeError();
26+
27+
switch (Preamble.sfp_magic) {
28+
case SFRAME_MAGIC:
29+
break;
30+
case byteswap(SFRAME_MAGIC):
31+
// Fix endianness.
32+
Preamble.sfp_magic = SFRAME_MAGIC;
33+
// And make sure everything that comes afterwards is read correctly.
34+
Data = DataExtractor(Data.getData(), !Data.isLittleEndian(),
35+
Data.getAddressSize());
36+
break;
37+
default:
38+
return make_error<GenericBinaryError>("invalid magic number",
39+
object_error::parse_failed);
40+
}
41+
Preamble.sfp_version = Data.getU8(Cursor);
42+
Preamble.sfp_flags = Data.getU8(Cursor);
43+
if (!Cursor)
44+
return Cursor.takeError();
45+
46+
if (Preamble.sfp_version != SFRAME_VERSION_2) {
47+
return make_error<GenericBinaryError>("invalid/unsupported version number",
48+
object_error::parse_failed);
49+
}
50+
51+
Header.sfh_abi_arch = Data.getU8(Cursor);
52+
Header.sfh_cfa_fixed_fp_offset = (int8_t)Data.getU8(Cursor);
53+
Header.sfh_cfa_fixed_ra_offset = (int8_t)Data.getU8(Cursor);
54+
Header.sfh_auxhdr_len = Data.getU8(Cursor);
55+
Header.sfh_num_fdes = Data.getU32(Cursor);
56+
Header.sfh_num_fres = Data.getU32(Cursor);
57+
Header.sfh_fre_len = Data.getU32(Cursor);
58+
Header.sfh_fdeoff = Data.getU32(Cursor);
59+
Header.sfh_freoff = Data.getU32(Cursor);
60+
61+
if (!Cursor)
62+
return Cursor.takeError();
63+
64+
return SFrameParser(Data, Header);
65+
}
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_3b --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, 0x2)
24+
25+
- Name: .sframe_bad_magic
26+
Type: SHT_PROGBITS
27+
Flags: [ SHF_ALLOC ]
28+
ContentArray: [ 0xde, 0xad ]
29+
# CASE1-LABEL: Contents of SFrame section '.sframe_bad_magic':
30+
# CASE1: warning: {{.*}}: invalid magic number
31+
32+
- Name: .sframe_3b
33+
Type: SHT_PROGBITS
34+
Flags: [ SHF_ALLOC ]
35+
ContentArray: [ 0xe2, 0xde, 0x01 ]
36+
# CASE1-LABEL: Contents of SFrame section '.sframe_3b':
37+
# CASE1: warning: {{.*}}: unexpected end of data at offset 0x3 while reading [0x3, 0x4)
38+
39+
- Name: .sframe_bad_version
40+
Type: SHT_PROGBITS
41+
Flags: [ SHF_ALLOC ]
42+
ContentArray: [
43+
0xe2, 0xde, 0x01, 0x00 # Preamble (magic, version, flags)
44+
]
45+
# CASE1-LABEL: Contents of SFrame section '.sframe_bad_version':
46+
# CASE1: warning: {{.*}}: invalid/unsupported version number
47+
48+
- Name: .sframe_6b
49+
Type: SHT_PROGBITS
50+
Flags: [ SHF_ALLOC ]
51+
ContentArray: [
52+
0xe2, 0xde, 0x02, 0x00, # Preamble (magic, version, flags)
53+
0x01, 0x02
54+
]
55+
56+
# CASE1-LABEL: Contents of SFrame section '.sframe_6b':
57+
# CASE1: warning: {{.*}}: unexpected end of data at offset 0x6 while reading [0x6, 0x7)
58+
59+
- Name: .sframe_header
60+
Type: SHT_PROGBITS
61+
Flags: [ SHF_ALLOC ]
62+
ContentArray: [
63+
0xe2, 0xde, 0x02, 0x00, # Preamble (magic, version, flags)
64+
# Header:
65+
0x03, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
66+
0x01, 0x00, 0x00, 0x00, # Number of FDEs
67+
0x10, 0x00, 0x00, 0x00, # Number of FREs
68+
0x00, 0x10, 0x00, 0x00, # FRE length
69+
0x04, 0x00, 0x00, 0x00, # FDE offset
70+
0x00, 0x01, 0x00, 0x00, # FRE offset
71+
]
72+
# CASE1-LABEL: Contents of SFrame section '.sframe_header':
73+
# CASE1: Header {
74+
# CASE1-NEXT: Magic: 0xDEE2
75+
# CASE1-NEXT: Version: SFRAME_VERSION_2 (0x2)
76+
# CASE1-NEXT: Flags [ (0x0)
77+
# CASE1-NEXT: ]
78+
# CASE1-NEXT: ABI: SFRAME_ABI_AMD64_ENDIAN_LITTLE (0x3)
79+
# CASE1-NEXT: CFA fixed RA offset: 71
80+
# CASE1-NEXT: CFA fixed FP offset (unused): 66
81+
# CASE1-NEXT: Auxiliary header length: 0
82+
# CASE1-NEXT: Num FDEs: 1
83+
# CASE1-NEXT: Num FREs: 16
84+
# CASE1-NEXT: FRE subsection length: 4096
85+
# CASE1-NEXT: FDE subsection offset: 4
86+
# CASE1-NEXT: FRE subsection offset: 256
87+
# CASE1-NEXT: }
88+
89+
--- !ELF
90+
FileHeader:
91+
Class: ELFCLASS64
92+
Data: ELFDATA2MSB
93+
Type: ET_EXEC
94+
Machine: EM_AARCH64
95+
Sections:
96+
- Name: .sframe
97+
Type: SHT_PROGBITS
98+
Flags: [ SHF_ALLOC ]
99+
ContentArray: [
100+
0xde, 0xe2, 0x02, 0x00, # Preamble (magic, version, flags)
101+
# Header:
102+
0x01, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
103+
0x00, 0x00, 0x00, 0x01, # Number of FDEs
104+
0x00, 0x00, 0x00, 0x10, # Number of FREs
105+
0x00, 0x00, 0x10, 0x00, # FRE length
106+
0x00, 0x00, 0x00, 0x04, # FDE offset
107+
0x00, 0x00, 0x01, 0x00, # FRE offset
108+
]
109+
# CASE2-LABEL: Contents of SFrame section '.sframe':
110+
# CASE2: Header {
111+
# CASE2-NEXT: Magic: 0xDEE2
112+
# CASE2-NEXT: Version: SFRAME_VERSION_2 (0x2)
113+
# CASE2-NEXT: Flags [ (0x0)
114+
# CASE2-NEXT: ]
115+
# CASE2-NEXT: ABI: SFRAME_ABI_AARCH64_ENDIAN_BIG (0x1)
116+
# CASE2-NEXT: CFA fixed RA offset (unused): 71
117+
# CASE2-NEXT: CFA fixed FP offset (unused): 66
118+
# CASE2-NEXT: Auxiliary header length: 0
119+
# CASE2-NEXT: Num FDEs: 1
120+
# CASE2-NEXT: Num FREs: 16
121+
# CASE2-NEXT: FRE subsection length: 4096
122+
# CASE2-NEXT: FDE subsection offset: 4
123+
# CASE2-NEXT: FRE subsection offset: 256
124+
# CASE2-NEXT: }

0 commit comments

Comments
 (0)