Mail Archives: djgpp/2001/11/25/08:11:01
Pleasy reply also directly to me, thanks
At 21:29 24.11.2001 +0200, you wrote:
>If the crashes are accompanied by the normal DJGPP crash message with
>registers and EIP traceback, please post here one of these messages
>in its entirety.
While composing this message i found a problem within the wrapper's code
and fixed this but now the situation gets even more worse: Under bare DOS
the program crashes without being debugged (SIGSEGV) in a call to getch()
at getch()+153 (this is after the installation of the IRQ Handler) which i
use to loop a sound until one presses a key.
DS to GS are all zero and the stack selector is invalid.
At least i'm now sure that the problem lies in my code...
>Please tell more details; it's hard to answer that question because
>it's too general. Debugging programs that hook hardware interrupts
>is a bit tricky, but should in general work.
>To give a more specific answer, we need to know what hardware
>interrupts does your program hook, and how (in protected mode, real
>mode, or both).
Oh i suspected that there would be no easy way ;-)
In my test program i'm hooking the SoundBlaster interrupt, in my case IRQ5
(INT 0D). I'm handling the interrupt completly without chaining to the
previous handler in pmode. All memory accessed by the handler is locked.
>A source of your wrapper function might be useful.
Ok, if you have time here is it:
wrapper.S:
------
#include "irq.h"
.text
.global _irqwrapper, __immediate_addr, __old_handler_off, __old_handler_sel
.global __irqwrapper_end
/* Will call the previously installed IRQ Handler if the C-Routine returns */
/* nonzero, else the old routine wont be called */
_irqwrapper:
pushal
pushw %ds
pushw %es
pushw %fs
pushw %gs
cs:
movw (___djgpp_ds_alias),%ax /* set up ds correctly */
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
movw %ss,%ax /* save old stack in ax, ebx */
movl %esp,%ebx
movl $_st,%edx
movl $-2,%ecx
xor %esi,%esi
_stack_search: /* find a free stack */
addl $2,%ecx
cmpl $MAXSTACKS * 2,%ecx
je _outofstacks
cmpl 12(%edx,%ecx,8),%esi
jnz _stack_search
incl 12(%edx,%ecx,8) /* indicate stack is in use */
movw 4(%edx,%ecx,8),%ss /* set up locked stack */
movl 8(%edx,%ecx,8),%esp /* load size of stack */
decl %esp
andl $0xfffffffc,%esp /* be sure its dword aligned */
pushl %ecx /* save index */
pushl %eax /* old ss */
pushl %ebx /* old esp */
.byte 0xb8 /* movw __immediate_addr,%eax */
__immediate_addr: .long 0x0
call *%eax /* call the irq handler */
popl %ebx /* old esp now in ebx */
popl %ecx /* old ss */
popl %esi /* get the old index into _st */
cli
movl %ebx,%esp
movw %cx,%ss /* DPMI IRQ Stack restored */
movl $_st,%edx
decl 12(%edx,%esi,8) /* stack is free for use again */
orl %eax,%eax /* shell we call the previous handler? */
jz _outofstacks /* no */
popw %gs
popw %fs
popw %es
popw %ds
popal
.byte 0xea /* far jump to previous handler */
__old_handler_off: .long 0x0
__old_handler_sel: .word 0x0
_outofstacks:
popw %gs
popw %fs
popw %es
popw %ds
popal
sti
iret
__irqwrapper_end:
------
Here comes the struct i'm using for handling the stacks:
------
struct stackInfo
{
void* addr; // holds address relative to ds (normal C Pointer)
int sel; // holds the selector used to access the stack
int size; // size of stack
int free; // 0 indicates stack is free
};
typedef struct stackInfo stacks[MAXSTACKS];
------
_st is of type stacks.
Now allocate_locked_stack() which is called MAXSTACKS-times:
------
static int firstcall_to_allocate_locked_stack = 1;
// Returns selector for this stack or otherwise -1
int allocate_locked_stack(unsigned size)
{
int i,sel;
long addr;
void* h;
if (firstcall_to_allocate_locked_stack)
{
firstcall_to_allocate_locked_stack = 0;
LOCK_VARIABLE(st);
for (i=0;i<MAXSTACKS;i++)
{
st[i].addr = 0;
st[i].sel =-1;
st[i].size = 0;
st[i].free = 0;
}
}
if (!(h = (void*)malloc(size))) return -1;
if ((sel = __dpmi_allocate_ldt_descriptors(1)) == -1)
{
free(h);
return -1;
}
__dpmi_get_segment_base_address(_my_ds(),&addr);
if (__dpmi_set_segment_base_address((unsigned short)sel,(unsigned)h + addr)\
== -1)
{
__dpmi_free_ldt_descriptor(sel);
free(h);
return -1;
}
if (__dpmi_set_segment_limit(sel,size-1) == -1)
{
__dpmi_free_ldt_descriptor(sel);
free(h);
return -1;
}
if (__dpmi_set_descriptor_access_rights(sel,DATASEG |\
((_my_cs() & 3) << 5)) == -1)
{
__dpmi_free_ldt_descriptor(sel);
free(h);
return -1;
}
// ok, sel is now ready to be used find free slot in table st
i = 0;
while ((i<MAXSTACKS) && (st[i].sel != -1)) i++;
if (i == MAXSTACKS)
{
__dpmi_free_ldt_descriptor(sel);
free(h);
return -1;
}
LOCK_DATA(h,size);
st[i].addr = h;
st[i].size = size;
return st[i].sel = sel;
}
The install_irqHandler() Routine copies the wrappers code to a newly
malloc'ed area, locks it and fills the immediate operands into the code,
this could be a critical part too:
I'm using the following defines to access the immediate operands from C:
------
extern unsigned irqwrapper;
extern unsigned _irqwrapper_end;
extern unsigned _immediate_addr;
extern unsigned _old_handler_sel;
extern unsigned _old_handler_off;
#define WRAPPERSIZE (unsigned) &_irqwrapper_end - (unsigned)
&irqwrapper
#define MY_IRQHANDLER (unsigned) &_immediate_addr - (unsigned) &irqwrapper
#define OLDHANDLER_CS (unsigned) &_old_handler_sel - (unsigned) &irqwrapper
#define OLDHANDLER_OFF (unsigned) &_old_handler_off - (unsigned) &irqwrapper
------
static int firstcall_to_install_irqHandler = 1;
static void* hand[MAXHANDLERS];
// Returns 0 if handler has been installed, else nonzero
int install_irqHandler(int vec, void* handler)
{
int i;
char* wrapperMem;
_go32_dpmi_seginfo inf;
if (firstcall_to_install_irqHandler)
{
firstcall_to_install_irqHandler = 0;
// prepare_irq_stacks() simply calls allocate_locked_stack() MAXSTACKS-
// times
if (prepare_irq_stacks() == -1) return 1;
for (i = 0; i < MAXHANDLERS; i++) hand[i] = (void*) 0;
}
i = 0;
while ((hand[i] != (void*) 0) && (i < MAXHANDLERS)) i++;
if (i == MAXHANDLERS) return 1;
if ((wrapperMem = (char*) malloc(WRAPPERSIZE)) == 0) return 1; // no mem
for wrapper
_go32_dpmi_get_protected_mode_interrupt_vector(vec,&inf);
memcpy(wrapperMem,(void*) &irqwrapper,WRAPPERSIZE); // copy the wrapper
// ohh well, casting is nice ;-)
*((unsigned*)((unsigned)(unsigned)wrapperMem + MY_IRQHANDLER)) =
(unsigned)handler; // this copies the addr. of the C-Routine into the wrapper
// The next two line copy the selector and the offset of the previous
handler into
// the wrapper
*((unsigned short*)((unsigned)(unsigned)wrapperMem + OLDHANDLER_CS)) =
inf.pm_selector;
*((unsigned*)((unsigned)(unsigned)wrapperMem + OLDHANDLER_OFF)) =
(unsigned)inf.pm_offset;
/* the code of the wrapper is in DS, in case of DJGPP this doesnt matter
'cause DS's and CS's BASE are equal */
LOCK_DATA(wrapperMem,WRAPPERSIZE);
// install the wrapper for handling the interrupt
inf.pm_selector = _my_cs();
inf.pm_offset = (unsigned long) wrapperMem;
_go32_dpmi_set_protected_mode_interrupt_vector(vec,&inf);
hand[i] = (void*)wrapperMem;
return 0;
}
I know the casting looks ugly but i didn't get it done another way and the
generated asm-source does the right thing, but maybe someone of you may
give me help how to do it better.
I hope this is not too confusing/ too much and you get an overview and can
help me.
It would be even good if you could just verify that the wrapper is correct now.
Thank you!
Martin
- Raw text -