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