VOGONS


First post, by GloriousCow

User metadata
Rank Member
Rank
Member

I come seeking advice for how to implement what I thought should be a fairly straightforward emulator feature - I'd like to be able to set a breakpoint on DOS program start.
I know I can run a debugger under emulation, but it would be nice if I could just pause the emulator at the first instruction of a new program run from command.com. I can sort of do this knowing that the first program I run after boot will usually be loaded at a specific address assuming the machine parameters and DOS version are the same, but it's a hack and only works for the first program run. For DOS 3.3, for example, the first program will usually get loaded at 0CA2:0100. For DOS 5.0, it's 0F19:0100. I'd really like something that didn't rely on magic numbers.

int21h, 4b (https://stanislavs.org/helppc/int_21-4b.html) seemed like a promising place to start. But it doesn't seem to return while the process is running.
Stanislav's lists int21, 55h (https://stanislavs.org/helppc/int_21-55.html) as an undocumented interrupt that sets up a new PSP. It says it is valid from DOS 2.0 and on, but I don't actually see it called on either DOS 3.3 or 5 when logging all interrupt 21h calls.

All I really need is some reliable way to determine the code segment of the new process after int21h, 4bh is invoked. Any ideas?

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 1 of 8, by superfury

User metadata
Rank l33t++
Rank
l33t++

Well, DOS transfers to segment:100h after loading the binary and setting up it's data/stack segments (although for .COM executables only. .EXE have it in their file headers, which are dynamically allocated).

In UniPCemu, you can specify a breakpoint with just an offset, making it ignore the segment part of the breakpoint.
Just add O to the breakpoint segment:offset.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 3 of 8, by GloriousCow

User metadata
Rank Member
Rank
Member
superfury wrote on 2023-02-19, 09:53:

Well, DOS transfers to segment:100h after loading the binary and setting up it's data/stack segments (although for .COM executables only. .EXE have it in their file headers, which are dynamically allocated).

In UniPCemu, you can specify a breakpoint with just an offset, making it ignore the segment part of the breakpoint.
Just add O to the breakpoint segment:offset.

That's an elegant solution for COM files. Don't know why I didn't think of it. Shame it won't work for EXE files, but at least that will help me debug MUSHROOM.COM.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 4 of 8, by llm

User metadata
Rank Member
Rank
Member

its not clear what you are trying to reach?

debugging of DOS exe or com programs can be done using:
-(very archaic) using the debug command from a real MS DOS: https://en.wikipedia.org/wiki/Debug_(command)
-using the dosbox internal debugger (much better then the real DOS debugger): Guide to the DOSBox debugger
-Turbo Debugger from Borland or WD Debugger from Open Watcom V2: https://en.wikipedia.org/wiki/Borland_Turbo_Debugger, https://github.com/Baron-von-Riedesel/HX-OpenWatcom-Debugger
-serveral other DOS-able debuggers - but i normaly only using the dosbox debugger for my reversing projects

maybe you don't know that there are so many working debugger solutions for DOS or i didn't understand you questions

but for understanding a (maybe small) COM program like MUSHROOM.COM the best option is a disassembler like IDA Pro or Ghidra, im always using my licensed version of IDA for reversing and re-assembling of DOS programs

Official IDA Pro 5 Freeware: https://www.scummvm.org/news/20180331/ - the only Freeware Version that supports DOS EXE/COM

but at least that will help me debug MUSHROOM.COM.

the song playing thing?

Reply 5 of 8, by GloriousCow

User metadata
Rank Member
Rank
Member
llm wrote on 2023-03-03, 07:04:

its not clear what you are trying to reach?
...
maybe you don't know that there are so many working debugger solutions for DOS or i didn't understand you questions

I'm writing my own emulator. I would like to be able to drop into my emulator's native debugger when a program starts. I am aware I can debug inside the emulated machine, but that's not exactly what I'm looking for.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 7 of 8, by llm

User metadata
Rank Member
Rank
Member
jmarsh wrote on 2023-03-05, 00:02:

Write your own .com that calls int21.4b with al=1 to load the program to be debugged, then jump to the new ip with the trap flag set (or some other method to notify your emulator to break).

jmarsh idea is the best i think - you can't activate a debugger by just hooking some interrupts because you're then too early in the process

but some sort of "preapre for debug" program that that loads (and not directly executes - as jmars explains) with int 21h/4b/al=1 combined with some control-handover to your emulation (using interrupts, ports, whatever to let your emulation know that it should start the internal debugger) is i think the only good or always working solution

Reply 8 of 8, by GloriousCow

User metadata
Rank Member
Rank
Member
jmarsh wrote on 2023-03-05, 00:02:

Write your own .com that calls int21.4b with al=1 to load the program to be debugged, then jump to the new ip with the trap flag set (or some other method to notify your emulator to break).

Thanks, I went with this method and it works pretty well. Now I'm wondering if I couldn't intercept calls to 4bh and actually change the parameter of AH to 1, then intercept the write to the parameter block.

execute:
mov ax, ds
mov word [pb_cmdline_seg], ax ; Fill out data segment for command line param
mov ax, word [cmdline]
mov word [pb_cmdline_offset], ax ; Fill out offset for command line param
mov ah, 4bh ; EXEC/Load and Execute Program
mov al, 01h ; Create program segment prefix but don't execute
mov dx, fn_buf ; Point to filename
mov bx, pb_env_seg ; ES:BX to parameter block
clc
int 21h ; Execute
jnc success
jmp fail

success:
mov ah, 09h
mov dx, execute_ok
int 21h
mov ah, 01h ; Emulator service 01h = debug program
mov bx, [pb_cs]
mov cx, [pb_ip]
int 0fch ; Emulator service interrupt
jmp exit

Appreciate everyone's suggestions!

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc