<<>> <> <> <> <> <> <<>> DIRECTORY Basics, Commander, CommanderOps, Convert, DisassembleSPARC, InstallationBasicComforts, IO, Process, RefText, Rope, SparcInstruction, UXStrings, VM; DisassembleSPARCImpl: PROGRAM IMPORTS Basics, Commander, CommanderOps, Convert, InstallationBasicComforts, IO, Process, RefText, Rope, UXStrings, VM EXPORTS DisassembleSPARC ~ BEGIN OPEN SparcInstruction, DisassembleSPARC; ROPE: TYPE = Rope.ROPE; PC: TYPE = CARD; CString: TYPE ~ UXStrings.CString; AddressFault: PUBLIC ERROR [address: LONG POINTER] ~ CODE; Failed: PUBLIC ERROR [errMsg: ROPE] ~ CODE; localNub: DebugNub = NEW[DebugNubPrivate ¬ [ LocalMatchingSymEntryByName, LocalMatchingSymEntryByValue, LocalSymEntryByID, LocalGetInterfaceSlot, LocalPCtoInfo, LocalFetchWord ]]; PutPCInfo: PROC [to: REF TEXT, nub: DebugNub, pc: PC] RETURNS [result: REF TEXT, offset: CARD := 0] = { PutBase: PROC [p: ROPE] ~ { lim: INT = MIN[p.Length[], 200]; start: INT := 0; end: INT := 0; FOR i: NAT IN [0..lim) DO c: CHAR ~ p.Fetch[i]; SELECT c FROM '/ => start := i+1; '. => IF end <= start THEN end := i; ENDCASE; REPEAT FINISHED => IF end <= start THEN end := lim; ENDLOOP; to := RefText.AppendRope[to, p, start, end-start]; }; info: PCInfo := nub.PCtoInfo[nub, pc]; IF info#nullPCInfo THEN { se: SymEntry ¬ nub.GetSymEntryByID[nub, info.procSymID]; PutBase[info.guessedEmbeddedFileName]; to := RefText.AppendChar[to, '.]; IF se#nullSymEntry THEN { to := RefText.AppendRope[to, se.name]; offset := pc-se.value; }; }; result := to; }; CardFromRope: PUBLIC PROC [num: ROPE] RETURNS [CARD] ~ { IF Rope.Match["0x*", num, FALSE] THEN RETURN Convert.CardFromRope[Rope.Substr[num, 2], 16 !Convert.Error => Convert.Error[reason, index+2]] ELSE RETURN Convert.CardFromRope[num] }; FindSym: PUBLIC PROC [name: ROPE, nub: DebugNub, textOnly: BOOL ¬ TRUE] RETURNS [SymEntry] = { ENABLE Convert.Error => Failed[Rope.Concat["invalid pc: ", name]]; e1: SymEntry; types: CARD ~ IF textOnly THEN typeText ELSE allTypes; IF (Rope.Size[name] > 0 AND Rope.Fetch[name, 0] IN ['0..'9]) THEN { x: CARD ~ CardFromRope[name]; e1 := nub.GetMatchingSymEntryByValue[nub: nub, val: x, types: types, classes: all, nth: 0, from: nullID ]; } ELSE { IF Rope.Match["*.*", name] THEN { <> dot: INT ~ Rope.Index[name, 0, "."]; outer: ROPE ~ Rope.Substr[name, 0, dot]; inner: ROPE ~ Rope.Substr[name, dot+1]; slot: CARD ~ nub.GetInterfaceSlot[nub, outer, inner]; filePat: ROPE; eMod: SymEntry ¬ nullSymEntry; IF slot # nullAddr THEN { <> procVal: WORD ~ nub.FetchWord[nub, slot]; e1 := nub.GetMatchingSymEntryByValue[nub: nub, val: procVal, types: types, classes: all, nth: 0, from: nullID ]; GOTO Got}; filePat ¬ outer.Concat[".*"]; DO eMod ¬ nub.GetMatchingSymEntryByName[nub, filePat, TRUE, typeModule, all, 1, eMod.symID]; IF eMod=nullSymEntry THEN EXIT; IF eMod.size>0 THEN { e1 ¬ eMod; DO e1 ¬ nub.GetMatchingSymEntryByValue[nub, nullVal, types, all, 1, e1.symID]; SELECT TRUE FROM e1=nullSymEntry => EXIT; e1.value < eMod.value => NULL--can't happen--; e1.value-eMod.value >= eMod.size => EXIT; e1.name.Equal[inner] => GOTO Got; ENDCASE => NULL; ENDLOOP; }; ENDLOOP; }; e1 := nub.GetMatchingSymEntryByName[nub: nub, pattern: name, caseSensitive: TRUE, types: types, classes: all, nth: 1, from: nullID ]; EXITS Got => NULL}; IF e1 = nullSymEntry THEN Failed[Rope.Concat["undefined: ", name]]; RETURN [e1]}; LocalGetInterfaceSlot: PUBLIC PROC [nub: DebugNub, ifc, item: ROPE] RETURNS [addr: CARD] ~ { p: PROCEDURE ANY RETURNS ANY ~ InstallationBasicComforts.BasicProcFromNamedInterface[interfaceName: ifc, procName: item]; IF p=NIL THEN RETURN [nullAddr] ELSE RETURN[LOOPHOLE[p]]}; EstSize: PUBLIC PROC [nub: DebugNub, e1: SymEntry, textOnly: BOOL] RETURNS [nBytes: CARD] ~ { e2: SymEntry = nub.GetMatchingSymEntryByValue[nub: nub, val: nullVal, types: IF textOnly THEN typeText ELSE allTypes, classes: all, nth: 1, from: e1.symID ]; RETURN [nBytes: IF e2 = nullSymEntry THEN unknownSize ELSE (e2.value-e1.value)]}; LocalMatchingSymEntryByName: PROC [nub: DebugNub, pattern: ROPE ¬ NIL, caseSensitive: BOOLEAN, types: CARD ¬ allTypes, classes: Classes ¬ all, nth: INT, from: SymID ¬ nullID] RETURNS [SymEntry] ~ { LookupMatchingSymEntryByNameInner: PROC [ symID: CARD, pattern: CString, caseSensitive: BOOLEAN, wantedTypes: CARD, ignoreClasses: CARD, numToSkip: INT, buf: SWSymEntryPtr] RETURNS [INT] = MACHINE CODE {"CirioNubLocalGetMatchingSymEntryByName"}; buf: SWSymEntry; result: INT ¬ LookupMatchingSymEntryByNameInner[from, IF pattern=NIL THEN NIL ELSE UXStrings.Create[pattern], caseSensitive, types, classes.ORD, nth, @buf]; RETURN[ExportSymEntry[result, buf]]}; LocalMatchingSymEntryByValue: PROC [nub: DebugNub, val: CARD ¬ nullVal, types: CARD ¬ allTypes, classes: Classes ¬ all, nth: INT, from: SymID ¬ nullID] RETURNS [SymEntry] ~ { LookupMatchingSymEntryByValueInner: PROC [symID: CARD, val: CARD, wantedTypes: CARD, ignoreClasses: CARD, numToSkip: INT, buf: SWSymEntryPtr] RETURNS [INT] = TRUSTED MACHINE CODE {"CirioNubLocalGetMatchingSymEntryByValue"}; buf: SWSymEntry; result: INT ¬ LookupMatchingSymEntryByValueInner[from, val, types, classes.ORD, nth, @buf]; RETURN[ExportSymEntry[result, buf]]}; LocalSymEntryByID: PROC [nub: DebugNub, id: SymID] RETURNS [SymEntry] ~ { LookupSymEntryByIDInner: PROC[symID: CARD, buf: SWSymEntryPtr] RETURNS [INT] = TRUSTED MACHINE CODE { "CirioNubLocalLookupSymEntryByID"}; buf: SWSymEntry; result: INT ¬ LookupSymEntryByIDInner[id, @buf]; RETURN[ExportSymEntry[result, buf]]}; SWSymEntryPtr: TYPE ~ POINTER TO SWSymEntry; SWSymEntry: TYPE = MACHINE DEPENDENT RECORD [ symID: CARD, name: CString, type: CARD, value: CARD, size: CARD, fileSeqNum: CARD]; ExportSymEntry: PROC [result: INT, buf: SWSymEntry] RETURNS [SymEntry] ~ { IF result#0 THEN RETURN [nullSymEntry]; RETURN [[ symID: buf.symID, name: UXStrings.ToRope[buf.name], type: buf.type, value: buf.value, size: buf.size, fileSeqNum: buf.fileSeqNum]]}; LocalPCtoInfo: PROC [nub: DebugNub, pc: CARD] RETURNS [PCInfo] ~ { <> SWPCInfoPtr: TYPE ~ POINTER TO SWPCInfo; SWPCInfo: TYPE = MACHINE DEPENDENT RECORD [ procName: CString, procSymID: CARD, fileName: CString, fileSeqNum: CARD, guessedEmbeddedFileName: CString, guessedEmbeddedFileSymID: CARD ]; PCtoInfoInner: PROC [pc: CARD, buf: SWPCInfoPtr] RETURNS [INT] = TRUSTED MACHINE CODE {"CirioNubLocalPCtoInfo"}; buf: SWPCInfo; result: INT ¬ PCtoInfoInner[pc, @buf]; IF result#0 THEN RETURN [nullPCInfo]; RETURN [[ procName: UXStrings.ToRope[buf.procName], procSymID: buf.procSymID, fileName: UXStrings.ToRope[buf.fileName], fileSeqNum: buf.fileSeqNum, guessedEmbeddedFileName: UXStrings.ToRope[buf.guessedEmbeddedFileName], guessedEmbeddedFileSymID: buf.guessedEmbeddedFileSymID ]]}; GetMess: PROC RETURNS [BOOL] ~ MACHINE CODE { "+extern int XR_msgFromMemerrHandler;\n"; "#define GetMessHelp() (XR_msgFromMemerrHandler)\n"; ".GetMessHelp"; }; SetMess: PROC [BOOL] ~ MACHINE CODE { "+#define SetMessHelp(new) XR_msgFromMemerrHandler = new\n"; ".SetMessHelp"; }; LocalFetchWord: PROC [nub: DebugNub, addr: CARD] RETURNS [word: WORD] = { p: POINTER TO WORD = LOOPHOLE[addr]; save: BOOL ~ GetMess[]; SetMess[FALSE]; { ENABLE { VM.AddressFault => AddressFault[address]; UNWIND => SetMess[save] }; word := LOOPHOLE[addr, POINTER TO WORD]­; }; SetMess[save]; }; huh: REF TEXT = "???"; ldstOpNames: ARRAY LdStOp OF REF TEXT := [ "ld", "ldub", "lduh", "ldd", "st", "stb", "sth", "std", huh, "ldsb", "ldsh", huh, huh, "ldstub", huh, "swap", "lda", "lduba", "lduha", "ldda", "sta", "stba", "stha", "stda", huh, "ldsba", "ldsha", huh, huh, "ldstuba", huh, "swapa", "ldf", "ldfsr", huh, "lddf", "stf", "stfsr", "stdfq", "stdf", huh, huh, huh, huh, huh, huh, huh, huh, "ldc", "ldcsr", huh, "lddc", "stc", "stcsr", "stdcq", "stdc", huh, huh, huh, huh, huh, huh, huh, huh ]; regOpNames: ARRAY RegOp OF REF TEXT := [ "add", "and", "or", "xor", "sub", "andn", "orn", "xnor", "addx", huh, huh, huh, "subx", huh, huh, huh, "addcc", "andcc", "orcc", "xorcc", "subcc", "andncc", "orncc", "xnorcc", "addxcc", huh, huh, huh, "subxcc", huh, huh, huh, "taddcc", "tsubcc", "taddcctv", "tsubcctv", "mulscc", "sll", "srl", "sra", "rdy", "rdpsr", "rdwim", "rdtbr", huh, huh, huh, huh, "wry", "wrpsr", "wrwim", "wrtbr", "FPop1", "FPop2", "CPop1", "CPop2", "jmpl", "rett", "te", "iflush", "save", "restore", huh, huh ]; biccNames: ARRAY Bicc OF REF TEXT := [ "bn", "be", "ble", "bl", "bleu", "bcs", "bm", "bvs", "ba", "bne", "bg", "bge", "bgu", "bcc", "bp", "bvc" ]; fbiccNames: ARRAY FBicc OF REF TEXT := [ "fbn", "fbne", "fblg", "fbul", "fbl", "fbug", "fbg", "fbu", "fba", "fbe", "fbue", "fbge", "fbuge", "fble", "fbule", "fbo" ]; hexlit: ARRAY BIT4 OF REF TEXT := [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0xA", "0xB", "0xC", "0xD", "0xE", "0xF" ]; regNames: ARRAY Register OF REF TEXT := [ "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o6", "%o7", "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i6", "%i7" ]; FPCompareOps: TYPE ~ [50H..57H]; -- These are FPop2, others are FPop1. FP2ArgOps: TYPE ~ [40H..8FH]; -- These use rs1, others ignore it. fpOp1Names: ARRAY BYTE OF REF TEXT := [ <<00>> NIL, "fmovs", NIL, NIL, NIL, "fnegs", NIL, NIL, NIL, "fabss", NIL, NIL, NIL, NIL, NIL, NIL, <<10>> NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <<20>> NIL, "fints", "fintd", "fintx", NIL, "fintrzs", "fintrzd", "fintrzx", NIL, "fsqrts", "fsqrtd", "fsqrtx", NIL, NIL, NIL, NIL, <<30>> NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <<40>> NIL, "fadds", "faddd", "faddx", NIL, "fsubs", "fsubd", "fsubx", NIL, "fmuls", "fmuld", "fmulx", NIL, "fdivs", "fdivd", "fdivx", <<50>> NIL, "fcmps", "fcmpd", "fcmpx", NIL, "fcmpes", "fcmped", "fcmpex", NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <<60>> NIL, "frems", "fremd", "fremx", NIL, "fquos", "fquod", "fquox", NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <<70>> NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <<80>> NIL, NIL, NIL, NIL, "fscales", NIL, NIL, NIL, "fscaled", NIL, NIL, NIL, "fscalex", NIL, NIL, NIL, <<90>> NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <> NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <> NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <> NIL, "fstoir", "fdtoir", "fxtoir", "fitos", NIL, "fdtos", "fxtos", "fitod", "fstod", NIL, "fxtod", "fitox", "fstox", "fdtox", NIL, <> NIL, "fstoi", "fdtoi", "fxtoi", NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <> NIL, "fclasss", "fclassd", "fclassx", NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, <> NIL, "fexpos", "fexpod", "fexpox", NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL ]; fregNamesArray: ARRAY Register OF REF TEXT ¬ ALL[NIL]; fregNames: PROC [fr: Register] RETURNS [REF TEXT] ~ { t: REF TEXT ¬ fregNamesArray[fr]; IF t = NIL THEN { t ¬ RefText.Append[NEW[TEXT[4]], "%f"]; t ¬ Convert.AppendInt[t, fr]; fregNamesArray[fr] ¬ t; }; RETURN [t] }; Disp22: PROC [d: [0..2**22)] RETURNS [CARD] ~ { <> RETURN [IF d > 2**21-1 THEN CARD[d] + (LAST[CARD]-(2**22-1)) ELSE d]; }; DisassembleInstr: PUBLIC PROC [to: REF TEXT, pc: CARD, word: WORD, nub: DebugNub, regs: RegisterModel ¬ NIL] RETURNS [REF TEXT] = { instr: InstructionOverlay := LOOPHOLE[word]; line: REF TEXT := to; sep: {null, comma, operand, comment, space, plus} := null; PutChar: PROC [char: CHAR] ~ { line := RefText.AppendChar[line, char] }; Op: PROC [op: REF TEXT] = { line := RefText.Append[line, op]; sep ¬ operand }; Text: PROC [text: REF TEXT] = { line := RefText.Append[line, text] }; Hex: PROC [val: CARD] = { Sep[]; line := RefText.ReserveChars[line, 12]; Text["0x"]; line := PutHexCard[line, [lc[val]]]; sep := comma; }; Lit: PROC [text: REF TEXT] = { Sep[]; Text[text]; sep := comma; }; Decimal: PROC [int: INT] = { Sep[]; line := Convert.AppendInt[line, int]; sep := comma; }; TabTo: PROC [col: INTEGER] ~ { len: INTEGER ~ col-1; IF line.length < len THEN { line := RefText.ReserveChars[line, len-line.length]; FOR i: NAT IN [line.length..len) DO line[i] ¬ ' ; ENDLOOP; line.length ¬ len; } ELSE {PutChar[' ]}; }; Sep: PROC = { SELECT sep FROM null => {}; comment => { TabTo[46]; PutChar['!]; PutChar[' ]; }; operand => { TabTo[26]; }; comma => {PutChar[',]}; space => {PutChar[' ]}; plus => {PutChar['+]}; ENDCASE; sep := null; }; Source2: PROC [s2: Src2] = { WITH s2: s2 SELECT FROM zero => { Lit[regNames[s2.rs2]]; IF s2.asi # 0 THEN { sep := space; Decimal[s2.asi]}; }; one => { signed13: BIT13 = s2.signed13; val: INT = IF signed13 >= 2**12 THEN INT[signed13]-INT[2**13] ELSE signed13; Decimal[val]; }; ENDCASE; }; EaddrVal: PROC [rs1: Register, s2: Src2] RETURNS [RegisterContents] = { asi: NAT := 0; val: WORD := regs[rs1].val; IF NOT regs[rs1].known THEN RETURN [[0,FALSE]]; WITH s2: s2 SELECT FROM zero => { rs2: Register = s2.rs2; IF NOT regs[rs2].known THEN RETURN [[0,FALSE]]; val := val + regs[rs2].val; asi := s2.asi; }; one => { signed13: BIT13 = s2.signed13; delta: INT = IF signed13 >= 2**12 THEN INT[signed13]-INT[2**13] ELSE signed13; val := val + LOOPHOLE[delta, CARD]; }; ENDCASE; IF asi # 0 THEN RETURN [[0,FALSE]]; RETURN[[val,TRUE]] }; Eaddr: PROC [rs1: Register, s2: Src2] = { asi: NAT := 0; Sep[]; Text["["]; IF rs1 # 0 THEN { Lit[regNames[rs1]]; sep := plus }; WITH s2: s2 SELECT FROM zero => { rs2: Register = s2.rs2; IF sep=null OR rs2 # 0 THEN { Lit[regNames[rs2]]; }; asi := s2.asi; }; one => { signed13: BIT13 = s2.signed13; val: INT = IF signed13 >= 2**12 THEN INT[signed13]-INT[2**13] ELSE signed13; IF val < 0 THEN sep := null; Decimal[val]; }; ENDCASE; Text["]"]; IF asi # 0 THEN { sep := space; Decimal[asi] }; sep := comma; }; forget: BOOL := FALSE; resultReg: Register := 0; jumpTarget: CARD := 0; IF regs=NIL THEN regs ¬ NEW[RegisterModelRep]; regs[0] := [0, TRUE]; -- the constant 0 register SELECT instr.op FROM 0 => { SELECT instr.brop FROM sethi => { Op["sethi"]; Sep[]; Text["&hi("]; Hex[instr.imm22*(2**10)]; Text[")"]; Lit[regNames[instr.rd]]; regs[instr.rd] := [instr.imm22*(2**10), TRUE]; forget ¬ FALSE; resultReg := instr.rd; }; Bicc => { Op[biccNames[instr.cond]]; IF instr.annul THEN Text[",a"]; Hex[Disp22[instr.disp22]*4+pc]; }; FBicc => { Op[fbiccNames[instr.fcond]]; IF instr.annul THEN Text[",a"]; Hex[Disp22[instr.disp22]*4+pc]; }; CBccc => { Op["cbicc"]; IF instr.annul THEN Text[",a"]; Lit[hexlit[instr.ccond]]; Hex[Disp22[instr.disp22]*4+pc]; }; ENDCASE => { Op[".dw"]; Hex[word] }; }; 1 => { target: PC ~ CARD[instr.disp30]*4+pc; offset: CARD := 0; Op["call"]; Hex[target]; sep := comment; Sep[]; [line, offset] := PutPCInfo[line, nub, target]; IF offset # 0 THEN { sep := plus; Hex[offset] }; }; 2 => { SELECT instr.regop FROM FPop1, FPop2 => { fopName: REF TEXT ¬ fpOp1Names[instr.opf1 MOD 256]; IF fopName = NIL OR instr.opf1 >= 256 OR ((instr.opf1 IN FPCompareOps) # (instr.regop=FPop2)) THEN {Op[".dw"]; Hex[word]} ELSE { Op[fopName]; IF instr.opf1 IN FP2ArgOps THEN Lit[fregNames[instr.fp1rs1]]; Lit[fregNames[instr.fp1rs2]]; IF instr.regop#FPop2 THEN Lit[fregNames[instr.fp1rd]]; forget := FALSE; }; }; ENDCASE => { Op[regOpNames[instr.regop]]; Lit[regNames[instr.rs1]]; Source2[instr.s2]; Lit[regNames[instr.rd]]; forget := FALSE; SELECT instr.regop FROM or, add, sub, jmpl => { s2: Src2 ~ instr.s2; sr1: Register ~ instr.rs1; sr2: Register := 0; i2: CARD := 0; WITH s2: s2 SELECT FROM zero => { sr2 := s2.rs2; IF s2.asi # 0 THEN {regs[sr2].known := FALSE}; }; one => { signed13: BIT13 = s2.signed13; val: INT = IF signed13 >= 2**12 THEN INT[signed13]-INT[2**13] ELSE signed13; i2 := LOOPHOLE[val]; }; ENDCASE; IF regs[sr1].known AND regs[sr2].known THEN { v1: CARD ~ regs[sr1].val; v2: CARD ~ regs[sr2].val + i2; val: CARD ~ SELECT instr.regop FROM or => Basics.BITOR[v1, v2], add => v1+v2, sub => v1-v2, jmpl => pc, ENDCASE => ERROR; regs[instr.rd] := [val, TRUE]; regs[0] := [0, TRUE]; resultReg := instr.rd; IF instr.regop = jmpl THEN { resultReg := 0; jumpTarget := v1+v2; }; } ELSE regs[instr.rd].known := FALSE; }; ENDCASE => regs[instr.rd].known := FALSE; }; }; 3 => { Op[ldstOpNames[instr.ldstop]]; SELECT instr.ldstop FROM ld, ldub, lduh, ldd, ldsb, ldsh, ldstub, swap, lda, lduba, lduha, ldda, ldsba, ldsha, ldstuba, swapa => { Eaddr[instr.rs1, instr.s2]; Lit[regNames[instr.rd]]; forget := FALSE; resultReg := instr.rd; IF instr.ldstop = ld THEN { ea: RegisterContents := EaddrVal[instr.rs1, instr.s2]; regs[instr.rd].known := FALSE; IF ea.known AND (ea.val MOD 4 = 0) THEN { ENABLE AddressFault => { Text[" !??"]; CONTINUE}; w: WORD := nub.FetchWord[nub, ea.val]; regs[instr.rd] := [w, TRUE]; }; } ELSE regs[instr.rd].known := FALSE; regs[0] := [0,TRUE]; }; st, stb, sth, std, sta, stba, stha, stda => { Lit[regNames[instr.rd]]; Eaddr[instr.rs1, instr.s2]; forget := FALSE; }; ldf, ldfsr, lddf, ldc, ldcsr, lddc => { Eaddr[instr.rs1, instr.s2]; Lit[fregNames[instr.rd]]; forget := FALSE; }; stf, stfsr, stdfq, stdf, stc, stcsr, stdcq, stdc => { Lit[fregNames[instr.rd]]; Eaddr[instr.rs1, instr.s2]; forget := FALSE; }; ENDCASE => Hex[word]; }; ENDCASE; IF forget THEN regs­ := ALL[[0, FALSE]]; IF jumpTarget # 0 THEN { target: PC := jumpTarget; offset: CARD := 0; sep := comment; Sep[]; [line, offset] := PutPCInfo[line, nub, target]; IF offset # 0 THEN { sep := plus; Hex[offset] }; }; IF resultReg # 0 AND regs[resultReg].known THEN { sep := comment; Hex[regs[resultReg].val]; }; RETURN [line] }; PutHexCard: PROC [line: REF TEXT, num: Basics.LongNumber] RETURNS [REF TEXT] ~ { PutChar: PROC [char: CHAR] ~ { line := RefText.AppendChar[line, char] }; PutHexit: PROC [nybble: [0..16)] ~ { PutChar[(IF nybble < 10 THEN '0 ELSE 'A-10) + nybble]; }; PutHexByte: PROC [byte: BYTE] ~ { PutHexit[byte/16]; PutHexit[byte MOD 16]; }; PutHexByte[num.hh]; PutHexByte[num.hl]; PutHexByte[num.lh]; PutHexByte[num.ll]; RETURN [line] }; DisassembleCommand: Commander.CommandProc = TRUSTED { ENABLE { AddressFault => { CommanderOps.Failed[IO.PutFR1["<<< Address Fault at 0x%08x >>>", [cardinal[LOOPHOLE[address]]]]]; }; Failed => CommanderOps.Failed[errMsg]}; argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd]; regs: RegisterModel = NEW[RegisterModelRep]; IF argv.argc<2 OR argv.argc>10 THEN CommanderOps.Failed[cmd.procData.doc] ELSE { e1: SymEntry = FindSym[argv[1], localNub, TRUE]; nBytes: CARD ~ EstSize[localNub, e1, TRUE]; FOR i: NAT IN [2..argv.argc) DO ENABLE Convert.Error => CommanderOps.Failed[IO.PutFR["Syntax error in contents (%g) of register i%g", [rope[argv[i]]], [integer[i-2]] ]]; regs[22+i] ¬ [CardFromRope[argv[i]], TRUE]; ENDLOOP; DisassembleProc[cmd.out, e1.value, nBytes, localNub, regs]; }; }; DisassembleProc: PUBLIC PROC [to: IO.STREAM, startPC, nBytes: CARD, nub: DebugNub, regs: RegisterModel ¬ NIL, stop: REF BOOL ¬ NIL] ~ { line: REF TEXT := RefText.ObtainScratch[100]; PutChar: PROC [char: CHAR] ~ { line := RefText.AppendChar[line, char] }; size: NAT := IF nBytes IN [8..30000] THEN nBytes ELSE 200; stopped: BOOL ¬ FALSE; IF regs=NIL THEN regs ¬ NEW[RegisterModelRep]; IO.PutF1[to, "%L", [rope["f"]]]; line.length := 0; IO.PutBlock[to, PutPCInfo[line, nub, startPC].result]; IO.PutChar[to, '\n]; FOR i: CARD := 0, i+4 WHILE i < size DO pc: CARD := startPC+i; word: WORD := nub.FetchWord[nub, pc]; line.length := 0; line := PutHexCard[line, [lc[pc]]]; PutChar[':]; PutChar[' ]; line := PutHexCard[line, [lc[word]]]; PutChar[' ]; line := DisassembleInstr[line, pc, word, nub, regs]; PutChar['\n]; IO.PutBlock[to, line]; Process.CheckForAbort[]; IF stop#NIL AND stop­ THEN {stopped ¬ TRUE; EXIT}; ENDLOOP; RefText.ReleaseScratch[line]; IF stopped THEN IO.PutRope[to, "(stopped)\n"] ELSE IF size < nBytes THEN IO.PutRope[to, ". . .\n"]; IO.PutF1[to, "%L", [rope["F"]]]; }; SymbolFromPCCommand: Commander.CommandProc = TRUSTED { ENABLE { AddressFault => { CommanderOps.Failed[IO.PutFR1["<<< Address Fault at 0x%08x >>>", [cardinal[LOOPHOLE[address]]]]]; }; Failed => CommanderOps.Failed[errMsg]}; name: ROPE = CommanderOps.NextArgument[cmd]; IF name = NIL THEN CommanderOps.Failed[cmd.procData.doc] ELSE { entr: SymEntry = FindSym[name, localNub, TRUE]; line: REF TEXT := RefText.ObtainScratch[100]; IO.PutBlock[cmd.out, PutPCInfo[line, localNub, entr.value].result]; IO.PutChar[cmd.out, '\n]; RefText.ReleaseScratch[line]; }; }; PCFromSymbolCommand: Commander.CommandProc = TRUSTED { ENABLE { AddressFault => { CommanderOps.Failed[IO.PutFR1["<<< Address Fault at 0x%08x >>>", [cardinal[LOOPHOLE[address]]]]]; }; Failed => CommanderOps.Failed[errMsg]}; arg: ROPE = CommanderOps.NextArgument[cmd]; IF arg = NIL THEN CommanderOps.Failed[cmd.procData.doc] ELSE { entr: SymEntry = FindSym[arg, localNub, TRUE]; IO.PutF1[cmd.out, "0x%08x\n", [cardinal[entr.value]]]; }; }; Commander.Register["Disassemble", DisassembleCommand, "| [i0 [i1 [i2 [i3 [i4 [i5 [i6 [i7]]]]]]]]--- Disassemble from memory"]; Commander.Register["SymbolFromPC", SymbolFromPCCommand, "Shows the c-procedure name for a given pc: SymbolFromPC |"]; Commander.Register["PCFromSymbol", PCFromSymbolCommand, "Shows the address for a given procedure: PCFromSymbol |"]; END.