Date: Thu, 30 Dec 1999 09:23:46 +0200 (IST) From: Eli Zaretskii X-Sender: eliz AT is To: salvador cc: djgpp-workers AT delorie DOT com, Charles Sandmann Subject: Re: GDB, DOS 6.22, CWSDPMI and Interrupts In-Reply-To: <386A109F.34C6272F@inti.gov.ar> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Reply-To: djgpp-workers AT delorie DOT com X-Mailing-List: djgpp-workers AT delorie DOT com X-Unsubscribes-To: listserv AT delorie DOT com Precedence: bulk [Note that I've redirected this thread to djgpp-workers. For those who didn't follow the thread on c.o.m.d.: Salvador have found that under a debugger, programs enter `main' with interrupts disabled and don't get any interrupts unless they call a real-mode service.] On Wed, 29 Dec 1999, salvador wrote: > The following program: > > #include > #include > #include > > int main(int argc, char *argv[]) > { > int rv; > time_t tiempo; > __asm__ __volatile__("pushf; popl %0" : "=g" (rv)); > rv = (rv>>9) & 1; > printf("%d\n",rv); > > //enable(); > > unsigned long cont; > tiempo=time(0); > for (cont=0;cont<0xfffffffe;cont++); > tiempo=time(0)-tiempo; > printf("Tiempo: %d\n",tiempo); > > return 0; > } > > Gives 24 outside the debugger and 0 inside the debugger. > > Note: If I uncomment the enable() line the program works, but the > real program doesn't (interrupts gets disabled automagically). I looked into this and I think I understand the cause, at least in part. The debuggee starts like it should, with the interrupt bit set (`v2loadimage' initializes EFLAGS to 0x3202), but it gets reset inside the startup code, more then once. (In the simple test program that you posted earlier, I can get the normal behavior if I issue a STI at the beginning of `main'.) To get a clear picture, I ran the startup code with a watchpoint set right on the interrupt bit in EFLAGS (it's amazing how easy this is with GDB!), and saw the places where the bit gets reset. It looks like the culprit is in the following fragment from _i31_hook (on dbgcom.c): Lc31_set_flags_and_iret: pushl %eax pushf popl %eax /* store the right flags for iret */ movl %eax,12(%esp) popl %eax Lc31_iret: iret As far as I could see, every function of Int 31h hooked by dbgcom.c which ends up in this fragement, returns to the debuggee with the interrupt bit reset. This fragment survived unaltered since at least v2.01 (and I suspect in v2.0 as well), the only changes were that more and more functions of Int 31h are hooked and pass through this code. I think this explains why all debuggers, including the old ports, exhibit the bug. Can someone spot what's wrong with this code and suggest how to repair it? It is also possible that the actual problem is not with the above fragment per se, but with the Lc31_* hooks that jump to it: I see that some of them don't preserve EFLAGS across calls to subroutines like _change_handle, _add_descriptors, etc. Until the problem is solved in dbgcom.c, a work-around would be to insert __asm__("sti") at the beginning of `main' and after each function call that can possibly call one of the affected DPMI functions. The most probable candidates are `malloc', `free', and `realloc'; functions that allocate/free DOS memory; and functions that allocate and free selectors. The `malloc' case is probably the nastiest, since library functions and any non-trivial program call it all over the place. Perhaps hacking `malloc' and `free' to add a STI would be a good idea, if this problem prevents you from debugging some program efficiently.