xog: slightly better debug output
[urforth.git] / level1 / 01_segfault_handler.f
blobb7a74be44637ec65ef35112fafab2ab8f33e3e41
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; UrForth level 1: self-hosting 32-bit Forth compiler
3 ;; Copyright (C) 2020 Ketmar Dark // Invisible Vector
4 ;; GPLv3 ONLY
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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
33 ;; print char from AL
34 ;; all registers are preserved, including flags
36 urfsegfault_emit_al:
37 save_all_regs
38 push eax ;; we will write from here
39 ld eax,4 ;; write
40 ld ebx,[urfsegfault_output_fd]
41 ld ecx,esp ;; address
42 ld edx,1 ;; length
43 syscall
44 pop eax
45 restore_all_regs
46 ret
49 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50 ;; print string from ECX, length in EDX
51 ;; all registers are preserved, including flags
53 urfsegfault_emit_str_ecx_edx:
54 save_all_regs
55 ld eax,4 ;; write
56 ld ebx,[urfsegfault_output_fd]
57 syscall
58 restore_all_regs
59 ret
62 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
63 ;; print string from ECX, length in EDX
64 ;; all registers are preserved, including flags
66 urfsegfault_emit_str_ecx_edx_safe:
67 save_all_regs
68 .prloop:
69 or edx,edx
70 jr z,.done
71 movzx eax,byte [ecx]
72 cp al,32
73 jr nc,@f
74 ld al,'?'
75 @@:
76 call urfsegfault_emit_al
77 inc ecx
78 dec edx
79 jr .prloop
80 .done:
81 restore_all_regs
82 ret
85 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
86 ;; print AL as hex
87 ;; all registers are preserved, including flags
89 urfsegfault_emit_hex_al:
90 pushfd
91 push eax
92 push eax
93 shr al,4
94 Nibble2Hex
95 call urfsegfault_emit_al
96 pop eax
97 Nibble2Hex
98 call urfsegfault_emit_al
99 pop eax
100 popfd
104 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
105 ;; print AX as hex
106 ;; all registers are preserved, including flags
108 urfsegfault_emit_hex_ax:
109 pushfd
110 push eax
111 push eax
112 shr eax,8
113 call urfsegfault_emit_hex_al
114 pop eax
115 call urfsegfault_emit_hex_al
116 pop eax
117 popfd
121 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
122 ;; print EAX as hex
123 ;; all registers are preserved, including flags
125 urfsegfault_emit_hex_eax:
126 pushfd
127 push eax
128 push eax
129 shr eax,16
130 call urfsegfault_emit_hex_ax
131 pop eax
132 call urfsegfault_emit_hex_ax
133 pop eax
134 popfd
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:
144 save_all_regs
145 or eax,eax
146 jr ns,@f
147 urfsegfault_emit '-'
148 neg eax
150 call .prloop
151 restore_all_regs
153 .prloop:
154 ld ecx,10
155 xor edx,edx
156 div ecx
157 ;; EAX: quotient; EDX: remainder
158 or eax,eax
159 jr z,@f
160 ;; recurse
161 push eax
162 push edx
163 call .prloop
164 pop edx
165 pop eax
167 xchg eax,edx
168 ;; EDX: quotient; EAX: remainder
169 add al,'0'
170 call urfsegfault_emit_al
174 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
175 ;; get source file name from nfa
177 ;; IN:
178 ;; EAX: nfa
179 ;; OUT:
180 ;; EAX: byte-counted string (or 0)
181 ;; other registers are preserved (except flags)
183 urfsegfault_nfa_get_fname:
184 ld eax,[eax-20]
185 or eax,eax
186 jr z,.none
187 ld eax,[eax+4]
188 .none:
192 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
193 ;; get source file name from nfa
195 ;; IN:
196 ;; EAX: nfa
197 ;; OUT:
198 ;; none
199 ;; all registers are preserved (except flags)
201 urfsegfault_nfa_write_fname:
202 push eax
203 push ecx
204 push esi
205 call urfsegfault_nfa_get_fname
206 or eax,eax
207 jr z,.nofname
208 movzx ecx,byte [eax]
209 jecxz .nofname
210 lea esi,[eax+1]
211 urfsegfault_emit ':'
212 .nloop:
213 lodsb
214 urfsegfault_emit al
215 loop .nloop
216 .nofname:
217 pop esi
218 pop ecx
219 pop eax
223 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
224 ;; move to cfa from nfa
226 ;; IN:
227 ;; EAX: nfa
228 ;; OUT:
229 ;; EAX: cfa
230 ;; other registers are preserved (except flags)
232 urfsegfault_nfa2cfa:
233 push ecx
234 movzx ecx,byte [eax]
235 add eax,ecx
236 $if URFORTH_ALIGN_CFA
237 add eax,4
238 or eax,3
239 inc eax
240 $else
241 add eax,4+1 ;; lenflags, trailing length
242 $endif
243 pop ecx
247 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
248 ;; move to nfa from cfa
250 ;; IN:
251 ;; EAX: cfa
252 ;; OUT:
253 ;; EAX: nfa
254 ;; other registers are preserved (except flags)
256 urfsegfault_cfa2nfa:
257 push ecx
258 movzx ecx,byte [eax-1]
259 add ecx,4+1 ;; lenflags, trailing length
260 sub eax,ecx
261 pop ecx
265 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
266 ;; type word name
267 ;; correctly handles the case when EAX == 0
269 ;; IN:
270 ;; EAX: nfa
271 ;; OUT:
272 ;; all registers are preserved (except flags)
274 urfsegfault_nfaprint:
275 push eax
276 push ecx
277 push edx
278 or eax,eax
279 jr z,.noword
280 ;; load length to edx
281 movzx edx,byte [eax]
282 or edx,edx
283 jr z,.nonamed
284 add eax,4 ;; skip length and flags
285 ld ecx,eax ;; starting address
286 call urfsegfault_emit_str_ecx_edx_safe
287 .nonamed:
288 pop edx
289 pop ecx
290 pop eax
292 .noword:
293 urfsegfault_printstr "<???>"
294 jr .nonamed
297 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
298 ;; skip word argument
299 ;; correctly handles the case when EAX == 0
301 ;; IN:
302 ;; EAX: nfa
303 ;; ESI: code pointer
304 ;; OUT:
305 ;; EAX: dead
306 ;; ESI: (new) code pointer
307 ;; all registers are preserved (except flags)
309 urfsegfault_nfa_skip_arg:
310 or eax,eax
311 jr nz,.cont
313 .cont:
314 ;; load arg type
315 movzx eax,byte [eax+1]
317 urfsegfault_nfa_skip_arg_type_in_eax:
318 ;; branch?
319 cp al,WARG_BRANCH
320 jr nz,@f
321 add esi,4
322 jr .done
324 ;; 4 byte literal?
325 cp al,WARG_LIT
326 jr nz,@f
327 add esi,4
328 jr .done
330 ;; 1 byte unsigned literal?
331 cp al,WARG_U8
332 jr nz,@f
333 inc esi
334 jr .done
336 ;; 1 byte signed literal?
337 cp al,WARG_S8
338 jr nz,@f
339 inc esi
340 jr .done
342 ;; 2 byte unsigned literal?
343 cp al,WARG_U16
344 jr nz,@f
345 add esi,2
346 jr .done
348 ;; 2 byte signed literal?
349 cp al,WARG_S16
350 jr nz,@f
351 add esi,2
352 jr .done
354 ;; cell-counted string?
355 cp al,WARG_C4STRZ
356 jr nz,@f
357 lodsd
358 add esi,eax
359 ;; skip trailing zero byte and align
360 or esi,3
361 inc esi
362 jr .done
364 ;; byte-counted string?
365 cp al,WARG_C1STRZ
366 jr nz,@f
367 lodsb
368 movzx eax,al
369 add esi,eax
370 ;; skip trailing zero byte and align
371 or esi,3
372 inc esi
373 jr .done
375 ;; cfa?
376 cp al,WARG_CFA
377 jr nz,@f
378 add esi,4
379 jr .done
381 ;; cblock?
382 cp al,WARG_CBLOCK
383 jr nz,@f
384 lodsd
385 ld esi,eax
386 jr .done
388 ;; vocid?
389 cp al,WARG_VOCID
390 jr nz,@f
391 add esi,4
393 .done:
397 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
398 ;; type word argument
399 ;; correctly handles the case when EAX == 0
401 ;; IN:
402 ;; EAX: nfa
403 ;; ESI: code pointer
404 ;; OUT:
405 ;; ESI: (new) code pointer
406 ;; all registers are preserved (except flags)
408 urfsegfault_nfa_print_arg:
409 push eax
410 push ecx
411 push edx
412 or eax,eax
413 jr z,.done
414 ;; load arg type
415 ld cl,byte [eax+1]
416 jecxz .done
417 ;; branch?
418 cp cl,WARG_BRANCH
419 jr nz,@f
420 urfsegfault_emit ' '
421 lodsd
422 call urfsegfault_emit_hex_eax
423 .done:
424 pop edx
425 pop ecx
426 pop eax
429 ;; literal?
430 cp cl,WARG_LIT
431 jr nz,@f
432 lodsd
433 .printlit:
434 urfsegfault_emit ' '
435 call urfsegfault_emit_dec_eax
436 jr .done
438 ;; 1 byte unsigned literal?
439 cp cl,WARG_U8
440 jr nz,@f
441 lodsb
442 movzx eax,al
443 jr .printlit
445 ;; 1 byte signed literal?
446 cp cl,WARG_S8
447 jr nz,@f
448 lodsb
449 movsx eax,al
450 jr .printlit
452 ;; 2 byte unsigned literal?
453 cp cl,WARG_U16
454 jr nz,@f
455 lodsw
456 movzx eax,ax
457 jr .printlit
459 ;; 1 byte signed literal?
460 cp cl,WARG_S16
461 jr nz,@f
462 lodsw
463 movsx eax,ax
464 jr .printlit
466 ;; cell-counted string?
467 cp cl,WARG_C4STRZ
468 jr nz,@f
469 urfsegfault_printstr ' "' ;; '
470 lodsd
471 ld edx,eax
472 ld ecx,esi
473 add esi,eax
474 ;; skip trailing zero byte and align
475 or esi,3
476 inc esi
477 call urfsegfault_emit_str_ecx_edx_safe
478 urfsegfault_emit '"' ;; '
479 jr .done
481 ;; byte-counted string?
482 cp cl,WARG_C1STRZ
483 jr nz,@f
484 urfsegfault_printstr ' "' ;; '
485 lodsb
486 movzx eax,al
487 ld edx,eax
488 ld ecx,esi
489 add esi,eax
490 ;; skip trailing zero byte and align
491 or esi,3
492 inc esi
493 call urfsegfault_emit_str_ecx_edx_safe
494 urfsegfault_emit '"' ;; '
495 jp .done
497 ;; cfa?
498 cp cl,WARG_CFA
499 jr nz,@f
500 urfsegfault_emit ' '
501 lodsd
502 ;;call urfsegfault_find_by_addr
503 call urfsegfault_cfa2nfa
504 call urfsegfault_nfaprint
505 jp .done
507 ;; cblock?
508 cp cl,WARG_CBLOCK
509 jr nz,@f
510 urfsegfault_printstr " {cblock}"
511 lodsd
512 ld esi,eax
513 jp .done
515 ;; vocid?
516 cp cl,WARG_VOCID
517 jr nz,@f
518 urfsegfault_printstr " {vocid}"
519 lodsd
520 jp .done
522 jp .done
525 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
526 ;; find line for the PC
528 ;; IN:
529 ;; EAX: pc
530 ;; ESI: nfa
531 ;; OUT:
532 ;; EAX: line
533 ;; other registers are preserved (except flags)
535 urfsegfault_find_pc_line_nfa:
536 push edi
537 push esi
538 push ecx
539 push edx
540 push ebx
541 or esi,esi
542 jr z,.fail
543 ;; load debug info address
544 ;; EDI will contain current PC
545 ld edi,esi
546 ;; move EDI to CFA
547 movzx ebx,byte [edi]
548 add edi,ebx
549 $if URFORTH_ALIGN_CFA
550 add edi,4
551 or edi,3
552 inc edi
553 $else
554 add edi,5 ;; skip lenflags, and trailing len
555 $endif
556 ;; load pointer to debug info
557 ld esi,[esi-20]
558 or esi,esi
559 jr z,.fail
560 ;; load and check number of items
561 movzx ecx,word [esi]
562 ;; check number of items (just in case)
563 jecxz .fail
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)
567 add esi,2+2+4
568 ;; check if PC is higher
569 cmp eax,edi
570 jr c,.done
571 .scanloop:
572 ;; get next PC
573 movzx ebx,byte [esi]
574 inc esi
575 cp bl,255
576 jr nz,@f
577 movzx ebx,word [esi]
578 add esi,2
580 add edi,ebx
581 cp eax,edi
582 jr c,.done
583 ;; get next line
584 movzx ebx,byte [esi]
585 inc esi
586 cp bl,255
587 jr nz,@f
588 movzx ebx,word [esi]
589 add esi,2
591 add edx,ebx
592 loop .scanloop
593 .fail:
594 xor edx,edx
595 .done:
596 ld eax,edx
597 pop ebx
598 pop edx
599 pop ecx
600 pop esi
601 pop edi
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
612 ;; IN:
613 ;; EAX: address
614 ;; ESI: vocptr (at latestptr)
615 ;; OUT:
616 ;; EAX: nfa or 0
617 ;; ZERO SET if EAX is 0
618 ;; other registers are preserved (except flags)
620 urfsegfault_find_by_addr_in_voc:
621 push esi
622 push edi
623 ;; ESI: lfa
624 .findvoc_loop:
625 ;; follow lfa
626 ld esi,[esi]
627 or esi,esi
628 jr z,.not_found
629 ;; load sfa
630 ld edi,[esi-8]
631 ;; check for invalid sfa
632 cp esi,edi
633 jr nc,.findvoc_loop
634 ;; EAX>=ESI?
635 cp eax,esi
636 jr c,.findvoc_loop
637 ;; EAX<EDI?
638 cp eax,edi
639 jr nc,.findvoc_loop
640 ;; i found her!
641 ;; move ESI to nfa
642 add esi,8
643 ld [urfsegfault_fba_nfa],esi
644 ld [urfsegfault_fba_end],edi
645 .not_found:
646 ld eax,esi
647 or eax,eax ;; fix zero flag
648 pop edi
649 pop esi
653 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
654 ;; find which word owns the specified address
655 ;; this assumes that all words are sequential in memory
657 ;; IN:
658 ;; EAX: address
659 ;; OUT:
660 ;; EAX: nfa or 0
661 ;; ZERO SET if EAX is 0
662 ;; other registers are preserved (except flags)
664 urfsegfault_find_by_addr:
665 push esi
666 push ecx
667 ld ecx,eax
668 ld esi,[pfa "(voc-link)"]
669 .vocloop:
670 or esi,esi
671 jr z,.quit
672 sub esi,4 ;; move to latestptr
673 ld eax,ecx
674 call urfsegfault_find_by_addr_in_voc
675 ld esi,[esi+4] ;; load next voclink
676 jr z,.vocloop
677 pop ecx
678 pop esi
680 .quit:
681 xor eax,eax
682 pop ecx
683 pop esi
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]
696 jr nc,@f
697 ;; underflow
698 urfsegfault_printstrnl " UNDERFLOWED ==="
700 sar eax,2 ;; divide by cell
701 push eax
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
709 push eax
710 call urfsegfault_nfaprint
711 ;; print line number if we know it
712 ld esi,[esp]
713 ld eax,[urfsegfault_reg_esi]
714 sub eax,4 ;; because we just loaded it
715 call urfsegfault_find_pc_line_nfa
716 or eax,eax
717 jr z,@f
718 urfsegfault_printstr " {"
719 call urfsegfault_emit_dec_eax
720 ld eax,[esp]
721 call urfsegfault_nfa_write_fname
722 urfsegfault_printstr "}"
724 pop esi
725 urfsegfault_cr
727 pop ecx
728 ld esi,[urfsegfault_reg_ebp]
729 or ecx,ecx
730 jr nz,@f
733 cp ecx,[urfsegfault_dump_rdepth]
734 jr c,.printloop
735 ld ecx,[urfsegfault_dump_rdepth]
737 .printloop:
738 ld eax,[esi]
739 urfsegfault_printstr " "
740 call urfsegfault_find_by_addr
741 push eax ;; for line number
742 call urfsegfault_nfaprint
744 ;; print hex value
745 ld eax,[esi]
746 urfsegfault_printstr " | "
747 call urfsegfault_emit_hex_eax
748 ;; print decimal value
749 ld eax,[esi]
750 urfsegfault_printstr " | "
751 call urfsegfault_emit_dec_eax
753 ;; print line number if we know it
754 xchg esi,[esp]
755 sub eax,4 ;; pushed value is "next to execute"
756 push esi
757 call urfsegfault_find_pc_line_nfa
758 or eax,eax
759 jr z,@f
760 urfsegfault_printstr " {"
761 call urfsegfault_emit_dec_eax
762 ld eax,[esp]
763 call urfsegfault_nfa_write_fname
764 urfsegfault_printstr "}"
766 add esp,4
767 pop esi
769 urfsegfault_cr
770 add esi,4
771 dec ecx
772 jp nz,.printloop
776 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
777 ;; print data stack
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]
786 jr nc,@f
787 ;; underflow
788 urfsegfault_printstrnl " UNDERFLOWED ==="
791 sar eax,2 ;; divide by cell
792 push eax
793 urfsegfault_printdec eax
794 urfsegfault_printstrnl " CELLS DEPTH ==="
795 pop ecx
796 or ecx,ecx
797 jp z,urfsegfault_cmd_printdstack_quit0
799 urfsegfault_printstr "ESP="
800 ld eax,[urfsegfault_reg_esp]
801 urfsegfault_printhex eax
802 urfsegfault_cr
804 cp ecx,1
805 jp z,urfsegfault_cmd_printdstack_tos
806 cp ecx,[urfsegfault_dump_ddepth]
807 jr c,@f
808 ld ecx,[urfsegfault_dump_ddepth]
810 ;; now print cells
811 dec ecx ;; TOS
812 ld esi,[urfsegfault_reg_esp]
813 shl ecx,2
814 add esi,ecx
815 shr ecx,2
817 or ecx,ecx
818 jr z,@f
819 sub esi,4
820 ld eax,[esi]
821 urfsegfault_printstr " "
822 urfsegfault_printhex esi
823 urfsegfault_printstr ": "
824 urfsegfault_printhex eax
825 urfsegfault_printstr " | "
826 urfsegfault_printdec eax
827 urfsegfault_cr
828 dec ecx
829 jr @b
831 urfsegfault_cmd_printdstack_tos:
832 ;; print 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]
839 urfsegfault_cr
841 urfsegfault_cmd_printdstack_quit0:
845 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
846 ;; debugger segfault handler
848 SA_NOCLDSTOP equ 1
849 SA_NOCLDWAIT equ 2
850 SA_SIGINFO equ 4
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.
863 urfd_sigact:
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
870 ;; struc siginfo {
871 ;; .si_signo dword 1
872 ;; .si_errno dword 1
873 ;; .si_code dword 1
874 ;; ; for segfaults
875 ;; ;._addr dword 1
876 ;; ._pad dword 29
877 ;; if 0
878 ;; ._kill: ;kill
879 ;; ._timer: ;timer
880 ;; .__rt: ;_rt
881 ;; ._sigchld: ;sigchld
882 ;; ._sigfault: ;sigfault
883 ;; ._sigpoll: ;sigpoll
884 ;; ._pad dword 29
885 ;; end if
886 ;; }
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 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
935 ;;db 2 ;; SIGINT
936 urfsegfault_segfault_signames:
937 ;; signum, errcode-addr, errmessage
938 ;; segfault
939 db 11 ;; SIGSEGV
940 dd pfa "ERR-SEGFAULT"
941 db "SEGFAULT",0
942 ;; sigfpe
943 db 8 ;; SIGFPE
944 dd pfa "ERR-MATH-ZERO-DIVIDE"
945 db "DIVISION BY ZERO",0
946 ;; sigill
947 db 4 ;; SIGILL
948 dd pfa "ERR-UNDEFINED-INSTRUCTION"
949 db "BAD INSTRUCTION",0
950 ;; no more
951 db 0 ;; no more
953 urfsegfault_segfault_errcode_addr: dd pfa "ERR-SEGFAULT"
955 urfsegfault_segfault_action:
956 ld ebp,esp
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
966 ld esi,[ebp+12]
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
988 ;; need a trace?
989 cp dword [urfsegfault_stacktrace],0
990 jp z,.skiptrace
992 urfsegfault_printstr "***TRAP: "
994 ld esi,urfsegfault_segfault_signames
995 .nameloop:
996 lodsb
997 or al,al
998 jr z,.signotfound
999 cp al,byte [ebp+4]
1000 jr z,.sigfound
1001 lodsd
1002 .zeroloop:
1003 lodsb
1004 or al,al
1005 jr nz,.zeroloop
1006 jr .nameloop
1007 .signotfound:
1008 ld esi,urfsegfault_segfault_signames+1
1009 .sigfound:
1010 lodsd
1011 ld [urfsegfault_segfault_errcode_addr],eax
1012 .printloop:
1013 lodsb
1014 or al,al
1015 jr z,.printdone
1016 urfsegfault_emit al
1017 jr .printloop
1018 .printdone:
1020 ;;urfsegfault_printstr "***TRAP: SEGFAULT!"
1022 ld esi,[ebp+12]
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
1040 urfsegfault_cr
1042 ld eax,[esi+ucontext_t.uc_mcontext+sigcontext_t.eip]
1043 call urfsegfault_find_by_addr
1044 or eax,eax
1045 jr z,@f
1046 urfsegfault_printstr "*** CURRENT WORD: "
1047 call urfsegfault_nfaprint
1048 ;; print line number if we know it
1049 push eax
1050 ld esi,eax
1051 ld eax,[esi+ucontext_t.uc_mcontext+sigcontext_t.eip]
1052 call urfsegfault_find_pc_line_nfa
1053 or eax,eax
1054 jr z,@f
1055 urfsegfault_printstr " {"
1056 call urfsegfault_emit_dec_eax
1057 ld eax,[esp]
1058 call urfsegfault_nfa_write_fname
1059 urfsegfault_printstr "}"
1061 pop eax
1062 urfsegfault_cr
1064 call urfsegfault_cmd_printdstack
1065 call urfsegfault_cmd_printrstack
1067 .skiptrace:
1068 cp dword [urfsegfault_throw_error],0
1069 jr nz,.throwit
1071 .byebye:
1072 ld eax,1
1073 ld ebx,1
1074 syscall
1076 .throwit:
1077 ;; restore stacks
1078 ld ERP,[urfsegfault_reg_ebp]
1079 ld esp,[urfsegfault_reg_esp]
1080 ld TOS,[urfsegfault_reg_ecx]
1081 push TOS
1082 ;;ld TOS,[pfa "ERR-SEGFAULT"]
1083 ld TOS,[urfsegfault_segfault_errcode_addr]
1084 ld TOS,[TOS]
1085 ld eax,cfa "error"
1086 jp eax
1089 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1090 ;; called by the startup code
1092 urforth_setup_segfault_handler:
1093 save_all_regs
1095 ld esi,urfsegfault_segfault_signames
1096 .sigloop:
1097 lodsb
1098 or al,al
1099 jr z,.done
1100 movzx ebx,al ;; signal number
1101 ld eax,67 ;; syscall number
1102 ld ecx,urfd_sigact
1103 xor edx,edx ;; ignore old info
1104 push esi
1105 syscall
1106 pop esi
1107 or eax,eax
1108 jr z,.noerr
1109 urfsegfault_printstrnl "TRAP: cannot setup signal handler."
1110 .noerr:
1111 lodsd
1112 .skipmsg:
1113 lodsb
1114 or al,al
1115 jr nz,.skipmsg
1116 jr .sigloop
1117 .done:
1118 restore_all_regs
1120 endcode
1121 (hidden) (codeblock)