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 13 #include "llvm/Object/GOFFObjectFile.h" 14 #include "llvm/BinaryFormat/GOFF.h" 15 #include "llvm/Object/GOFF.h" 16 #include "llvm/Support/Debug.h" 17 #include "llvm/Support/Errc.h" 18 #include "llvm/Support/raw_ostream.h" 19 20 #ifndef DEBUG_TYPE 21 #define DEBUG_TYPE "goff" 22 #endif 23 24 using namespace llvm::object; 25 using namespace llvm; 26 27 Expected<std::unique_ptr<ObjectFile>> 28 ObjectFile::createGOFFObjectFile(MemoryBufferRef Object) { 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 36 GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err) 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) { 41 Err = createStringError( 42 object_error::unexpected_eof, 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) { 52 Err = createStringError(object_error::parse_failed, 53 "object file must start with HDR record"); 54 return; 55 } 56 if ((base()[Object.getBufferSize() - GOFF::RecordLength + 1] & 0xF0) >> 4 != 57 GOFF::RT_END) { 58 Err = createStringError(object_error::parse_failed, 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) { 80 Err = createStringError(object_error::parse_failed, 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) { 90 Err = createStringError(object_error::parse_failed, 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) { 97 Err = createStringError(object_error::parse_failed, 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 for (size_t J = 0; J < GOFF::RecordLength; ++J) { 109 const uint8_t *P = I + J; 110 if (J % 8 == 0) 111 LLVM_DEBUG(dbgs() << " "); 112 113 LLVM_DEBUG(dbgs() << format("%02hhX", *P)); 114 } 115 switch (RecordType) { 116 case GOFF::RT_ESD: { 117 // Save ESD record. 118 uint32_t EsdId; 119 ESDRecord::getEsdId(I, EsdId); 120 EsdPtrs.grow(EsdId); 121 EsdPtrs[EsdId] = I; 122 123 // Determine and save the "sections" in GOFF. 124 // A section is saved as a tuple of the form 125 // case (1): (ED,child PR) 126 // - where the PR must have non-zero length. 127 // case (2a) (ED,0) 128 // - where the ED is of non-zero length. 129 // case (2b) (ED,0) 130 // - where the ED is zero length but 131 // contains a label (LD). 132 GOFF::ESDSymbolType SymbolType; 133 ESDRecord::getSymbolType(I, SymbolType); 134 SectionEntryImpl Section; 135 uint32_t Length; 136 ESDRecord::getLength(I, Length); 137 if (SymbolType == GOFF::ESD_ST_ElementDefinition) { 138 // case (2a) 139 if (Length != 0) { 140 Section.d.a = EsdId; 141 SectionList.emplace_back(Section); 142 } 143 } else if (SymbolType == GOFF::ESD_ST_PartReference) { 144 // case (1) 145 if (Length != 0) { 146 uint32_t SymEdId; 147 ESDRecord::getParentEsdId(I, SymEdId); 148 Section.d.a = SymEdId; 149 Section.d.b = EsdId; 150 SectionList.emplace_back(Section); 151 } 152 } else if (SymbolType == GOFF::ESD_ST_LabelDefinition) { 153 // case (2b) 154 uint32_t SymEdId; 155 ESDRecord::getParentEsdId(I, SymEdId); 156 const uint8_t *SymEdRecord = EsdPtrs[SymEdId]; 157 uint32_t EdLength; 158 ESDRecord::getLength(SymEdRecord, EdLength); 159 if (!EdLength) { // [ EDID, PRID ] 160 // LD child of a zero length parent ED. 161 // Add the section ED which was previously ignored. 162 Section.d.a = SymEdId; 163 SectionList.emplace_back(Section); 164 } 165 } 166 LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n"); 167 break; 168 } 169 case GOFF::RT_END: 170 LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n"); 171 break; 172 case GOFF::RT_HDR: 173 LLVM_DEBUG(dbgs() << " -- HDR (GOFF record type) unhandled\n"); 174 break; 175 default: 176 llvm_unreachable("Unknown record type"); 177 } 178 PrevRecordType = RecordType; 179 PrevContinuationBits = I[1] & 0x03; 180 } 181 } 182 183 const uint8_t *GOFFObjectFile::getSymbolEsdRecord(DataRefImpl Symb) const { 184 const uint8_t *EsdRecord = EsdPtrs[Symb.d.a]; 185 return EsdRecord; 186 } 187 188 Expected<StringRef> GOFFObjectFile::getSymbolName(DataRefImpl Symb) const { 189 if (EsdNamesCache.count(Symb.d.a)) { 190 auto &StrPtr = EsdNamesCache[Symb.d.a]; 191 return StringRef(StrPtr.second.get(), StrPtr.first); 192 } 193 194 SmallString<256> SymbolName; 195 if (auto Err = ESDRecord::getData(getSymbolEsdRecord(Symb), SymbolName)) 196 return std::move(Err); 197 198 SmallString<256> SymbolNameConverted; 199 ConverterEBCDIC::convertToUTF8(SymbolName, SymbolNameConverted); 200 201 size_t Size = SymbolNameConverted.size(); 202 auto StrPtr = std::make_pair(Size, std::make_unique<char[]>(Size)); 203 char *Buf = StrPtr.second.get(); 204 memcpy(Buf, SymbolNameConverted.data(), Size); 205 EsdNamesCache[Symb.d.a] = std::move(StrPtr); 206 return StringRef(Buf, Size); 207 } 208 209 Expected<StringRef> GOFFObjectFile::getSymbolName(SymbolRef Symbol) const { 210 return getSymbolName(Symbol.getRawDataRefImpl()); 211 } 212 213 Expected<uint64_t> GOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { 214 uint32_t Offset; 215 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb); 216 ESDRecord::getOffset(EsdRecord, Offset); 217 return static_cast<uint64_t>(Offset); 218 } 219 220 uint64_t GOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { 221 uint32_t Offset; 222 const uint8_t *EsdRecord = getSymbolEsdRecord(Symb); 223 ESDRecord::getOffset(EsdRecord, Offset); 224 return static_cast<uint64_t>(Offset); 225 } 226 227 uint64_t GOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { 228 return 0; 229 } 230 231 bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const { 232 const uint8_t *Record = getSymbolEsdRecord(Symb); 233 GOFF::ESDSymbolType SymbolType; 234 ESDRecord::getSymbolType(Record, SymbolType); 235 236 if (SymbolType == GOFF::ESD_ST_ExternalReference) 237 return true; 238 if (SymbolType == GOFF::ESD_ST_PartReference) { 239 uint32_t Length; 240 ESDRecord::getLength(Record, Length); 241 if (Length == 0) 242 return true; 243 } 244 return false; 245 } 246 247 bool GOFFObjectFile::isSymbolIndirect(DataRefImpl Symb) const { 248 const uint8_t *Record = getSymbolEsdRecord(Symb); 249 bool Indirect; 250 ESDRecord::getIndirectReference(Record, Indirect); 251 return Indirect; 252 } 253 254 Expected<uint32_t> GOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { 255 uint32_t Flags = 0; 256 if (isSymbolUnresolved(Symb)) 257 Flags |= SymbolRef::SF_Undefined; 258 259 const uint8_t *Record = getSymbolEsdRecord(Symb); 260 261 GOFF::ESDBindingStrength BindingStrength; 262 ESDRecord::getBindingStrength(Record, BindingStrength); 263 if (BindingStrength == GOFF::ESD_BST_Weak) 264 Flags |= SymbolRef::SF_Weak; 265 266 GOFF::ESDBindingScope BindingScope; 267 ESDRecord::getBindingScope(Record, BindingScope); 268 269 if (BindingScope != GOFF::ESD_BSC_Section) { 270 Expected<StringRef> Name = getSymbolName(Symb); 271 if (Name && *Name != " ") { // Blank name is local. 272 Flags |= SymbolRef::SF_Global; 273 if (BindingScope == GOFF::ESD_BSC_ImportExport) 274 Flags |= SymbolRef::SF_Exported; 275 else if (!(Flags & SymbolRef::SF_Undefined)) 276 Flags |= SymbolRef::SF_Hidden; 277 } 278 } 279 280 return Flags; 281 } 282 283 Expected<SymbolRef::Type> 284 GOFFObjectFile::getSymbolType(DataRefImpl Symb) const { 285 const uint8_t *Record = getSymbolEsdRecord(Symb); 286 GOFF::ESDSymbolType SymbolType; 287 ESDRecord::getSymbolType(Record, SymbolType); 288 GOFF::ESDExecutable Executable; 289 ESDRecord::getExecutable(Record, Executable); 290 291 if (SymbolType != GOFF::ESD_ST_SectionDefinition && 292 SymbolType != GOFF::ESD_ST_ElementDefinition && 293 SymbolType != GOFF::ESD_ST_LabelDefinition && 294 SymbolType != GOFF::ESD_ST_PartReference && 295 SymbolType != GOFF::ESD_ST_ExternalReference) { 296 uint32_t EsdId; 297 ESDRecord::getEsdId(Record, EsdId); 298 return createStringError(llvm::errc::invalid_argument, 299 "ESD record %" PRIu32 300 " has invalid symbol type 0x%02" PRIX8, 301 EsdId, SymbolType); 302 } 303 switch (SymbolType) { 304 case GOFF::ESD_ST_SectionDefinition: 305 case GOFF::ESD_ST_ElementDefinition: 306 return SymbolRef::ST_Other; 307 case GOFF::ESD_ST_LabelDefinition: 308 case GOFF::ESD_ST_PartReference: 309 case GOFF::ESD_ST_ExternalReference: 310 if (Executable != GOFF::ESD_EXE_CODE && Executable != GOFF::ESD_EXE_DATA && 311 Executable != GOFF::ESD_EXE_Unspecified) { 312 uint32_t EsdId; 313 ESDRecord::getEsdId(Record, EsdId); 314 return createStringError(llvm::errc::invalid_argument, 315 "ESD record %" PRIu32 316 " has unknown Executable type 0x%02X", 317 EsdId, Executable); 318 } 319 switch (Executable) { 320 case GOFF::ESD_EXE_CODE: 321 return SymbolRef::ST_Function; 322 case GOFF::ESD_EXE_DATA: 323 return SymbolRef::ST_Data; 324 case GOFF::ESD_EXE_Unspecified: 325 return SymbolRef::ST_Unknown; 326 } 327 } 328 } 329 330 Expected<section_iterator> 331 GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { 332 DataRefImpl Sec; 333 334 if (isSymbolUnresolved(Symb)) 335 return section_iterator(SectionRef(Sec, this)); 336 337 const uint8_t *SymEsdRecord = EsdPtrs[Symb.d.a]; 338 uint32_t SymEdId; 339 ESDRecord::getParentEsdId(SymEsdRecord, SymEdId); 340 const uint8_t *SymEdRecord = EsdPtrs[SymEdId]; 341 342 for (size_t I = 0, E = SectionList.size(); I < E; ++I) { 343 bool Found; 344 const uint8_t *SectionPrRecord = getSectionPrEsdRecord(I); 345 if (SectionPrRecord) { 346 Found = SymEsdRecord == SectionPrRecord; 347 } else { 348 const uint8_t *SectionEdRecord = getSectionEdEsdRecord(I); 349 Found = SymEdRecord == SectionEdRecord; 350 } 351 352 if (Found) { 353 Sec.d.a = I; 354 return section_iterator(SectionRef(Sec, this)); 355 } 356 } 357 return createStringError(llvm::errc::invalid_argument, 358 "symbol with ESD id " + std::to_string(Symb.d.a) + 359 " refers to invalid section with ESD id " + 360 std::to_string(SymEdId)); 361 } 362 363 const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const { 364 SectionEntryImpl EsdIds = SectionList[Sec.d.a]; 365 const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a]; 366 return EsdRecord; 367 } 368 369 const uint8_t *GOFFObjectFile::getSectionPrEsdRecord(DataRefImpl &Sec) const { 370 SectionEntryImpl EsdIds = SectionList[Sec.d.a]; 371 const uint8_t *EsdRecord = nullptr; 372 if (EsdIds.d.b) 373 EsdRecord = EsdPtrs[EsdIds.d.b]; 374 return EsdRecord; 375 } 376 377 const uint8_t * 378 GOFFObjectFile::getSectionEdEsdRecord(uint32_t SectionIndex) const { 379 DataRefImpl Sec; 380 Sec.d.a = SectionIndex; 381 const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); 382 return EsdRecord; 383 } 384 385 const uint8_t * 386 GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const { 387 DataRefImpl Sec; 388 Sec.d.a = SectionIndex; 389 const uint8_t *EsdRecord = getSectionPrEsdRecord(Sec); 390 return EsdRecord; 391 } 392 393 section_iterator GOFFObjectFile::section_begin() const { 394 DataRefImpl Sec; 395 moveSectionNext(Sec); 396 return section_iterator(SectionRef(Sec, this)); 397 } 398 399 section_iterator GOFFObjectFile::section_end() const { 400 DataRefImpl Sec; 401 return section_iterator(SectionRef(Sec, this)); 402 } 403 404 void GOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { 405 for (uint32_t I = Symb.d.a + 1, E = EsdPtrs.size(); I < E; ++I) { 406 if (EsdPtrs[I]) { 407 const uint8_t *EsdRecord = EsdPtrs[I]; 408 GOFF::ESDSymbolType SymbolType; 409 ESDRecord::getSymbolType(EsdRecord, SymbolType); 410 // Skip EDs - i.e. section symbols. 411 bool IgnoreSpecialGOFFSymbols = true; 412 bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) || 413 (SymbolType == GOFF::ESD_ST_SectionDefinition)) && 414 IgnoreSpecialGOFFSymbols; 415 if (!SkipSymbol) { 416 Symb.d.a = I; 417 return; 418 } 419 } 420 } 421 Symb.d.a = 0; 422 } 423 424 basic_symbol_iterator GOFFObjectFile::symbol_begin() const { 425 DataRefImpl Symb; 426 moveSymbolNext(Symb); 427 return basic_symbol_iterator(SymbolRef(Symb, this)); 428 } 429 430 basic_symbol_iterator GOFFObjectFile::symbol_end() const { 431 DataRefImpl Symb; 432 return basic_symbol_iterator(SymbolRef(Symb, this)); 433 } 434 435 Error Record::getContinuousData(const uint8_t *Record, uint16_t DataLength, 436 int DataIndex, SmallString<256> &CompleteData) { 437 // First record. 438 const uint8_t *Slice = Record + DataIndex; 439 size_t SliceLength = 440 std::min(DataLength, (uint16_t)(GOFF::RecordLength - DataIndex)); 441 CompleteData.append(Slice, Slice + SliceLength); 442 DataLength -= SliceLength; 443 Slice += SliceLength; 444 445 // Continuation records. 446 for (; DataLength > 0; 447 DataLength -= SliceLength, Slice += GOFF::PayloadLength) { 448 // Slice points to the start of the new record. 449 // Check that this block is a Continuation. 450 assert(Record::isContinuation(Slice) && "Continuation bit must be set"); 451 // Check that the last Continuation is terminated correctly. 452 if (DataLength <= 77 && Record::isContinued(Slice)) 453 return createStringError(object_error::parse_failed, 454 "continued bit should not be set"); 455 456 SliceLength = std::min(DataLength, (uint16_t)GOFF::PayloadLength); 457 Slice += GOFF::RecordPrefixLength; 458 CompleteData.append(Slice, Slice + SliceLength); 459 } 460 return Error::success(); 461 } 462 463 Error HDRRecord::getData(const uint8_t *Record, 464 SmallString<256> &CompleteData) { 465 uint16_t Length = getPropertyModuleLength(Record); 466 return getContinuousData(Record, Length, 60, CompleteData); 467 } 468 469 Error ESDRecord::getData(const uint8_t *Record, 470 SmallString<256> &CompleteData) { 471 uint16_t DataSize = getNameLength(Record); 472 return getContinuousData(Record, DataSize, 72, CompleteData); 473 } 474 475 Error ENDRecord::getData(const uint8_t *Record, 476 SmallString<256> &CompleteData) { 477 uint16_t Length = getNameLength(Record); 478 return getContinuousData(Record, Length, 26, CompleteData); 479 } 480