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; 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 0) DO scnName: REF TEXT; scnName _ readSectionName[stream]; IF Rope.EqualSubstrs[s1: elfDataSectionName, len1: elfDataSectionName.Length[], s2: Rope.FromRefText[s: scnName], len2: elfDataSectionName.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] - elfScnNameLen + elfScnHdrSize]; -- advance to next section header ENDLOOP; Kludge for testing - confusion! search whole file. This routine handles both XCOFF (AIX) and ECOFF (DEC/MIPS) as the differences in the object file formats between ECOFF and XCOFF are not large enough to affect the stamp-finding algorithm. PROC[stream: IO.STREAM] RETURNS [matches: BOOLEAN _ FALSE, start, end: CARD] isXCoff also checks if the binary is a valid dec ECOFF executable. an object file. seek to section headers at end of optional a.out header find data section section and determine where to search for stamps confusion! search whole file. PROC[stream: IO.STREAM] RETURNS [matches: BOOLEAN _ FALSE, start, end: CARD] an object file. confusion! search whole file. PROC[stream: IO.STREAM] RETURNS [matches: BOOLEAN _ FALSE, start, end: CARD] Κ I•NewlineDelimiter –(cedarcode) style™™Jšœ Οeœ7™BJ™"J™#J™—codešΟk ˜ Kšœžœž œ˜-K˜ K˜ K˜Kšœ˜Kšžœžœ;žœ™KKšžœ˜K˜K˜ —K˜KšΠbnœžœž˜#Kšžœ+žœ"˜Všœž˜K˜Kšžœžœžœ˜K˜K™9K™Kšœ)™)K˜Kšœžœ Οc$˜BKšœžœ 3˜PKšœžœ 0˜JK˜Kšœ,™,K˜Kšœžœ -˜HKšœžœ  #˜DKšœžœ 6˜\Kšœžœ 5˜\Kšœžœ 7˜_Kšœžœ ˜:Kšœžœ ˜7Kšœžœ ˜%K˜K™%K˜Kšœžœ +˜DKšœžœ  !˜@Kšœžœ 6˜ZKšœžœ 3˜XKšœžœ 5˜[Kšœžœ ˜6Kšœžœ ˜3Kšœžœ ˜#K˜K˜š Ÿœžœžœžœžœžœ˜8K˜Kšœžœ ˜Kšœžœ ˜Kšžœ ˜K˜—K˜š Οnœžœ žœžœžœžœ˜;K˜ Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšžœ˜K˜K˜—š ‘ œžœ žœžœžœžœ˜9K˜ Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšžœ˜K˜—K˜š ‘œžœ žœžœžœžœ˜;K˜ Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšžœ˜K˜K˜—K™ŽK˜šŸœ-˜KšœL™LKšœ*žœ˜.K˜š ’œžœžœžœžœžœ˜4K™DKš žœžœ žœ žœ žœ˜QK˜—š’œžœžœžœžœžœžœ˜;Kš œžœžœžœžœ˜)Kšœžœ5˜