(and-record trace [ label:string-address contents:string-address ]) (address trace-address (trace)) (array trace-address-array (trace-address)) (address trace-address-array-address (trace-address-array)) (address trace-address-array-address-address (trace-address-array-address)) (and-record instruction-trace [ call-stack:string-address-array-address pc:string-address ; should be integer? instruction:string-address children:trace-address-array-address ]) (address instruction-trace-address (instruction-trace)) (array instruction-trace-address-array (instruction-trace-address)) (address instruction-trace-address-array-address (instruction-trace-address-array)) (function parse-traces [ ; stream-address -> instruction-trace-address-array-address (default-space:space-address <- new space:literal 30:literal) ;? ($print (("parse-traces\n" literal))) ;? 2 (in:stream-address <- next-input) ; check input size ($print (("counting lines\n" literal))) (n:integer <- copy 0:literal) { begin (done?:boolean <- end-of-stream? in:stream-address) (break-if done?:boolean) ;? ($start-tracing) ;? 1 (c:character <- read-character in:stream-address) { begin (newline?:boolean <- equal c:character ((#\newline literal))) (break-unless newline?:boolean) (n:integer <- add n:integer 1:literal) { begin ;? (print?:boolean <- divides? n:integer 100:literal) ;? (break-unless print?:boolean) ($print ((" " literal))) ($print n:integer) ($print (("\n" literal))) } } ;? ($quit) ;? 1 (loop) } ($print n:integer) ($print ((" lines\n" literal))) (in:stream-address <- rewind-stream in:stream-address) ; prepare result (result:buffer-address <- init-buffer 30:literal) (curr-tail:instruction-trace-address <- copy nil:literal) (ch:buffer-address <- init-buffer 5:literal) ; accumulator for traces between instructions (run:string-address/const <- new "run") ($print (("parsing\n" literal))) (n:integer <- copy 0:literal) ; reading each line from 'in' { begin next-line (done?:boolean <- end-of-stream? in:stream-address) ;? ($print done?:boolean) ;? 1 ;? ($print (("\n" literal))) ;? 1 (break-if done?:boolean) ; parse next line as a generic trace (line:string-address <- read-line in:stream-address) { begin (n:integer <- add n:integer 1:literal) (print?:boolean <- divides? n:integer 100:literal) (break-unless print?:boolean) ($print ((" " literal))) ($print n:integer) ($print (("\n" literal))) } ;? (print-string nil:literal/terminal line:string-address) ;? 1 (f:trace-address <- parse-trace line:string-address) (l:string-address <- get f:trace-address/deref label:offset) { begin ; if it's an instruction trace with label 'run' (inst?:boolean <- string-equal l:string-address run:string-address/const) (break-unless inst?:boolean) ; add accumulated traces to curr-tail { begin (break-unless curr-tail:instruction-trace-address) (c:trace-address-array-address-address <- get-address curr-tail:instruction-trace-address/deref children:offset) (c:trace-address-array-address-address/deref <- to-array ch:buffer-address) ; clear 'ch' (ch:buffer-address <- init-buffer 5:literal) } ; append a new curr-tail to result (curr-tail:instruction-trace-address <- parse-instruction-trace f:trace-address) (result:buffer-address <- append result:buffer-address curr-tail:instruction-trace-address) (jump next-line:offset) ; loop } ; otherwise accumulate trace (loop-unless curr-tail:instruction-trace-address) (ch:buffer-address <- append ch:buffer-address f:trace-address) (loop) } ; add accumulated traces to final curr-tail ; todo: test { begin (break-unless curr-tail:instruction-trace-address) (c:trace-address-array-address-address <- get-address curr-tail:instruction-trace-address/deref children:offset) (c:trace-address-array-address-address/deref <- to-array ch:buffer-address) } (s:instruction-trace-address-array-address <- to-array result:buffer-address) (reply s:instruction-trace-address-array-address) ]) (function parse-instruction-trace [ ; trace-address -> instruction-trace-address (default-space:space-address <- new space:literal 30:literal) ;? ($print (("parse-instruction-trace\n" literal))) ;? 1 (in:trace-address <- next-input) (buf:string-address <- get in:trace-address/deref contents:offset) ;? (print-string nil:literal buf:string-address) ;? 1 ;? ($print (("\n" literal))) ;? 1 (result:instruction-trace-address <- new instruction-trace:literal) (f1:string-address rest:string-address <- split-first buf:string-address ((#\space literal))) ;? ($print (("call-stack: " literal))) ;? 1 ;? (print-string nil:literal f1:string-address) ;? 1 ;? ($print (("\n" literal))) ;? 1 (cs:string-address-array-address-address <- get-address result:instruction-trace-address/deref call-stack:offset) (cs:string-address-array-address-address/deref <- split f1:string-address ((#\/ literal))) (p:string-address-address <- get-address result:instruction-trace-address/deref pc:offset) (delim:string-address <- new ": ") (p:string-address-address/deref rest:string-address <- split-first-at-substring rest:string-address delim:string-address) (inst:string-address-address <- get-address result:instruction-trace-address/deref instruction:offset) (inst:string-address-address/deref <- copy rest:string-address) (reply result:instruction-trace-address) ]) (function parse-trace [ ; string-address -> trace-address (default-space:space-address <- new space:literal 30:literal) ;? ($print (("parse-trace\n" literal))) ;? 1 (in:string-address <- next-input) (result:trace-address <- new trace:literal) (delim:string-address <- new ": ") (first:string-address rest:string-address <- split-first-at-substring in:string-address delim:string-address) (l:string-address-address <- get-address result:trace-address/deref label:offset) (l:string-address-address/deref <- copy first:string-address) (c:string-address-address <- get-address result:trace-address/deref contents:offset) (c:string-address-address/deref <- copy rest:string-address) (reply result:trace-address) ]) (function print-trace [ (default-space:space-address <- new space:literal 30:literal) (screen:terminal-address <- next-input) (x:trace-address <- next-input) (l:string-address <- get x:trace-address/deref label:offset) (clear-line screen:terminal-address) (print-string screen:terminal-address l:string-address) (print-character screen:terminal-address ((#\space literal))) (print-character screen:terminal-address ((#\: literal))) (print-character screen:terminal-address ((#\space literal))) (c:string-address <- get x:trace-address/deref contents:offset)
# The stack shouldn't grow into the code area.
== code
check-stack:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
#
89/<- %eax 4/r32/esp
81 7/subop/compare %eax 0x01000000/imm32
{
7f/jump-if-> break/disp8
(abort "stack overflow")
}
$check-stack:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
show-stack-state:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
#
89/<- %edx 4/r32/esp
# save old cursor position
(cursor-position 0) # => eax, ecx
# print at top-right
(set-cursor-position 0 0x70 0)
(draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 %edx 0xf 0xc)
# restore cursor position
(set-cursor-position %eax %ecx)
$check-stack:end:
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# Helper for debugging deeply recursive calls without logs or traces.
# Turn it on, insert calls in the right places, and you get a terse sense of
# important parts of the call stack. A poor sophont's stack trace.
debug-print: # x: (addr array byte), fg: int, bg: int # x is very short; usually a single character
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
51/push-ecx
#
{
81 7/subop/compare *Really-debug-print 0/imm32/false
74/jump-if-= break/disp8
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+8) *(ebp+0xc) *(ebp+0x10))
# clear the screen and continue if we got too close to the bottom
(cursor-position 0) # => eax, ecx
81 7/subop/compare %ecx 0x28/imm32
75/jump-if-!= break/disp8
(clear-screen 0)
(set-cursor-position 0 0 0)
}
$debug-print:end:
# . restore registers
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
debug-print?: # -> _/eax: boolean
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
8b/-> *Really-debug-print 0/r32/eax
$debug-print?:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
turn-on-debug-print:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
c7 0/subop/copy *Really-debug-print 1/imm32/true
$turn-on-debug-print:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
turn-off-debug-print:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
c7 0/subop/copy *Really-debug-print 0/imm32/false
$turn-off-debug-print:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
== data
Really-debug-print:
0/imm32/false
#? 1/imm32/true