added some "immediate-noop" words, removed some "$if"
[urforth.git] / level0 / urforth0_segfault.asm
blob4e3b927054d2d8257019ab09bbf547049cb6678f
1 ;; Native x86 GNU/Linux Forth System, Direct Threaded Code
2 ;; Forth segfault handler
3 ;;
4 ;; Copyright (C) 2020 Ketmar Dark // Invisible Vector
5 ;;
6 ;; This program is free software: you can redistribute it and/or modify
7 ;; it under the terms of the GNU General Public License as published by
8 ;; the Free Software Foundation, version 3 of the License ONLY.
9 ;;
10 ;; This program is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ;; GNU General Public License for more details.
15 ;; You should have received a copy of the GNU General Public License
16 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20 urfsegfault_output_fd: dd 2
22 urfsegfault_dump_ddepth: dd 16 ; default depth of the data stack dump-1
23 urfsegfault_dump_rdepth: dd 24 ; default depth of the data stack dump-1
25 urfsegfault_dbg_retaddr: dd 0
26 urfsegfault_reg_eax: dd 0
27 urfsegfault_reg_ebx: dd 0
28 urfsegfault_reg_ecx: dd 0
29 urfsegfault_reg_edx: dd 0
30 urfsegfault_reg_esi: dd 0
31 urfsegfault_reg_edi: dd 0
32 urfsegfault_reg_ebp: dd 0
33 urfsegfault_reg_esp: dd 0
34 urfsegfault_reg_flags: dd 0
36 ; set in startup code
37 urfsegfault_stack_bottom: dd 0
40 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
41 macro urfsegfault_save_all_registers_no_eax_f {
42 push ebx
43 push ecx
44 push edx
45 push esi
46 push edi
47 push ebp
50 macro urfsegfault_restore_all_registers_no_eax_f {
51 pop ebp
52 pop edi
53 pop esi
54 pop edx
55 pop ecx
56 pop ebx
60 macro urfsegfault_save_all_registers {
61 pushfd
62 pushad
65 macro urfsegfault_restore_all_registers {
66 popad
67 popfd
71 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
72 ;; print char from AL
73 ;; all registers are preserved, including flags
75 urfsegfault_emit_al:
76 urfsegfault_save_all_registers
77 push eax ; we will write from here
78 ld eax,4 ; write
79 ld ebx,[urfsegfault_output_fd]
80 ld ecx,esp ; address
81 ld edx,1 ; length
82 syscall
83 pop eax
84 urfsegfault_restore_all_registers
85 ret
88 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
89 ;; print string from ECX, length in EDX
90 ;; all registers are preserved, including flags
92 urfsegfault_emit_str_ecx_edx:
93 urfsegfault_save_all_registers
94 ld eax,4 ; write
95 ld ebx,[urfsegfault_output_fd]
96 syscall
97 urfsegfault_restore_all_registers
98 ret
101 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
102 ;; print string from ECX, length in EDX
103 ;; all registers are preserved, including flags
105 urfsegfault_emit_str_ecx_edx_safe:
106 urfsegfault_save_all_registers
107 .prloop:
108 or edx,edx
109 jr z,.done
110 ld al,[ecx]
111 cp al,32
112 jr nc,@f
113 ld al,'?'
115 call urfsegfault_emit_al
116 inc ecx
117 dec edx
118 jr .prloop
119 .done:
120 urfsegfault_restore_all_registers
124 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
125 ;; print char
126 ;; all registers are preserved, including flags
128 macro urfsegfault_emit char {
129 if char eq al
130 call urfsegfault_emit_al
131 else
132 push eax
133 ld al,char
134 call urfsegfault_emit_al
135 pop eax
136 end if
139 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
140 ;; print newline
141 ;; all registers are preserved, including flags
143 macro urfsegfault_cr {
144 urfsegfault_emit 10
147 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
148 ;; print string
149 ;; string data immediately follows the code
150 ;; all registers are preserved, including flags
152 macro urfsegfault_printstr [str] {
153 common
154 local nstart
155 local nend
156 jmp nend
157 nstart = $
158 forward
159 db str
160 common
161 nend = $
162 push ecx
163 push edx
164 ld ecx,nstart ; address
165 ld edx,nend-nstart ; length
166 call urfsegfault_emit_str_ecx_edx
167 pop edx
168 pop ecx
171 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
172 ;; print string with a newline
173 ;; string data immediately follows the code
174 ;; all registers are preserved, including flags
176 macro urfsegfault_printstrnl [str] {
177 common
178 local nstart
179 local nend
180 jmp nend
181 nstart = $
182 forward
183 db str
184 common
185 nend = $
186 urfsegfault_save_all_registers
187 ld eax,4 ; write
188 ld ebx,[urfsegfault_output_fd]
189 ld ecx,nstart ; address
190 ld edx,nend-nstart ; length
191 syscall
192 urfsegfault_restore_all_registers
193 urfsegfault_cr
197 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
198 ;; print AL as hex
199 ;; all registers are preserved, including flags
201 urfsegfault_emit_hex_al:
202 pushfd
203 push eax
204 push eax
205 shr al,4
206 Nibble2Hex
207 call urfsegfault_emit_al
208 pop eax
209 Nibble2Hex
210 call urfsegfault_emit_al
211 pop eax
212 popfd
216 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
217 ;; print AX as hex
218 ;; all registers are preserved, including flags
220 urfsegfault_emit_hex_ax:
221 pushfd
222 push eax
223 push eax
224 shr eax,8
225 call urfsegfault_emit_hex_al
226 pop eax
227 call urfsegfault_emit_hex_al
228 pop eax
229 popfd
233 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
234 ;; print EAX as hex
235 ;; all registers are preserved, including flags
237 urfsegfault_emit_hex_eax:
238 pushfd
239 push eax
240 push eax
241 shr eax,16
242 call urfsegfault_emit_hex_ax
243 pop eax
244 call urfsegfault_emit_hex_ax
245 pop eax
246 popfd
250 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
251 ;; print EAX as signed decimal
252 ;; all registers are preserved, including flags
253 ;; i could do this without divs, but meh
255 urfsegfault_emit_dec_eax:
256 urfsegfault_save_all_registers
257 test eax,0x80000000
258 jz @f
259 urfsegfault_emit '-'
260 neg eax
262 call .prloop
263 urfsegfault_restore_all_registers
265 .prloop:
266 ld ecx,10
267 xor edx,edx
268 div ecx
269 ; EAX: quotient; EDX: remainder
270 or eax,eax
271 jr z,@f
272 ; recurse
273 push eax
274 push edx
275 call .prloop
276 pop edx
277 pop eax
279 xchg eax,edx
280 ; EDX: quotient; EAX: remainder
281 add al,'0'
282 call urfsegfault_emit_al
286 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
287 ;; print byte in hex
288 ;; all registers are preserved, including flags
290 macro urfsegfault_printhex_byte bval {
291 if bval eq al
292 call urfsegfault_emit_hex_al
293 else
294 push eax
295 ld al,bval
296 call urfsegfault_emit_hex_al
297 pop eax
298 end if
302 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
303 ;; print register in hex
304 ;; all registers are preserved, including flags
306 macro urfsegfault_printhex reg {
307 if reg eq eax
308 call urfsegfault_emit_hex_eax
309 else
310 push eax
311 ld eax,reg
312 call urfsegfault_emit_hex_eax
313 pop eax
314 end if
318 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
319 ;; print register as signed decimal
320 ;; all registers are preserved, including flags
322 macro urfsegfault_printdec reg {
323 if reg eq eax
324 call urfsegfault_emit_dec_eax
325 else
326 push eax
327 ld eax,reg
328 call urfsegfault_emit_dec_eax
329 pop eax
330 end if
334 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
335 ;; move to cfa from nfa
337 ;; IN:
338 ;; EAX: nfa
339 ;; OUT:
340 ;; EAX: cfa
341 ;; other registers are preserved (except flags)
343 urfsegfault_nfa2cfa:
344 push ecx
345 movzx ecx,byte [eax]
346 add ecx,4+1 ; lenflags, trailing length
347 add eax,ecx
348 pop ecx
352 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
353 ;; move to nfa from cfa
355 ;; IN:
356 ;; EAX: cfa
357 ;; OUT:
358 ;; EAX: nfa
359 ;; other registers are preserved (except flags)
361 urfsegfault_cfa2nfa:
362 push ecx
363 movzx ecx,byte [eax-1]
364 add ecx,4+1 ; lenflags, trailing length
365 sub eax,ecx
366 pop ecx
370 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
371 ;; type word name
372 ;; correctly handles the case when EAX == 0
374 ;; IN:
375 ;; EAX: nfa
376 ;; OUT:
377 ;; all registers are preserved (except flags)
379 urfsegfault_nfaprint:
380 push eax
381 push ecx
382 push edx
383 or eax,eax
384 jz .noword
385 ; load length to edx
386 movzx edx,byte [eax]
387 or edx,edx
388 jz .nonamed
389 add eax,4 ; skip length and flags
390 ld ecx,eax ; starting address
391 call urfsegfault_emit_str_ecx_edx_safe
392 .nonamed:
393 pop edx
394 pop ecx
395 pop eax
397 .noword:
398 urfsegfault_printstr "<???>"
399 jmp .nonamed
402 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
403 ;; skip word argument
404 ;; correctly handles the case when EAX == 0
406 ;; IN:
407 ;; EAX: nfa
408 ;; ESI: code pointer
409 ;; OUT:
410 ;; EAX: dead
411 ;; ESI: (new) code pointer
412 ;; all registers are preserved (except flags)
414 urfsegfault_nfa_skip_arg:
415 or eax,eax
416 jr nz,.cont
418 .cont:
419 ; load arg type
420 movzx eax,byte [eax+1]
421 urfsegfault_nfa_skip_arg_type_in_eax:
422 ; branch?
423 cp al,WARG_BRANCH
424 jr nz,@f
425 add esi,4
426 jr .done
428 ; literal?
429 cp al,WARG_LIT
430 jr nz,@f
431 add esi,4
432 jr .done
434 ; cell-counted string?
435 cp al,WARG_C4STRZ
436 jr nz,@f
437 lodsd
438 add esi,eax
439 inc esi ; skip trailing zero byte
440 jr .done
442 ; cfa?
443 cp al,WARG_CFA
444 jr nz,@f
445 add esi,4
447 ; cblock?
448 cp al,WARG_CBLOCK
449 jr nz,@f
450 lodsd
451 ld esi,eax
453 .done:
457 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
458 ;; type word argument
459 ;; correctly handles the case when EAX == 0
461 ;; IN:
462 ;; EAX: nfa
463 ;; ESI: code pointer
464 ;; OUT:
465 ;; ESI: (new) code pointer
466 ;; all registers are preserved (except flags)
468 urfsegfault_nfa_print_arg:
469 push eax
470 push ecx
471 push edx
472 or eax,eax
473 jr z,.done
474 ; load arg type
475 ld cl,byte [eax+1]
476 jecxz .done
477 ; branch?
478 cp cl,WARG_BRANCH
479 jr nz,@f
480 urfsegfault_emit ' '
481 lodsd
482 call urfsegfault_emit_hex_eax
483 .done:
484 pop edx
485 pop ecx
486 pop eax
489 ; literal?
490 cp cl,WARG_LIT
491 jr nz,@f
492 urfsegfault_emit ' '
493 lodsd
494 call urfsegfault_emit_dec_eax
495 jr .done
497 ; cell-counted string?
498 cp cl,WARG_C4STRZ
499 jr nz,@f
500 urfsegfault_printstr ' "'
501 lodsd
502 ld edx,eax
503 ld ecx,esi
504 add esi,eax
505 inc esi ;; skip trailing zero byte
506 call urfsegfault_emit_str_ecx_edx_safe
507 urfsegfault_emit '"'
508 jr .done
510 ; cfa?
511 cp cl,WARG_CFA
512 jr nz,@f
513 urfsegfault_emit ' '
514 lodsd
515 ;call urfsegfault_find_by_addr
516 call urfsegfault_cfa2nfa
517 call urfsegfault_nfaprint
518 jr .done
520 ; cblock?
521 cp cl,WARG_CBLOCK
522 jr nz,@f
523 urfsegfault_printstr " {cblock}"
524 lodsd
525 ld esi,eax
526 jr .done
528 jr .done
531 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
532 ;; find line for the PC
534 ;; IN:
535 ;; EAX: pc
536 ;; ESI: nfa
537 ;; OUT:
538 ;; EAX: line
539 ;; other registers are preserved (except flags)
541 urfsegfault_find_pc_line_nfa:
542 push esi
543 push ecx
544 push edx
545 or esi,esi
546 jr z,.fail
547 ; load debug info address
548 ld esi,[esi-20]
549 or esi,esi
550 jr z,.fail
551 ; load and check number of items
552 ld ecx,[esi]
553 add esi,4
554 ; check number of items (just in case)
555 or ecx,ecx
556 jr z,.fail
557 test ecx,0x80000000
558 jr nz,.fail
559 ; latest line we've seen will be in EDX
560 xor edx,edx
561 .scanloop:
562 cmp eax,[esi]
563 jr c,@f
564 ld edx,[esi+4]
566 add esi,8
567 loop .scanloop
568 ld eax,edx
569 jr .done
570 .fail:
571 xor eax,eax
572 .done:
573 pop edx
574 pop ecx
575 pop esi
579 ; the following two will be set (ONLY!) by successfull call to `urfsegfault_find_by_addr`
580 urfsegfault_fba_nfa: dd 0
581 urfsegfault_fba_end: dd 0
583 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
584 ;; find which word owns the specified address
586 ;; IN:
587 ;; EAX: address
588 ;; ESI: vocptr (at latestptr)
589 ;; OUT:
590 ;; EAX: nfa or 0
591 ;; ZERO SET if EAX is 0
592 ;; other registers are preserved (except flags)
594 urfsegfault_find_by_addr_in_voc:
595 push esi
596 push edi
597 ; ESI: lfa
598 .findvoc_loop:
599 ; follow lfa
600 ld esi,[esi]
601 or esi,esi
602 jr z,.not_found
603 ; load sfa
604 ld edi,[esi-8]
605 ; check for invalid sfa
606 cp esi,edi
607 jr nc,.findvoc_loop
608 ; EAX>=ESI?
609 cp eax,esi
610 jr c,.findvoc_loop
611 ; EAX<EDI?
612 cp eax,edi
613 jr nc,.findvoc_loop
614 ; i found her!
615 ; move ESI to nfa
616 add esi,8
617 ld [urfsegfault_fba_nfa],esi
618 ld [urfsegfault_fba_end],edx
619 .not_found:
620 ld eax,esi
621 or eax,eax ; fix zero flag
622 pop edi
623 pop esi
627 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
628 ;; find which word owns the specified address
629 ;; this assumes that all words are sequential in memory
631 ;; IN:
632 ;; EAX: address
633 ;; OUT:
634 ;; EAX: nfa or 0
635 ;; ZERO SET if EAX is 0
636 ;; other registers are preserved (except flags)
638 urfsegfault_find_by_addr:
639 push esi
640 push ecx
641 ld ecx,eax
642 ld esi,[fvar_voclink_data]
644 or esi,esi
645 jr z,@f
646 sub esi,4 ; move to latestptr
647 ld eax,ecx
648 call urfsegfault_find_by_addr_in_voc
649 ld esi,[esi+4] ; load next voclink
650 jr z,@b
651 pop ecx
652 pop esi
655 xor eax,eax
656 pop ecx
657 pop esi
661 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
662 ;; print return stack
664 urfsegfault_cmd_printrstack:
665 ; print first 8 items, that should be enough
666 ; print return stack depth
667 urfsegfault_printstr "=== RETURN STACK: "
668 ld eax,[fvar_rp0_data]
669 sub eax,[urfsegfault_reg_ebp]
670 jr nc,@f
671 ; underflow
672 urfsegfault_printstrnl " UNDERFLOWED ==="
674 sar eax,2 ; divide by cell
675 push eax
676 urfsegfault_printdec eax
677 urfsegfault_printstrnl " CELLS DEPTH ==="
678 ; print current word
679 urfsegfault_printstr "**"
680 ld eax,[urfsegfault_reg_esi]
681 sub eax,4 ; because we just loaded it
682 call urfsegfault_find_by_addr
683 push eax
684 call urfsegfault_nfaprint
685 ; print line number if we know it
686 pop esi
687 ld eax,[urfsegfault_reg_esi]
688 sub eax,4 ; because we just loaded it
689 call urfsegfault_find_pc_line_nfa
690 or eax,eax
691 jr z,@f
692 urfsegfault_printstr " {"
693 call urfsegfault_emit_dec_eax
694 urfsegfault_printstr "}"
696 urfsegfault_cr
698 pop ecx
699 ld esi,[urfsegfault_reg_ebp]
700 or ecx,ecx
701 jr nz,@f
704 cp ecx,[urfsegfault_dump_rdepth]
705 jr c,.printloop
706 ld ecx,[urfsegfault_dump_rdepth]
708 .printloop:
709 ld eax,[esi]
710 urfsegfault_printstr " "
711 call urfsegfault_find_by_addr
712 push eax ; for line number
713 call urfsegfault_nfaprint
715 ; print hex value
716 ld eax,[esi]
717 urfsegfault_printstr " | "
718 call urfsegfault_emit_hex_eax
719 ; print decimal value
720 ld eax,[esi]
721 urfsegfault_printstr " | "
722 call urfsegfault_emit_dec_eax
724 ; print line number if we know it
725 xchg esi,[esp]
726 call urfsegfault_find_pc_line_nfa
727 or eax,eax
728 jr z,@f
729 urfsegfault_printstr " {"
730 call urfsegfault_emit_dec_eax
731 urfsegfault_printstr "}"
733 pop esi
735 urfsegfault_cr
736 add esi,4
737 dec ecx
738 jr nz,.printloop
742 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
743 ;; print data stack
745 urfsegfault_cmd_printdstack:
746 ; print first 8 items, that should be enough
747 ; also, print them in backwards order (i.e. TOS will be printed last)
748 ; print data stack depth
749 urfsegfault_printstr "=== DATA STACK: "
750 ld eax,[fvar_sp0_data]
751 sub eax,[urfsegfault_reg_esp]
752 jp nc,@f
753 ; underflow
754 urfsegfault_printstrnl " UNDERFLOWED ==="
757 sar eax,2 ; divide by cell
758 push eax
759 urfsegfault_printdec eax
760 urfsegfault_printstrnl " CELLS DEPTH ==="
761 pop ecx
762 or ecx,ecx
763 jr z,urfsegfault_cmd_printdstack_quit0
765 urfsegfault_printstr "ESP="
766 ld eax,[urfsegfault_reg_esp]
767 urfsegfault_printhex eax
768 urfsegfault_cr
770 cp ecx,1
771 jr z,urfsegfault_cmd_printdstack_tos
772 cp ecx,[urfsegfault_dump_ddepth]
773 jr c,@f
774 ld ecx,[urfsegfault_dump_ddepth]
776 ; now print cells
777 dec ecx ; TOS
778 ld esi,[urfsegfault_reg_esp]
779 shl ecx,2
780 add esi,ecx
781 shr ecx,2
783 or ecx,ecx
784 jr z,@f
785 sub esi,4
786 ld eax,[esi]
787 urfsegfault_printstr " "
788 urfsegfault_printhex esi
789 urfsegfault_printstr ": "
790 urfsegfault_printhex eax
791 urfsegfault_printstr " | "
792 urfsegfault_printdec eax
793 urfsegfault_cr
794 dec ecx
795 jr @b
797 urfsegfault_cmd_printdstack_tos:
798 ; print TOS
799 urfsegfault_printstr " "
800 urfsegfault_printstr " TOS "
801 urfsegfault_printstr ": "
802 urfsegfault_printhex [urfsegfault_reg_ecx]
803 urfsegfault_printstr " | "
804 urfsegfault_printdec [urfsegfault_reg_ecx]
805 urfsegfault_cr
807 urfsegfault_cmd_printdstack_quit0:
811 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
812 ;; debugger segfault handler
814 urfd_sigact:
815 urfd_sigact.sa_handler: ;dd 0 ; union with .sa_sigaction
816 urfd_sigact.sa_sigaction: dd urfsegfault_segfault_action
817 urfd_sigact.sa_mask: dd 0 ;0xffffffff
818 urfd_sigact.sa_flags: dd 4 ; SA_SIGINFO
819 urfd_sigact.sa_restorer: dd 0
821 struc siginfo {
822 .si_signo rd 1
823 .si_errno rd 1
824 .si_code rd 1
825 ; for segfaults
826 ;._addr rd 1
827 ._pad rd 29
828 if 0
829 ._kill: ;kill
830 ._timer: ;timer
831 .__rt: ;_rt
832 ._sigchld: ;sigchld
833 ._sigfault: ;sigfault
834 ._sigpoll: ;sigpoll
835 ._pad rd 29
836 end if
839 struc sigcontext {
840 .gs rw 1
841 .__gsh rw 1
842 .fs rw 1
843 .__fsh rw 1
844 .es rw 1
845 .__esh rw 1
846 .ds rw 1
847 .__dsh rw 1
848 .edi rd 1
849 .esi rd 1
850 .ebp rd 1
851 .esp rd 1
852 .ebx rd 1
853 .edx rd 1
854 .ecx rd 1
855 .eax rd 1
856 .trapno rd 1
857 .err rd 1
858 .eip rd 1
859 .cs rw 1
860 .__csh rw 1
861 .eflags rd 1
862 .esp_at_signal rd 1
863 .ss rw 1
864 .__ssh rw 1
865 .fpstate rd 1
866 .oldmask rd 1
867 .cr2 rd 1
870 struc sigaltstack {
871 .ss_sp rd 1
872 .ss_flags rd 1
873 .ss_size rd 1
876 struc sigset {
877 .sig rd 2
880 struc ucontext {
881 .uc_flags rd 1
882 .uc_link rd 1
883 .uc_stack sigaltstack
884 .uc_mcontext sigcontext
885 .uc_sigmask sigset
888 virtual at 0
889 ucshit ucontext
890 end virtual
892 virtual at 0
893 sinfoshit siginfo
894 end virtual
896 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
897 urfsegfault_segfault_action:
898 ld ebp,esp
899 ; switch to our own stack
900 ;ld eax,[fvar_dp_data]
901 ;add eax,1024*128
902 ld eax,[urfsegfault_stack_bottom]
903 ld esp,eax
905 ; signum : dword [ebp+4]
906 ; siginfoptr : dword [ebp+8]
907 ; ucontextptr: dword [ebp+12]
909 ; copy registers from context to debugger data structures
910 ld esi,[ebp+12]
911 ld eax,[esi+ucshit.uc_mcontext.eip]
912 ld [urfsegfault_dbg_retaddr],eax
913 ld eax,[esi+ucshit.uc_mcontext.eax]
914 ld [urfsegfault_reg_eax],eax
915 ld eax,[esi+ucshit.uc_mcontext.ebx]
916 ld [urfsegfault_reg_ebx],eax
917 ld eax,[esi+ucshit.uc_mcontext.ecx]
918 ld [urfsegfault_reg_ecx],eax
919 ld eax,[esi+ucshit.uc_mcontext.edx]
920 ld [urfsegfault_reg_edx],eax
921 ld eax,[esi+ucshit.uc_mcontext.esi]
922 ld [urfsegfault_reg_esi],eax
923 ld eax,[esi+ucshit.uc_mcontext.edi]
924 ld [urfsegfault_reg_edi],eax
925 ld eax,[esi+ucshit.uc_mcontext.ebp]
926 ld [urfsegfault_reg_ebp],eax
927 ld eax,[esi+ucshit.uc_mcontext.esp]
928 ld [urfsegfault_reg_esp],eax
929 ld eax,[esi+ucshit.uc_mcontext.eflags]
930 ld [urfsegfault_reg_flags],eax
933 urfsegfault_printstr "***TRAP: SEGFAULT!"
936 ld esi,[ebp+12]
938 ld eax,[esi+ucshit.uc_mcontext.eip]
939 urfsegfault_printstr " EIP="
940 urfsegfault_printhex eax
942 ld eax,[esi+ucshit.uc_mcontext.esp]
943 urfsegfault_printstr " ESP="
944 urfsegfault_printhex eax
946 ld eax,[esi+ucshit.uc_mcontext.ebp]
947 urfsegfault_printstr " EBP="
948 urfsegfault_printhex eax
950 ld eax,[esi+ucshit.uc_mcontext.esi]
951 urfsegfault_printstr " ESI="
952 urfsegfault_printhex eax
954 urfsegfault_cr
956 ld eax,[esi+ucshit.uc_mcontext.eip]
957 call urfsegfault_find_by_addr
958 or eax,eax
959 jz @f
960 urfsegfault_printstr "*** CURRENT WORD: "
961 call urfsegfault_nfaprint
962 ; print line number if we know it
963 ld esi,eax
964 ld eax,[esi+ucshit.uc_mcontext.eip]
965 call urfsegfault_find_pc_line_nfa
966 or eax,eax
967 jr z,@f
968 urfsegfault_printstr " {"
969 call urfsegfault_emit_dec_eax
970 urfsegfault_printstr "}"
972 urfsegfault_cr
974 call urfsegfault_cmd_printdstack
975 call urfsegfault_cmd_printrstack
977 ld eax,1
978 ld ebx,1
979 syscall
982 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
983 ;; called by the startup code
985 urforth_setup_segfault_handler:
986 urfsegfault_save_all_registers
987 ; set segfault hanlder
988 ld eax,67
989 ld ebx,11 ; SIGSEGV
990 ;ld ebx,2 ; SIGTERM
991 ld ecx,urfd_sigact
992 xor edx,edx ; ignore old info
993 syscall
994 or eax,eax
995 jr z,@f
996 urfsegfault_printstrnl "TRAP: cannot setup segfault handler."
998 urfsegfault_restore_all_registers