1111 lines
38 KiB
C++
1111 lines
38 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <fstream>
|
|
#include "utils.h"
|
|
#include "cray_softcpu.h"
|
|
#include <fstream>
|
|
#include <type_traits>
|
|
|
|
// 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 << " <image file> [options]" << std::endl;
|
|
std::cout << std::endl;
|
|
std::cout << "\t" << "Options:" << std::endl;
|
|
std::cout << "\t" << "-i <image offset>: specifies image offset in 64-bit words" << std::endl;
|
|
std::cout << "\t" << "-o <load offset>: specifies load offset in 64-bit words" << std::endl;
|
|
std::cout << "\t" << "-s <start>: specifies the start address (in Cray address format) to start disassembly from" << std::endl;
|
|
std::cout << "\t" << "-e <end>: specifies the end address (in Cray address format) to end disassembly at" << std::endl;
|
|
std::cout << "\t" << "-ib <base>: specifies the instruction base address (in word address format) for the image" << std::endl;
|
|
std::cout << "\t" << "-db <base>: 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 <file>: 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<uint64_t> ReadFields(std::istream &aStrm) const {
|
|
size_t StructSize = (mSize + 63) / 64;
|
|
std::vector<uint64_t> 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<uint64_t> mRawBuffer;
|
|
std::vector<class FieldBase_c *> mFields;
|
|
std::vector<class ArrFieldBase_c *> 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<char *, tType>::value>::type * = nullptr
|
|
> tType Get(std::vector<uint64_t> &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<char *, tType>::value>::type * = nullptr
|
|
> char * Get(std::vector<uint64_t> &aRawBuffer) const {
|
|
CRAY_ASSERT((mStart % 8) == 0);
|
|
CRAY_ASSERT((mEnd % 8) == 0);
|
|
size_t Ofs = mStart / 8;
|
|
return ((char *)(&aRawBuffer[0])) + Ofs;
|
|
}
|
|
template <typename tType> tType Get() const {
|
|
return Get<tType>(mParent.mRawBuffer);
|
|
}
|
|
virtual void Fill() = 0;
|
|
|
|
size_t mStart;
|
|
size_t mEnd;
|
|
RangeContainer_c &mParent;
|
|
|
|
friend RangeContainer_c;
|
|
friend class ArrFieldBase_c;
|
|
};
|
|
|
|
template <typename tType> 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>();
|
|
}
|
|
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<size_t>();
|
|
}
|
|
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<char> 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 <typename tType> class ArrField_T : public ArrFieldBase_c {
|
|
public:
|
|
ArrField_T(RangeContainer_c &aParent, FieldBase_c &aLen) : ArrFieldBase_c(aParent, aLen) {
|
|
}
|
|
const std::vector<tType> &Get() const { return mValue; }
|
|
protected:
|
|
std::vector<tType> 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<uint64_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<uint64_t> pdthdsz; // Word size of header area
|
|
Field_T<uint64_t> pdtblsz; // Word size of block area
|
|
Field_T<uint64_t> pdtensz; // Word size of entry area
|
|
Field_T<uint64_t> pdtexsz; // Word size of external area
|
|
Field_T<uint64_t> pdtmdy; // MM/DD/YY - this compilation
|
|
Field_T<uint64_t> pdthms; // HH:MM:SS - this compilation
|
|
Field_T<uint64_t> pdtcmpid; // Generating product name
|
|
Field_T<uint64_t> pdtcmpvr; // Generating product version
|
|
Field_T<uint64_t> pdtosvr; // Host OS version
|
|
Field_T<uint64_t> pdtudt; // UNICOS time stamp (date)
|
|
Field_T<uint64_t> filler01; // (Unused, reserved by CRI)
|
|
Field_T<uint64_t> pdtfe; // Fatal error flag (1==true)
|
|
Field_T<uint64_t> pdtbd; // Block data module (1==true)
|
|
Field_T<uint64_t> pdtmpa; // Module passed address flag
|
|
Field_T<uint64_t> pdtdc; // Dual case names flag(1==true)
|
|
Field_T<uint64_t> pdtusr; // (Unused, reserved for user)
|
|
Field_T<uint64_t> filler02; // (Unused, reserved by CRI)
|
|
Field_T<uint64_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<uint64_t> pdtfnl; // Char count in file name
|
|
Field_T<uint64_t> pdtmnl; // Char count in module name
|
|
Field_T<uint64_t> pdtss; // Stack size requirement
|
|
Field_T<uint64_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<uint64_t>(aParent, aParent.pdthdsz) {}
|
|
inline void ExtraField_c::Read(std::istream &aStrm) {
|
|
ProgDescTable_c &Parent = static_cast<ProgDescTable_c&>(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<uint64_t> pdtbkcb; // Common block flag (1==true)
|
|
Field_T<BlockLocation_e> pdtbkl; // Block location
|
|
Field_T<BlockContent_e> pdtbkc; // Block contents
|
|
Field_T<BlockType_e> pdtbkt; // Block type
|
|
Field_T<BlockAlign_e> pdtbal; // Block align flag
|
|
Field_T<uint64_t> pdtbef; // Block entry flag
|
|
Field_T<uint64_t> filler01; // (Unused, reserved by CRI)
|
|
Field_T<uint64_t> pdtbusr; // (Unused, reserved for user)
|
|
Field_T<uint64_t> pdtbknl; // Char count in block name
|
|
Field_T<uint64_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<int64_t> EntryPointInBits; // Entry point (signed) value - in bits
|
|
Field_T<uint64_t> PrimaryEntryFlag; // Primary entry flag (1==true)
|
|
Field_T<uint64_t> filler01; // (Unused, reserved by CRI)
|
|
Field_T<uint64_t> NameLength; // Char count in entry name
|
|
Field_T<uint64_t> SuggestedRelocationMode; // Suggested relocation mode
|
|
Field_T<uint64_t> filler02; // (Unused, reserved by CRI)
|
|
Field_T<uint64_t> filler03; // (Unused, reserved by CRI)
|
|
Field_T<uint64_t> filler04; // (Unused, reserved by CRI)
|
|
Field_T<uint64_t> pdteusr; // (Unused, reserved for user)
|
|
Field_T<uint64_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<uint64_t> pdtxmn; // Module specification
|
|
Field_T<uint64_t> filler00; // (Unused, reserved by CRI)
|
|
Field_T<uint64_t> NameLength; // Char count in external name
|
|
Field_T<uint64_t> pdtxsf; // Soft external (1==true)
|
|
Field_T<CallTreeInfo_e> pdtxct; // Call tree information
|
|
Field_T<uint64_t> ExternalPassedAsArgument; // External passed as argument
|
|
Field_T<uint64_t> filler01; // (Unused, reserved by CRI)
|
|
Field_T<uint64_t> filler02; // (Unused, reserved by CRI)
|
|
Field_T<uint64_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<TableType_e> hdr_type; // Table type
|
|
Field_T<uint64_t> hdr_undef; // (Unused, reserved by CRI)
|
|
Field_T<uint64_t> hdr_bi; // Block index (optional)
|
|
Field_T<uint64_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<int64_t> mIncrementBetweenDups;
|
|
Field_T<uint64_t> mStartingBitAddress;
|
|
Field_T<uint64_t> mNumberOfBitsInLastWord;
|
|
Field_T<uint64_t> mUnusedUsr1;
|
|
Field_T<uint64_t> mUnusedUsr2;
|
|
Field_T<uint64_t> mUnusedCRI;
|
|
Field_T<uint64_t> mNumOfDuplications;
|
|
Field_T<uint64_t> mNumberOfTextWords;
|
|
// Text words immediately follow the two word header,
|
|
// the number of which is specified by txtntw.
|
|
ArrField_T<uint64_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<uint64_t> RelocationType;
|
|
Field_T<uint64_t> RelocationIndex;
|
|
Field_T<uint64_t> RightmostBitAddress;
|
|
Field_T<uint64_t> FieldLengthInBits;
|
|
Field_T<RelocationMode_e> 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_e> RelocationType;
|
|
Field_T<uint16_t> RelocationIndex;
|
|
Field_T<uint64_t> UnusedUser;
|
|
Field_T<uint64_t> UnusedCRI1;
|
|
Field_T<uint64_t> ExtendedAddress;
|
|
Field_T<SpecialRelocation_e> SpecialRelocation;
|
|
Field_T<uint64_t> SignBeforeRelocation;
|
|
Field_T<SignSpecResult_e> SignSpecificationResult;
|
|
Field_T<uint64_t> FieldLengthInBits;
|
|
Field_T<RelocationMode_e> RelocationMode;
|
|
Field_T<uint64_t> UnusedCRI2;
|
|
Field_T<uint64_t> RightmostBitAddress;
|
|
};
|
|
|
|
class TxtBlock_c {
|
|
public:
|
|
std::vector<TxtItem_c> mTxtItems;
|
|
std::vector<RelItem_c> mRelItems;
|
|
std::vector<XRelItem_c> 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<uint8_t> &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<BlockDesc_c> mBlocks;
|
|
std::vector<EntryDesc_c> mEntries;
|
|
std::vector<ExternDesc_c> mExterns;
|
|
std::vector<TxtBlock_c> 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<uint32_t>(CommandLine.GetNextParam());
|
|
}
|
|
else if (CurParam == "-o") {
|
|
Offset = FromString<uint32_t>(CommandLine.GetNextParam());
|
|
}
|
|
else if (CurParam == "-s") {
|
|
StartAddr = FromString<CCombinedAddr_t>(CommandLine.GetNextParam());
|
|
}
|
|
else if (CurParam == "-e") {
|
|
EndAddr = FromString<CCombinedAddr_t>(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<uint8_t> &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 << " <EXT " << Extern.mName.Get() << " EXT>";
|
|
EntryFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!EntryFound) {
|
|
Disassembly << " <EXT " << RelIndex << " EXT>";
|
|
}
|
|
}
|
|
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 << " <BLK " << Block.mName.Get() << " BLK>";
|
|
EntryFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!EntryFound) {
|
|
Disassembly << " <BLK " << RelIndex << " BLK>";
|
|
}
|
|
}
|
|
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<uint64_t>(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<uint8_t> &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<uint64_t>(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 << " <EXT " << Extern.mName.Get() << " EXT>";
|
|
EntryFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!EntryFound) {
|
|
*Out << " <EXT " << RelIndex << " EXT>";
|
|
}
|
|
}
|
|
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 << " <BLK " << Block.mName.Get() << " BLK>";
|
|
EntryFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!EntryFound) {
|
|
*Out << " <BLK " << RelIndex << " BLK>";
|
|
}
|
|
}
|
|
}
|
|
*Out << std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
while (CurAddr < EndAddr.Addr) {
|
|
CProgramAddr_t PhysicalAddress = (CurAddr + CProgramAddr_t(size_t(InstBaseAddr) * 4));
|
|
CParcel_t Data = SwapBytes(Mainframe.MemReadByType<CParcel_t>(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());
|
|
}
|
|
}
|
|
|