1 ;; Native x86 GNU/Linux Forth System, Direct Threaded Code
4 ;; Copyright (C) 2020 Ketmar Dark // Invisible Vector
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.
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 urfdebug_active_flag: dd 0
21 urfdebug_input_fd: dd 0 ; default input is stdin
23 urfdebug_dump_ddepth: dd 7 ; default depth of the data stack dump-1
24 urfdebug_dump_rdepth: dd 7 ; default depth of the data stack dump-1
26 urfdebug_bp_rdepth: dd 0xffffffff ; otherwise activate when return stack depth reaches this
27 urfdebug_sobp_address: dd 0xffffffff ; breakpoint address (at which we should restore dword)
28 ;urfdebug_sobp_value: dd 0 ; breakpoint address (at which we should restore dword)
31 URFORTH_DEBUG_MAX_BPS
= 16
34 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
37 ld
dword [urfdebug_active_flag
],1
38 ld
dword [urforth_next_ptr
],urfdebug_next
41 urfdebug_deactivate_it:
42 ld
dword [urfdebug_active_flag
],0
43 ld
dword [urforth_next_ptr
],urforth_next_normal
47 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
48 ;; print asciiz string from EAX
52 ;; EAX: right after terminating zero
53 ;; all other registers are preserved (excluding flags)
55 urfdebug_emit_str_asciiz_eax:
62 call urfsegfault_emit_al
70 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
72 ;; all registers are preserved, excluding EAX
73 ;; on EOF, EAX is 0, and zero flag is set
74 ;; on success, EAX is !0, and zero flag is reset
77 urfsegfault_save_all_registers_no_eax_f
79 push eax ; we will read char here
81 mov ebx,[urfdebug_input_fd
]
85 ; check number of read chars
90 and eax,0xff ; safety, and zero check
93 or al,al ; reset zero flag
95 urfsegfault_restore_all_registers_no_eax_f
98 xor eax,eax ; also sets zero flag
102 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
103 ;; read input line into urfdebug_tib
106 ;; ECX: line length, without CR
107 ;; zero flag: set on EOF (never set on non-empty line)
108 ;; other flags are dead
109 ;; other registers are preserved
110 ;; always terminates input string with 0
115 mov ecx,urfdebug_tib_size
-1
116 urfdebug_getline_loop:
118 ; ECX: bytes left in destination (excluding room for terminating 0)
120 jz urfdebug_getline_eof
122 jz urfdebug_getline_done
124 jz urfdebug_getline_done
126 loop urfdebug_getline_loop
127 ; either EOL, or end of input buffer
129 urfdebug_getline_done:
130 ; store terminating 0
133 ; calculate line length
134 mov eax,urfdebug_tib_size
-1
140 urfdebug_getline_exit:
145 urfdebug_getline_eof:
146 ; eof: check for empty line
148 jnz urfdebug_getline_done
149 ; empty line and eof: real eof
150 ; store terminating zero
153 ; return 0 length, and zero flag set
155 jmp urfdebug_getline_exit
158 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
162 ;; ESI: input buffer start
164 ;; ESI: pointer to non-blank or zero char
165 ;; EAX: non-blank char
166 ;; ZERO SET if ESI points to zero char (i.e. on EOL)
167 ;; all other registers are preserved, except flags
169 urfdebug_skip_blanks:
172 jz urfdebug_skip_blanks_stop
174 jc urfdebug_skip_blanks
175 urfdebug_skip_blanks_stop:
181 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
182 ;; convert AL to digit in hex
183 ;; sets carry on error (and AL is undefined)
184 ;; all other registers are preserved, except flags
204 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
208 ;; ESI: input buffer start (blanks must be skipped!)
210 ;; ESI: pointer to non-blank or zero char
211 ;; EAX: parsed number
212 ;; CARRY SET if not a number (in this case ESI is not modified, and EAX is garbage)
213 ;; all other registers are preserved, except flags
215 urfdebug_parse_number:
216 push esi ; we may need to restore it
218 push eax ; negate flag
219 push eax ; number base
220 push eax ; number accumulator
222 ; [esp] -- accumulator
224 ; [esp+8] -- negate flag
227 jr z
,urfdebug_parse_number_error
229 ; check for negative/positive
234 jr urfdebug_parse_number_check_prefixes
241 urfdebug_parse_number_check_prefixes:
244 ; check for possible sigils
261 ; check for possible C-like prefix
263 jr nz
,urfdebug_parse_number_no_c_prefix
268 jr urfdebug_parse_number_no_c_prefix
274 jr urfdebug_parse_number_no_c_prefix
280 jr urfdebug_parse_number_no_c_prefix
286 jr urfdebug_parse_number_no_c_prefix
292 jr urfdebug_parse_number_no_c_prefix
298 jr urfdebug_parse_number_no_c_prefix
304 jr urfdebug_parse_number_no_c_prefix
310 jr urfdebug_parse_number_no_c_prefix
313 urfdebug_parse_number_no_c_prefix:
314 ; first must be a digit
316 call urfdebug_digit_al
317 jr c
,urfdebug_parse_number_error
319 jr nc
,urfdebug_parse_number_error
321 urfdebug_parse_number_loop:
324 jr c
,urfdebug_parse_number_complete
326 jr z
,urfdebug_parse_number_loop
327 call urfdebug_digit_al
328 jr c
,urfdebug_parse_number_error
330 jr nc
,urfdebug_parse_number_error
346 jr urfdebug_parse_number_loop
348 urfdebug_parse_number_complete:
349 dec esi ; back to the last non-number char
350 call urfdebug_skip_blanks
357 or eax,eax ; reset carry
360 urfdebug_parse_number_error:
367 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
371 ;; ESI: input buffer start
374 ;; ESI: next input buffer token (blanks skipped)
375 ;; EAX: command handler address
381 ;; all registers are preserved, except flags
383 urfdebug_find_command:
384 push esi ; in case we'll need to restore it
385 call urfdebug_skip_blanks
386 jz urfdebug_find_command_eol
387 ; save two reginster we will use as working set
391 mov edi,urfdebug_command_table
392 urfdebug_find_command_loop:
395 ; EAX,ECX: scratchpad
396 mov eax,[edi] ; handler address
398 jz urfdebug_find_command_not_found
399 ; EAX contains handler address
403 add edi,4 ; skip handler address
404 ; save esi, because we will need to restore it on failure
406 ; compare until different, or until table name terminates
407 urfdebug_find_command_cmpname_loop:
408 mov al,[esi] ; input byte
409 ; if space, convert to 0, so we can compare it with name terminator
411 jnc urfdebug_find_command_cmpname_loop_good_al
413 urfdebug_find_command_cmpname_loop_good_al:
414 cmp al,[edi] ; compare with name byte
415 jnz urfdebug_find_command_cmpname_loop_failed
416 ; the bytes are the same, advance pointers
419 ; check for end-of-word
421 jnz urfdebug_find_command_cmpname_loop
422 ; command name matches
423 ; ESI: after the command text, and the last space/0
424 ; EDI: after the command name in the table, and the trailing 0
425 ; on stack: original ESI, handler address
426 dec esi ; backup one char in case it was 0
427 call urfdebug_skip_blanks
428 pop eax ; drop original ESI, we don't need it anymore
429 pop eax ; this is our return result
430 ; restore trashed registers
433 add esp,4 ; ignore saved oritinal ESI
436 urfdebug_find_command_cmpname_loop_failed:
437 ; ESI: in the command text
438 ; EDI: in the name text
439 ; on stack: original ESI, handler address
440 pop esi ; restore original ESI
441 pop eax ; we don't need it, so this is just "drop"
442 ; skip the rest of the name
443 urfdebug_find_command_cmpname_loop_failed_skip:
447 jnz urfdebug_find_command_cmpname_loop_failed_skip
454 jmp urfdebug_find_command_loop
456 urfdebug_find_command_not_found:
459 urfdebug_find_command_eol:
465 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
466 if URFORTH_EXTRA_STACK_CHECKS
467 ;; flags and EAX are already saved; all others should be preserved
468 urfdebug_stack_check:
469 ld
eax,[fvar_sp0_data
]
474 ld
dword [urfdebug_active_flag
],1
480 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
481 ;; main debugger entry point
482 ;; all registers are preserved, including flags
485 ; save eax and flags, check for early exit
487 cmp dword [urfdebug_active_flag
],0xffffffff
490 if URFORTH_EXTRA_STACK_CHECKS
491 call urfdebug_stack_check
493 cmp dword [urfdebug_active_flag
],0
494 jr nz
,urfdebug_active
495 ; special flag, means "no breakpoint checks"
496 ; check for breakpoints
497 ld
eax,[urfdebug_sobp_address
]
498 add eax,4 ; compensate for loaded dword
501 ; check for rdepth breakpoint
502 cp ERP
,[urfdebug_bp_rdepth
]
504 ; no breakpoints, get out
511 ; debugger is active here
513 ; save other registers
514 pop eax ; original eax
515 mov [urfsegfault_reg_eax
],eax
517 mov [urfsegfault_reg_flags
],eax
518 mov [urfsegfault_reg_ebx
],ebx
519 mov [urfsegfault_reg_ebx
],ebx
520 mov [urfsegfault_reg_ecx
],ecx
521 mov [urfsegfault_reg_edx
],edx
522 mov [urfsegfault_reg_esi
],esi
523 mov [urfsegfault_reg_edi
],edi
524 mov [urfsegfault_reg_ebp
],ebp
529 mov [urfsegfault_dbg_retaddr
],eax
531 ; now save stack pointer
532 mov [urfsegfault_reg_esp
],esp
533 ; just in case, ensure that the direction flag is clear (autoincrement)
536 ; switch to our own stack
537 ;ld eax,[fvar_dp_data]
539 ld
eax,[urfsegfault_stack_bottom
]
543 ;ld dword [urfdebug_active_flag],1
544 call urfdebug_activate_it
545 ; reset rdepth breakpoint
546 ld
dword [urfdebug_bp_rdepth
],0xffffffff
547 ; reset step-over breakpoint
548 ld
dword [urfdebug_sobp_address
],0xffffffff
552 ; print debugger prompt, data stack depth, return stack depth
553 ld
eax,[urfsegfault_reg_esp
]
554 call urfsegfault_emit_hex_eax
556 urfsegfault_printstr
"UDBG:D("
558 ; print data stack depth
559 mov eax,[fvar_sp0_data
]
560 sub eax,[urfsegfault_reg_esp
]
561 sar eax,2 ; divide by cell
562 urfsegfault_printdec
eax
564 ; print return stack depth
565 urfsegfault_printstr
"):R("
566 mov eax,[fvar_rp0_data
]
567 sub eax,[urfsegfault_reg_ebp
]
568 sar eax,2 ; divide by cell
569 urfsegfault_printdec
eax
571 ; print the word we're currently executing
572 urfsegfault_printstr
"):"
573 mov eax,[urfsegfault_reg_esi
]
574 sub eax,4 ; because we just loaded it
575 call urfsegfault_find_by_addr
576 ; print line number if we know it
579 ld
eax,[urfsegfault_reg_esi
]
580 sub eax,4 ; because we just loaded it
581 call urfsegfault_find_pc_line_nfa
584 urfsegfault_printstr
"{"
585 call urfsegfault_emit_dec_eax
586 urfsegfault_printstr
"}"
590 call urfsegfault_nfaprint
592 ; print the word we'll jump into
593 urfsegfault_printstr
" -> "
594 mov eax,[urfsegfault_reg_eax
]
595 call urfsegfault_find_by_addr
597 call urfsegfault_nfaprint
599 ld
esi,[urfsegfault_reg_esi
]
600 call urfsegfault_nfa_print_arg
603 urfsegfault_printstr
" | "
604 mov eax,[urfsegfault_reg_esi
]
605 sub eax,4 ; because we just loaded it
606 call urfsegfault_emit_hex_eax
609 urfsegfault_printstr
" -> "
610 mov eax,[urfsegfault_reg_eax
]
611 call urfsegfault_emit_hex_eax
613 ; print the rest of the prompt
614 urfsegfault_printstr
" |>"
617 call urfdebug_getline
618 ; ECX is length; ZERO SET on EOF
620 jz urfdebug_deactivate
621 ; continue on empty command
626 call urfdebug_find_command
627 jz urfdebug_unknown_command
629 ;call uefdebug_call_eax
633 urfdebug_unknown_command:
634 ; for now, simply echo the command
639 jz urfdebug_echo_loop_done
640 call urfsegfault_emit_al
641 jmp urfdebug_echo_loop
642 urfdebug_echo_loop_done:
643 ;urfsegfault_emit '|'
645 urfsegfault_printstrnl
"? what?"
650 urfdebug_deactivate_nocr:
651 ;mov dword [urfdebug_active_flag],0
652 call urfdebug_deactivate_it
656 mov ebx,[urfsegfault_reg_ebx
]
657 mov ecx,[urfsegfault_reg_ecx
]
658 mov edx,[urfsegfault_reg_edx
]
659 mov esi,[urfsegfault_reg_esi
]
660 mov edi,[urfsegfault_reg_edi
]
661 mov ebp,[urfsegfault_reg_ebp
]
663 mov eax,[urfsegfault_reg_flags
]
667 mov esp,[urfsegfault_reg_esp
]
669 ; push return address
670 mov eax,[urfsegfault_dbg_retaddr
]
673 ; restore eax, and exit
674 mov eax,[urfsegfault_reg_eax
]
679 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
681 ;; handler will be called with ESI pointing to unparsed arguments (blanks skipped)
683 urfdebug_command_table:
684 dd urfdebug_cmd_printdstack
686 db "dump data stack",0
687 dd urfdebug_cmd_printrstack
689 db "dump return stack",0
690 dd urfdebug_cmd_step_out
692 db "continue until current word returned",0
693 dd urfdebug_cmd_step_over
695 db "step over the current word",0
696 dd urfdebug_cmd_deactivate
698 db "deactivate debugger",0
702 db "drop number from data stack",0
705 db "swap numbers at data stack",0
708 db "push number at data stack",0
710 dd urfdebug_cmd_ddepth
712 db "set data stack dump depth",0
713 dd urfdebug_cmd_rdepth
715 db "set return stack dump depth",0
719 db "decompile forth word",0
721 dd urfdebug_cmd_fcall
723 db "call forth word",0
727 db "show this help",0
731 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
732 ;; drop value from data stack
735 ld
eax,[fvar_sp0_data
]
736 sub eax,[urfsegfault_reg_esp
]
739 urfsegfault_printstrnl
"stack underflowed"
744 ld
edi,[urfsegfault_reg_esp
]
747 ld
[urfsegfault_reg_ecx
],eax
749 ld
[urfsegfault_reg_esp
],edi
753 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
754 ;; swap values on data stack
757 ld
eax,[fvar_sp0_data
]
758 sub eax,[urfsegfault_reg_esp
]
761 urfsegfault_printstrnl
"stack underflowed"
766 urfsegfault_printstrnl
"stack should have at least two values"
770 ld
edi,[urfsegfault_reg_esp
]
772 ld
ecx,[urfsegfault_reg_ecx
]
774 ld
[urfsegfault_reg_ecx
],eax
778 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
779 ;; push value on data stack
782 ld
eax,[fvar_sp0_data
]
783 sub eax,[urfsegfault_reg_esp
]
786 urfsegfault_printstrnl
"stack underflowed"
789 urfdebug_cmd_push_parse_loop:
790 call urfdebug_skip_blanks
792 call urfdebug_parse_number
794 urfsegfault_printstrnl
"not a number!"
797 ld
edi,[urfsegfault_reg_esp
]
798 ld
ecx,[urfsegfault_reg_ecx
]
801 ld
[urfsegfault_reg_ecx
],eax
802 ld
[urfsegfault_reg_esp
],edi
803 jr urfdebug_cmd_push_parse_loop
806 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
810 urfsegfault_printstrnl
"------ HELP ------"
811 ld
esi,urfdebug_command_table
812 urfdebug_cmd_help_loop:
817 urfsegfault_printstr
" "
818 call urfdebug_emit_str_asciiz_eax
820 call urfdebug_emit_str_asciiz_eax
823 jr urfdebug_cmd_help_loop
826 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
827 ;; deactivate until current word exited
829 urfdebug_cmd_step_out:
830 ; check return stack depth
831 ld
eax,[fvar_rp0_data
]
832 cmp eax,[urfsegfault_reg_ebp
]
833 jr z
,urfdebug_cmd_step_out_cannot
834 jr c
,urfdebug_cmd_step_out_cannot
835 ld
eax,[urfsegfault_reg_ebp
]
836 add eax,4 ; one level up
837 ld
[urfdebug_bp_rdepth
],eax
838 ; done, deactivate debugger
839 ;;jp urfdebug_deactivate_nocr
840 ld
dword [urfdebug_active_flag
],0
842 urfdebug_cmd_step_out_cannot:
843 urfsegfault_printstrnl
"cannot step out, return stack is empty!"
847 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
848 ;; perform "step over"
850 urfdebug_cmd_step_over:
851 ; sanity check, just in case
852 cp
dword [urfdebug_sobp_address
],0xffffffff
853 jr nz
,urfdebug_cmd_step_over_error
854 ; check if the next address is still in the current word
855 ; that next address is actually in EIP
856 mov eax,[urfsegfault_reg_esi
]
857 call urfsegfault_find_by_addr
858 jr z
,urfdebug_cmd_step_over_bad_addr
860 mov eax,[urfsegfault_reg_esi
]
861 sub eax,4 ; current instruction
862 call urfsegfault_find_by_addr
863 jr z
,urfdebug_cmd_step_over_bad_addr
865 jr nz
,urfdebug_cmd_step_over_bad_addr
867 mov eax,[urfsegfault_reg_eax
]
868 call urfsegfault_find_by_addr
869 jr z
,urfdebug_cmd_step_over_bad_addr
871 movzx eax,word [edi+2]
872 test eax,FLAG_NORETURN
873 jr nz
,urfdebug_cmd_step_over_noreturn
875 movzx eax,byte [edi+1]
876 ld
esi,[urfsegfault_reg_esi
]
877 ; check instruction argument type
879 jr z
,urfdebug_cmd_step_over_branch
881 call urfsegfault_nfa_skip_arg_type_in_eax
882 urfdebug_cmd_step_over_set_sobp:
883 ; setup debugger activation address
884 ld
dword [urfdebug_sobp_address
],esi
885 ; done, deactivate debugger
886 ;;jp urfdebug_deactivate_nocr
887 ld
dword [urfdebug_active_flag
],0
889 urfdebug_cmd_step_over_error:
890 urfsegfault_printstrnl
"step-over breakpoint already set for some strange reason!"
892 urfdebug_cmd_step_over_bad_addr:
893 ;urfsegfault_printstrnl "cannot step-over outside of the word!"
895 ; just continue into it
897 urfdebug_cmd_step_over_branch:
898 ;urfsegfault_printstrnl "cannot step over branches yet!"
900 ; just continue into it
902 urfdebug_cmd_step_over_noreturn:
903 ;urfsegfault_printstrnl "cannot step over NORETURN words!"
905 ; just continue into it
909 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
910 ;; print return stack
912 urfdebug_cmd_printrstack:
913 push dword [urfsegfault_dump_rdepth
]
914 ld
eax,[urfdebug_dump_rdepth
]
915 ld
[urfsegfault_dump_rdepth
],eax
916 call urfsegfault_cmd_printrstack
917 pop dword [urfsegfault_dump_rdepth
]
921 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
924 urfdebug_cmd_printdstack:
925 push dword [urfsegfault_dump_ddepth
]
926 ld
eax,[urfdebug_dump_ddepth
]
927 ld
[urfsegfault_dump_ddepth
],eax
928 call urfsegfault_cmd_printdstack
929 pop dword [urfsegfault_dump_ddepth
]
933 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
934 ;; deactivate debugger
936 urfdebug_cmd_deactivate:
937 jmp urfdebug_deactivate_nocr
940 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
941 ;; set data stack dump depth
944 call urfdebug_parse_number
946 urfsegfault_printstrnl
"number expected!"
951 urfsegfault_printstrnl
"minimum value is 2!"
956 urfsegfault_printstrnl
"minimum value is 200!"
960 ld
[urfdebug_dump_ddepth
],eax
964 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
965 ;; set return stack dump depth
968 call urfdebug_parse_number
970 urfsegfault_printstrnl
"number expected!"
975 urfsegfault_printstrnl
"minimum value is 2!"
980 urfsegfault_printstrnl
"minimum value is 200!"
984 ld
[urfdebug_dump_rdepth
],eax
988 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
989 ;; decompile forth word
992 ; find argument length
994 urfdebug_cmd_see_arglen_loop:
997 jr nc
,urfdebug_cmd_see_arglen_loop
1002 urfsegfault_printstrnl
"what word?"
1005 ; save starting address and length
1010 mov ebp,[urfsegfault_reg_ebp
]
1011 ld
eax,fword_par_wfind_str
1017 call urfsegfault_emit_str_ecx_edx_safe
1018 urfsegfault_printstrnl
"? what is it?"
1022 pop edx ; saved count
1023 pop ecx ; saved address
1024 call urfsegfault_emit_str_ecx_edx_safe
1025 urfsegfault_printstr
" is "
1027 call urfsegfault_find_by_addr
1030 urfsegfault_printstrnl
"some shit"
1033 ;ld esi,eax ; save cfa
1034 ;call urfsegfault_cfa2nfa
1035 ld
[urfdebug_cmd_see_nfa
],eax ; we'll need it for debug info printing
1036 call urfsegfault_nfaprint
1037 urfsegfault_printstr
" at (nfa) 0x"
1038 call urfsegfault_emit_hex_eax
1042 ld
eax,[urfsegfault_fba_nfa
]
1043 call urfsegfault_nfa2cfa
1047 jr nz
,urfdebug_cmd_see_notforth
1051 cp
ecx,fword_par_urforth_nocall_doforth
1052 jr nz
,urfdebug_cmd_see_notforth
1053 urfdebug_cmd_see_loop:
1054 cmp esi,[urfsegfault_fba_end
]
1055 jr nc
,urfdebug_cmd_see_loop_done
1056 ; print address (and store it on the stack)
1059 call urfsegfault_emit_hex_eax
1060 urfsegfault_printstr
": "
1062 call urfsegfault_cfa2nfa
1063 call urfsegfault_nfaprint
1065 call urfsegfault_nfa_print_arg
1066 ; print source code line
1069 ld
esi,[urfdebug_cmd_see_nfa
]
1070 call urfsegfault_find_pc_line_nfa
1074 urfsegfault_printstr
9,"; line #"
1076 call urfsegfault_emit_dec_eax
1081 jr urfdebug_cmd_see_loop
1083 urfdebug_cmd_see_loop_done:
1087 urfdebug_cmd_see_notforth:
1088 urfsegfault_printstrnl
"cannot decompile non-Forth words yet."
1091 urfdebug_cmd_see_nfa: dd 0
1094 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1098 ; find argument length
1099 call urfdebug_skip_blanks
1109 ;urfsegfault_printstrnl "what word?"
1112 ; save starting address and length
1117 mov ebp,[urfsegfault_reg_ebp
]
1118 ld
eax,fword_par_wfind_str
1122 ; try to parse it as a number
1127 call urfdebug_parse_number
1130 ld
edi,[urfsegfault_reg_esp
]
1131 ld
ecx,[urfsegfault_reg_ecx
]
1134 ld
[urfsegfault_reg_ecx
],eax
1135 ld
[urfsegfault_reg_esp
],edi
1139 jr urfdebug_cmd_fcall
1143 call urfsegfault_emit_str_ecx_edx_safe
1144 urfsegfault_printstrnl
"? what is it?"
1148 ; switch data stacks
1149 ld
[urfdebug_cmd_fcall_esp
],esp
1150 ld
esp,[urfsegfault_reg_esp
]
1151 ld TOS
,[urfsegfault_reg_ecx
]
1153 ld
[urfsegfault_reg_ecx
],TOS
1154 ld
[urfsegfault_reg_esp
],esp
1155 ld
esp,[urfdebug_cmd_fcall_esp
]
1156 ; skip word and continue
1160 jr urfdebug_cmd_fcall
1162 urfdebug_cmd_fcall_esp: dd 0
1165 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1166 urfdebug_tib: db 256 dup
(0)
1167 urfdebug_tib_size
= $
-urfdebug_tib