<> <> <> DIRECTORY Basics USING [CompareINT, LowHalf], Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Failed, Parse], Convert USING [CardFromRope, Error], FS USING [Error, StreamOpen], IO, LarkPrograms, List USING [Reverse], OrderedSymbolTableRef, Rope; MapParseImpl: CEDAR PROGRAM IMPORTS Basics, Commander, CommandTool, Convert, FS, IO, List, OrderedSymbolTableRef, Rope = BEGIN BadHex: ERROR = CODE; BadID: ERROR = CODE; BadAddress: ERROR = CODE; Hex4: PROC [r: Rope.ROPE, pos: INT] RETURNS [res: INT] = { res _ (Hex1[r: r, pos: pos] * 4096) + (Hex1[r: r, pos: pos + 1] * 256); res _ res + (Hex1[r: r, pos: pos + 2] * 16) + Hex1[r: r, pos: pos + 3]; }; Hex2: PROC [r: Rope.ROPE, pos: INT] RETURNS [res: INT] = { res _ (Hex1[r: r, pos: pos] * 16) + Hex1[r: r, pos: pos + 1]; }; Hex1: PROC [r: Rope.ROPE, pos: INT] RETURNS [INT] = { c: CHAR _ r.Fetch[pos]; SELECT TRUE FROM Digit[c] => RETURN [c - '0]; c IN ['A..'F] => RETURN [(c - 'A) + 10]; ENDCASE => ERROR BadHex; }; Digit: PROC [c: CHAR] RETURNS [BOOL] = INLINE { RETURN [c IN ['0..'9]]; }; Letter: PROC [c: CHAR] RETURNS [BOOL] = INLINE { RETURN [c IN ['a..'z] OR c IN ['A..'Z]]; }; LowWord: PROC [i: INT] RETURNS [INT] = { c: CARDINAL _ Basics.LowHalf[i]; RETURN [c]; }; <> GetID: PROC [r: Rope.ROPE, pos: INT] RETURNS [Rope.ROPE] = { end: INT; c: CHAR; FOR i: INT IN [pos..r.Length[]) DO c _ r.Fetch[i]; IF NOT Letter[c] AND NOT Digit[c] THEN { IF c # '\n THEN ERROR BadID; end _ i; EXIT; }; REPEAT FINISHED => end _ r.Length[]; ENDLOOP; RETURN[Rope.Substr[base: r, start: pos, len: end - pos]]; }; GetMidID: PROC [r: Rope.ROPE, pos: INT] RETURNS [Rope.ROPE] = { end: INT; c: CHAR; FOR i: INT IN [pos..r.Length[]) DO c _ r.Fetch[i]; IF NOT Letter[c] AND NOT Digit[c] THEN { IF c # ' THEN ERROR BadID; end _ i; EXIT; }; REPEAT FINISHED => end _ r.Length[]; ENDLOOP; RETURN[Rope.Substr[base: r, start: pos, len: end - pos]]; }; GetVarAddress: PROC [r: Rope.ROPE, pos: INT] RETURNS [idAddr: INT] = { <
> DO IF pos <= 15 THEN ERROR BadAddress; IF HexChar[r.Fetch[pos]] THEN { idAddr _ Hex2[r: r, pos: pos - 1 ! BadHex => ERROR BadAddress] * 256; IF r.Fetch[pos - 2] # ' THEN ERROR BadAddress; idAddr _ idAddr + Hex2[r: r, pos: pos - 4 ! BadHex => ERROR BadAddress]; RETURN[LowWord[idAddr]]; }; pos _ pos - 1; ENDLOOP; }; HexChar: PROC [ch: CHAR] RETURNS [BOOL] = INLINE { RETURN [ch IN ['0..'9] OR ch IN ['A..'F]]; }; <> ScanFile: PROC [map, out: IO.STREAM] = { id: Rope.ROPE; idAddr: INT; l: Rope.ROPE; len: INT; semiColon: INT; address: INT; offset: INT; idPos: INT; fileName: Rope.ROPE; DO { l _ IO.GetLineRope[map]; len _ l.Length[]; IF map.EndOf[] THEN EXIT; IF len > 0 AND l.Fetch[0] = '; THEN { IF l.Find[";File "] = 0 THEN fileName _ Rope.Substr[base: l, start: 6, len: len - 6]; }; IF len < 10 THEN GOTO TryNextLine; <> IF l.Find["[0000]"] # 0 THEN GOTO TryNextLine; IF fileName # NIL THEN { idAddr _ Convert.CardFromRope[Rope.Substr[base: l, start: 6, len: 4], 16 ! Convert.Error => { out.PutF["Can't find address for file %g\n", IO.rope[fileName]]; idAddr _ 0; CONTINUE}]; EnterFile[id: fileName, idAddr: Convert.CardFromRope[Rope.Substr[base: l, start: 6, len: 4], 16]]; fileName _ NIL; }; <> IF l.Find["_"] = -1 THEN GOTO TryNextLine; <> semiColon _ l.Find[";"]; IF semiColon = -1 THEN GOTO TryNextLine; idPos _ l.Find["CALL", semiColon]; IF idPos # -1 THEN { IF l.Fetch[idPos + 4] # ' AND l.Fetch[idPos + 4] # '\t THEN GOTO TryNextLine; IF l.Fetch[idPos + 5] # '_ THEN GOTO TryNextLine; IF l.Find[": E8 ", 10] # 10 THEN GOTO TryNextLine; <
> address _ Hex4[r: l, pos: 6 ! BadHex => GOTO TryNextLine]; offset _ Hex2[r: l, pos: 16 ! BadHex => GOTO TryNextLine]; IF l.Fetch[18] # ' THEN GOTO TryNextLine; offset _ offset + (Hex2[r: l, pos: 19 ! BadHex => GOTO TryNextLine] * 256); idAddr _ address + offset + 3; idAddr _ LowWord[idAddr]; <> id _ GetID[r: l, pos: idPos + 6 ! BadID => GOTO TryNextLine]; EnterProc[id: id, idAddr: idAddr]; GOTO TryNextLine; }; idPos _ l.Find["MOV", semiColon]; IF idPos# -1 THEN { { IF l.Find[": 8B ", 10] = 10 THEN { <> idPos _ l.Find[",_", semiColon + 3]; IF idPos # -1 THEN { id _ GetID[r: l, pos: idPos + 2 ! BadID => GOTO TryNextLine]; GOTO FoundID; }; idPos _ l.Find[",WORD PTR _", semiColon + 3]; IF idPos # -1 THEN { id _ GetID[r: l, pos: idPos + 11 ! BadID => GOTO TryNextLine]; GOTO FoundID; }; }; IF l.Find[": BB ", 10] = 10 OR l.Find[": B9 ", 10] = 10 THEN { <> idPos _ l.Find[",OFFSET _", semiColon + 3]; IF idPos # -1 THEN { id _ GetID[r: l, pos: idPos + 9 ! BadID => GOTO TryNextLine]; GOTO FoundID; }; }; GOTO TryNextLine; EXITS FoundID => NULL; }; <
> idAddr _ GetVarAddress[r: l, pos: semiColon - 1 ! BadAddress => GOTO TryNextLine]; EnterVar[id: id, idAddr: idAddr]; GOTO TryNextLine; }; IF l.Find["LEA", semiColon] = semiColon + 1 THEN { <> idPos _ l.Find[",_", semiColon]; IF idPos = -1 THEN GOTO TryNextLine; id _ GetID[r: l, pos: idPos + 2 ! BadID => GOTO TryNextLine]; <
> idAddr _ GetVarAddress[r: l, pos: semiColon - 1 ! BadAddress => GOTO TryNextLine]; EnterVar[id: id, idAddr: idAddr]; GOTO TryNextLine; }; IF l.Find["INC", semiColon] = semiColon + 1 THEN { <> idPos _ l.Find["_", semiColon]; IF idPos = -1 THEN GOTO TryNextLine; id _ GetID[r: l, pos: idPos + 1 ! BadID => GOTO TryNextLine]; <
> idAddr _ GetVarAddress[r: l, pos: semiColon - 1 ! BadAddress => GOTO TryNextLine]; EnterVar[id: id, idAddr: idAddr]; GOTO TryNextLine; }; EXITS TryNextLine => NULL; }; ENDLOOP; }; TryForPublics: PROC [map, out: IO.STREAM] = { id: Rope.ROPE; idAddr: INT; l: Rope.ROPE; len: INT; addrPos: INT; DO { l _ IO.GetLineRope[map]; len _ l.Length[]; IF map.EndOf[] THEN EXIT; IF len > 0 AND l.Fetch[0] = '; THEN EXIT; IF len < 10 THEN GOTO TryNextLine; < NULL; }; ENDLOOP; }; <> nameTable: OrderedSymbolTableRef.Table _ NIL; addrTable: OrderedSymbolTableRef.Table _ NIL; fileTable: OrderedSymbolTableRef.Table _ NIL; CompareSTItemsByName: OrderedSymbolTableRef.CompareProc = { x: LarkPrograms.STItem _ NARROW[r1]; y: LarkPrograms.STItem _ NARROW[r2]; RETURN[Rope.Compare[s1: x.id, s2: y.id, case: FALSE]]; }; CompareSTItemsByAddr: OrderedSymbolTableRef.CompareProc = { x: LarkPrograms.STItem _ NARROW[r1]; y: LarkPrograms.STItem _ NARROW[r2]; RETURN[Basics.CompareINT[x.addr, y.addr]]; }; FileDataObject: TYPE = RECORD [ id: Rope.ROPE _ NIL, addr: INT _ 0, size: INT _ 0, codeAddr: INT _ 0, codeSize: INT _ 0, dataAddr: INT _ 0, dataSize: INT _ 0 ]; FileData: TYPE = REF FileDataObject; CompareFileItemsByAddr: OrderedSymbolTableRef.CompareProc = { x: FileData _ NARROW[r1]; y: FileData _ NARROW[r2]; RETURN[Basics.CompareINT[x.addr, y.addr]]; }; EnterProc: PROC [id: Rope.ROPE, idAddr: INT] = { item: LarkPrograms.STItem _ NEW[LarkPrograms.STObject _ [id: id, addr: idAddr, type: procedure]]; nameTable.Insert[item ! OrderedSymbolTableRef.DuplicateKey => CONTINUE]; <> }; EnterVar: PROC [id: Rope.ROPE, idAddr: INT] = { item: LarkPrograms.STItem _ NEW[LarkPrograms.STObject _ [id: id, addr: idAddr, type: variable]]; nameTable.Insert[item ! OrderedSymbolTableRef.DuplicateKey => CONTINUE]; <> }; EnterFile: PROC [id: Rope.ROPE, idAddr: INT] = { item: FileData _ NEW[FileDataObject _ [id: id, addr: idAddr]]; fileTable.Insert[item ! OrderedSymbolTableRef.DuplicateKey => CONTINUE]; }; MapParse: Commander.CommandProc = { map: IO.STREAM; extension: INT; scanFileSymbols: INT; argv: CommandTool.ArgumentVector; out: IO.STREAM _ cmd.out; PrintSTItem: PROC [a: REF ANY] RETURNS [BOOL _ FALSE] = { c: CHAR; item: LarkPrograms.STItem _ NARROW[a]; c _ SELECT item.type FROM procedure => 'P, variable => 'V, ENDCASE => ERROR; out.PutF["%c %04x %g\n", IO.char[c], IO.int[item.addr], IO.rope[item.id]]; }; EnterIntoAddrTable: PROC [a: REF ANY] RETURNS [BOOL _ FALSE] = { addrTable.Insert[a ! OrderedSymbolTableRef.DuplicateKey => { out.PutF["Duplicate:\n\t"]; [] _ PrintSTItem[a]; <> <> <<[] _ PrintSTItem[addrTable.Lookup[a]];>> CONTINUE; }]; }; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN RETURN[$Failure, msg]; IF argv.argc # 2 THEN { out.PutF["Usage: MapParse MapFileName (without extension)\n"]; RETURN; }; extension _ Rope.Find[s1: argv[1], s2: ".map", case: FALSE]; IF extension # -1 THEN argv[1] _ Rope.Substr[base: argv[1], start: 0, len: extension]; map _ FS.StreamOpen[fileName: Rope.Cat[argv[1], ".map"] ! FS.Error => { out.PutRope[error.explanation]; out.PutRope["\n"]; GOTO Die; }]; nameTable _ OrderedSymbolTableRef.CreateTable[compareProc: CompareSTItemsByName]; addrTable _ OrderedSymbolTableRef.CreateTable[compareProc: CompareSTItemsByAddr]; fileTable _ OrderedSymbolTableRef.CreateTable[compareProc: CompareFileItemsByAddr]; ScanFile[map: map, out: out]; scanFileSymbols _ nameTable.Size[]; map.SetIndex[0]; TryForPublics[map: map, out: out]; out.PutF["TryForPublics found %d more symbols\n", IO.card[nameTable.Size[] - scanFileSymbols]]; nameTable.EnumerateIncreasing[procToApply: EnterIntoAddrTable]; map.Close[]; out.PutF["\nIdentifiers: (%d items)\n", IO.int[nameTable.Size[]]]; { symsFileName: Rope.ROPE _ Rope.Cat[argv[1], ".syms"]; symsFile: IO.STREAM; PrintFileItem: PROC [a: REF ANY] RETURNS [BOOL _ FALSE] = { item: LarkPrograms.STItem _ NARROW[a]; symsFile.PutF["%04x %g\n", IO.int[item.addr], IO.rope[item.id]]; }; out.PutF["Writing symbol file: %g.\n", IO.rope[symsFileName]]; symsFile _ FS.StreamOpen[fileName: symsFileName, accessOptions: $create ! FS.Error => { out.PutRope[error.explanation]; out.PutRope["\n"]; GOTO Die; }]; WriteSortedFile[errors: out, tabFile: symsFile, byName: TRUE]; WriteSortedFile[errors: out, tabFile: symsFile, byName: FALSE]; symsFile.Close[]; symsFileName _ Rope.Cat[argv[1], ".files"]; out.PutF["Writing files file: %g.\n", IO.rope[symsFileName]]; symsFile _ FS.StreamOpen[fileName: symsFileName, accessOptions: $create ! FS.Error => { out.PutRope[error.explanation]; out.PutRope["\n"]; GOTO Die; }]; PrintFileData[tab: fileTable, syms: symsFile, log: out]; symsFile.Close[]; EXITS Die => NULL; }; out.PutF["Releasing RedBlackTrees.\n"]; IF nameTable # NIL THEN { nameTable.DestroyTable[]; nameTable _ NIL; }; IF addrTable # NIL THEN { addrTable.DestroyTable[]; addrTable _ NIL; }; IF fileTable # NIL THEN { fileTable.DestroyTable[]; fileTable _ NIL; }; EXITS Die => NULL; }; PrintFileData: PROC [tab: OrderedSymbolTableRef.Table, syms, log: IO.STREAM] = { fileList: LIST OF REF ANY; previous: FileData _ NIL; totalCode: INT _ 0; totalData: INT _ 0; GetSizes: PROC [a: REF ANY] RETURNS [BOOL _ FALSE] = { item: FileData _ NARROW[a]; IF previous # NIL THEN previous.size _ item.addr - previous.addr; previous _ item; }; CollectFileData: PROC [a: REF ANY] RETURNS [BOOL _ FALSE] = { item: FileData _ NARROW[a]; FOR l: LIST OF REF ANY _ fileList, l.rest WHILE l # NIL DO file: FileData _ NARROW[l.first]; IF Rope.Equal[item.id, file.id, FALSE] THEN { file.dataAddr _ item.addr; file.dataSize _ item.size; RETURN; }; ENDLOOP; item.codeAddr _ item.addr; item.codeSize _ item.size; fileList _ CONS[item, fileList]; }; tab.EnumerateIncreasing[procToApply: GetSizes]; tab.EnumerateIncreasing[procToApply: CollectFileData]; fileList _ List.Reverse[fileList]; syms.PutF["Module code size data size total\n"]; FOR l: LIST OF REF ANY _ fileList, l.rest WHILE l # NIL DO item: FileData _ NARROW[l.first]; totalCode _ totalCode + item.codeSize; totalData _ totalData + item.dataSize; syms.PutF["%-20g %04x %5d", IO.rope[item.id], IO.card[item.codeAddr], IO.card[item.codeSize]]; syms.PutF[" %04x %5d %5d\n", IO.card[item.dataAddr], IO.card[item.dataSize], IO.card[item.codeSize + item.dataSize]]; ENDLOOP; syms.PutF["Totals: Code %d, Data %d, Everything %d\n", IO.card[totalCode], IO.card[totalData], IO.card[totalCode + totalData]]; }; WriteSortedFile: PROC [errors: IO.STREAM, tabFile: IO.STREAM, byName: BOOL] = { tab: OrderedSymbolTableRef.Table _ IF byName THEN nameTable ELSE addrTable; PrintSTItem: PROC [a: REF ANY] RETURNS [BOOL _ FALSE] = { c: CHAR; item: LarkPrograms.STItem _ NARROW[a]; c _ SELECT item.type FROM procedure => 'P, variable => 'V, ENDCASE => ERROR; tabFile.PutF["%c %04x %g\n", IO.char[c], IO.int[item.addr], IO.rope[item.id]]; }; tabFile.PutF[IF byName THEN "Names %d\n" ELSE "Addresses %d\n", IO.int[tab.Size[]]]; tab.EnumerateIncreasing[procToApply: PrintSTItem]; }; Commander.Register[key: "MapParse", proc: MapParse, doc: "MapParse usage: MapParse Lark for Lark.map"]; END. November 15, 1982 9:51 pm, L. Stewart, Created November 16, 1982 8:46 am, L. Stewart, added RedBlackTree stuff November 16, 1982 2:39 pm, L. Stewart, integration with Teleload November 19, 1982 4:59 pm, L. Stewart December 6, 1982 4:41 pm, L. Stewart, Cedar 3.5 December 18, 1982 4:38 pm, L. Stewart, Stand alone service May 2, 1983 12:47 pm, L. Stewart, LarkPrograms December 22, 1983 1:56 pm, L. Stewart, Cedar 5