1 # Dump a stack trace when you abort.
5 abort: # e: (addr array byte)
10 (set-cursor-position-on-real-screen 0 0)
11 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+8) 0xf 0xc) # 0/real-screen, 0xf/fg=white, 0xc/bg=red
18 # Helpers below this point are not intended to be reused; they assume the
19 # program will soon crash. In particular, they destroy the heap.
30 # var labels/edx: (addr stream {start-address, label-slice} 0x5000)
31 # start addresses are in ascending order
32 81 5/subop/subtract %esp 0x3c000/imm32 # 0x5000 labels * 12 bytes per label
38 (load-debug-symbols %edx) # destroys the heap
39 # traverse the linked list of ebp pointers: https://wiki.osdev.org/Stack_Trace
42 # loop termination check
43 81 7/subop/compare %ebx 0/imm32
44 0f 84/jump-if-= break/disp32
46 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "\n" 0 0xc)
47 (draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebx+4) 0xf 0xc)
48 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 " " 0 0xc)
49 (containing-function %edx *(ebx+4)) # => eax, ecx
50 (draw-slice-wrapping-right-then-down-from-cursor-over-full-screen 0 %eax %ecx 0 0xc)
58 81 0/subop/add %esp 0x100c/imm32
69 load-debug-symbols: # labels: (addr stream {start-address, label-slice})
78 # create space for a stream on the heap, clobbering any existing data
79 # var s/ecx: (addr stream byte)
80 b9/copy-to-ecx 0x03000000/imm32
81 c7 0/subop/copy *ecx 0/imm32 # write index
82 c7 0/subop/copy *(ecx+4) 0/imm32 # read index
83 c7 0/subop/copy *(ecx+8) 0x01000000/imm32 # stream capacity = 16MB
84 # load sectors starting from sector 10080 = 0x2760
85 (load-sectors Primary-bus-primary-drive 0x2760 0x800 %ecx) # 0x800 sectors = 1MB
86 # - parse pointers to portions of this stream into labels
87 # var curr/ecx: (addr byte) = s->data
88 81 0/subop/add %ecx 0xc/imm32
90 # loop termination check
91 b8/copy-to-eax 0/imm32
92 8a/byte-> *ecx 0/r32/eax
93 3d/compare-eax-and 0/imm32
94 0f 84/jump-if-= break/disp32
96 (skip-to-next-space %ecx) # => edx
98 (skip-to-next-newline %edx) # => ebx
99 (parse-hex-int-helper %edx %ebx) # => eax
101 (label-append *(ebp+8) %eax %ecx %edx)
107 $load-debug-symbols:end:
108 # . restore registers
118 skip-to-next-space: # curr: (addr byte) -> _/edx: (addr byte)
125 b8/copy-to-eax 0/imm32
127 8b/-> *(ebp+8) 2/r32/edx
129 8a/byte-> *edx 0/r32/eax
130 3d/compare-eax-and 0x20/imm32/space
131 0f 84/jump-if-= break/disp32
132 3d/compare-eax-and 0/imm32
134 75/jump-if-!= break/disp8
135 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "done loading" 7 0)
140 3d/compare-eax-and 0xa/imm32/newline
142 75/jump-if-!= break/disp8
143 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "unexpected newline" 7 0)
151 $skip-to-next-space:end:
152 # . restore registers
159 skip-to-next-newline: # curr: (addr byte) -> _/ebx: (addr byte)
166 b8/copy-to-eax 0/imm32
168 8b/-> *(ebp+8) 3/r32/ebx
170 8a/byte-> *ebx 0/r32/eax
171 3d/compare-eax-and 0xa/imm32/newline
172 0f 84/jump-if-= break/disp32
173 3d/compare-eax-and 0/imm32
175 75/jump-if-!= break/disp8
176 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "done loading" 7 0)
181 3d/compare-eax-and 0x20/imm32/space
183 75/jump-if-!= break/disp8
184 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "unexpected space" 7 0)
192 $skip-to-next-newline:end:
193 # . restore registers
200 label-append: # labels: (addr stream {start-address, label-slice}), address: int, start: int, end: int
209 8b/-> *(ebp+8) 6/r32/esi
210 # ecx = labels->write
212 # labels->data[labels->write] = address
213 8b/-> *(ebp+0xc) 0/r32/eax
214 89/<- *(esi+ecx+0xc) 0/r32/eax
215 # labels->data[labels->write+4] = start
216 8b/-> *(ebp+0x10) 0/r32/eax
217 89/<- *(esi+ecx+0x10) 0/r32/eax
218 # labels->data[labels->write+8] = end
219 8b/-> *(ebp+0x14) 0/r32/eax
220 89/<- *(esi+ecx+0x14) 0/r32/eax
221 # labels->write += 12
222 81 0/subop/add *esi 0xc/imm32
224 # . restore registers
233 containing-function: # labels: (addr stream {start-address, label-slice}), address: int -> start/eax: (addr byte), end/ecx: (addr byte)
242 8b/-> *(ebp+8) 6/r32/esi
243 # var curr/ecx: (addr byte) = labels->data
244 8d/copy-address *(esi+0xc) 1/r32/ecx
245 # var max/edx: (addr byte) = labels->data + labels->write
247 01/add-to %edx 1/r32/ecx
248 # var previous-function-name/ebx: (addr slice) = 0
249 bb/copy-to-ebx 0/imm32
252 39/compare %ecx 2/r32/edx
254 0f 82/jump-if-addr< break/disp32
255 (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "failed to find function for address " 7 0)
256 (draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0xc) 7 0)
261 # if *curr > address, break
263 3b/compare 0/r32/eax *(ebp+0xc)
264 0f 87/jump-if-addr> break/disp32
265 # if **(curr+4) not '$' or '@', save curr to previous-function-name
267 8b/-> *(ecx+4) 0/r32/eax
268 8a/byte-> *eax 0/r32/eax
269 25/and-with-eax 0xff/imm32
270 3d/compare-eax-and 0x24/imm32/$
271 74/jump-if-= break/disp8
272 3d/compare-eax-and 0x40/imm32/@
273 74/jump-if-= break/disp8
274 8d/copy-address *(ecx+4) 3/r32/ebx
277 81 0/subop/add %ecx 0xc/imm32
282 8b/-> *(ebx+4) 1/r32/ecx
283 $containing-function:end:
284 # . restore registers
293 # unlike variants in .mu files, this only supports ASCII
294 draw-slice-wrapping-right-then-down-from-cursor-over-full-screen: # screen: (addr screen), start: (addr byte), end: (addr byte), color: int, background-color: int
302 # var curr/ecx: (addr byte) = start
303 8b/-> *(ebp+0xc) 1/r32/ecx
305 8b/-> *(ebp+0x10) 2/r32/edx
307 b8/copy-to-eax 0/imm32
309 # if (curr >= end) break
310 39/compare %ecx 2/r32/edx
311 73/jump-if-addr>= break/disp8
313 8a/byte-> *ecx 0/r32/eax
314 (draw-grapheme-at-cursor-over-full-screen *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18))
320 $draw-slice-wrapping-right-then-down-from-cursor-over-full-screen:end:
321 # . restore registers