much love
[mu.git] / 317abort.subx
blob6b0fc7c7490f6188341e4338678b213fde30dfa7
1 # Dump a stack trace when you abort.
3 == code
5 abort:  # e: (addr array byte)
6     # . prologue
7     55/push-ebp
8     89/<- %ebp 4/r32/esp
9     #
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
12     (dump-call-stack)
13     # crash
14     {
15       eb/jump loop/disp8
16     }
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.
21 dump-call-stack:
22     # . prologue
23     55/push-ebp
24     89/<- %ebp 4/r32/esp
25     # . save registers
26     50/push-eax
27     51/push-ecx
28     52/push-edx
29     53/push-ebx
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
33     68/push  0x3c000/imm32
34     68/push  0/imm32/read
35     68/push  0/imm32/write
36     89/<- %edx 4/r32/esp
37     #
38     (load-debug-symbols %edx)  # destroys the heap
39     # traverse the linked list of ebp pointers: https://wiki.osdev.org/Stack_Trace
40     8b/-> *ebp 3/r32/ebx
41     {
42       # loop termination check
43       81 7/subop/compare %ebx 0/imm32
44       0f 84/jump-if-= break/disp32
45       # loop body
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)
51       # loop update
52       8b/-> *ebx 3/r32/ebx
53       #
54       e9/jump loop/disp32
55     }
56 $dump-call-stack:end:
57     # . reclaim locals
58     81 0/subop/add %esp 0x100c/imm32
59     # . restore registers
60     5b/pop-to-ebx
61     5a/pop-to-edx
62     59/pop-to-ecx
63     58/pop-to-eax
64     # . epilogue
65     89/<- %esp 5/r32/ebp
66     5d/pop-to-ebp
67     c3/return
69 load-debug-symbols:  # labels: (addr stream {start-address, label-slice})
70     # . prologue
71     55/push-ebp
72     89/<- %ebp 4/r32/esp
73     # . save registers
74     50/push-eax
75     51/push-ecx
76     52/push-edx
77     53/push-ebx
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
89     {
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
95       # loop body
96       (skip-to-next-space %ecx)  # => edx
97       42/increment-edx
98       (skip-to-next-newline %edx)  # => ebx
99       (parse-hex-int-helper %edx %ebx)  # => eax
100       43/increment-ebx
101       (label-append *(ebp+8) %eax %ecx %edx)
102       # loop update
103       89/<- %ecx 3/r32/ebx
104       #
105       e9/jump loop/disp32
106     }
107 $load-debug-symbols:end:
108     # . restore registers
109     5b/pop-to-ebx
110     5a/pop-to-edx
111     59/pop-to-ecx
112     58/pop-to-eax
113     # . epilogue
114     89/<- %esp 5/r32/ebp
115     5d/pop-to-ebp
116     c3/return
118 skip-to-next-space:  # curr: (addr byte) -> _/edx: (addr byte)
119     # . prologue
120     55/push-ebp
121     89/<- %ebp 4/r32/esp
122     # . save registers
123     50/push-eax
124     # eax = 0
125     b8/copy-to-eax 0/imm32
126     #
127     8b/-> *(ebp+8) 2/r32/edx
128     {
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
133       {
134         75/jump-if-!= break/disp8
135         (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "done loading" 7 0)
136         {
137           eb/jump loop/disp8
138         }
139       }
140       3d/compare-eax-and 0xa/imm32/newline
141       {
142         75/jump-if-!= break/disp8
143         (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "unexpected newline" 7 0)
144         {
145           eb/jump loop/disp8
146         }
147       }
148       42/increment-edx
149       e9/jump loop/disp32
150     }
151 $skip-to-next-space:end:
152     # . restore registers
153     58/pop-to-eax
154     # . epilogue
155     89/<- %esp 5/r32/ebp
156     5d/pop-to-ebp
157     c3/return
159 skip-to-next-newline:  # curr: (addr byte) -> _/ebx: (addr byte)
160     # . prologue
161     55/push-ebp
162     89/<- %ebp 4/r32/esp
163     # . save registers
164     50/push-eax
165     # eax = 0
166     b8/copy-to-eax 0/imm32
167     #
168     8b/-> *(ebp+8) 3/r32/ebx
169     {
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
174       {
175         75/jump-if-!= break/disp8
176         (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "done loading" 7 0)
177         {
178           eb/jump loop/disp8
179         }
180       }
181       3d/compare-eax-and 0x20/imm32/space
182       {
183         75/jump-if-!= break/disp8
184         (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "unexpected space" 7 0)
185         {
186           eb/jump loop/disp8
187         }
188       }
189       43/increment-ebx
190       e9/jump loop/disp32
191     }
192 $skip-to-next-newline:end:
193     # . restore registers
194     58/pop-to-eax
195     # . epilogue
196     89/<- %esp 5/r32/ebp
197     5d/pop-to-ebp
198     c3/return
200 label-append:  # labels: (addr stream {start-address, label-slice}), address: int, start: int, end: int
201     # . prologue
202     55/push-ebp
203     89/<- %ebp 4/r32/esp
204     # . save registers
205     50/push-eax
206     51/push-ecx
207     56/push-esi
208     # esi = labels
209     8b/-> *(ebp+8) 6/r32/esi
210     # ecx = labels->write
211     8b/-> *esi 1/r32/ecx
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
223 $label-append:end:
224     # . restore registers
225     5e/pop-to-esi
226     59/pop-to-ecx
227     58/pop-to-eax
228     # . epilogue
229     89/<- %esp 5/r32/ebp
230     5d/pop-to-ebp
231     c3/return
233 containing-function:  # labels: (addr stream {start-address, label-slice}), address: int -> start/eax: (addr byte), end/ecx: (addr byte)
234     # . prologue
235     55/push-ebp
236     89/<- %ebp 4/r32/esp
237     # . save registers
238     52/push-edx
239     53/push-ebx
240     56/push-esi
241     # esi = labels
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
246     8b/-> *esi 2/r32/edx
247     01/add-to %edx 1/r32/ecx
248     # var previous-function-name/ebx: (addr slice) = 0
249     bb/copy-to-ebx 0/imm32
250     {
251       # abort if not found
252       39/compare %ecx 2/r32/edx
253       {
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)
257         {
258           eb/jump loop/disp8
259         }
260       }
261       # if *curr > address, break
262       8b/-> *ecx 0/r32/eax
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
266       {
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
275       }
276       # loop update
277       81 0/subop/add %ecx 0xc/imm32
278       #
279       e9/jump loop/disp32
280     }
281     8b/-> *ebx 0/r32/eax
282     8b/-> *(ebx+4) 1/r32/ecx
283 $containing-function:end:
284     # . restore registers
285     5e/pop-to-esi
286     5b/pop-to-ebx
287     5a/pop-to-edx
288     # . epilogue
289     89/<- %esp 5/r32/ebp
290     5d/pop-to-ebp
291     c3/return
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
295     # . prologue
296     55/push-ebp
297     89/<- %ebp 4/r32/esp
298     # . save registers
299     50/push-eax
300     51/push-ecx
301     52/push-edx
302     # var curr/ecx: (addr byte) = start
303     8b/-> *(ebp+0xc) 1/r32/ecx
304     # edx = end
305     8b/-> *(ebp+0x10) 2/r32/edx
306     # eax = 0
307     b8/copy-to-eax 0/imm32
308     {
309       # if (curr >= end) break
310       39/compare %ecx 2/r32/edx
311       73/jump-if-addr>= break/disp8
312       # print *curr
313       8a/byte-> *ecx 0/r32/eax
314       (draw-code-point-at-cursor-over-full-screen *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18))
315       #
316       41/increment-ecx
317       #
318       eb/jump loop/disp8
319     }
320 $draw-slice-wrapping-right-then-down-from-cursor-over-full-screen:end:
321     # . restore registers
322     5a/pop-to-edx
323     59/pop-to-ecx
324     58/pop-to-eax
325     # . epilogue
326     89/<- %esp 5/r32/ebp
327     5d/pop-to-ebp
328     c3/return