Skip to content

Commit 1a219aa

Browse files
author
George Rimar
committedSep 24, 2019
[yaml2obj/obj2yaml] - Add support for .stack_sizes sections.
.stack_sizes is a SHT_PROGBITS section that contains pairs of <address (4/8 bytes), stack size (uleb128)>. This patch teach tools to parse and dump it. Differential revision: https://reviews.llvm.org/D67757 llvm-svn: 372762
1 parent c526fca commit 1a219aa

File tree

8 files changed

+480
-15
lines changed

8 files changed

+480
-15
lines changed
 

‎llvm/include/llvm/Object/ELF.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,16 @@ class ELFFile {
150150

151151
static Expected<ELFFile> create(StringRef Object);
152152

153+
bool isLE() const {
154+
return getHeader()->getDataEncoding() == ELF::ELFDATA2LSB;
155+
}
156+
153157
bool isMipsELF64() const {
154158
return getHeader()->e_machine == ELF::EM_MIPS &&
155159
getHeader()->getFileClass() == ELF::ELFCLASS64;
156160
}
157161

158-
bool isMips64EL() const {
159-
return isMipsELF64() &&
160-
getHeader()->getDataEncoding() == ELF::ELFDATA2LSB;
161-
}
162+
bool isMips64EL() const { return isMipsELF64() && isLE(); }
162163

163164
Expected<Elf_Shdr_Range> sections() const;
164165

‎llvm/include/llvm/ObjectYAML/ELFYAML.h

+26
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ struct DynamicEntry {
117117
llvm::yaml::Hex64 Val;
118118
};
119119

120+
struct StackSizeEntry {
121+
llvm::yaml::Hex64 Address;
122+
llvm::yaml::Hex64 Size;
123+
};
124+
120125
struct Section {
121126
enum class SectionKind {
122127
Dynamic,
@@ -126,6 +131,7 @@ struct Section {
126131
NoBits,
127132
Verdef,
128133
Verneed,
134+
StackSizes,
129135
SymtabShndxSection,
130136
Symver,
131137
MipsABIFlags
@@ -163,6 +169,21 @@ struct Section {
163169
Optional<llvm::yaml::Hex64> ShSize;
164170
};
165171

172+
struct StackSizesSection : Section {
173+
Optional<yaml::BinaryRef> Content;
174+
Optional<std::vector<StackSizeEntry>> Entries;
175+
176+
StackSizesSection() : Section(SectionKind::StackSizes) {}
177+
178+
static bool classof(const Section *S) {
179+
return S->Kind == SectionKind::StackSizes;
180+
}
181+
182+
static bool nameMatches(StringRef Name) {
183+
return Name == ".stack_sizes";
184+
}
185+
};
186+
166187
struct DynamicSection : Section {
167188
std::vector<DynamicEntry> Entries;
168189
Optional<yaml::BinaryRef> Content;
@@ -326,6 +347,7 @@ struct Object {
326347
} // end namespace ELFYAML
327348
} // end namespace llvm
328349

350+
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry)
329351
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry)
330352
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
331353
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Section>)
@@ -461,6 +483,10 @@ struct MappingTraits<ELFYAML::Symbol> {
461483
static StringRef validate(IO &IO, ELFYAML::Symbol &Symbol);
462484
};
463485

486+
template <> struct MappingTraits<ELFYAML::StackSizeEntry> {
487+
static void mapping(IO &IO, ELFYAML::StackSizeEntry &Rel);
488+
};
489+
464490
template <> struct MappingTraits<ELFYAML::DynamicEntry> {
465491
static void mapping(IO &IO, ELFYAML::DynamicEntry &Rel);
466492
};

‎llvm/lib/ObjectYAML/ELFEmitter.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ObjectYAML/ELFYAML.h"
2020
#include "llvm/ObjectYAML/yaml2obj.h"
2121
#include "llvm/Support/EndianStream.h"
22+
#include "llvm/Support/LEB128.h"
2223
#include "llvm/Support/MemoryBuffer.h"
2324
#include "llvm/Support/WithColor.h"
2425
#include "llvm/Support/YAMLTraits.h"
@@ -167,6 +168,9 @@ template <class ELFT> class ELFState {
167168
void writeSectionContent(Elf_Shdr &SHeader,
168169
const ELFYAML::DynamicSection &Section,
169170
ContiguousBlobAccumulator &CBA);
171+
void writeSectionContent(Elf_Shdr &SHeader,
172+
const ELFYAML::StackSizesSection &Section,
173+
ContiguousBlobAccumulator &CBA);
170174
ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH);
171175

172176
public:
@@ -411,6 +415,8 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
411415
writeSectionContent(SHeader, *S, CBA);
412416
} else if (auto S = dyn_cast<ELFYAML::VerdefSection>(Sec)) {
413417
writeSectionContent(SHeader, *S, CBA);
418+
} else if (auto S = dyn_cast<ELFYAML::StackSizesSection>(Sec)) {
419+
writeSectionContent(SHeader, *S, CBA);
414420
} else {
415421
llvm_unreachable("Unknown section type");
416422
}
@@ -781,6 +787,26 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
781787
SHeader.sh_size = Section.Entries.size() * SHeader.sh_entsize;
782788
}
783789

790+
template <class ELFT>
791+
void ELFState<ELFT>::writeSectionContent(
792+
Elf_Shdr &SHeader, const ELFYAML::StackSizesSection &Section,
793+
ContiguousBlobAccumulator &CBA) {
794+
using uintX_t = typename ELFT::uint;
795+
raw_ostream &OS =
796+
CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);
797+
798+
if (Section.Content) {
799+
Section.Content->writeAsBinary(OS);
800+
SHeader.sh_size = Section.Content->binary_size();
801+
return;
802+
}
803+
804+
for (const ELFYAML::StackSizeEntry &E : *Section.Entries) {
805+
support::endian::write<uintX_t>(OS, E.Address, ELFT::TargetEndianness);
806+
SHeader.sh_size += sizeof(uintX_t) + encodeULEB128(E.Size, OS);
807+
}
808+
}
809+
784810
template <class ELFT>
785811
void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
786812
const ELFYAML::VerdefSection &Section,

‎llvm/lib/ObjectYAML/ELFYAML.cpp

+41-8
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,12 @@ static void sectionMapping(IO &IO, ELFYAML::RawContentSection &Section) {
10171017
IO.mapOptional("Info", Section.Info);
10181018
}
10191019

1020+
static void sectionMapping(IO &IO, ELFYAML::StackSizesSection &Section) {
1021+
commonSectionMapping(IO, Section);
1022+
IO.mapOptional("Content", Section.Content);
1023+
IO.mapOptional("Entries", Section.Entries);
1024+
}
1025+
10201026
static void sectionMapping(IO &IO, ELFYAML::NoBitsSection &Section) {
10211027
commonSectionMapping(IO, Section);
10221028
IO.mapOptional("Size", Section.Size, Hex64(0));
@@ -1142,20 +1148,40 @@ void MappingTraits<std::unique_ptr<ELFYAML::Section>>::mapping(
11421148
sectionMapping(IO, *cast<ELFYAML::SymtabShndxSection>(Section.get()));
11431149
break;
11441150
default:
1145-
if (!IO.outputting())
1146-
Section.reset(new ELFYAML::RawContentSection());
1147-
sectionMapping(IO, *cast<ELFYAML::RawContentSection>(Section.get()));
1151+
if (!IO.outputting()) {
1152+
StringRef Name;
1153+
IO.mapOptional("Name", Name, StringRef());
1154+
1155+
if (ELFYAML::StackSizesSection::nameMatches(Name))
1156+
Section = std::make_unique<ELFYAML::StackSizesSection>();
1157+
else
1158+
Section = std::make_unique<ELFYAML::RawContentSection>();
1159+
}
1160+
1161+
if (auto S = dyn_cast<ELFYAML::RawContentSection>(Section.get()))
1162+
sectionMapping(IO, *S);
1163+
else
1164+
sectionMapping(IO, *cast<ELFYAML::StackSizesSection>(Section.get()));
11481165
}
11491166
}
11501167

11511168
StringRef MappingTraits<std::unique_ptr<ELFYAML::Section>>::validate(
11521169
IO &io, std::unique_ptr<ELFYAML::Section> &Section) {
1153-
const auto *RawSection = dyn_cast<ELFYAML::RawContentSection>(Section.get());
1154-
if (!RawSection)
1170+
if (const auto *RawSection =
1171+
dyn_cast<ELFYAML::RawContentSection>(Section.get())) {
1172+
if (RawSection->Size && RawSection->Content &&
1173+
(uint64_t)(*RawSection->Size) < RawSection->Content->binary_size())
1174+
return "Section size must be greater than or equal to the content size";
11551175
return {};
1156-
if (RawSection->Size && RawSection->Content &&
1157-
(uint64_t)(*RawSection->Size) < RawSection->Content->binary_size())
1158-
return "Section size must be greater than or equal to the content size";
1176+
}
1177+
1178+
if (const auto *SS = dyn_cast<ELFYAML::StackSizesSection>(Section.get())) {
1179+
if (SS->Content && SS->Entries)
1180+
return ".stack_sizes: Content and Entries cannot be used together";
1181+
if (!SS->Content && !SS->Entries)
1182+
return ".stack_sizes: either Content or Entries tag must be specified";
1183+
return {};
1184+
}
11591185
return {};
11601186
}
11611187

@@ -1184,6 +1210,13 @@ struct NormalizedMips64RelType {
11841210

11851211
} // end anonymous namespace
11861212

1213+
void MappingTraits<ELFYAML::StackSizeEntry>::mapping(
1214+
IO &IO, ELFYAML::StackSizeEntry &E) {
1215+
assert(IO.getContext() && "The IO context is not initialized");
1216+
IO.mapOptional("Address", E.Address, Hex64(0));
1217+
IO.mapRequired("Size", E.Size);
1218+
}
1219+
11871220
void MappingTraits<ELFYAML::DynamicEntry>::mapping(IO &IO,
11881221
ELFYAML::DynamicEntry &Rel) {
11891222
assert(IO.getContext() && "The IO context is not initialized");

‎llvm/test/tools/llvm-readobj/stack-sizes.test

+4-3
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ Sections:
163163
Size: 16
164164
- Name: .stack_sizes
165165
Type: SHT_PROGBITS
166-
Size: 1
166+
Content: "00"
167167
Link: .text
168168
- Name: .rela.stack_sizes
169169
Type: SHT_RELA
@@ -468,7 +468,8 @@ Sections:
468468
Size: 16
469469
- Name: .stack_sizes
470470
Type: SHT_PROGBITS
471-
Size: 9
471+
Entries:
472+
- Size: 0
472473
Link: .text
473474
- Name: .rela.stack_sizes
474475
Type: SHT_RELA
@@ -504,8 +505,8 @@ Sections:
504505
Size: 8
505506
- Name: .stack_sizes
506507
Type: SHT_PROGBITS
507-
Size: 16
508508
Link: .text
509+
Entries: []
509510
- Name: .rela.stack_sizes
510511
Type: SHT_RELA
511512
Info: .stack_sizes
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
## Check how obj2yaml produces YAML .stack_sizes descriptions.
2+
3+
## Check that obj2yaml uses the "Entries" tag to describe a .stack_sizes section
4+
## when it can extract <address, size> pairs.
5+
6+
# RUN: yaml2obj --docnum=1 %s -o %t1
7+
# RUN: obj2yaml %t1 | FileCheck %s --check-prefix=VALID
8+
9+
# VALID: --- !ELF
10+
# VALID-NEXT: FileHeader:
11+
# VALID-NEXT: Class: ELFCLASS64
12+
# VALID-NEXT: Data: ELFDATA2LSB
13+
# VALID-NEXT: Type: ET_EXEC
14+
# VALID-NEXT: Machine: EM_X86_64
15+
# VALID-NEXT: Sections:
16+
# VALID-NEXT: - Name: .stack_sizes
17+
# VALID-NEXT: Type: SHT_PROGBITS
18+
# VALID-NEXT: Entries:
19+
# VALID-NEXT: - Address: 0x0000000000000010
20+
# VALID-NEXT: Size: 0x0000000000000020
21+
# VALID-NEXT: - Address: 0x0000000000000030
22+
# VALID-NEXT: Size: 0x0000000000000040
23+
24+
--- !ELF
25+
FileHeader:
26+
Class: ELFCLASS64
27+
Data: ELFDATA2LSB
28+
Type: ET_EXEC
29+
Machine: EM_X86_64
30+
Sections:
31+
- Name: .stack_sizes
32+
Type: SHT_PROGBITS
33+
Content: "100000000000000020300000000000000040"
34+
35+
## Check that obj2yaml uses the "Content" tag to describe a .stack_sizes section
36+
## when it can't extract the entries, for example, when section data is truncated.
37+
38+
# RUN: yaml2obj --docnum=2 %s -o %t2
39+
# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=INVALID
40+
41+
# INVALID: --- !ELF
42+
# INVALID-NEXT: FileHeader:
43+
# INVALID-NEXT: Class: ELFCLASS64
44+
# INVALID-NEXT: Data: ELFDATA2LSB
45+
# INVALID-NEXT: Type: ET_EXEC
46+
# INVALID-NEXT: Machine: EM_X86_64
47+
# INVALID-NEXT: Sections:
48+
# INVALID-NEXT: - Name: .stack_sizes
49+
# INVALID-NEXT: Type: SHT_PROGBITS
50+
# INVALID-NEXT: Content: '1000000000000000203000000000000000'
51+
52+
--- !ELF
53+
FileHeader:
54+
Class: ELFCLASS64
55+
Data: ELFDATA2LSB
56+
Type: ET_EXEC
57+
Machine: EM_X86_64
58+
Sections:
59+
- Name: .stack_sizes
60+
Type: SHT_PROGBITS
61+
Content: "1000000000000000203000000000000000"
62+
63+
## Check obj2yaml can dump empty .stack_sizes.
64+
65+
# RUN: yaml2obj --docnum=3 %s -o %t3
66+
# RUN: obj2yaml %t3 | FileCheck %s --check-prefix=EMPTY
67+
68+
# EMPTY: --- !ELF
69+
# EMPTY-NEXT: FileHeader:
70+
# EMPTY-NEXT: Class: ELFCLASS64
71+
# EMPTY-NEXT: Data: ELFDATA2LSB
72+
# EMPTY-NEXT: Type: ET_EXEC
73+
# EMPTY-NEXT: Machine: EM_X86_64
74+
# EMPTY-NEXT: Sections:
75+
# EMPTY-NEXT: - Name: .stack_sizes
76+
# EMPTY-NEXT: Type: SHT_PROGBITS
77+
# EMPTY-NEXT: Content: ''
78+
79+
--- !ELF
80+
FileHeader:
81+
Class: ELFCLASS64
82+
Data: ELFDATA2LSB
83+
Type: ET_EXEC
84+
Machine: EM_X86_64
85+
Sections:
86+
- Name: .stack_sizes
87+
Type: SHT_PROGBITS
88+
Content: ""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
## Check how yaml2obj produces .stack_sizes sections.
2+
3+
## Test the following cases when the .stack_sizes Content field is specified:
4+
## 1) We can produce a .stack_sizes section from a description with
5+
## a valid section content.
6+
## 2) We can produce an incorrect .stack_sizes section from a description with
7+
## a broken (truncated) section content.
8+
## 3) We can produce an empty .stack_sizes section from a description with
9+
## empty section content.
10+
11+
# RUN: yaml2obj --docnum=1 %s -o %t1
12+
# RUN: llvm-readobj --sections --section-data %t1 | FileCheck %s
13+
14+
## Case 1: valid content.
15+
# CHECK: Section {
16+
# CHECK: Index: 1
17+
# CHECK-NEXT: Name: .stack_sizes (1)
18+
# CHECK-NEXT: Type: SHT_PROGBITS (0x1)
19+
# CHECK-NEXT: Flags [ (0x0)
20+
# CHECK-NEXT: ]
21+
# CHECK-NEXT: Address: 0x0
22+
# CHECK-NEXT: Offset: 0x40
23+
# CHECK-NEXT: Size: 9
24+
# CHECK-NEXT: Link: 0
25+
# CHECK-NEXT: Info: 0
26+
# CHECK-NEXT: AddressAlignment: 0
27+
# CHECK-NEXT: EntrySize: 0
28+
# CHECK-NEXT: SectionData (
29+
# CHECK-NEXT: 0000: 10000000 00000000 20
30+
# CHECK-NEXT: )
31+
# CHECK-NEXT: }
32+
33+
## Case 2: truncated content.
34+
# CHECK: Name: .stack_sizes
35+
# CHECK: Size:
36+
# CHECK-SAME: 8
37+
# CHECK: SectionData (
38+
# CHECK-NEXT: 0000: 10000000 00000000
39+
40+
## Case 3: empty content.
41+
# CHECK: Name: .stack_sizes
42+
# CHECK: Size:
43+
# CHECK-SAME: 0
44+
45+
--- !ELF
46+
FileHeader:
47+
Class: ELFCLASS64
48+
Data: ELFDATA2LSB
49+
Type: ET_EXEC
50+
Machine: EM_X86_64
51+
Sections:
52+
## Valid.
53+
- Name: '.stack_sizes [1]'
54+
Type: SHT_PROGBITS
55+
Content: "100000000000000020"
56+
## Truncated.
57+
- Name: '.stack_sizes [2]'
58+
Type: SHT_PROGBITS
59+
Content: "1000000000000000"
60+
## Empty.
61+
- Name: '.stack_sizes [3]'
62+
Type: SHT_PROGBITS
63+
Content: ""
64+
65+
## Check we can describe .stack_sizes section using <address, size> pairs.
66+
67+
# RUN: yaml2obj --docnum=2 %s -o %t2
68+
# RUN: llvm-readobj --sections --section-data %t2 | FileCheck %s --check-prefix=ENTRIES-LE64-BOTH
69+
# RUN: yaml2obj --docnum=3 %s -o %t3
70+
# RUN: llvm-readobj --sections --section-data %t3 | FileCheck %s --check-prefix=ENTRIES-BE64-BOTH
71+
# RUN: yaml2obj --docnum=4 %s -o %t4
72+
# RUN: llvm-readobj --sections --section-data %t4 | FileCheck %s --check-prefix=ENTRIES-LE32-BOTH
73+
# RUN: yaml2obj --docnum=5 %s -o %t5
74+
# RUN: llvm-readobj --sections --section-data %t5 | FileCheck %s --check-prefix=ENTRIES-BE32-BOTH
75+
76+
# ENTRIES-LE64-BOTH: Name: .stack_sizes
77+
# ENTRIES-LE64-BOTH: SectionData (
78+
# ENTRIES-LE64-BOTH-NEXT: 0000: 10000000 00000000 20300000 00000000 |
79+
# ENTRIES-LE64-BOTH-NEXT: 0010: 0040 |
80+
81+
# ENTRIES-BE64-BOTH: Name: .stack_sizes
82+
# ENTRIES-BE64-BOTH: SectionData (
83+
# ENTRIES-BE64-BOTH-NEXT: 0000: 00000000 00000010 20000000 00000000 |
84+
# ENTRIES-BE64-BOTH-NEXT: 0010: 3040
85+
86+
# ENTRIES-LE32-BOTH: Name: .stack_sizes
87+
# ENTRIES-LE32-BOTH: SectionData (
88+
# ENTRIES-LE32-BOTH-NEXT: 0000: 10000000 20300000 0040 |
89+
90+
# ENTRIES-BE32-BOTH: Name: .stack_sizes
91+
# ENTRIES-BE32-BOTH: SectionData (
92+
# ENTRIES-BE32-BOTH-NEXT: 0000: 00000010 20000000 3040 |
93+
94+
--- !ELF
95+
FileHeader:
96+
Class: ELFCLASS64
97+
Data: ELFDATA2LSB
98+
Type: ET_EXEC
99+
Machine: EM_X86_64
100+
Sections:
101+
- Name: .stack_sizes
102+
Type: SHT_PROGBITS
103+
Entries:
104+
- Address: 0x10
105+
Size: 0x20
106+
- Address: 0x30
107+
Size: 0x40
108+
109+
--- !ELF
110+
FileHeader:
111+
Class: ELFCLASS64
112+
Data: ELFDATA2MSB
113+
Type: ET_EXEC
114+
Machine: EM_X86_64
115+
Sections:
116+
- Name: .stack_sizes
117+
Type: SHT_PROGBITS
118+
Entries:
119+
- Address: 0x10
120+
Size: 0x20
121+
- Address: 0x30
122+
Size: 0x40
123+
124+
--- !ELF
125+
FileHeader:
126+
Class: ELFCLASS32
127+
Data: ELFDATA2LSB
128+
Type: ET_EXEC
129+
Machine: EM_386
130+
Sections:
131+
- Name: .stack_sizes
132+
Type: SHT_PROGBITS
133+
Entries:
134+
- Address: 0x10
135+
Size: 0x20
136+
- Address: 0x30
137+
Size: 0x40
138+
139+
--- !ELF
140+
FileHeader:
141+
Class: ELFCLASS32
142+
Data: ELFDATA2MSB
143+
Type: ET_EXEC
144+
Machine: EM_386
145+
Sections:
146+
- Name: .stack_sizes
147+
Type: SHT_PROGBITS
148+
Entries:
149+
- Address: 0x10
150+
Size: 0x20
151+
- Address: 0x30
152+
Size: 0x40
153+
154+
## Check we can omit the "Address" tag. In this case the address will be zero.
155+
156+
# RUN: yaml2obj --docnum=6 %s -o %t6
157+
# RUN: llvm-readobj --sections --section-data %t6 | FileCheck %s --check-prefix=ENTRIES-NOADDR
158+
159+
# ENTRIES-NOADDR: Name: .stack_sizes
160+
# ENTRIES-NOADDR: SectionData (
161+
# ENTRIES-NOADDR-NEXT: 0000: 00000000 00000000 10000000 00000000 |
162+
# ENTRIES-NOADDR-NEXT: 0010: 0020 |
163+
164+
--- !ELF
165+
FileHeader:
166+
Class: ELFCLASS64
167+
Data: ELFDATA2LSB
168+
Type: ET_EXEC
169+
Machine: EM_X86_64
170+
Sections:
171+
- Name: .stack_sizes
172+
Type: SHT_PROGBITS
173+
Entries:
174+
- Size: 0x10
175+
- Size: 0x20
176+
177+
## Check that "Size" tag is mandatory when we describe .stack_sizes using "Entries".
178+
179+
# RUN: not yaml2obj --docnum=7 %s 2>&1 | FileCheck %s --check-prefix=ENTRIES-NOSIZE
180+
181+
# ENTRIES-NOSIZE: error: missing required key 'Size'
182+
183+
--- !ELF
184+
FileHeader:
185+
Class: ELFCLASS64
186+
Data: ELFDATA2LSB
187+
Type: ET_EXEC
188+
Machine: EM_X86_64
189+
Sections:
190+
- Name: .stack_sizes
191+
Type: SHT_PROGBITS
192+
Entries:
193+
- Address: 0x10
194+
195+
## Check we can't use both "Content" and "Entries" tags at the same time.
196+
197+
# RUN: not yaml2obj --docnum=8 %s 2>&1 | FileCheck %s --check-prefix=ENTRIES-AND-CONTENT
198+
199+
# ENTRIES-AND-CONTENT: error: .stack_sizes: Content and Entries cannot be used together
200+
201+
--- !ELF
202+
FileHeader:
203+
Class: ELFCLASS64
204+
Data: ELFDATA2LSB
205+
Type: ET_EXEC
206+
Machine: EM_X86_64
207+
Sections:
208+
- Name: .stack_sizes
209+
Type: SHT_PROGBITS
210+
Content: "00"
211+
Entries:
212+
- Address: 0x10
213+
Size: 0x20
214+
215+
## Check we must specify either "Content" or "Entries" tag when describing .stack_sizes.
216+
217+
# RUN: not yaml2obj --docnum=9 %s 2>&1 | FileCheck %s --check-prefix=NO-TAGS
218+
219+
# NO-TAGS: error: .stack_sizes: either Content or Entries tag must be specified
220+
221+
--- !ELF
222+
FileHeader:
223+
Class: ELFCLASS64
224+
Data: ELFDATA2LSB
225+
Type: ET_EXEC
226+
Machine: EM_X86_64
227+
Sections:
228+
- Name: .stack_sizes
229+
Type: SHT_PROGBITS

‎llvm/tools/obj2yaml/elf2yaml.cpp

+61
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "llvm/ADT/STLExtras.h"
1212
#include "llvm/Object/ELFObjectFile.h"
1313
#include "llvm/ObjectYAML/ELFYAML.h"
14+
#include "llvm/Support/DataExtractor.h"
1415
#include "llvm/Support/ErrorHandling.h"
1516
#include "llvm/Support/YAMLTraits.h"
1617

@@ -67,6 +68,10 @@ class ELFDumper {
6768
Expected<ELFYAML::VerneedSection *> dumpVerneedSection(const Elf_Shdr *Shdr);
6869
Expected<ELFYAML::Group *> dumpGroup(const Elf_Shdr *Shdr);
6970
Expected<ELFYAML::MipsABIFlags *> dumpMipsABIFlags(const Elf_Shdr *Shdr);
71+
Expected<ELFYAML::StackSizesSection *>
72+
dumpStackSizesSection(const Elf_Shdr *Shdr);
73+
74+
Expected<ELFYAML::Section *> dumpSpecialSection(const Elf_Shdr *Shdr);
7075

7176
public:
7277
ELFDumper(const object::ELFFile<ELFT> &O);
@@ -284,6 +289,17 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
284289
LLVM_FALLTHROUGH;
285290
}
286291
default: {
292+
// Recognize some special SHT_PROGBITS sections by name.
293+
if (Sec.sh_type == ELF::SHT_PROGBITS) {
294+
Expected<ELFYAML::Section *> SpecialSecOrErr = dumpSpecialSection(&Sec);
295+
if (!SpecialSecOrErr)
296+
return SpecialSecOrErr.takeError();
297+
if (*SpecialSecOrErr) {
298+
Y->Sections.emplace_back(*SpecialSecOrErr);
299+
break;
300+
}
301+
}
302+
287303
Expected<ELFYAML::RawContentSection *> SecOrErr =
288304
dumpContentSection(&Sec);
289305
if (!SecOrErr)
@@ -432,6 +448,18 @@ Error ELFDumper<ELFT>::dumpCommonSection(const Elf_Shdr *Shdr,
432448
return Error::success();
433449
}
434450

451+
template <class ELFT>
452+
Expected<ELFYAML::Section *>
453+
ELFDumper<ELFT>::dumpSpecialSection(const Elf_Shdr *Shdr) {
454+
auto NameOrErr = getUniquedSectionName(Shdr);
455+
if (!NameOrErr)
456+
return NameOrErr.takeError();
457+
458+
if (ELFYAML::StackSizesSection::nameMatches(*NameOrErr))
459+
return dumpStackSizesSection(Shdr);
460+
return nullptr;
461+
}
462+
435463
template <class ELFT>
436464
Error ELFDumper<ELFT>::dumpCommonRelocationSection(
437465
const Elf_Shdr *Shdr, ELFYAML::RelocationSection &S) {
@@ -450,6 +478,39 @@ Error ELFDumper<ELFT>::dumpCommonRelocationSection(
450478
return Error::success();
451479
}
452480

481+
template <class ELFT>
482+
Expected<ELFYAML::StackSizesSection *>
483+
ELFDumper<ELFT>::dumpStackSizesSection(const Elf_Shdr *Shdr) {
484+
auto S = std::make_unique<ELFYAML::StackSizesSection>();
485+
if (Error E = dumpCommonSection(Shdr, *S))
486+
return std::move(E);
487+
488+
auto ContentOrErr = Obj.getSectionContents(Shdr);
489+
if (!ContentOrErr)
490+
return ContentOrErr.takeError();
491+
492+
ArrayRef<uint8_t> Content = *ContentOrErr;
493+
DataExtractor Data(Content, Obj.isLE(), ELFT::Is64Bits ? 8 : 4);
494+
495+
std::vector<ELFYAML::StackSizeEntry> Entries;
496+
DataExtractor::Cursor Cur(0);
497+
while (Cur && Cur.tell() < Content.size()) {
498+
uint64_t Address = Data.getAddress(Cur);
499+
uint64_t Size = Data.getULEB128(Cur);
500+
Entries.push_back({Address, Size});
501+
}
502+
503+
if (Content.empty() || !Cur) {
504+
// If .stack_sizes cannot be decoded, we dump it as an array of bytes.
505+
consumeError(Cur.takeError());
506+
S->Content = yaml::BinaryRef(Content);
507+
} else {
508+
S->Entries = std::move(Entries);
509+
}
510+
511+
return S.release();
512+
}
513+
453514
template <class ELFT>
454515
Expected<ELFYAML::DynamicSection *>
455516
ELFDumper<ELFT>::dumpDynamicSection(const Elf_Shdr *Shdr) {

0 commit comments

Comments
 (0)
Please sign in to comment.