1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; UrForth level
1: self
-hosting
32-bit Forth compiler
3 ;; Copyright
(C
) 2020 Ketmar Dark
// Invisible Vector
5 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7 code: (URFORTH-SEGFAULT-CODEBLOCK)
9 urfsegfault_output_fd
: dd
2
11 urfsegfault_dump_ddepth
: dd
16 ;; default depth of the data stack dump
-1
12 urfsegfault_dump_rdepth
: dd
24 ;; default depth of the data stack dump
-1
14 urfsegfault_dbg_retaddr
: dd
0
15 urfsegfault_reg_eax
: dd
0
16 urfsegfault_reg_ebx
: dd
0
17 urfsegfault_reg_ecx
: dd
0
18 urfsegfault_reg_edx
: dd
0
19 urfsegfault_reg_esi
: dd
0
20 urfsegfault_reg_edi
: dd
0
21 urfsegfault_reg_ebp
: dd
0
22 urfsegfault_reg_esp
: dd
0
23 urfsegfault_reg_flags
: dd
0
25 ;; set in startup code
26 urfsegfault_stack_bottom
: dd
0
28 urfsegfault_throw_error
: dd
1
29 urfsegfault_stacktrace
: dd
1
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34 ;; all registers are preserved
, including flags
38 push eax
;; we will
write from here
40 ld ebx
,[urfsegfault_output_fd
]
49 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50 ;; print string from ECX
, length in EDX
51 ;; all registers are preserved
, including flags
53 urfsegfault_emit_str_ecx_edx
:
56 ld ebx
,[urfsegfault_output_fd
]
62 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
63 ;; print string from ECX
, length in EDX
64 ;; all registers are preserved
, including flags
66 urfsegfault_emit_str_ecx_edx_safe
:
76 call urfsegfault_emit_al
85 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
87 ;; all registers are preserved
, including flags
89 urfsegfault_emit_hex_al
:
95 call urfsegfault_emit_al
98 call urfsegfault_emit_al
104 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
106 ;; all registers are preserved
, including flags
108 urfsegfault_emit_hex_ax
:
113 call urfsegfault_emit_hex_al
115 call urfsegfault_emit_hex_al
121 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
123 ;; all registers are preserved
, including flags
125 urfsegfault_emit_hex_eax
:
130 call urfsegfault_emit_hex_ax
132 call urfsegfault_emit_hex_ax
138 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
139 ;; print EAX as signed decimal
140 ;; all registers are preserved
, including flags
141 ;; i could
do this without divs
, but meh
143 urfsegfault_emit_dec_eax
:
157 ;; EAX
: quotient
; EDX
: remainder
168 ;; EDX
: quotient
; EAX
: remainder
170 call urfsegfault_emit_al
174 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
175 ;; get source file name from nfa
180 ;; EAX
: byte
-counted string
(or
0)
181 ;; other registers are preserved
(except flags
)
183 urfsegfault_nfa_get_fname
:
192 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
193 ;; get source file name from nfa
199 ;; all registers are preserved
(except flags
)
201 urfsegfault_nfa_write_fname
:
205 call urfsegfault_nfa_get_fname
223 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
224 ;; move
to cfa from nfa
230 ;; other registers are preserved
(except flags
)
236 $
if URFORTH_ALIGN_CFA
241 add eax
,4+1 ;; lenflags
, trailing length
247 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
248 ;; move
to nfa from cfa
254 ;; other registers are preserved
(except flags
)
258 movzx ecx
,byte
[eax
-1]
259 add ecx
,4+1 ;; lenflags
, trailing length
265 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
267 ;; correctly handles the case when EAX
== 0
272 ;; all registers are preserved
(except flags
)
274 urfsegfault_nfaprint
:
280 ;; load length
to edx
284 add eax
,4 ;; skip length and flags
285 ld ecx
,eax
;; starting address
286 call urfsegfault_emit_str_ecx_edx_safe
293 urfsegfault_printstr
"<???>"
297 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
298 ;; skip word argument
299 ;; correctly handles the case when EAX
== 0
306 ;; ESI
: (new
) code pointer
307 ;; all registers are preserved
(except flags
)
309 urfsegfault_nfa_skip_arg
:
315 movzx eax
,byte
[eax
+1]
317 urfsegfault_nfa_skip_arg_type_in_eax
:
330 ;; 1 byte unsigned literal?
336 ;; 1 byte signed literal?
342 ;; 2 byte unsigned literal?
348 ;; 2 byte signed literal?
354 ;; cell
-counted string?
359 ;; skip trailing zero byte and align
364 ;; byte
-counted string?
370 ;; skip trailing zero byte and align
397 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
398 ;; type word argument
399 ;; correctly handles the case when EAX
== 0
405 ;; ESI
: (new
) code pointer
406 ;; all registers are preserved
(except flags
)
408 urfsegfault_nfa_print_arg
:
422 call urfsegfault_emit_hex_eax
435 call urfsegfault_emit_dec_eax
438 ;; 1 byte unsigned literal?
445 ;; 1 byte signed literal?
452 ;; 2 byte unsigned literal?
459 ;; 1 byte signed literal?
466 ;; cell
-counted string?
469 urfsegfault_printstr
' "' ;; '
474 ;; skip trailing zero byte and align
477 call urfsegfault_emit_str_ecx_edx_safe
478 urfsegfault_emit '"' ;; '
481 ;; byte-counted string?
484 urfsegfault_printstr ' "' ;; '
490 ;; skip trailing zero byte and align
493 call urfsegfault_emit_str_ecx_edx_safe
494 urfsegfault_emit
'"' ;; '
502 ;;call urfsegfault_find_by_addr
503 call urfsegfault_cfa2nfa
504 call urfsegfault_nfaprint
510 urfsegfault_printstr " {cblock}"
518 urfsegfault_printstr " {vocid}"
525 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
526 ;; find line for the PC
533 ;; other registers are preserved (except flags)
535 urfsegfault_find_pc_line_nfa:
543 ;; load debug info address
544 ;; EDI will contain current PC
549 $if URFORTH_ALIGN_CFA
554 add edi,5 ;; skip lenflags, and trailing len
556 ;; load pointer to debug info
560 ;; load and check number of items
562 ;; check number of items (just in case)
564 ;; latest line we've seen will be in EDX
565 movzx edx
,word
[esi
+2]
566 ;; skip header
(we aren
't using file name pointer yet)
568 ;; check if PC is higher
605 ;; the following two will be set (ONLY!) by successfull call to `urfsegfault_find_by_addr`
606 urfsegfault_fba_nfa: dd 0
607 urfsegfault_fba_end: dd 0
609 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
610 ;; find which word owns the specified address
614 ;; ESI: vocptr (at latestptr)
617 ;; ZERO SET if EAX is 0
618 ;; other registers are preserved (except flags)
620 urfsegfault_find_by_addr_in_voc:
631 ;; check for invalid sfa
643 ld [urfsegfault_fba_nfa],esi
644 ld [urfsegfault_fba_end],edi
647 or eax,eax ;; fix zero flag
653 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
654 ;; find which word owns the specified address
655 ;; this assumes that all words are sequential in memory
661 ;; ZERO SET if EAX is 0
662 ;; other registers are preserved (except flags)
664 urfsegfault_find_by_addr:
668 ld esi,[pfa "(voc-link)"]
672 sub esi,4 ;; move to latestptr
674 call urfsegfault_find_by_addr_in_voc
675 ld esi,[esi+4] ;; load next voclink
687 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
688 ;; print return stack
690 urfsegfault_cmd_printrstack:
691 ;; print first 8 items, that should be enough
692 ;; print return stack depth
693 urfsegfault_printstr "=== RETURN STACK: "
694 ld eax,ts:[ua_ofs_rp0]
695 sub eax,[urfsegfault_reg_ebp]
698 urfsegfault_printstrnl " UNDERFLOWED ==="
700 sar eax,2 ;; divide by cell
702 urfsegfault_printdec eax
703 urfsegfault_printstrnl " CELLS DEPTH ==="
704 ;; print current word
705 urfsegfault_printstr "**"
706 ld eax,[urfsegfault_reg_esi]
707 sub eax,4 ;; because we just loaded it
708 call urfsegfault_find_by_addr
710 call urfsegfault_nfaprint
711 ;; print line number if we know it
713 ld eax,[urfsegfault_reg_esi]
714 sub eax,4 ;; because we just loaded it
715 call urfsegfault_find_pc_line_nfa
718 urfsegfault_printstr " {"
719 call urfsegfault_emit_dec_eax
721 call urfsegfault_nfa_write_fname
722 urfsegfault_printstr "}"
728 ld esi,[urfsegfault_reg_ebp]
733 cp ecx,[urfsegfault_dump_rdepth]
735 ld ecx,[urfsegfault_dump_rdepth]
739 urfsegfault_printstr " "
740 call urfsegfault_find_by_addr
741 push eax ;; for line number
742 call urfsegfault_nfaprint
746 urfsegfault_printstr " | "
747 call urfsegfault_emit_hex_eax
748 ;; print decimal value
750 urfsegfault_printstr " | "
751 call urfsegfault_emit_dec_eax
753 ;; print line number if we know it
755 sub eax,4 ;; pushed value is "next to execute"
757 call urfsegfault_find_pc_line_nfa
760 urfsegfault_printstr " {"
761 call urfsegfault_emit_dec_eax
763 call urfsegfault_nfa_write_fname
764 urfsegfault_printstr "}"
776 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
779 urfsegfault_cmd_printdstack:
780 ;; print first 8 items, that should be enough
781 ;; also, print them in backwards order (i.e. TOS will be printed last)
782 ;; print data stack depth
783 urfsegfault_printstr "=== DATA STACK: "
784 ld eax,ts:[ua_ofs_sp0]
785 sub eax,[urfsegfault_reg_esp]
788 urfsegfault_printstrnl " UNDERFLOWED ==="
791 sar eax,2 ;; divide by cell
793 urfsegfault_printdec eax
794 urfsegfault_printstrnl " CELLS DEPTH ==="
797 jp z,urfsegfault_cmd_printdstack_quit0
799 urfsegfault_printstr "ESP="
800 ld eax,[urfsegfault_reg_esp]
801 urfsegfault_printhex eax
805 jp z,urfsegfault_cmd_printdstack_tos
806 cp ecx,[urfsegfault_dump_ddepth]
808 ld ecx,[urfsegfault_dump_ddepth]
812 ld esi,[urfsegfault_reg_esp]
821 urfsegfault_printstr " "
822 urfsegfault_printhex esi
823 urfsegfault_printstr ": "
824 urfsegfault_printhex eax
825 urfsegfault_printstr " | "
826 urfsegfault_printdec eax
831 urfsegfault_cmd_printdstack_tos:
833 urfsegfault_printstr " "
834 urfsegfault_printstr " TOS "
835 urfsegfault_printstr ": "
836 urfsegfault_printhex [urfsegfault_reg_ecx]
837 urfsegfault_printstr " | "
838 urfsegfault_printdec [urfsegfault_reg_ecx]
841 urfsegfault_cmd_printdstack_quit0:
845 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
846 ;; debugger segfault handler
851 SA_ONSTACK equ 0x08000000
852 SA_RESTART equ 0x10000000
853 SA_NODEFER equ 0x40000000
854 SA_RESETHAND equ 0x80000000
855 SA_RESTORER equ 0x04000000
858 ;; sadly, we cannot return to OS to allow it reset "signal handled" flag, so we have to use "SA_NODEFER".
859 ;; this is COMPLETELY WRONG, and should never be done like this, but tbh, anything i'll
do to return
860 ;; from SEGFAULT is a hackery anyway
. it is not supposed
to be used like this
.
861 ;; we can prolly use some
"sys_sigreturn" magic
, but it is as fragile as any other thing
.
864 urfd_sigact
.sa_handler
: ;;dd
0 ;; union with
.sa_sigaction
865 urfd_sigact
.sa_sigaction
: dd urfsegfault_segfault_action
866 urfd_sigact
.sa_mask
: dd
0 ;; 0xffffffff
867 urfd_sigact
.sa_flags
: dd SA_SIGINFO
+SA_NODEFER
;; "nodefer", because we will never correctly
return from here
868 urfd_sigact
.sa_restorer
: dd
0
881 ;; ._sigchld
: ;sigchld
882 ;; ._sigfault
: ;sigfault
883 ;; ._sigpoll
: ;sigpoll
888 sigcontext_t
.gs equ
0 ;; word
1
889 sigcontext_t
.__gsh equ
2 ;; word
1
890 sigcontext_t
.fs equ
4 ;; word
1
891 sigcontext_t
.__fsh equ
6 ;; word
1
892 sigcontext_t
.es equ
8 ;; word
1
893 sigcontext_t
.__esh equ
10 ;; word
1
894 sigcontext_t
.ds equ
12 ;; word
1
895 sigcontext_t
.__dsh equ
14 ;; word
1
896 sigcontext_t
.edi equ
16 ;; dword
1
897 sigcontext_t
.esi equ
20 ;; dword
1
898 sigcontext_t
.ebp equ
24 ;; dword
1
899 sigcontext_t
.esp equ
28 ;; dword
1
900 sigcontext_t
.ebx equ
32 ;; dword
1
901 sigcontext_t
.edx equ
36 ;; dword
1
902 sigcontext_t
.ecx equ
40 ;; dword
1
903 sigcontext_t
.eax equ
44 ;; dword
1
904 sigcontext_t
.trapno equ
48 ;; dword
1
905 sigcontext_t
.err equ
52 ;; dword
1
906 sigcontext_t
.eip equ
56 ;; dword
1
907 sigcontext_t
.cs equ
60 ;; word
1
908 sigcontext_t
.__csh equ
62 ;; word
1
909 sigcontext_t
.eflags equ
64 ;; dword
1
910 sigcontext_t
.esp_at_signal equ
68 ;; dword
1
911 sigcontext_t
.ss equ
72 ;; word
1
912 sigcontext_t
.__ssh equ
74 ;; word
1
913 sigcontext_t
.fpstate equ
78 ;; dword
1
914 sigcontext_t
.oldmask equ
82 ;; dword
1
915 sigcontext_t
.cr2 equ
86 ;; dword
1
916 sigcontext_t
._size_ equ
88
918 sigaltstack_t
.ss_sp equ
0 ;; dword
1
919 sigaltstack_t
.ss_flags equ
4 ;; dword
1
920 sigaltstack_t
.ss_size equ
8 ;; dword
1
921 sigaltstack_t
._size_ equ
12
923 sigset_t
.sig equ
0 ;; dword
2
924 sigset_t
._size_ equ
8
926 ucontext_t
.uc_flags equ
0 ;; dword
1
927 ucontext_t
.uc_link equ
4 ;; dword
1
928 ucontext_t
.uc_stack equ
8
929 ucontext_t
.uc_mcontext equ ucontext_t
.uc_stack
+sigaltstack_t
._size_
930 ucontext_t
.uc_sigmask equ ucontext_t
.uc_mcontext
+sigcontext_t
._size_
931 ucontext_t
._size_ equ ucontext_t
.uc_sigmask
+sigset_t
._size_
934 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
936 urfsegfault_segfault_signames
:
937 ;; signum
, errcode
-addr
, errmessage
940 dd pfa
"ERR-SEGFAULT"
944 dd pfa
"ERR-MATH-ZERO-DIVIDE"
945 db
"DIVISION BY ZERO",0
948 dd pfa
"ERR-UNDEFINED-INSTRUCTION"
949 db
"BAD INSTRUCTION",0
953 urfsegfault_segfault_errcode_addr
: dd pfa
"ERR-SEGFAULT"
955 urfsegfault_segfault_action
:
957 ;; switch to our own stack
958 ld esp
,[urfsegfault_stack_bottom
]
961 ;; signum
: dword
[ebp
+4]
962 ;; siginfoptr
: dword
[ebp
+8]
963 ;; ucontextptr
: dword
[ebp
+12]
965 ;; copy registers from context
to debugger data structures
967 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.eip
]
968 ld
[urfsegfault_dbg_retaddr
],eax
969 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.eax
]
970 ld
[urfsegfault_reg_eax
],eax
971 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.ebx
]
972 ld
[urfsegfault_reg_ebx
],eax
973 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.ecx
]
974 ld
[urfsegfault_reg_ecx
],eax
975 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.edx
]
976 ld
[urfsegfault_reg_edx
],eax
977 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.esi
]
978 ld
[urfsegfault_reg_esi
],eax
979 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.edi
]
980 ld
[urfsegfault_reg_edi
],eax
981 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.ebp
]
982 ld
[urfsegfault_reg_ebp
],eax
983 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.esp
]
984 ld
[urfsegfault_reg_esp
],eax
985 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.eflags
]
986 ld
[urfsegfault_reg_flags
],eax
989 cp dword
[urfsegfault_stacktrace
],0
992 urfsegfault_printstr
"***TRAP: "
994 ld esi
,urfsegfault_segfault_signames
1008 ld esi
,urfsegfault_segfault_signames
+1
1011 ld
[urfsegfault_segfault_errcode_addr
],eax
1020 ;;urfsegfault_printstr
"***TRAP: SEGFAULT!"
1024 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.eip
]
1025 urfsegfault_printstr
" EIP="
1026 urfsegfault_printhex eax
1028 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.esp
]
1029 urfsegfault_printstr
" ESP="
1030 urfsegfault_printhex eax
1032 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.ebp
]
1033 urfsegfault_printstr
" EBP="
1034 urfsegfault_printhex eax
1036 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.esi
]
1037 urfsegfault_printstr
" ESI="
1038 urfsegfault_printhex eax
1042 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.eip
]
1043 call urfsegfault_find_by_addr
1046 urfsegfault_printstr
"*** CURRENT WORD: "
1047 call urfsegfault_nfaprint
1048 ;; print line number
if we know it
1051 ld eax
,[esi
+ucontext_t
.uc_mcontext
+sigcontext_t
.eip
]
1052 call urfsegfault_find_pc_line_nfa
1055 urfsegfault_printstr
" {"
1056 call urfsegfault_emit_dec_eax
1058 call urfsegfault_nfa_write_fname
1059 urfsegfault_printstr
"}"
1064 call urfsegfault_cmd_printdstack
1065 call urfsegfault_cmd_printrstack
1068 cp dword
[urfsegfault_throw_error
],0
1078 ld ERP
,[urfsegfault_reg_ebp
]
1079 ld esp
,[urfsegfault_reg_esp
]
1080 ld TOS
,[urfsegfault_reg_ecx
]
1082 ;;ld TOS
,[pfa
"ERR-SEGFAULT"]
1083 ld TOS
,[urfsegfault_segfault_errcode_addr
]
1089 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1090 ;; called by the startup code
1092 urforth_setup_segfault_handler
:
1095 ld esi
,urfsegfault_segfault_signames
1100 movzx ebx
,al
;; signal number
1101 ld eax
,67 ;; syscall number
1103 xor edx
,edx
;; ignore old info
1109 urfsegfault_printstrnl
"TRAP: cannot setup signal handler."
1121 (hidden
) (codeblock
)