<<>> <> <> <> <<>> DIRECTORY Basics, IO, RefText, Commander, CommanderOps, VM; MemoryDumpImpl: CEDAR PROGRAM IMPORTS IO, RefText, Commander, CommanderOps, VM ~ BEGIN bytesPerLine: NAT ~ 16; << XXXXXXXX: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX *................* >> Dump: PROC [out: IO.STREAM, byteAddress: CARD32, byteCount: INT] ~ { startByteAddress: CARD32 ~ (byteAddress/bytesPerLine)*bytesPerLine; limit: CARD32 ~ byteAddress+byteCount; base: LONG POINTER TO Basics.RawBytes ~ LOOPHOLE[startByteAddress]; line: REF TEXT ¬ RefText.ObtainScratch[100]; Fetch: PROC [offset: CARD] RETURNS [BYTE] ~ TRUSTED INLINE { RETURN [base[offset]] }; PutChar: PROC [char: CHAR] ~ { line[line.length] ¬ char; line.length ¬ line.length + 1 }; 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]; }; PutHexCard: PROC [num: Basics.LongNumber] ~ { PutHexByte[num.hh]; PutHexByte[num.hl]; PutHexByte[num.lh]; PutHexByte[num.ll]; }; colon: CHAR ~ ':; space: CHAR ~ ' ; star: CHAR ~ '*; dot: CHAR ~ '.; tilde: CHAR ~ '~; newline: CHAR ~ '\n; Printable: TYPE ~ CHAR[' ..'~]; {ENABLE VM.AddressFault => { IO.PutBlock[out, line]; IO.PutRope[out, "<<< Address Fault >>>\n"]; CONTINUE; }; FOR i: CARD ¬ 0, i+bytesPerLine WHILE (startByteAddress+i) < limit DO FillLine: PROC ~ { PutHexCard[[lc[startByteAddress+i]]]; PutChar[colon]; FOR j: CARD IN [0..bytesPerLine) DO IF j MOD 4 = 0 THEN { PutChar[space]; }; IF startByteAddress+i+j IN [byteAddress..limit) THEN { PutHexByte[Fetch[i+j]] } ELSE { PutChar[space]; PutChar[space]; }; ENDLOOP; PutChar[space]; PutChar[star]; FOR j: CARD IN [0..bytesPerLine) DO IF startByteAddress+i+j IN [byteAddress..limit) THEN { char: CHAR ~ VAL[Fetch[i+j]]; PutChar[IF char IN Printable THEN char ELSE dot] } ELSE { PutChar[tilde] }; ENDLOOP; PutChar[star]; PutChar[newline]; }; line.length ¬ 0; NoMess[FillLine]; IO.PutBlock[out, line]; ENDLOOP; }; RefText.ReleaseScratch[line]; }; MemoryDumpCommand: Commander.CommandProc ~ { cmds: IO.STREAM ~ IO.RIS[cmd.commandLine]; GetNumber: PROC [default: CARD] RETURNS [CARD] ~ { number: CARD ¬ default; number ¬ IO.GetCard[cmds ! IO.EndOfStream => CONTINUE; IO.Error => CommanderOps.Failed[cmd.procData.doc]; ]; RETURN [number] }; start: CARD ~ GetNumber[0]; count: CARD ~ GetNumber[40]; IF start = 0 THEN CommanderOps.Failed[cmd.procData.doc]; IO.PutF1[cmd.out, "%l", [rope["f"]]]; Dump[cmd.out, start, count]; IO.PutF1[cmd.out, "%l", [rope["F"]]]; }; GetMess: PROC RETURNS [BOOL] ~ TRUSTED MACHINE CODE { "+extern int XR_msgFromMemerrHandler;\n"; "#define GetMessHelp() (XR_msgFromMemerrHandler)\n"; ".GetMessHelp"; }; SetMess: PROC [BOOL] ~ TRUSTED MACHINE CODE { "+#define SetMessHelp(new) XR_msgFromMemerrHandler = new\n"; ".SetMessHelp"; }; NoMess: PROC [proc: PROC] ~ { save: BOOL ~ GetMess[]; SetMess[FALSE]; proc[ ! UNWIND => SetMess[save]]; SetMess[save]; }; Commander.Register["MemoryDump", MemoryDumpCommand, "Dump local memory:\nMemoryDump startAddress [ byteCount ]\nParameters follow Cedar numeric literal syntax"]; END.