DIRECTORY
Basics USING [ShortNumber, LongNumber],
MoberyPrivate,
IO USING [EndOf, GetBlock, GetByte, GetIndex, GetLength, SetIndex, STREAM],
IO,
Rope,
UXStrings, UnixTypes;
~
BEGIN
ROPE: TYPE = Rope.ROPE;
a.out portions of this file created from MoberyImpl.mesa.
a.out know-how (thanks to Michael Plass)
aoutHeaderBytes: INT = 4+4*7; -- size of header for a.out .o files
aoutTextSizeOffset: INT = 4; -- byte offset of text size field in a.out .o files
aoutMagicOffset: INT = 2; -- byte offset of magic number in a.out .o files
XCOFF know-how (thanks to IBM documentation)
xcoffMagicOffset: INT = 0; -- byte offset of magic number in xcoff files
xcoffHeaderBytes: INT = 4+4*3+4; -- size of header for xcoff filehdr
xcoffOptionalHdrSizeOffset: INT = 16; -- offset of optional header (aouthdr) size in filehdr
xcoffScnHdrSectionNameOffset: INT = 0; -- byte offset of section name field within xcoff scn
xcoffScnHdrSectionStartOffset: INT = 8; -- byte offset of section start offset within xcoff scn
xcoffScnHdrSize: INT = 40; -- size of xcoff section header
xcoffScnNameLen: INT = 8; -- size of xcoff section name
xcoffDataSectionName: ROPE = ".data";
ReadBinaryShort:
PROC [s:
IO.
STREAM]
RETURNS [
INT16] ~ {
sn: Basics.ShortNumber ← [si[0]];
sn.hi ← IO.GetByte[s];
sn.lo ← IO.GetByte[s];
RETURN [sn.sc];
};
ReadBinaryINT:
PROC [stream:
IO.
STREAM]
RETURNS [
INT] ~ {
ln: Basics.LongNumber ← [li[0]];
ln.hh ← IO.GetByte[stream];
ln.hl ← IO.GetByte[stream];
ln.lh ← IO.GetByte[stream];
ln.ll ← IO.GetByte[stream];
RETURN [ln.li]
};
ReadBinaryUINT:
PROC [stream:
IO.
STREAM]
RETURNS [
CARD] ~ {
ln: Basics.LongNumber ← [lc[0]];
ln.hh ← IO.GetByte[stream];
ln.hl ← IO.GetByte[stream];
ln.lh ← IO.GetByte[stream];
ln.ll ← IO.GetByte[stream];
RETURN [ln.lc]
};
This routine handles both XCOFF (AIX) and ECOFF (DEC/MIPS/SGI) as the differences in the object file formats between ECOFF and XCOFF are not large enough to affect the stamp-finding algorithm.
MoberyXCoffTester: MoberyPrivate.ObjectFileTypeMatcherProc ~ {
PROC[stream: IO.STREAM] RETURNS [matches: BOOLEAN ← FALSE, start, end: CARD]
magicNumber, numOfSections, optHdrLength: INT;
isXCoff:
PROC[num:
INT]
RETURNS [
BOOLEAN] =
INLINE {
isXCoff also checks if the binary is a valid dec ECOFF executable.
RETURN [num = 0730B OR num = 0735B OR num = 0737B OR num = 6201H OR num = 0160H];
};
readSectionName:
PROC [s:
IO.
STREAM]
RETURNS [
REF
TEXT] ~ {
b: REF TEXT = NEW[TEXT[xcoffScnNameLen]];
[] ← IO.GetBlock[self: s, block: b, count: xcoffScnNameLen];
RETURN [b];
};
IF
NOT stream.EndOf[]
THEN {
IO.SetIndex[self: stream, index: xcoffMagicOffset];
magicNumber ← ReadBinaryShort[stream];
IF isXCoff[magicNumber] THEN {
an object file.
matches ← TRUE;
numOfSections ← ReadBinaryShort[stream]; -- read number of sections
IO.SetIndex[self: stream, index: xcoffOptionalHdrSizeOffset];
optHdrLength ← ReadBinaryShort[stream]; -- get length of optional header (a.out)
seek to section headers at end of optional a.out header
IO.SetIndex[stream, IO.GetIndex[self: stream] - 2 + optHdrLength + (xcoffHeaderBytes - xcoffOptionalHdrSizeOffset)];
find data section section and determine where to search for stamps
WHILE (numOfSections > 0)
DO
scnName: REF TEXT;
scnName ← readSectionName[stream];
IF Rope.EqualSubstrs[s1: xcoffDataSectionName, len1: xcoffDataSectionName.Length[], s2: Rope.FromRefText[s: scnName], len2: xcoffDataSectionName.Length[]]
THEN {
size: CARD;
[] ← ReadBinaryUINT[stream]; -- skip physical address field
[] ← ReadBinaryUINT[stream]; -- skip virtual address field
size ← ReadBinaryUINT[stream];
start ← ReadBinaryUINT[stream];
end ← start + size;
EXIT;
};
numOfSections ← numOfSections - 1;
IO.SetIndex[stream, IO.GetIndex[stream] - xcoffScnNameLen + xcoffScnHdrSize]; -- advance to next section header
ENDLOOP;
IF (numOfSections <= 0)
OR (
NOT start
IN [0..end)
AND end <=
IO.GetLength[stream])
THEN {
confusion! search whole file.
start ← 0;
end ← IO.GetLength[stream];
};
};
};
};
MoberyADotOutTester: MoberyPrivate.ObjectFileTypeMatcherProc ~ {
PROC[stream: IO.STREAM] RETURNS [matches: BOOLEAN ← FALSE, start, end: CARD]
magicNumber: INT;
isADotOut:
PROC[num:
INT]
RETURNS [
BOOLEAN] =
INLINE {
RETURN [num = 0407B OR num = 0410B OR num = 0413B];
};
IO.SetIndex[self: stream, index: aoutMagicOffset];
IF
NOT stream.EndOf[]
THEN {
magicNumber ← ReadBinaryShort[stream];
IF isADotOut[magicNumber]
THEN {
an object file.
matches ← TRUE;
IO.SetIndex[self: stream, index: aoutTextSizeOffset];
start ← aoutHeaderBytes + ReadBinaryINT[stream];
end ← start + ReadBinaryINT[stream];
IF
NOT start
IN [0..end)
AND end <=
IO.GetLength[stream]
THEN {
confusion! search whole file.
start ← 0;
end ← IO.GetLength[stream];
};
};
};
};
MoberyPrivate.RegisterObjectFileType[MoberyADotOutTester];
MoberyPrivate.RegisterObjectFileType[MoberyXCoffTester];