Register data from exceptions

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Crazed123

Register data from exceptions

Post 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.
AR

Re:Register data from exceptions

Post 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.
Crazed123

Re:Register data from exceptions

Post 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.
oswizard

Re:Register data from exceptions

Post 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
Crazed123

Re:Register data from exceptions

Post 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.
oswizard

Re:Register data from exceptions

Post 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
Crazed123

Re:Register data from exceptions

Post 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!
Post Reply