<<>> <> <> <> <> <<>> DIRECTORY Basics USING [BITLSHIFT, Word16, LongNumber], Commander, CommanderOps, Convert, MoberyPrivate, <> IO, Rope, UserProfile; MoberyObjectFileImpl: CEDAR PROGRAM IMPORTS Basics, Commander, CommanderOps, Convert, IO, MoberyPrivate, Rope, UserProfile ~ BEGIN ROPE: TYPE = Rope.ROPE; <> <<>> <> 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 <> 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"; <> elfMagicOffset: INT = 0; -- byte offset of magic number in elf files elfHeaderBytes: INT = 4+4*3+4; -- size of header for elf filehdr elfOptionalHdrSizeOffset: INT = 16; -- offset of optional header (aouthdr) size in filehdr elfScnHdrSectionNameOffset: INT = 0; -- byte offset of section name field within elf scn elfScnHdrSectionStartOffset: INT = 8; -- byte offset of section start offset within elf scn elfScnHdrSize: INT = 40; -- size of elf section header elfScnNameLen: INT = 8; -- size of elf section name elfDataSectionName: ROPE = ".data"; ReadBinaryShort: PROC [s: IO.STREAM] RETURNS [INT16] ~ { sn: Basics.Word16 ¬ [int[0]]; sn.hi ¬ IO.GetByte[s]; sn.lo ¬ IO.GetByte[s]; RETURN [sn.card]; }; ReadThreeBytes: PROC [stream: IO.STREAM] RETURNS [CARD] ~ { ln: Basics.LongNumber _ [lc[0]]; ln.hl _ IO.GetByte[stream]; ln.lh _ IO.GetByte[stream]; ln.ll _ IO.GetByte[stream]; RETURN [ln.lc] }; 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] }; <> MoberyELFTester: MoberyPrivate.ObjectFileTypeMatcherProc ~ { <> magicNumber, numOfSections: INT; <> ElfMagic: CARD = (Basics.BITLSHIFT[177B, 24] + Basics.BITLSHIFT['E.ORD, 16] + Basics.BITLSHIFT['L.ORD, 8] + 'F.ORD); isELF: PROC[num: CARD] RETURNS [BOOLEAN] = INLINE { <> RETURN [num = ElfMagic]; }; readSectionName: PROC [s: IO.STREAM] RETURNS [REF TEXT] ~ { b: REF TEXT = NEW[TEXT[elfScnNameLen]]; [] _ IO.GetBlock[self: s, block: b, count: elfScnNameLen]; RETURN [b]; }; IF NOT stream.EndOf[] THEN { cardLen: CARD; IO.SetIndex[self: stream, index: elfMagicOffset]; magicNumber _ ReadBinaryUINT[stream]; IF isELF[magicNumber] THEN { <> matches _ TRUE; <> <> <> <> <> <> < 0) DO>> <> <> <> <> <<[] _ ReadBinaryUINT[stream]; -- skip physical address field>> <<[] _ ReadBinaryUINT[stream]; -- skip virtual address field>> <> <> <> <> <<};>> <> <> <> <<>> <> numOfSections _ -1; start _ 0; end _ 0; IF (numOfSections <= 0) OR (NOT start IN [0..end) AND end <= (cardLen ¬ IO.GetLength[stream]) ) THEN { <> start _ 0; end _ IO.GetLength[stream]; }; }; }; }; <> MoberyXCoffTester: MoberyPrivate.ObjectFileTypeMatcherProc ~ { <> magicNumber, numOfSections, optHdrLength: INT; isXCoff: PROC[num: INT] RETURNS [BOOLEAN] = INLINE { <> 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 { cardLen: CARD; IO.SetIndex[self: stream, index: xcoffMagicOffset]; magicNumber ¬ ReadBinaryShort[stream]; IF isXCoff[magicNumber] THEN { <> 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) <> IO.SetIndex[stream, IO.GetIndex[self: stream] - 2 + optHdrLength + (xcoffHeaderBytes - xcoffOptionalHdrSizeOffset)]; <> 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 <= (cardLen ¬ IO.GetLength[stream]) ) THEN { <> start ¬ 0; end ¬ cardLen; }; }; }; }; MoberyADotOutTester: MoberyPrivate.ObjectFileTypeMatcherProc ~ { <> 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 { <> cardLen: CARD; matches ¬ TRUE; IO.SetIndex[self: stream, index: aoutTextSizeOffset]; start ¬ aoutHeaderBytes + ReadBinaryINT[stream]; end ¬ start + ReadBinaryINT[stream]; IF NOT start IN [0..end) AND end <= (cardLen ¬ IO.GetLength[stream]) THEN { <> start ¬ 0; end ¬ cardLen; }; }; }; }; UserDefinedCheckers: MoberyPrivate.ObjectFileTypeMatcherProc ~ { <> Look: PROC[cL: LIST OF ConsistencyChecker] RETURNS[doesMatch: BOOL ¬ FALSE] ~ { num: CARD; FOR uL: LIST OF ConsistencyChecker ¬ cL, uL.rest UNTIL uL = NIL DO IO.SetIndex[self: stream, index: uL.first.offset]; SELECT uL.first.numBytes FROM 1 => num ¬ LOOPHOLE[IO.GetByte[stream]]; 2 => num ¬ ReadBinaryShort[stream]; 3 => num ¬ ReadThreeBytes[stream]; 4 => num ¬ ReadBinaryUINT[stream]; ENDCASE => LOOP; IF num = uL.first.value THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; IF Look[cmdCheckersList] OR Look[userCheckersList] THEN RETURN[TRUE, 0, IO.GetLength[stream]]; RETURN[FALSE, 0, 0]; }; OnProfileChange: UserProfile.ProfileChangedProc ~ { ENABLE Convert.Error => GOTO fail; checkList: LIST OF ROPE ~ UserProfile.ListOfTokens["MobStuff.Checkers", NIL]; cL: LIST OF ROPE ¬ checkList; userCheckersList ¬ NIL; UNTIL cL = NIL DO arg2, arg3: ROPE; offset, numBytes, value: CARD; arg1: ROPE ¬ cL.first; IF Rope.Equal[arg1, "{"] OR Rope.Equal[arg1, "}"] THEN IF ( cL ¬ cL.rest ) = NIL THEN EXIT ELSE LOOP; arg1 ¬ cL.first; IF ( cL ¬ cL.rest ) = NIL THEN EXIT; arg2 ¬ cL.first; IF ( cL ¬ cL.rest ) = NIL THEN EXIT; arg3 ¬ cL.first; cL ¬ cL.rest; numBytes ¬ Convert.CardFromRope[arg2]; IF numBytes = 0 OR numBytes > 4 THEN LOOP; -- ignore if numBytes > 4 offset ¬ Convert.CardFromRope[arg1]; value ¬ Convert.CardFromRope[arg3]; userCheckersList ¬ CONS[[offset, numBytes, value], userCheckersList]; ENDLOOP; EXITS fail => NULL; }; MobStuffCheckersCmd: Commander.CommandProc ~ { ENABLE Convert.Error => GOTO fail; arg1: ROPE; UNTIL ( arg1 ¬ CommanderOps.NextArgument[cmd] ) = NIL DO arg2, arg3: ROPE; offset, numBytes, value: CARD; IF Rope.Equal[arg1, "{"] OR Rope.Equal[arg1, "}"] THEN LOOP; IF ( arg2 ¬ CommanderOps.NextArgument[cmd] ) = NIL THEN EXIT; IF ( arg3 ¬ CommanderOps.NextArgument[cmd] ) = NIL THEN EXIT; numBytes ¬ Convert.CardFromRope[arg2]; IF numBytes = 0 OR numBytes > 4 THEN LOOP; -- ignore if numBytes > 4 offset ¬ Convert.CardFromRope[arg1]; value ¬ Convert.CardFromRope[arg3]; cmdCheckersList ¬ CONS[[offset, numBytes, value], cmdCheckersList]; ENDLOOP; EXITS fail => NULL; }; PrintMobStuffCheckersCmd: Commander.CommandProc ~ { FOR list: LIST OF ConsistencyChecker ¬ cmdCheckersList, list.rest UNTIL list = NIL DO cmd.out.PutFL[template, LIST[[integer[list.first.offset]], [integer[list.first.numBytes]], [integer[list.first.value]], [integer[list.first.value]]] ]; ENDLOOP; FOR list: LIST OF ConsistencyChecker ¬ userCheckersList, list.rest UNTIL list = NIL DO cmd.out.PutFL[template, LIST[[integer[list.first.offset]], [integer[list.first.numBytes]], [integer[list.first.value]], [integer[list.first.value]]] ]; ENDLOOP; }; template: ROPE ~ "[offset: %g, numBytes: %g, value: %g (%xH)]\n"; cmdCheckersList: LIST OF ConsistencyChecker ¬ NIL; userCheckersList: LIST OF ConsistencyChecker ¬ NIL; ConsistencyChecker: TYPE ~ RECORD[offset, numBytes, value: CARD]; UserProfile.CallWhenProfileChanges[OnProfileChange]; MoberyPrivate.RegisterObjectFileType[MoberyADotOutTester]; MoberyPrivate.RegisterObjectFileType[MoberyXCoffTester]; MoberyPrivate.RegisterObjectFileType[MoberyELFTester]; MoberyPrivate.RegisterObjectFileType[UserDefinedCheckers]; Commander.Register["MobStuff.Checkers", MobStuffCheckersCmd, "add consistency checkers: syntax is { offset numBytes value }*; braces optional; 0