6e05a8fa27
Unix text-mode terminals transparently support utf-8 these days, and so I treat utf-8 sequences (which I call graphemes in Mu) as fundamental. I then blindly carried over this state of affairs to bare-metal Mu, where it makes no sense. If you don't have a terminal handling font-rendering for you, fonts are most often indexed by code points and not utf-8 sequences.
329 lines
9.2 KiB
Plaintext
329 lines
9.2 KiB
Plaintext
# Dump a stack trace when you abort.
|
|
|
|
== code
|
|
|
|
abort: # e: (addr array byte)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
#
|
|
(set-cursor-position-on-real-screen 0 0)
|
|
(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
|
|
(dump-call-stack)
|
|
# crash
|
|
{
|
|
eb/jump loop/disp8
|
|
}
|
|
|
|
# Helpers below this point are not intended to be reused; they assume the
|
|
# program will soon crash. In particular, they destroy the heap.
|
|
|
|
dump-call-stack:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
# var labels/edx: (addr stream {start-address, label-slice} 0x5000)
|
|
# start addresses are in ascending order
|
|
81 5/subop/subtract %esp 0x3c000/imm32 # 0x5000 labels * 12 bytes per label
|
|
68/push 0x3c000/imm32
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/<- %edx 4/r32/esp
|
|
#
|
|
(load-debug-symbols %edx) # destroys the heap
|
|
# traverse the linked list of ebp pointers: https://wiki.osdev.org/Stack_Trace
|
|
8b/-> *ebp 3/r32/ebx
|
|
{
|
|
# loop termination check
|
|
81 7/subop/compare %ebx 0/imm32
|
|
0f 84/jump-if-= break/disp32
|
|
# loop body
|
|
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "\n" 0 0xc)
|
|
(draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebx+4) 0xf 0xc)
|
|
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 " " 0 0xc)
|
|
(containing-function %edx *(ebx+4)) # => eax, ecx
|
|
(draw-slice-wrapping-right-then-down-from-cursor-over-full-screen 0 %eax %ecx 0 0xc)
|
|
# loop update
|
|
8b/-> *ebx 3/r32/ebx
|
|
#
|
|
e9/jump loop/disp32
|
|
}
|
|
$dump-call-stack:end:
|
|
# . reclaim locals
|
|
81 0/subop/add %esp 0x100c/imm32
|
|
# . restore registers
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
load-debug-symbols: # labels: (addr stream {start-address, label-slice})
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
# create space for a stream on the heap, clobbering any existing data
|
|
# var s/ecx: (addr stream byte)
|
|
b9/copy-to-ecx 0x03000000/imm32
|
|
c7 0/subop/copy *ecx 0/imm32 # write index
|
|
c7 0/subop/copy *(ecx+4) 0/imm32 # read index
|
|
c7 0/subop/copy *(ecx+8) 0x01000000/imm32 # stream capacity = 16MB
|
|
# load sectors starting from sector 10080 = 0x2760
|
|
(load-sectors Primary-bus-primary-drive 0x2760 0x800 %ecx) # 0x800 sectors = 1MB
|
|
# - parse pointers to portions of this stream into labels
|
|
# var curr/ecx: (addr byte) = s->data
|
|
81 0/subop/add %ecx 0xc/imm32
|
|
{
|
|
# loop termination check
|
|
b8/copy-to-eax 0/imm32
|
|
8a/byte-> *ecx 0/r32/eax
|
|
3d/compare-eax-and 0/imm32
|
|
0f 84/jump-if-= break/disp32
|
|
# loop body
|
|
(skip-to-next-space %ecx) # => edx
|
|
42/increment-edx
|
|
(skip-to-next-newline %edx) # => ebx
|
|
(parse-hex-int-helper %edx %ebx) # => eax
|
|
43/increment-ebx
|
|
(label-append *(ebp+8) %eax %ecx %edx)
|
|
# loop update
|
|
89/<- %ecx 3/r32/ebx
|
|
#
|
|
e9/jump loop/disp32
|
|
}
|
|
$load-debug-symbols:end:
|
|
# . restore registers
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
skip-to-next-space: # curr: (addr byte) -> _/edx: (addr byte)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
# eax = 0
|
|
b8/copy-to-eax 0/imm32
|
|
#
|
|
8b/-> *(ebp+8) 2/r32/edx
|
|
{
|
|
8a/byte-> *edx 0/r32/eax
|
|
3d/compare-eax-and 0x20/imm32/space
|
|
0f 84/jump-if-= break/disp32
|
|
3d/compare-eax-and 0/imm32
|
|
{
|
|
75/jump-if-!= break/disp8
|
|
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "done loading" 7 0)
|
|
{
|
|
eb/jump loop/disp8
|
|
}
|
|
}
|
|
3d/compare-eax-and 0xa/imm32/newline
|
|
{
|
|
75/jump-if-!= break/disp8
|
|
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "unexpected newline" 7 0)
|
|
{
|
|
eb/jump loop/disp8
|
|
}
|
|
}
|
|
42/increment-edx
|
|
e9/jump loop/disp32
|
|
}
|
|
$skip-to-next-space:end:
|
|
# . restore registers
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
skip-to-next-newline: # curr: (addr byte) -> _/ebx: (addr byte)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
# eax = 0
|
|
b8/copy-to-eax 0/imm32
|
|
#
|
|
8b/-> *(ebp+8) 3/r32/ebx
|
|
{
|
|
8a/byte-> *ebx 0/r32/eax
|
|
3d/compare-eax-and 0xa/imm32/newline
|
|
0f 84/jump-if-= break/disp32
|
|
3d/compare-eax-and 0/imm32
|
|
{
|
|
75/jump-if-!= break/disp8
|
|
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "done loading" 7 0)
|
|
{
|
|
eb/jump loop/disp8
|
|
}
|
|
}
|
|
3d/compare-eax-and 0x20/imm32/space
|
|
{
|
|
75/jump-if-!= break/disp8
|
|
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "unexpected space" 7 0)
|
|
{
|
|
eb/jump loop/disp8
|
|
}
|
|
}
|
|
43/increment-ebx
|
|
e9/jump loop/disp32
|
|
}
|
|
$skip-to-next-newline:end:
|
|
# . restore registers
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
label-append: # labels: (addr stream {start-address, label-slice}), address: int, start: int, end: int
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
56/push-esi
|
|
# esi = labels
|
|
8b/-> *(ebp+8) 6/r32/esi
|
|
# ecx = labels->write
|
|
8b/-> *esi 1/r32/ecx
|
|
# labels->data[labels->write] = address
|
|
8b/-> *(ebp+0xc) 0/r32/eax
|
|
89/<- *(esi+ecx+0xc) 0/r32/eax
|
|
# labels->data[labels->write+4] = start
|
|
8b/-> *(ebp+0x10) 0/r32/eax
|
|
89/<- *(esi+ecx+0x10) 0/r32/eax
|
|
# labels->data[labels->write+8] = end
|
|
8b/-> *(ebp+0x14) 0/r32/eax
|
|
89/<- *(esi+ecx+0x14) 0/r32/eax
|
|
# labels->write += 12
|
|
81 0/subop/add *esi 0xc/imm32
|
|
$label-append:end:
|
|
# . restore registers
|
|
5e/pop-to-esi
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
containing-function: # labels: (addr stream {start-address, label-slice}), address: int -> start/eax: (addr byte), end/ecx: (addr byte)
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
52/push-edx
|
|
53/push-ebx
|
|
56/push-esi
|
|
# esi = labels
|
|
8b/-> *(ebp+8) 6/r32/esi
|
|
# var curr/ecx: (addr byte) = labels->data
|
|
8d/copy-address *(esi+0xc) 1/r32/ecx
|
|
# var max/edx: (addr byte) = labels->data + labels->write
|
|
8b/-> *esi 2/r32/edx
|
|
01/add-to %edx 1/r32/ecx
|
|
# var previous-function-name/ebx: (addr slice) = 0
|
|
bb/copy-to-ebx 0/imm32
|
|
{
|
|
# abort if not found
|
|
39/compare %ecx 2/r32/edx
|
|
{
|
|
0f 82/jump-if-addr< break/disp32
|
|
(draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "failed to find function for address " 7 0)
|
|
(draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 *(ebp+0xc) 7 0)
|
|
{
|
|
eb/jump loop/disp8
|
|
}
|
|
}
|
|
# if *curr > address, break
|
|
8b/-> *ecx 0/r32/eax
|
|
3b/compare 0/r32/eax *(ebp+0xc)
|
|
0f 87/jump-if-addr> break/disp32
|
|
# if **(curr+4) not '$' or '@', save curr to previous-function-name
|
|
{
|
|
8b/-> *(ecx+4) 0/r32/eax
|
|
8a/byte-> *eax 0/r32/eax
|
|
25/and-with-eax 0xff/imm32
|
|
3d/compare-eax-and 0x24/imm32/$
|
|
74/jump-if-= break/disp8
|
|
3d/compare-eax-and 0x40/imm32/@
|
|
74/jump-if-= break/disp8
|
|
8d/copy-address *(ecx+4) 3/r32/ebx
|
|
}
|
|
# loop update
|
|
81 0/subop/add %ecx 0xc/imm32
|
|
#
|
|
e9/jump loop/disp32
|
|
}
|
|
8b/-> *ebx 0/r32/eax
|
|
8b/-> *(ebx+4) 1/r32/ecx
|
|
$containing-function:end:
|
|
# . restore registers
|
|
5e/pop-to-esi
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
# . epilogue
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# unlike variants in .mu files, this only supports ASCII
|
|
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
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
# var curr/ecx: (addr byte) = start
|
|
8b/-> *(ebp+0xc) 1/r32/ecx
|
|
# edx = end
|
|
8b/-> *(ebp+0x10) 2/r32/edx
|
|
# eax = 0
|
|
b8/copy-to-eax 0/imm32
|
|
{
|
|
# if (curr >= end) break
|
|
39/compare %ecx 2/r32/edx
|
|
73/jump-if-addr>= break/disp8
|
|
# print *curr
|
|
8a/byte-> *ecx 0/r32/eax
|
|
(draw-code-point-at-cursor-over-full-screen *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18))
|
|
#
|
|
41/increment-ecx
|
|
#
|
|
eb/jump loop/disp8
|
|
}
|
|
$draw-slice-wrapping-right-then-down-from-cursor-over-full-screen: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
|