blob: ed8f984f64ba05394003666c29d2cf9cb0375753 [file]
//===------ goff2yaml.cpp - obj2yaml conversion tool ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "obj2yaml.h"
#include "llvm/Object/GOFF.h"
#include "llvm/Object/GOFFObjectFile.h"
#include "llvm/ObjectYAML/ObjectYAML.h"
#include "llvm/Support/ConvertEBCDIC.h"
using namespace llvm;
static std::string getFixedLengthEBCDICString(DataExtractor &Data,
DataExtractor::Cursor &C,
uint64_t Length,
StringRef TrimChars = {"\0", 1}) {
StringRef FixedLenStr = Data.getBytes(C, Length);
SmallString<16> Str;
ConverterEBCDIC::convertToUTF8(FixedLenStr, Str);
return Str.str().trim(TrimChars).str();
}
class GOFFDumper {
const object::GOFFObjectFile &Obj;
GOFFYAML::Object YAMLObj;
Error dumpHeader(ArrayRef<uint8_t> Data);
Error dumpExternalSymbol(ArrayRef<uint8_t> Data);
Error dumpText(ArrayRef<uint8_t> Data);
Error dumpRelocationDirectory(ArrayRef<uint8_t> Data);
Error dumpDeferredLength(ArrayRef<uint8_t> Data);
Error dumpEnd(ArrayRef<uint8_t> Data);
public:
GOFFDumper(const object::GOFFObjectFile &Obj);
Error dump();
GOFFYAML::Object &getYAMLObj();
};
GOFFDumper::GOFFDumper(const object::GOFFObjectFile &Obj) : Obj(Obj) {}
Error GOFFDumper::dumpHeader(ArrayRef<uint8_t> Data) {
DataExtractor DE(Data, false);
DataExtractor::Cursor C(0);
// Flattened data contains: PTV header (bytes 0-2) + bytes 3-60 (prefix) +
// data from byte 60 onwards HDR data starts at byte 4 in the original record
C.seek(4); // Skip PTV header and record type
YAMLObj.Header.TargetEnvironment = DE.getU32(C);
YAMLObj.Header.TargetOperatingSystem = DE.getU32(C);
DE.skip(C, 2);
YAMLObj.Header.CCSID = DE.getU16(C);
YAMLObj.Header.CharacterSetName = getFixedLengthEBCDICString(DE, C, 16);
YAMLObj.Header.LanguageProductIdentifier =
getFixedLengthEBCDICString(DE, C, 16);
YAMLObj.Header.ArchitectureLevel = DE.getU32(C);
uint16_t PropertiesLength = DE.getU16(C);
DE.skip(C, 6);
if (PropertiesLength) {
YAMLObj.Header.InternalCCSID = DE.getU16(C);
PropertiesLength -= 2;
}
if (PropertiesLength) {
YAMLObj.Header.TargetSoftwareEnvironment = DE.getU8(C);
PropertiesLength -= 1;
}
if (!C)
return C.takeError();
return Error::success();
}
Error GOFFDumper::dumpExternalSymbol(ArrayRef<uint8_t> Data) {
// TODO: Implement dumping ESD records
return Error::success();
}
Error GOFFDumper::dumpText(ArrayRef<uint8_t> Data) {
// TODO: Implement dumping TXT records
return Error::success();
}
Error GOFFDumper::dumpRelocationDirectory(ArrayRef<uint8_t> Data) {
// TODO: Implement dumping RLD records
return Error::success();
}
Error GOFFDumper::dumpDeferredLength(ArrayRef<uint8_t> Records) {
// TODO: Implement if/when GOFF LEN records are emitted by current producers
// or covered by handcrafted-object tests.
return Error::success();
}
Error GOFFDumper::dumpEnd(ArrayRef<uint8_t> Records) {
// TODO: implement dumping END records
return Error::success();
}
Error GOFFDumper::dump() {
Error Err = Error::success();
// Use the pre-flattened data structure instead of iterating through records
const auto &FlattenedData = Obj.getFlattenedData();
for (const auto &[RecordType, Data] : FlattenedData) {
switch (RecordType) {
case GOFF::RT_HDR:
if (auto Err = dumpHeader(Data))
return Err;
break;
case GOFF::RT_ESD:
if (auto Err = dumpExternalSymbol(Data))
return Err;
break;
case GOFF::RT_TXT:
if (auto Err = dumpText(Data))
return Err;
break;
case GOFF::RT_RLD:
if (auto Err = dumpRelocationDirectory(Data))
return Err;
break;
case GOFF::RT_LEN:
if (auto Err = dumpDeferredLength(Data))
return Err;
break;
case GOFF::RT_END:
if (auto Err = dumpEnd(Data))
return Err;
break;
}
}
return Err;
}
GOFFYAML::Object &GOFFDumper::getYAMLObj() { return YAMLObj; }
Error goff2yaml(raw_ostream &Out, const llvm::object::GOFFObjectFile &Obj) {
GOFFDumper Dumper(Obj);
if (auto Err = Dumper.dump())
return Err;
yaml::Output Yout(Out);
Yout << Dumper.getYAMLObj();
return Error::success();
}