#include #include #include #include #include "utils.h" #include "cray_softcpu.h" #include #include // TODO: // - The data segments contain stack-frame info that's described in usr\include\cray\tnb.h. These entries are there for all file formats (even for the kernel). // there could be a routine that searches the binary for likely tnb records and creates 'symbol entries' for all of them. Then during disassembly these entries // can be referenced and printed out providing callee names and potentially even argument numbers. It can also list the size of const, temp, etc. sections // plus the name when encountering the entry point of such a function int PrintUsage(const char *aExecName, const char *ErrorStr = nullptr) { if (ErrorStr != nullptr) std::cout << "Error: " << ErrorStr << std::endl; std::cout << "Usage: " << aExecName << " [options]" << std::endl; std::cout << std::endl; std::cout << "\t" << "Options:" << std::endl; std::cout << "\t" << "-i : specifies image offset in 64-bit words" << std::endl; std::cout << "\t" << "-o : specifies load offset in 64-bit words" << std::endl; std::cout << "\t" << "-s : specifies the start address (in Cray address format) to start disassembly from" << std::endl; std::cout << "\t" << "-e : specifies the end address (in Cray address format) to end disassembly at" << std::endl; std::cout << "\t" << "-ib : specifies the instruction base address (in word address format) for the image" << std::endl; std::cout << "\t" << "-db : specifies the data base address (in word address format) for the image" << std::endl; std::cout << "\t" << "-raw: assumes binary is raw (doesn't try to parse executable header)" << std::endl; std::cout << "\t" << "-unicos: assumes binary is in unicos format" << std::endl; std::cout << "\t" << "-obj: assumes binary is in unicos object format" << std::endl; std::cout << "\t" << "-hex: print instruction codes in hex" << std::endl; std::cout << "\t" << "-patch: creates a patch file" << std::endl; std::cout << "\t" << "-xmp: assume X-MP image" << std::endl; std::cout << "\t" << "-ymp: assume Y-MP image" << std::endl; std::cout << "\t" << "-out : sets output file name" << std::endl; std::cout << "\t" << "Note: start and end addresses ARE base-relative" << std::endl; return 1; } // Definitions from relo.h enum TableType_e { LHT_TYPE = 001, // Library (build) header table BLD_TYPE = 002, // Build directory table MTT_TYPE = 010, // Module termination table SMT_TYPE = 011, // Module Symbol table XRL_TYPE = 014, // Extended relocation table REL_TYPE, // Relocation table TXT_TYPE, // Text table PDT_TYPE, // Program Descriptor table CMB_TYPE = 021, // Common Block Symbol table PAS_TYPE = 026, // Pass-through table for Fortran 90 GNT_TYPE = 027, // Global symbol table DMT_TYPE = 040, // Distributed module termination table DFI_TYPE = 042, // Distributed field initialization table DEX_TYPE, // Distributed Expression table DPD_TYPE = 047 // Distributed Program Descriptor table }; typedef uint64_t FIELD; class RangeContainer_c { public: RangeContainer_c() : mSize(0) {} std::vector ReadFields(std::istream &aStrm) const { size_t StructSize = (mSize + 63) / 64; std::vector RetVal(StructSize); aStrm.read((char*)(&RetVal[0]), StructSize * sizeof(uint64_t)); if (aStrm.bad()) throw Generic_x() << "Can't read from file"; // for (size_t Idx = 0; Idx < StructSize; ++Idx) { // RetVal[Idx] = SwapBytes(RetVal[Idx]); // } return RetVal; } void Read(std::istream &aStrm); size_t SizeInBits() const { return mSize; } size_t SizeInWords() const { return (mSize + 63) / 64; } protected: size_t mSize; std::vector mRawBuffer; std::vector mFields; std::vector mArrFields; friend class FieldBase_c; friend class ArrFieldBase_c; }; class FieldBase_c { public: FieldBase_c(RangeContainer_c &aParent, size_t aSize) : mStart(aParent.mSize), mEnd(aParent.mSize + aSize - 1), mParent(aParent) { aParent.mSize = mEnd + 1; aParent.mFields.push_back(this); } protected: template < typename tType, typename std::enable_if< ! std::is_same::value>::type * = nullptr > tType Get(std::vector &aRawBuffer) const { if (mEnd - mStart == 64) { CRAY_ASSERT((mStart % 64) == 0); return tType(SwapBytes(aRawBuffer[mStart / 64])); } size_t WordOfs = mStart / 64; size_t Start = mStart % 64; size_t End = mEnd % 64; uint64_t Val = GetBitsReverse(SwapBytes(aRawBuffer[WordOfs]), BitRange_s(uint8_t(Start), uint8_t(End))); return tType(Val); } template < typename tType, typename std::enable_if< std::is_same::value>::type * = nullptr > char * Get(std::vector &aRawBuffer) const { CRAY_ASSERT((mStart % 8) == 0); CRAY_ASSERT((mEnd % 8) == 0); size_t Ofs = mStart / 8; return ((char *)(&aRawBuffer[0])) + Ofs; } template tType Get() const { return Get(mParent.mRawBuffer); } virtual void Fill() = 0; size_t mStart; size_t mEnd; RangeContainer_c &mParent; friend RangeContainer_c; friend class ArrFieldBase_c; }; template class Field_T : public FieldBase_c { public: Field_T(RangeContainer_c &aParent, size_t aSize) : FieldBase_c(aParent, aSize) {} tType Get() const { return mValue; } protected: virtual void Fill() override { mValue = FieldBase_c::Get(); } tType mValue; }; class ArrFieldBase_c { protected: ArrFieldBase_c(RangeContainer_c &aParent, FieldBase_c &aLen) : mLen(aLen), mParent(aParent) { CRAY_ASSERT((aParent.mSize % 64) == 0); aParent.mArrFields.push_back(this); } virtual void Read(std::istream &aStrm) = 0; size_t Len() const { return mLen.Get(); } void AdjustParentSize(size_t aLen) const { mParent.mSize += aLen; } RangeContainer_c &mParent; FieldBase_c &mLen; friend RangeContainer_c; }; class StrField_c: public ArrFieldBase_c { public: StrField_c(RangeContainer_c &aParent, FieldBase_c &aLen) : ArrFieldBase_c(aParent, aLen) { } const std::string &Get() const { return mValue; } protected: std::string mValue; virtual void Read(std::istream &aStrm) override { size_t StrLen = Len(); if (StrLen == 0) { mValue = std::string(); return; } size_t WordLen = WordSize(); AdjustParentSize(WordLen * 64); std::vector StrChars(WordLen * 8 + 1); std::fill(StrChars.begin(), StrChars.end(), 0); aStrm.read((char*)(&StrChars[0]), WordLen * 8); mValue = std::string(&StrChars[0]); } size_t WordSize() const { return (Len() + 7) / 8; } }; template class ArrField_T : public ArrFieldBase_c { public: ArrField_T(RangeContainer_c &aParent, FieldBase_c &aLen) : ArrFieldBase_c(aParent, aLen) { } const std::vector &Get() const { return mValue; } protected: std::vector mValue; virtual void Read(std::istream &aStrm) override { size_t ArrLen = Len(); if (ArrLen == 0) { mValue.clear(); return; } AdjustParentSize(ArrLen * 64); mValue.resize(ArrLen); aStrm.read((char*)(&mValue[0]), ArrLen * sizeof(tType)); } }; class ExtraField_c : public ArrField_T { public: ExtraField_c(class ProgDescTable_c &aParent); protected: virtual void Read(std::istream &aStrm) override; }; void RangeContainer_c::Read(std::istream &aStrm) { mRawBuffer = ReadFields(aStrm); for (auto &Field : mFields) { Field->Fill(); } for (auto &ArrField : mArrFields) { ArrField->Read(aStrm); } } class ProgDescTable_c : public RangeContainer_c { public: ProgDescTable_c() : pdthdsz(*this, 16), pdtblsz(*this, 16), pdtensz(*this, 16), pdtexsz(*this, 16), pdtmdy(*this, 64), pdthms(*this, 64), pdtcmpid(*this, 64), pdtcmpvr(*this, 64), pdtosvr(*this, 64), pdtudt(*this, 64), filler01(*this, 1), pdtfe(*this, 1), pdtbd(*this, 1), pdtmpa(*this, 1), pdtdc(*this, 1), pdtusr(*this, 8), filler02(*this, 1), pdtmf(*this, 2), pdtfnl(*this, 8), pdtmnl(*this, 8), pdtss(*this, 32), pdtuqnm(*this, 64), mExtra(*this), mFileName(*this, pdtfnl), mModuleName(*this, pdtmnl) {} Field_T pdthdsz; // Word size of header area Field_T pdtblsz; // Word size of block area Field_T pdtensz; // Word size of entry area Field_T pdtexsz; // Word size of external area Field_T pdtmdy; // MM/DD/YY - this compilation Field_T pdthms; // HH:MM:SS - this compilation Field_T pdtcmpid; // Generating product name Field_T pdtcmpvr; // Generating product version Field_T pdtosvr; // Host OS version Field_T pdtudt; // UNICOS time stamp (date) Field_T filler01; // (Unused, reserved by CRI) Field_T pdtfe; // Fatal error flag (1==true) Field_T pdtbd; // Block data module (1==true) Field_T pdtmpa; // Module passed address flag Field_T pdtdc; // Dual case names flag(1==true) Field_T pdtusr; // (Unused, reserved for user) Field_T filler02; // (Unused, reserved by CRI) Field_T pdtmf; // Module flag for Fortran 90: // 0 = independent // 1 = first of a module // 2 = in a module set // 3 = last of a module Field_T pdtfnl; // Char count in file name Field_T pdtmnl; // Char count in module name Field_T pdtss; // Stack size requirement Field_T pdtuqnm; // Unique ID for module name ExtraField_c mExtra; StrField_c mFileName; StrField_c mModuleName; }; ExtraField_c::ExtraField_c(class ProgDescTable_c &aParent) : ArrField_T(aParent, aParent.pdthdsz) {} inline void ExtraField_c::Read(std::istream &aStrm) { ProgDescTable_c &Parent = static_cast(mParent); size_t ArrLen = size_t(Parent.pdthdsz.Get()) - size_t(10 + ((Parent.pdtmnl.Get() + 7) / 8) + ((Parent.pdtfnl.Get() + 7) / 8)); if (ArrLen == 0) { mValue.clear(); return; } AdjustParentSize(ArrLen * 64); mValue.resize(ArrLen); aStrm.read((char*)(&mValue[0]), ArrLen * sizeof(uint64_t)); } // Constants for the pdtbkl (block location) field enum BlockLocation_e { BKL_CM = 0, // Common memory, also CRAY-2 FGP instr memory BKL_LM = 1, // CRAY-2 local memory, also CRAY-2 FGP local memory BKL_LMA = 2, // CRAY-2 local memory absolute (unused by UNICOS) BKL_EM = 3, // CRAY X-MP extended memory BKL_AX = 4 // CRAY X-MP auxiliary memory }; // Constants for the pdtbkc (block contents) field enum BlockContent_e { BKC_UNK = 0, // Unknown BKC_IX = 1, // Instructions only BKC_DT = 2, // Data only BKC_BS = 3, // Data only with no text (bss) BKC_CN = 4, // Constants only BKC_ZD = 5 // Data only with no text (zero fill assumed) }; // Constants for the pdtbkt (block type) field enum BlockType_e { BKT_CM = 0, // Regular common block BKT_TCM = 2, // Task common block BKT_DBF = 4 // Dynamic block }; // Constants for the pdtbal (block align) flag enum BlockAlign_e { BAL_NA = 0, // No alignment BAL_AL = 1 // Align to instruction buffer boundary }; class BlockDesc_c : public RangeContainer_c { public: BlockDesc_c() : pdtbkcb(*this, 1), pdtbkl(*this, 3), pdtbkc(*this, 3), pdtbkt(*this, 3), pdtbal(*this, 1), pdtbef(*this, 1), filler01(*this, 4), pdtbusr(*this, 8), pdtbknl(*this, 8), pdtbkln(*this, 32), mName(*this, pdtbknl) {} Field_T pdtbkcb; // Common block flag (1==true) Field_T pdtbkl; // Block location Field_T pdtbkc; // Block contents Field_T pdtbkt; // Block type Field_T pdtbal; // Block align flag Field_T pdtbef; // Block entry flag Field_T filler01; // (Unused, reserved by CRI) Field_T pdtbusr; // (Unused, reserved for user) Field_T pdtbknl; // Char count in block name Field_T pdtbkln; // Block length (words) StrField_c mName; uint64_t FileOffset; } cBlockDesc; class EntryDesc_c: public RangeContainer_c { public: EntryDesc_c() : EntryPointInBits(*this, 64), PrimaryEntryFlag(*this, 1), filler01(*this, 1), NameLength(*this, 8), SuggestedRelocationMode(*this, 3), filler02(*this, 3), filler03(*this, 16), filler04(*this, 8), pdteusr(*this, 8), BlockIndex(*this, 16), mName(*this, NameLength) {} Field_T EntryPointInBits; // Entry point (signed) value - in bits Field_T PrimaryEntryFlag; // Primary entry flag (1==true) Field_T filler01; // (Unused, reserved by CRI) Field_T NameLength; // Char count in entry name Field_T SuggestedRelocationMode; // Suggested relocation mode Field_T filler02; // (Unused, reserved by CRI) Field_T filler03; // (Unused, reserved by CRI) Field_T filler04; // (Unused, reserved by CRI) Field_T pdteusr; // (Unused, reserved for user) Field_T BlockIndex; // Block index StrField_c mName; } cEntryDesc; // Constants for pdtxct (call tree information) field enum CallTreeInfo_e { XCT_EXT = 0, // Regular external XCT_THDO = 1, // External is task head XCT_THDS = 2 // External is both task head and subprogram }; class ExternDesc_c: public RangeContainer_c { public: ExternDesc_c() : pdtxmn(*this, 1), // Module specification filler00(*this, 1), // (Unused, reserved by CRI) NameLength(*this, 8), // Char count in external name pdtxsf(*this, 1), // Soft external (1==true) pdtxct(*this, 2), // Call tree information ExternalPassedAsArgument(*this, 1), // External passed as argument filler01(*this, 18), // (Unused, reserved by CRI) filler02(*this, 24), // (Unused, reserved by CRI) pdtxusr(*this, 8), // (Unused, reserved for user) mName(*this, NameLength) {} Field_T pdtxmn; // Module specification Field_T filler00; // (Unused, reserved by CRI) Field_T NameLength; // Char count in external name Field_T pdtxsf; // Soft external (1==true) Field_T pdtxct; // Call tree information Field_T ExternalPassedAsArgument; // External passed as argument Field_T filler01; // (Unused, reserved by CRI) Field_T filler02; // (Unused, reserved by CRI) Field_T pdtxusr; // (Unused, reserved for user) StrField_c mName; uint64_t FileOffset; } cExternRanges; class HdrDesc_c : public RangeContainer_c { public: HdrDesc_c() : hdr_type(*this, 7), hdr_undef(*this, 9), hdr_bi(*this, 16), hdr_len(*this, 32) {} Field_T hdr_type; // Table type Field_T hdr_undef; // (Unused, reserved by CRI) Field_T hdr_bi; // Block index (optional) Field_T hdr_len; // Table length }; // A text table (TXT) contains hdr_len words. One text table // contains zero or more subtables. Each subtable has a two // word header. Fields within this two word header are defined // as follows. class TxtItem_c: public RangeContainer_c { public: TxtItem_c(): mIncrementBetweenDups(*this, 17), mStartingBitAddress(*this, 38), mNumberOfBitsInLastWord(*this, 6), mUnusedUsr1(*this, 3), mUnusedUsr2(*this, 5), mUnusedCRI(*this, 8), mNumOfDuplications(*this, 19), mNumberOfTextWords(*this, 32), mContent(*this, mNumberOfTextWords) {} Field_T mIncrementBetweenDups; Field_T mStartingBitAddress; Field_T mNumberOfBitsInLastWord; Field_T mUnusedUsr1; Field_T mUnusedUsr2; Field_T mUnusedCRI; Field_T mNumOfDuplications; Field_T mNumberOfTextWords; // Text words immediately follow the two word header, // the number of which is specified by txtntw. ArrField_T mContent; }; // Constants for the SuggestedRelocationMode, relrm, and xrlrm (relocation mode) fields enum RelocationMode_e { RM_WORD = 0, // Word address RM_HALF = 1, // Half word address RM_PARC = 2, // Parcel address RM_BYTE = 3, // Byte address RM_BIT = 6, // Bit address RM_ENTR = 7 // Relocation mode from associated entry (SuggestedRelocationMode); legal on external references only. }; // A relocation table (REL) contains hdr_len words. One // relocation table contains zero or more single word // relocation entries. Fields within these single word entries // are defined as follows. class RelItem_c : public RangeContainer_c { public: RelItem_c() : RelocationType(*this, 1), RelocationIndex(*this, 16), RightmostBitAddress(*this, 38), FieldLengthInBits(*this, 6), RelocationMode(*this, 3) {} Field_T RelocationType; Field_T RelocationIndex; Field_T RightmostBitAddress; Field_T FieldLengthInBits; Field_T RelocationMode; }; // Constants for the relrt and xrlrt(relocation type) fields enum RelocationType_e { RT_BLK = 0, // Block entry RT_EXT = 1 // External entry }; // Constants for the xrlsp(special relocation) field enum SpecialRelocation_e { SP_NONE = 0, // no special relocation SP_RVHF = 1, // reversed halves relocation SP_TS3PARCEL = 2, // three-parcel relocation SP_TSHIGH = 3, // high part of split relocation SP_TSLOW = 4 // low part of split relocation }; // Constants for the xrlsr (sign specification of result) field enum SignSpecResult_e { SR_NONE = 0, // Sign does not matter SR_POS = 1, // Field must be positive SR_NEG = 2, // Field must be negative SR_EXT = 3 // Field is sign extended }; // An extended relocation table (XRL) contains hdr_len words. // One extended relocation table contains zero or more double // word relocation entries. Fields within these double word // entries are defined as follows. class XRelItem_c : public RangeContainer_c { public: XRelItem_c() : RelocationType(*this, 1), RelocationIndex(*this, 16), UnusedUser(*this, 8), UnusedCRI1(*this, 7), ExtendedAddress(*this, 16), SpecialRelocation(*this, 3), SignBeforeRelocation(*this, 1), SignSpecificationResult(*this, 3), FieldLengthInBits(*this, 6), RelocationMode(*this, 3), UnusedCRI2(*this, 26), RightmostBitAddress(*this, 38) {} Field_T RelocationType; Field_T RelocationIndex; Field_T UnusedUser; Field_T UnusedCRI1; Field_T ExtendedAddress; Field_T SpecialRelocation; Field_T SignBeforeRelocation; Field_T SignSpecificationResult; Field_T FieldLengthInBits; Field_T RelocationMode; Field_T UnusedCRI2; Field_T RightmostBitAddress; }; class TxtBlock_c { public: std::vector mTxtItems; std::vector mRelItems; std::vector mXRelItems; void Read(std::ifstream &aFile, const BlockDesc_c &aBlock) { if (aBlock.pdtbkc.Get() == BKC_BS || aBlock.pdtbkc.Get() == BKC_ZD) return; // These blocks don't have text or relo records associated with them size_t BlockLen = size_t(aBlock.pdtbkln.Get()); size_t WordsRead = 0; HdrDesc_c Header; Header.Read(aFile); while (WordsRead < BlockLen) { if (Header.hdr_type.Get() != TXT_TYPE) { throw Generic_x() << "Unknown TXT block header type: " << OctPrinter(Header.hdr_type.Get()); } // Read all the TXT sub-entries size_t SubBlockLen = Header.hdr_len.Get(); size_t SubBlockRead = Header.SizeInWords(); size_t SubBlockPayloadSize = 0; while (SubBlockRead < SubBlockLen) { TxtItem_c Item; Item.Read(aFile); SubBlockRead += Item.SizeInWords(); SubBlockPayloadSize += Item.mNumberOfTextWords.Get(); mTxtItems.push_back(Item); }; CRAY_ASSERT(SubBlockRead == SubBlockLen); WordsRead += SubBlockPayloadSize; Header.Read(aFile); } if (WordsRead != BlockLen) throw Generic_x() << "Too many words (" << HexPrinter(WordsRead) << ") read for block of size " << HexPrinter(BlockLen); while (Header.hdr_type.Get() == REL_TYPE || Header.hdr_type.Get() == XRL_TYPE) { switch (Header.hdr_type.Get()) { case REL_TYPE: { // Read all the REL sub-entries size_t SubBlockLen = Header.hdr_len.Get(); size_t SubBlockRead = Header.SizeInWords(); while (SubBlockRead < SubBlockLen) { RelItem_c Item; Item.Read(aFile); SubBlockRead += Item.SizeInWords(); mRelItems.push_back(Item); }; CRAY_ASSERT(SubBlockRead == SubBlockLen); //WordsRead += SubBlockRead; } break; case XRL_TYPE: { // Read all the XRL sub-entries size_t SubBlockLen = Header.hdr_len.Get(); size_t SubBlockRead = Header.SizeInWords(); while (SubBlockRead < SubBlockLen) { // Dump binary content uint64_t Content[2]; aFile.read((char*)Content, sizeof(Content)); aFile.seekg(-int(sizeof(Content)), std::ios::cur); // std::cout << "XREL location: " << HexPrinter(aFile.tellg()) << " content: " << HexPrinter(SwapBytes(Content[0])) << " " << HexPrinter(SwapBytes(Content[1])) << std::endl; XRelItem_c Item; Item.Read(aFile); SubBlockRead += Item.SizeInWords(); mXRelItems.push_back(Item); }; CRAY_ASSERT(SubBlockRead == SubBlockLen); //WordsRead += SubBlockRead; } break; default: CRAY_ASSERT(false); } Header.Read(aFile); } aFile.seekg(-int(Header.SizeInBits() / 8), std::ios::cur); // Undo the last header read } size_t Flatten(std::vector &aMemory, size_t aStartAddr) { size_t Addr = aStartAddr; for (auto &TxtItem : mTxtItems) { size_t SizeInBytes = TxtItem.mNumberOfTextWords.Get() * sizeof(uint64_t); memcpy(&aMemory[Addr], &TxtItem.mContent.Get()[0], SizeInBytes); Addr += SizeInBytes; } return Addr; } }; class ObjFile_c { public: std::vector mBlocks; std::vector mEntries; std::vector mExterns; std::vector mTxtBlocks; void Read(std::ifstream &aFile) { HdrDesc_c Header; Header.Read(aFile); if (Header.hdr_type.Get() != PDT_TYPE) throw Generic_x() << "Invalid object file format: file shouls start with a PDT"; ProgDescTable_c PDTTable; PDTTable.Read(aFile); uint64_t FileBase = uint64_t(aFile.tellg()) - 8; for (size_t Idx = 0; Idx < PDTTable.pdtblsz.Get(); ) { BlockDesc_c Blk; uint64_t FileOffs = aFile.tellg(); Blk.Read(aFile); Blk.FileOffset = FileOffs - FileBase; mBlocks.push_back(Blk); Idx += Blk.SizeInWords(); } for (size_t Idx = 0; Idx < PDTTable.pdtensz.Get(); ) { EntryDesc_c Blk; Blk.Read(aFile); mEntries.push_back(Blk); Idx += Blk.SizeInWords(); } FileBase = aFile.tellg(); for (size_t Idx = 0; Idx < PDTTable.pdtexsz.Get(); ) { ExternDesc_c Blk; uint64_t FileOffs = aFile.tellg(); Blk.Read(aFile); Blk.FileOffset = FileOffs - FileBase; mExterns.push_back(Blk); Idx += Blk.SizeInWords(); } for (auto &Block : mBlocks) { TxtBlock_c TxtBlock; TxtBlock.Read(aFile, Block); mTxtBlocks.push_back(TxtBlock); } bool Skip = false; do { Skip = false; Header.Read(aFile); if (Header.hdr_type.Get() == SMT_TYPE || Header.hdr_type.Get() == CMB_TYPE || Header.hdr_type.Get() == GNT_TYPE) { aFile.seekg(Header.hdr_len.Get() * sizeof(int64_t) - int(Header.SizeInBits() / 8), std::ios::cur); // Skip symbol tables for now... Skip = true; } } while (Skip); if (Header.hdr_type.Get() != MTT_TYPE) throw Generic_x() << "Didn't find MTT termination block where expected (found: " << OctPrinter(Header.hdr_type.Get()) << ")"; uint64_t ChkSum; aFile.read((char*)(&ChkSum), sizeof(ChkSum)); if (!aFile.good()) throw Generic_x() << "Can't read object file"; } }; int main(int argc, const char* argv[]) { CommandLine_c CommandLine(argc, argv); std::string ImageFile; std::string OutFileName; CCombinedAddr_t StartAddr; CCombinedAddr_t EndAddr; CAddr_t InstBaseAddr; CAddr_t DataBaseAddr; uint32_t Offset = 0; uint32_t ImageOffset = 0; bool ParseBinaryHeader = true; bool ParseObjectFile = false; bool UseHexCodes = false; bool CreatePatch = false; StartAddr.Addr = 0; StartAddr.IsParcelAddr = false; EndAddr.Addr = 0; EndAddr.IsParcelAddr = false; InstBaseAddr = 0; DataBaseAddr = 0; MachineTypes_e MachineType = MachineTypes_e::SV1; try { while (CommandLine.HasMoreParams()) { std::string CurParam = CommandLine.GetNextParam(); if (CurParam.length() == 0) continue; if (CurParam == "-i") { ImageOffset = FromString(CommandLine.GetNextParam()); } else if (CurParam == "-o") { Offset = FromString(CommandLine.GetNextParam()); } else if (CurParam == "-s") { StartAddr = FromString(CommandLine.GetNextParam()); } else if (CurParam == "-e") { EndAddr = FromString(CommandLine.GetNextParam()); } else if (CurParam == "-ib") { InstBaseAddr = FromString(CommandLine.GetNextParam(), StringFormat_e::DataAddr); } else if (CurParam == "-db") { DataBaseAddr = FromString(CommandLine.GetNextParam(), StringFormat_e::DataAddr); } else if (CurParam == "-raw") { ParseObjectFile = false; ParseBinaryHeader = false; } else if (CurParam == "-unicos") { ParseObjectFile = false; ParseBinaryHeader = true; } else if (CurParam == "-obj") { ParseObjectFile = true; ParseBinaryHeader = false; } else if (CurParam == "-hex") { UseHexCodes = true; } else if (CurParam == "-out") { OutFileName = CommandLine.GetNextParam(); } else if (CurParam == "-patch") { CreatePatch = true; } else if (CurParam == "-xmp") { MachineType = MachineTypes_e::XMP1xx; } else if (CurParam == "-ymp") { MachineType = MachineTypes_e::SV1; } else if (ImageFile.length() == 0) { ImageFile = CurParam; } else { throw Generic_x("Unkown command line parameter"); } } if (ImageFile.length() == 0) throw Generic_x() << "Image file name must be specified"; if (!boost::filesystem::exists(ImageFile)) throw Generic_x() << "File: " << ImageFile << " doesn't exist"; std::ostream *Out = &std::cout; std::ofstream OutFile; if (!OutFileName.empty()) { OutFile.open(OutFileName.c_str()); if (OutFile.bad()) throw Generic_x() << "Can't open output file " << OutFileName; Out = &OutFile; } struct Hdr_s { uint64_t Magic; uint64_t TextSize; uint64_t DataSize; uint64_t BbsSize; uint64_t SymTableSize; uint64_t EntryAddr; uint64_t BaseAddr; uint32_t Stripped; uint32_t InfoBlkPtr; } Hdr; const uint16_t A_MAGIC_ID = 0407; // new magic id const uint16_t A_MAGIC1_ID = 0407; // normal magic const uint16_t A_MAGIC2_ID = 0410; // shared text const uint16_t A_MAGIC3_ID = 0411; // normal ymp-32 bit magic const uint16_t A_MAGIC4_ID = 0412; // shared text ymp-32 bit magic uint64_t MemorySize; ObjFile_c ObjFile; if (ParseObjectFile) { std::ifstream File(ImageFile, std::ios::binary | std::ios::in); ObjFile.Read(File); ImageOffset = 0; MemorySize = 0; for (auto &Block : ObjFile.mBlocks) { if (Block.pdtbkln.Get() > MemorySize) MemorySize = Block.pdtbkln.Get(); } } else if (ParseBinaryHeader) { std::ifstream ImageStrm(ImageFile, std::ios::in | std::ios::binary); ImageStrm.read((char*)(&Hdr), sizeof(Hdr)); if (ImageStrm.bad()) throw Generic_x() << "Can't read file: " << ImageFile; ImageStrm.close(); uint64_t* HdrPtr = (uint64_t*)(&Hdr); for (size_t Idx = 0; Idx < sizeof(Hdr) / sizeof(uint64_t); ++Idx) { HdrPtr[Idx] = SwapBytes(HdrPtr[Idx]); } switch (Hdr.Magic & 0xffff) { case A_MAGIC_ID: { // Detect machine type switch ((Hdr.Magic >> 16) & 0xff) { case 0: // old-style header MachineType = MachineTypes_e::XMP1xx; break; case 4: // XMP mode-indifferent MachineType = MachineTypes_e::XMP1xx; break; case 7: // y-mp MachineType = MachineTypes_e::SV1; break; default: throw Generic_x() << "Machine type is not recognized"; } } break; case A_MAGIC2_ID: MachineType = MachineTypes_e::XMP1xx; break; case A_MAGIC3_ID: MachineType = MachineTypes_e::SV1; break; case A_MAGIC4_ID: MachineType = MachineTypes_e::SV1; break; default: throw Generic_x() << "Unrecognized file magic"; } ImageOffset = 0; MemorySize = Hdr.TextSize + Hdr.DataSize + Hdr.BaseAddr; std::cout << "Selecting machine type: " << int(MachineType) << std::endl; } else { MemorySize = boost::filesystem::file_size(ImageFile) / sizeof(CInt_t) + Offset - ImageOffset; } Mainframe_c Mainframe(MemorySize, MachineType); if (ParseBinaryHeader) { Mainframe.LoadImageFile(ImageFile.c_str(), CAddr_t(Hdr.BaseAddr), sizeof(Hdr), Hdr.TextSize * sizeof(uint64_t)); Mainframe.LoadImageFile(ImageFile.c_str(), CAddr_t(Hdr.BaseAddr + Hdr.TextSize), sizeof(Hdr) + Hdr.TextSize * sizeof(uint64_t), Hdr.DataSize * sizeof(uint64_t)); EndAddr.Addr = CAddr_t(Hdr.BaseAddr + Hdr.TextSize); EndAddr.IsParcelAddr = false; StartAddr.Addr = CAddr_t(Hdr.BaseAddr); StartAddr.IsParcelAddr = false; } else if (ParseObjectFile) { bool Found = false; for (size_t Idx = 0; Idx < ObjFile.mBlocks.size(); ++Idx) { if (ObjFile.mBlocks[Idx].pdtbkc.Get() != BKC_IX) continue; if (Found) { std::cout << "Multiple code section found, only first one will be disassembled" << std::endl; *Out << "Multiple code section found, only first one will be disassembled" << std::endl; continue; } Found = true; StartAddr.Addr = 0; StartAddr.IsParcelAddr = false; std::vector &Memory = Mainframe.GetMemory(); EndAddr.Addr = CAddr_t(ObjFile.mTxtBlocks[Idx].Flatten(Memory, 0) / sizeof(int64_t)); EndAddr.IsParcelAddr = false; } } else { Mainframe.LoadImageFile(ImageFile.c_str(), CAddr_t(Offset), ImageOffset * sizeof(CInt_t)); } // Convert to parcel address if it's not already if (!StartAddr.IsParcelAddr) StartAddr.Addr = uint32_t(StartAddr.Addr) * 4; if (!EndAddr.IsParcelAddr) EndAddr.Addr = uint32_t(EndAddr.Addr) * 4; if (EndAddr.Addr == CAddr_t(0)) { EndAddr.Addr = CAddr_t(Mainframe.GetMemorySize() / 2); } // Uggly cast to the proper CPU type, but we know it's that kind: in the disassembler we'll never instantiate anything but a soft CPU SoftCpu_c &Cpu = *(SoftCpu_c *)(&Mainframe.GetCpu(0)); Cpu.SetInstBaseAddr(InstBaseAddr); Cpu.SetDataBaseAddr(DataBaseAddr); CProgramAddr_t CurAddr = StartAddr.Addr; CProgramAddr_t EntryPoint = CProgramAddr_t(Hdr.EntryAddr); if (!CreatePatch) { while (CurAddr < EndAddr.Addr) { std::stringstream Disassembly; std::stringstream Explanation; std::stringstream InstCodes; std::stringstream HexInstCodes; CProgramAddr_t Increment = CProgramAddr_t(Cpu.Decode(CurAddr, Disassembly, Explanation, InstCodes, HexInstCodes)); CProgramAddr_t PhysicalAddress = (CurAddr + CProgramAddr_t(size_t(InstBaseAddr) * 4)); if (ParseBinaryHeader) { if (CurAddr == EntryPoint) *Out << "==>"; else *Out << " "; } int CharsPrinted = 0; if (ParseObjectFile) { bool Found = false; for (auto &Entry : ObjFile.mEntries) { if (Entry.EntryPointInBits.Get() == CurAddr * 16 && Entry.BlockIndex.Get() == 1) { // TODO: Block index should match the one we're actually disassembling. For right now (since we're only dealing with the first block) it's a constant. *Out << Entry.mName.Get() << std::endl; Found = true; } } if (Found) { *Out << "=>"; CharsPrinted += 2; } } if (ParseObjectFile) { bool Found = false; for (auto &RelItem : ObjFile.mTxtBlocks[0].mXRelItems) { int EndBit = int(RelItem.RightmostBitAddress.Get()) + 1; int StartBit = EndBit - int(RelItem.FieldLengthInBits.Get()); if (StartBit > int((CurAddr + Increment) * 16 - 1)) continue; if (EndBit <= int(CurAddr * 16)) continue; Found = true; if (RelItem.RelocationType.Get() == RT_EXT) { size_t RelIndex = size_t(RelItem.RelocationIndex.Get()); bool EntryFound = false; for (auto &Extern : ObjFile.mExterns) { if (Extern.FileOffset == RelIndex * sizeof(int64_t)) { Disassembly << " "; EntryFound = true; break; } } if (!EntryFound) { Disassembly << " "; } } else { size_t RelIndex = size_t(RelItem.RelocationIndex.Get()); bool EntryFound = false; for (auto &Block : ObjFile.mBlocks) { if (Block.FileOffset == RelIndex * sizeof(int64_t)) { Disassembly << " "; EntryFound = true; break; } } if (!EntryFound) { Disassembly << " "; } } break; } if (Found) { *Out << "*"; CharsPrinted += 1; } } for (; CharsPrinted < 4; ++CharsPrinted) *Out << ' '; *Out << InstAddr(CurAddr) << " (" << InstAddr(PhysicalAddress) << ") " << (UseHexCodes ? HexInstCodes.str() : InstCodes.str()) << " - " << std::left << std::setw(30) << Disassembly.str() << std::setw(0) << " | " << Explanation.str() << std::endl; CurAddr = CurAddr + Increment; } if (ParseBinaryHeader) { // Dump the text section *Out << "------------- TEXT section -------------" << std::endl; CAddr_t Addr = CAddr_t(Hdr.BaseAddr + Hdr.TextSize); while (Addr < Hdr.BaseAddr + Hdr.TextSize + Hdr.DataSize) { *Out << HexPrinter(Addr) << ": " << HexPrinter(Mainframe.MemRead(Addr)) << std::endl; Addr = Addr + 1; } } if (ParseObjectFile) { // Dump data sections for (size_t Idx = 0; Idx < ObjFile.mBlocks.size(); ++Idx) { auto &Block = ObjFile.mBlocks[Idx]; auto &Txt = ObjFile.mTxtBlocks[Idx]; if (Block.pdtbkc.Get() == BKC_DT || Block.pdtbkc.Get() == BKC_CN) { *Out << std::endl; *Out << "--------------- " << Block.mName.Get() << " ------------" << std::endl; StartAddr.Addr = 0; StartAddr.IsParcelAddr = false; std::vector &Memory = Mainframe.GetMemory(); EndAddr.Addr = CAddr_t(Txt.Flatten(Memory, 0) / sizeof(uint64_t)); EndAddr.IsParcelAddr = false; for (CAddr_t Addr = StartAddr.Addr; Addr < EndAddr.Addr; ++Addr) { XRelItem_c *FoundRelItem = nullptr; for (auto &RelItem : Txt.mXRelItems) { int EndBit = int(RelItem.RightmostBitAddress.Get()) + 1; int StartBit = EndBit - int(RelItem.FieldLengthInBits.Get()); if (StartBit > int((Addr + 1) * 64 - 1)) continue; if (EndBit <= int(Addr * 64)) continue; FoundRelItem = &RelItem; break; } if (FoundRelItem != nullptr) { *Out << "* "; } else { *Out << " "; } CInt_t Data = Mainframe.MemRead(Addr); *Out << HexPrinter(Addr) << ": " << HexPrinter(SwapBytes(Data)) << " - "; for (size_t j = 0; j < sizeof(CInt_t); ++j) { *Out << PrintableChar(char(Data & 0xff)); Data >>= 8; } if (FoundRelItem != nullptr) { if (FoundRelItem->RelocationType.Get() == RT_EXT) { size_t RelIndex = size_t(FoundRelItem->RelocationIndex.Get()); bool EntryFound = false; for (auto &Extern : ObjFile.mExterns) { if (Extern.FileOffset == RelIndex * sizeof(int64_t)) { *Out << " "; EntryFound = true; break; } } if (!EntryFound) { *Out << " "; } } else { size_t RelIndex = size_t(FoundRelItem->RelocationIndex.Get()); bool EntryFound = false; for (auto &Block : ObjFile.mBlocks) { if (Block.FileOffset == RelIndex * sizeof(int64_t)) { *Out << " "; EntryFound = true; break; } } if (!EntryFound) { *Out << " "; } } } *Out << std::endl; } } } } } else { while (CurAddr < EndAddr.Addr) { CProgramAddr_t PhysicalAddress = (CurAddr + CProgramAddr_t(size_t(InstBaseAddr) * 4)); CParcel_t Data = SwapBytes(Mainframe.MemReadByType(PhysicalAddress)); *Out << HexPrinter(Data); uint16_t Mask = 0xffff; if (ParseObjectFile) { for (auto &RelItem : ObjFile.mTxtBlocks[0].mXRelItems) { int EndBit = int(RelItem.RightmostBitAddress.Get()) + 1; int StartBit = EndBit - int(RelItem.FieldLengthInBits.Get()); if (StartBit > int(CurAddr * 16 + 15)) continue; if (EndBit <= int(CurAddr * 16)) continue; StartBit -= CurAddr * 16; EndBit -= CurAddr * 16; if (StartBit < 0) StartBit = 0; if (EndBit > 16) EndBit = 16; CRAY_ASSERT(StartBit <= 15); CRAY_ASSERT(EndBit > 0); Mask = ~(((1 << (EndBit - StartBit)) - 1) << StartBit); Mask = SwapBytes(Mask); break; } *Out << ":" << HexPrinter(Mask); } else { *Out << ":" << HexPrinter(Mask); } *Out << " # " << InstAddr(CurAddr) << std::endl; CurAddr += 1; } } return 0; } catch(std::exception &Ex) { return PrintUsage(argv[0], Ex.what()); } }