LLVM 18.0.0git
GOFFObjectFile.cpp
Go to the documentation of this file.
1//===- GOFFObjectFile.cpp - GOFF object file implementation -----*- 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// Implementation of the GOFFObjectFile class.
10//
11//===----------------------------------------------------------------------===//
12
15#include "llvm/Object/GOFF.h"
16#include "llvm/Support/Debug.h"
17#include "llvm/Support/Errc.h"
19
20#ifndef DEBUG_TYPE
21#define DEBUG_TYPE "goff"
22#endif
23
24using namespace llvm::object;
25using namespace llvm;
26
29 Error Err = Error::success();
30 std::unique_ptr<GOFFObjectFile> Ret(new GOFFObjectFile(Object, Err));
31 if (Err)
32 return std::move(Err);
33 return std::move(Ret);
34}
35
37 : ObjectFile(Binary::ID_GOFF, Object) {
38 ErrorAsOutParameter ErrAsOutParam(&Err);
39 // Object file isn't the right size, bail out early.
40 if ((Object.getBufferSize() % GOFF::RecordLength) != 0) {
43 "object file is not the right size. Must be a multiple "
44 "of 80 bytes, but is " +
45 std::to_string(Object.getBufferSize()) + " bytes");
46 return;
47 }
48 // Object file doesn't start/end with HDR/END records.
49 // Bail out early.
50 if (Object.getBufferSize() != 0) {
51 if ((base()[1] & 0xF0) >> 4 != GOFF::RT_HDR) {
53 "object file must start with HDR record");
54 return;
55 }
56 if ((base()[Object.getBufferSize() - GOFF::RecordLength + 1] & 0xF0) >> 4 !=
59 "object file must end with END record");
60 return;
61 }
62 }
63
64 SectionEntryImpl DummySection;
65 SectionList.emplace_back(DummySection); // Dummy entry at index 0.
66
67 uint8_t PrevRecordType = 0;
68 uint8_t PrevContinuationBits = 0;
69 const uint8_t *End = reinterpret_cast<const uint8_t *>(Data.getBufferEnd());
70 for (const uint8_t *I = base(); I < End; I += GOFF::RecordLength) {
71 uint8_t RecordType = (I[1] & 0xF0) >> 4;
72 bool IsContinuation = I[1] & 0x02;
73 bool PrevWasContinued = PrevContinuationBits & 0x01;
74 size_t RecordNum = (I - base()) / GOFF::RecordLength;
75
76 // If the previous record was continued, the current record should be a
77 // continuation.
78 if (PrevWasContinued && !IsContinuation) {
79 if (PrevRecordType == RecordType) {
81 "record " + std::to_string(RecordNum) +
82 " is not a continuation record but the "
83 "preceding record is continued");
84 return;
85 }
86 }
87 // Don't parse continuations records, only parse initial record.
88 if (IsContinuation) {
89 if (RecordType != PrevRecordType) {
91 "record " + std::to_string(RecordNum) +
92 " is a continuation record that does not "
93 "match the type of the previous record");
94 return;
95 }
96 if (!PrevWasContinued) {
98 "record " + std::to_string(RecordNum) +
99 " is a continuation record that is not "
100 "preceded by a continued record");
101 return;
102 }
103 PrevRecordType = RecordType;
104 PrevContinuationBits = I[1] & 0x03;
105 continue;
106 }
107
108#ifndef NDEBUG
109 for (size_t J = 0; J < GOFF::RecordLength; ++J) {
110 const uint8_t *P = I + J;
111 if (J % 8 == 0)
112 dbgs() << " ";
113
114 dbgs() << format("%02hhX", *P);
115 }
116#endif
117 switch (RecordType) {
118 case GOFF::RT_ESD: {
119 // Save ESD record.
120 uint32_t EsdId;
121 ESDRecord::getEsdId(I, EsdId);
122 EsdPtrs.grow(EsdId);
123 EsdPtrs[EsdId] = I;
124
125 // Determine and save the "sections" in GOFF.
126 // A section is saved as a tuple of the form
127 // case (1): (ED,child PR)
128 // - where the PR must have non-zero length.
129 // case (2a) (ED,0)
130 // - where the ED is of non-zero length.
131 // case (2b) (ED,0)
132 // - where the ED is zero length but
133 // contains a label (LD).
136 SectionEntryImpl Section;
140 // case (2a)
141 if (Length != 0) {
142 Section.d.a = EsdId;
143 SectionList.emplace_back(Section);
144 }
146 // case (1)
147 if (Length != 0) {
148 uint32_t SymEdId;
150 Section.d.a = SymEdId;
151 Section.d.b = EsdId;
152 SectionList.emplace_back(Section);
153 }
155 // case (2b)
156 uint32_t SymEdId;
158 const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
159 uint32_t EdLength;
160 ESDRecord::getLength(SymEdRecord, EdLength);
161 if (!EdLength) { // [ EDID, PRID ]
162 // LD child of a zero length parent ED.
163 // Add the section ED which was previously ignored.
164 Section.d.a = SymEdId;
165 SectionList.emplace_back(Section);
166 }
167 }
168 LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n");
169 break;
170 }
171 case GOFF::RT_END:
172 LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n");
173 break;
174 case GOFF::RT_HDR:
175 LLVM_DEBUG(dbgs() << " -- HDR (GOFF record type) unhandled\n");
176 break;
177 default:
178 llvm_unreachable("Unknown record type");
179 }
180 PrevRecordType = RecordType;
181 PrevContinuationBits = I[1] & 0x03;
182 }
183}
184
185const uint8_t *GOFFObjectFile::getSymbolEsdRecord(DataRefImpl Symb) const {
186 const uint8_t *EsdRecord = EsdPtrs[Symb.d.a];
187 return EsdRecord;
188}
189
191 if (EsdNamesCache.count(Symb.d.a)) {
192 auto &StrPtr = EsdNamesCache[Symb.d.a];
193 return StringRef(StrPtr.second.get(), StrPtr.first);
194 }
195
196 SmallString<256> SymbolName;
197 if (auto Err = ESDRecord::getData(getSymbolEsdRecord(Symb), SymbolName))
198 return std::move(Err);
199
200 SmallString<256> SymbolNameConverted;
201 ConverterEBCDIC::convertToUTF8(SymbolName, SymbolNameConverted);
202
203 size_t Size = SymbolNameConverted.size();
204 auto StrPtr = std::make_pair(Size, std::make_unique<char[]>(Size));
205 char *Buf = StrPtr.second.get();
206 memcpy(Buf, SymbolNameConverted.data(), Size);
207 EsdNamesCache[Symb.d.a] = std::move(StrPtr);
208 return StringRef(Buf, Size);
209}
210
212 return getSymbolName(Symbol.getRawDataRefImpl());
213}
214
215Expected<uint64_t> GOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
217 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
218 ESDRecord::getOffset(EsdRecord, Offset);
219 return static_cast<uint64_t>(Offset);
220}
221
222uint64_t GOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
224 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
225 ESDRecord::getOffset(EsdRecord, Offset);
226 return static_cast<uint64_t>(Offset);
227}
228
229uint64_t GOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
230 return 0;
231}
232
233bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const {
234 const uint8_t *Record = getSymbolEsdRecord(Symb);
237
239 return true;
243 if (Length == 0)
244 return true;
245 }
246 return false;
247}
248
249bool GOFFObjectFile::isSymbolIndirect(DataRefImpl Symb) const {
250 const uint8_t *Record = getSymbolEsdRecord(Symb);
251 bool Indirect;
253 return Indirect;
254}
255
256Expected<uint32_t> GOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
257 uint32_t Flags = 0;
258 if (isSymbolUnresolved(Symb))
260
261 const uint8_t *Record = getSymbolEsdRecord(Symb);
262
263 GOFF::ESDBindingStrength BindingStrength;
264 ESDRecord::getBindingStrength(Record, BindingStrength);
265 if (BindingStrength == GOFF::ESD_BST_Weak)
267
268 GOFF::ESDBindingScope BindingScope;
269 ESDRecord::getBindingScope(Record, BindingScope);
270
271 if (BindingScope != GOFF::ESD_BSC_Section) {
273 if (Name && *Name != " ") { // Blank name is local.
275 if (BindingScope == GOFF::ESD_BSC_ImportExport)
277 else if (!(Flags & SymbolRef::SF_Undefined))
279 }
280 }
281
282 return Flags;
283}
284
286GOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
287 const uint8_t *Record = getSymbolEsdRecord(Symb);
290 GOFF::ESDExecutable Executable;
291 ESDRecord::getExecutable(Record, Executable);
292
298 uint32_t EsdId;
301 "ESD record %" PRIu32
302 " has invalid symbol type 0x%02" PRIX8,
303 EsdId, SymbolType);
304 }
305 switch (SymbolType) {
308 return SymbolRef::ST_Other;
312 if (Executable != GOFF::ESD_EXE_CODE && Executable != GOFF::ESD_EXE_DATA &&
313 Executable != GOFF::ESD_EXE_Unspecified) {
314 uint32_t EsdId;
317 "ESD record %" PRIu32
318 " has unknown Executable type 0x%02X",
319 EsdId, Executable);
320 }
321 switch (Executable) {
325 return SymbolRef::ST_Data;
328 }
329 llvm_unreachable("Unhandled ESDExecutable");
330 }
331 llvm_unreachable("Unhandled ESDSymbolType");
332}
333
335GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
336 DataRefImpl Sec;
337
338 if (isSymbolUnresolved(Symb))
339 return section_iterator(SectionRef(Sec, this));
340
341 const uint8_t *SymEsdRecord = EsdPtrs[Symb.d.a];
342 uint32_t SymEdId;
343 ESDRecord::getParentEsdId(SymEsdRecord, SymEdId);
344 const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
345
346 for (size_t I = 0, E = SectionList.size(); I < E; ++I) {
347 bool Found;
348 const uint8_t *SectionPrRecord = getSectionPrEsdRecord(I);
349 if (SectionPrRecord) {
350 Found = SymEsdRecord == SectionPrRecord;
351 } else {
352 const uint8_t *SectionEdRecord = getSectionEdEsdRecord(I);
353 Found = SymEdRecord == SectionEdRecord;
354 }
355
356 if (Found) {
357 Sec.d.a = I;
358 return section_iterator(SectionRef(Sec, this));
359 }
360 }
362 "symbol with ESD id " + std::to_string(Symb.d.a) +
363 " refers to invalid section with ESD id " +
364 std::to_string(SymEdId));
365}
366
367const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const {
368 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
369 const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a];
370 return EsdRecord;
371}
372
373const uint8_t *GOFFObjectFile::getSectionPrEsdRecord(DataRefImpl &Sec) const {
374 SectionEntryImpl EsdIds = SectionList[Sec.d.a];
375 const uint8_t *EsdRecord = nullptr;
376 if (EsdIds.d.b)
377 EsdRecord = EsdPtrs[EsdIds.d.b];
378 return EsdRecord;
379}
380
381const uint8_t *
382GOFFObjectFile::getSectionEdEsdRecord(uint32_t SectionIndex) const {
383 DataRefImpl Sec;
384 Sec.d.a = SectionIndex;
385 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
386 return EsdRecord;
387}
388
389const uint8_t *
390GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const {
391 DataRefImpl Sec;
392 Sec.d.a = SectionIndex;
393 const uint8_t *EsdRecord = getSectionPrEsdRecord(Sec);
394 return EsdRecord;
395}
396
398 DataRefImpl Sec;
399 moveSectionNext(Sec);
400 return section_iterator(SectionRef(Sec, this));
401}
402
404 DataRefImpl Sec;
405 return section_iterator(SectionRef(Sec, this));
406}
407
409 for (uint32_t I = Symb.d.a + 1, E = EsdPtrs.size(); I < E; ++I) {
410 if (EsdPtrs[I]) {
411 const uint8_t *EsdRecord = EsdPtrs[I];
414 // Skip EDs - i.e. section symbols.
415 bool IgnoreSpecialGOFFSymbols = true;
416 bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) ||
418 IgnoreSpecialGOFFSymbols;
419 if (!SkipSymbol) {
420 Symb.d.a = I;
421 return;
422 }
423 }
424 }
425 Symb.d.a = 0;
426}
427
429 DataRefImpl Symb;
430 moveSymbolNext(Symb);
431 return basic_symbol_iterator(SymbolRef(Symb, this));
432}
433
435 DataRefImpl Symb;
436 return basic_symbol_iterator(SymbolRef(Symb, this));
437}
438
440 int DataIndex, SmallString<256> &CompleteData) {
441 // First record.
442 const uint8_t *Slice = Record + DataIndex;
443 size_t SliceLength =
444 std::min(DataLength, (uint16_t)(GOFF::RecordLength - DataIndex));
445 CompleteData.append(Slice, Slice + SliceLength);
446 DataLength -= SliceLength;
447 Slice += SliceLength;
448
449 // Continuation records.
450 for (; DataLength > 0;
451 DataLength -= SliceLength, Slice += GOFF::PayloadLength) {
452 // Slice points to the start of the new record.
453 // Check that this block is a Continuation.
454 assert(Record::isContinuation(Slice) && "Continuation bit must be set");
455 // Check that the last Continuation is terminated correctly.
456 if (DataLength <= 77 && Record::isContinued(Slice))
458 "continued bit should not be set");
459
460 SliceLength = std::min(DataLength, (uint16_t)GOFF::PayloadLength);
462 CompleteData.append(Slice, Slice + SliceLength);
463 }
464 return Error::success();
465}
466
468 SmallString<256> &CompleteData) {
470 return getContinuousData(Record, Length, 60, CompleteData);
471}
472
474 SmallString<256> &CompleteData) {
475 uint16_t DataSize = getNameLength(Record);
476 return getContinuousData(Record, DataSize, 72, CompleteData);
477}
478
480 SmallString<256> &CompleteData) {
482 return getContinuousData(Record, Length, 26, CompleteData);
483}
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DEBUG(X)
Definition: Debug.h:101
std::string Name
uint64_t Size
bool End
Definition: ELF_riscv.cpp:469
#define I(x, y, z)
Definition: MD5.cpp:58
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
FunctionLoweringInfo::StatepointRelocationRecord RecordType
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition: DenseMap.h:151
Helper for Errors used as out-parameters.
Definition: Error.h:1102
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Tagged union holding either a T or a Error.
Definition: Error.h:474
StorageT::size_type size() const
Definition: IndexedMap.h:78
void grow(IndexT n)
Definition: IndexedMap.h:68
const char * getBufferEnd() const
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
void append(StringRef RHS)
Append from a StringRef.
Definition: SmallString.h:68
size_t size() const
Definition: SmallVector.h:91
pointer data()
Return a pointer to the vector's buffer, even if empty().
Definition: SmallVector.h:289
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
MemoryBufferRef Data
Definition: Binary.h:37
static Error getData(const uint8_t *Record, SmallString< 256 > &CompleteData)
static uint16_t getNameLength(const uint8_t *Record)
Definition: GOFF.h:274
static void getIndirectReference(const uint8_t *Record, bool &Indirect)
Definition: GOFF.h:236
static void getBindingStrength(const uint8_t *Record, GOFF::ESDBindingStrength &Strength)
Definition: GOFF.h:222
static void getOffset(const uint8_t *Record, uint32_t &Offset)
Definition: GOFF.h:120
static void getEsdId(const uint8_t *Record, uint32_t &EsdId)
Definition: GOFF.h:112
static Error getData(const uint8_t *Record, SmallString< 256 > &CompleteData)
static void getLength(const uint8_t *Record, uint32_t &Length)
Definition: GOFF.h:124
static void getParentEsdId(const uint8_t *Record, uint32_t &EsdId)
Definition: GOFF.h:116
static void getSymbolType(const uint8_t *Record, GOFF::ESDSymbolType &SymbolType)
Definition: GOFF.h:105
static uint16_t getNameLength(const uint8_t *Record)
Definition: GOFF.h:263
static void getExecutable(const uint8_t *Record, GOFF::ESDExecutable &Executable)
Definition: GOFF.h:208
static void getBindingScope(const uint8_t *Record, GOFF::ESDBindingScope &Scope)
Definition: GOFF.h:242
section_iterator section_begin() const override
basic_symbol_iterator symbol_end() const override
GOFFObjectFile(MemoryBufferRef Object, Error &Err)
section_iterator section_end() const override
Expected< StringRef > getSymbolName(SymbolRef Symbol) const
void moveSymbolNext(DataRefImpl &Symb) const override
basic_symbol_iterator symbol_begin() const override
static Error getData(const uint8_t *Record, SmallString< 256 > &CompleteData)
static uint16_t getPropertyModuleLength(const uint8_t *Record)
Definition: GOFF.h:81
This class is the base class for all object file types.
Definition: ObjectFile.h:229
friend class SymbolRef
Definition: ObjectFile.h:247
friend class SectionRef
Definition: ObjectFile.h:261
const uint8_t * base() const
Definition: ObjectFile.h:235
static Expected< std::unique_ptr< ObjectFile > > createGOFFObjectFile(MemoryBufferRef Object)
Represents a GOFF physical record.
Definition: GOFF.h:31
static bool isContinued(const uint8_t *Record)
Definition: GOFF.h:36
static Error getContinuousData(const uint8_t *Record, uint16_t DataLength, int DataIndex, SmallString< 256 > &CompleteData)
static bool isContinuation(const uint8_t *Record)
Definition: GOFF.h:42
This is a value type class that represents a single symbol in the list of symbols in the object file.
Definition: ObjectFile.h:168
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void convertToUTF8(StringRef Source, SmallVectorImpl< char > &Result)
@ RT_ESD
Definition: GOFF.h:32
@ RT_HDR
Definition: GOFF.h:37
@ RT_END
Definition: GOFF.h:36
constexpr uint8_t RecordPrefixLength
Definition: GOFF.h:25
constexpr uint8_t PayloadLength
Definition: GOFF.h:26
ESDExecutable
Definition: GOFF.h:96
@ ESD_EXE_Unspecified
Definition: GOFF.h:97
@ ESD_EXE_CODE
Definition: GOFF.h:99
@ ESD_EXE_DATA
Definition: GOFF.h:98
ESDBindingScope
Definition: GOFF.h:121
@ ESD_BSC_ImportExport
Definition: GOFF.h:126
@ ESD_BSC_Section
Definition: GOFF.h:123
constexpr uint8_t RecordLength
Definition: GOFF.h:24
ESDSymbolType
Definition: GOFF.h:40
@ ESD_ST_PartReference
Definition: GOFF.h:44
@ ESD_ST_ElementDefinition
Definition: GOFF.h:42
@ ESD_ST_LabelDefinition
Definition: GOFF.h:43
@ ESD_ST_SectionDefinition
Definition: GOFF.h:41
@ ESD_ST_ExternalReference
Definition: GOFF.h:45
ESDBindingStrength
Definition: GOFF.h:109
@ ESD_BST_Weak
Definition: GOFF.h:111
content_iterator< SectionRef > section_iterator
Definition: ObjectFile.h:47
content_iterator< BasicSymbolRef > basic_symbol_iterator
Definition: SymbolicFile.h:143
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:440
@ Length
Definition: DWP.cpp:440
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1244
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
Helper object to track which of three possible relocation mechanisms are used for a particular value ...
struct llvm::object::DataRefImpl::@351 d