https://github.com/akkartik/mu/blob/main/315stack-debug.subx
  1 # The stack shouldn't grow into the code area.
  2 
  3 == code
  4 
  5 check-stack:
  6     # . prologue
  7     55/push-ebp
  8     89/<- %ebp 4/r32/esp
  9     # . save registers
 10     50/push-eax
 11     #
 12     89/<- %eax 4/r32/esp
 13     81 7/subop/compare %eax 0x01000000/imm32
 14     {
 15       7f/jump-if-> break/disp8
 16       (abort "stack overflow")
 17     }
 18 $check-stack:end:
 19     # . restore registers
 20     58/pop-to-eax
 21     # . epilogue
 22     89/<- %esp 5/r32/ebp
 23     5d/pop-to-ebp
 24     c3/return
 25 
 26 show-stack-state:
 27     # . prologue
 28     55/push-ebp
 29     89/<- %ebp 4/r32/esp
 30     # . save registers
 31     50/push-eax
 32     51/push-ecx
 33     52/push-edx
 34     #
 35     89/<- %edx 4/r32/esp
 36     # save old cursor position
 37     (cursor-position 0)  # => eax, ecx
 38     # print at top-right
 39     (set-cursor-position 0 0x70 0)
 40     (draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 %edx 0xf 0xc)
 41     # restore cursor position
 42     (set-cursor-position %eax %ecx)
 43 $check-stack:end:
 44     # . restore registers
 45     5a/pop-to-edx
 46     59/pop-to-ecx
 47     58/pop-to-eax
 48     # . epilogue
 49     89/<- %esp 5/r32/ebp
 50     5d/pop-to-ebp
 51     c3/return
 52 
 53 # Helper for debugging deeply recursive calls without logs or traces.
 54 # Turn it on, insert calls in the right places, and you get a terse sense of
 55 # important parts of the call stack. A poor sophont's stack trace.
 56 debug-print:  # x: (addr array byte), fg: int, bg: int    # x is very short; usually a single character
 57     # . prologue
 58     55/push-ebp
 59     89/<- %ebp 4/r32/esp
 60     # . save registers
 61     50/push-eax
 62     51/push-ecx
 63     #
 64     {
 65       81 7/subop/compare *Really-debug-print 0/imm32/false
 66       74/jump-if-= break/disp8
 67       (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+8) *(ebp+0xc) *(ebp+0x10))
 68       # clear the screen and continue if we got too close to the bottom
 69       (cursor-position 0)  # => eax, ecx
 70       81 7/subop/compare %ecx 0x28/imm32
 71       75/jump-if-!= break/disp8
 72       (clear-screen 0)
 73       (set-cursor-position 0 0 0)
 74     }
 75 $debug-print:end:
 76     # . restore registers
 77     59/pop-to-ecx
 78     58/pop-to-eax
 79     # . epilogue
 80     89/<- %esp 5/r32/ebp
 81     5d/pop-to-ebp
 82     c3/return
 83 
 84 debug-print?:  # -> _/eax: boolean
 85     # . prologue
 86     55/push-ebp
 87     89/<- %ebp 4/r32/esp
 88     #
 89     8b/-> *Really-debug-print 0/r32/eax
 90 $debug-print?:end:
 91     # . epilogue
 92     89/<- %esp 5/r32/ebp
 93     5d/pop-to-ebp
 94     c3/return
 95 
 96 turn-on-debug-print:
 97     # . prologue
 98     55/push-ebp
 99     89/<- %ebp 4/r32/esp
100     #
101     c7 0/subop/copy *Really-debug-print 1/imm32/true
102 $turn-on-debug-print:end:
103     # . epilogue
104     89/<- %esp 5/r32/ebp
105     5d/pop-to-ebp
106     c3/return
107 
108 turn-off-debug-print:
109     # . prologue
110     55/push-ebp
111     89/<- %ebp 4/r32/esp
112     #
113     c7 0/subop/copy *Really-debug-print 0/imm32/false
114 $turn-off-debug-print:end:
115     # . epilogue
116     89/<- %esp 5/r32/ebp
117     5d/pop-to-ebp
118     c3/return
119 
120 == data
121 Really-debug-print:
122   0/imm32/false
123 #?   1/imm32/true