Page 1 of 1
Register data from exceptions
Posted: Thu Jul 14, 2005 9:37 pm
by Crazed123
If anyone could help me figure out the correct structure to access the register data my exception stubs in assembler pass to their Pascal handlers, I'd be extremely grateful.
Code: Select all
exception_0_stub:
cli
push 0
push 0
pusha
push ds
push es
push fs
push gs
mov ax,$08
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov eax,esp
push eax
mov eax,ExceptionHandlers
call [eax]
pop eax
pop gs
pop fs
pop es
pop ds
popa
add esp,8
iret
The other exception stubs are the same except that some don't push a false error code, they each access a different index of ExceptionHandlers to find their Pascal handlers, and each one pushes its own exception number. I improvised/copied them from Bran's Kernel Development Tutorial on BonaFide and use the same structure that it recommends to access the data.
Code: Select all
type
TExceptionSavedRegisters = packed record
ds,es,fs,gs: longword;
edi,esi,ebp,esp,ebx,edx,ecx,eax: longword;
lwISRIndex,lwErrorCode: longword;
eip,cs,eflags,useresp,ss: longword;
end;
PExceptionSavedRegisters = ^TExceptionSavedRegisters;
Each Pascal handler sees its only parameter as being a PExceptionSavedRegisters pointer, which seems to be working correctly because the data being accessed is consistent, but faulty.
The problem is that for any exception I get the eip is always 0x52A112. This has happened with a naturally ocurring exception I was working on and with a contrived Divide by Zero exception I set up. Anyone know what is going wrong here, I seem to be accessing something from the register data, but not the right thing.
Re:Register data from exceptions
Posted: Thu Jul 14, 2005 10:20 pm
by AR
I think you've got your segment registers backwards. Other than that you may want to dump the contents of each entry to see which one contains EIP and figure out where it goes wrong.
Re:Register data from exceptions
Posted: Mon Jul 18, 2005 9:06 pm
by Crazed123
I wrote up a WriteRegs() function to dump the entire record to screen and got this on a contrived Divide by Zero Exception.
Code: Select all
The Global Descriptor Table is set up with code and data segments for rings 1, 2
and 3.
The basic exceptions are installed and so is the Interrupt Descriptor Table.
The Programmable Interrupt Controllers have been remapped to put IRQs $00-$0F at
IDT entries $20-$28.
gs: $8
fs: $8
es: $8
ds: $8
edi: $CDFC2
esi: $BDFC2
ebp: $813021
ebx: $013021
edx: $013021
ecx: $013021
eax: $313021
int #: $013021
error code: $013021
eip: $419001
cs: $019001
eflags: $200011
useresp: $0EE761
ss: $C20001
Division by Zero Exception
Somehow those segment registers at the top are the only ones with anything right to them.
Re:Register data from exceptions
Posted: Tue Jul 19, 2005 7:34 am
by oswizard
It looks like it should work, so I am assuming it is a problem with the pascal side. A google search turned up:
The compiler treats functions with FORTRAN or Pascal linkage as follows:
It does not prefix an underscore (_) to global names.
It converts all global names to uppercase.
It does not append type information to function names.
It pushes arguments onto the stack from left to right.
The called function cleans the stack.
Structures, floats, and doubles are returned by allocating a temporary variable on the stack and passing a hidden pointer to it. The called function copies the return values into this variable and returns a pointer to it. This method is reentrant.
So, although unrelated, you can remove the pop eax after the call [eax], as the called function cleans the stack.
I was thinking that perhaps the arguments were passed in registers, like the C __fastcall calling convention, but they are not.
Where in the register dump is 0x52A112?
Is 0x08 really the data segment descriptor? Usually 0x08 is code, 0x10 is data, and is that way in Bran's tutorial. If you set up your GDT to use 0x08 as data, that is okay.
Other than that I don't really know what to try. Perhaps you need to use pushad/popad instead of pusha/popa? Also, the SS/ESP values will only be valid if the exception came from usermode. If you came from V86 mode, then some more segment registers will be added on after SS/ESP on the stack.
Good luck,
Mike
Re:Register data from exceptions
Posted: Tue Jul 19, 2005 10:00 am
by Crazed123
Why is this topic so wide now?
The $52A112 has disappeared and been replaced by the listed eip value. That was a minor bug in my printing functions, which is now fixed.
Yes, I set my GDT so that $08 is a Ring0 data segment and $10 is Ring0 code.
Thanks for noticing about the pop eax.
The ss/esp values are just written into the structure there so I can use them if coming from usermode. For V86 mode I'll probably make a seperate register structure for seperate exception handlers. Right now I'm in kernelmode.
Let's see... the difference between pusha/popa and their *d forms is that pushad will push the 32-bit registers while pusha pushes the 16-bit, right? That might be the problem.
EDIT: I tried writing pushad/popad, and it turned out that the assembler was in 32-bit mode anyway. No change.
Re:Register data from exceptions
Posted: Tue Jul 19, 2005 6:07 pm
by oswizard
@Pype - sorry about that pre tag!
@Crazed123-
Can you post any more code, like the ExceptionHandlers pointer, the actual handler routine, and the printstring function, or some combination of them? I don't know much pascal, but the assembly looks correct. I basically do the same thing except have a common routine, and I push the seg regs before the pusha (but that better not make any difference!)
Have you tried setting a breakpoint in Bochs and stepping through the code?
That's about all I can think of now.
And by the way, never accidentally make half of your kernel paged out! My page fault handler was still valid, but its return address wasn't, and it wasn't expecting a page fault from the kernel. Infinite loop --> stack overflow --> triple fault! Argh!!!
Mike
Re:Register data from exceptions
Posted: Thu Jul 21, 2005 12:00 am
by Crazed123
Actually, it turned out to be an error in my HexToStr function that made it print backwards (fixed now AND smaller memory footprint) and the fact that I didn't zero out said string in between uses messing things up. All fixed, thanks for the help!