[Solved] C++ - Only divide by zero is caught

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
User avatar
max9403
Posts: 17
Joined: Sun Feb 09, 2014 3:25 pm

[Solved] C++ - Only divide by zero is caught

Post by max9403 »

The divide by zero is caught correctly (at least it appears so) and reports error "0" but when I try to call

Code: Select all

__asm__ __volatile__ ("INT3")
It returns error code 4026595393 (it is consistent through a complete rebuild, as well as if I were to use random letters instead of INT3) instead of 2. The assembly for both exceptions are the same with the difference only being in the name

Code: Select all

isr<number>:
     cli
     push 0x0
     push 0x<Hex value of number>
     call isr_handler

isr_handler:
     pusha
     push %ds
     push %es
     push %fs
     push %gs
     mov %ax, 0x10
     mov %ds, %ax
     mov %es, %ax
     mov %fs, %ax
     mov %gs, %ax
     call <C function>
     pop %gs
     pop %fs
     pop %es
     pop %ds
     popa
     add %esp, 8
     iret
and this is my C function:

Code: Select all

		struct regs {
			unsigned int gs, fs, es, ds;
			unsigned int edi, esi, edp, esp, ebx, edx, ecx, eax;
			unsigned int int_no, err_code;
			unsigned int eip, cs, eflags, usersp, ss;
		};
	extern "C" {
		void fault_handler(struct regs* r) {
		     Terminal::print("Error: ");
		     Terminal::println(Functions::intToChar(r->int_no));
     
		     if(r->int_no < 32) {
		          Terminal::println(exceptionMessage[r->int_no]);
		     }
		     for(;;);
		}
	}
I'm guess there is an error in my idt set gate function but I'm lost as to what it could be:

Code: Select all

struct IDT::idt_entry {
	uint16_t base_low;
	uint16_t sel;
	uint8_t always0;
	uint8_t flags;
	uint16_t base_hi;
} __attribute__((packed));

void IDT::idtSetGate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags) {
	idt[num].base_low = (base & 0xFFFF);
	idt[num].base_hi = (base >> 16) & 0xFFFF;
	
	idt[num].sel = sel;
	idt[num].always0 = 0;
	idt[num].flags = flags;
}
In case you want to read through the rest of the source here is a link to it and you can ask question if you want - not that I'd stop you XD

Any help is appreciated, include how to create other exception, I followed a tutorial on osdever.net on how to setup the GPT, etc and peeked at the source of this tutorial: http://www.websofia.com/writing-your-own-toy-operating-system/ (there is source code in C for a kernel in the complete source he gives - which looks similar to how the tutorial osdev.net has implemented it), the tutorial on osdev.net was also C based and I have tried to convert it to C++ as much as I can
Last edited by max9403 on Sat Apr 12, 2014 4:48 am, edited 1 time in total.
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: C++ - Only divide by zero is caught

Post by qw »

After a quick look: isr_handler isn't pushing the argument to the C function, and esp is not balanced correctly at the end.
User avatar
max9403
Posts: 17
Joined: Sun Feb 09, 2014 3:25 pm

Re: C++ - Only divide by zero is caught

Post by max9403 »

Thanks I'll look into how to pass it properly, about the esp are you talking about the add %esp 8?

Originally the function was called like this:

Code: Select all

move %eax, %esp
push %eax
mov %eax, <c function>
call %eax
pop %eax
however that would make bochs spew "LOCK prefix unallowed" which I'm guessing means it isn't calling the function it goes somewhere else, is that correct assumption?
Nable
Member
Member
Posts: 453
Joined: Tue Nov 08, 2011 11:35 am

Re: C++ - Only divide by zero is caught

Post by Nable »

max9403 wrote:which I'm guessing means it isn't calling the function it goes somewhere else, is that correct assumption?
Assumptions are fu^W evil. You can use bochs's built-in debugger (very nice tool) to find what is actually happening.
User avatar
max9403
Posts: 17
Joined: Sun Feb 09, 2014 3:25 pm

Re: C++ - Only divide by zero is caught

Post by max9403 »

it would only say "LOCK prefix unallowed" in the console, guess I'll go enable the GUI
cyr1x
Member
Member
Posts: 207
Joined: Tue Aug 21, 2007 1:41 am
Location: Germany

Re: C++ - Only divide by zero is caught

Post by cyr1x »

Try "pushl" instead of "push". AFAIK "push" will sign-extend the operand.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: C++ - Only divide by zero is caught

Post by jnc100 »

You probably want to replace 'call isr_handler' with 'jmp isr_handler' as you do not need the extra information that call pushes to the stack (as you iret directly from 'isr_handler') and this extra information will be placed between 'intno' and 'eax' in your structure.

Having said this, pushing the registers like this makes significant assumptions on how the particular ABI you are using passes structures to functions.

Regards,
John.
User avatar
max9403
Posts: 17
Joined: Sun Feb 09, 2014 3:25 pm

Re: C++ - Only divide by zero is caught

Post by max9403 »

cyr1x wrote:Try "pushl" instead of "push". AFAIK "push" will sign-extend the operand.
this is what my function looks like at the moment:

Code: Select all

.code32
.inter_syntax noprefix

--snip--

.extern fault_handler
isr_common_stub:
	xchg bx, bx
	pusha
	push ds
	push es
	push fs
	push gs
	xchg bx, bx
	mov ax, 0x10
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov eax, esp
	push eax
	xchg bx, bx
	lea eax, fault_handler
	xchg bx, bx
	call eax
	xchg bx, bx
	pop eax
	pop gs
	pop fs
	pop es
	pop ds
	popa
	add esp, 8
	iret
--snip--
in bochs with the AT&T switch enable it looks like this:

Code: Select all

	xchgw %bx, %bx
	pushal
	pushl %ds
	pushl %es
	pushl %fs
	pushl %gs
	xchgw %bx, %bx
	movw $0x0010, %ax
	movw %ax, %ds
	movw %ax, %es
	movw %ax, %fs
	movw %ax, %gs
	movl %esp, %eax
	pushl %eax
	xchgw %bx, %bx
	leal %ds:0x1009e0, %eax
	xchgw %bx, %bx
	call %eax
	xchgw %bx, %bx
	popl %eax
	popl %gs
	popl %fs
	popl %es
	popl %ds
	popal
	addl $0x00000008, %esp
	iretd
(btw it won't let me assemble it if change it to pushl manually guessing that has to do with the .intel_syntax)

while using objdump it gives me this:

Code: Select all

100176:	66 87 db             	xchg   %bx,%bx
  100179:	60                   	pusha  
  10017a:	1e                   	push   %ds
  10017b:	06                   	push   %es
  10017c:	0f a0                	push   %fs
  10017e:	0f a8                	push   %gs
  100180:	66 87 db             	xchg   %bx,%bx
  100183:	66 b8 10 00          	mov    $0x10,%ax
  100187:	8e d8                	mov    %eax,%ds
  100189:	8e c0                	mov    %eax,%es
  10018b:	8e e0                	mov    %eax,%fs
  10018d:	8e e8                	mov    %eax,%gs
  10018f:	89 e0                	mov    %esp,%eax
  100191:	50                   	push   %eax
  100192:	66 87 db             	xchg   %bx,%bx
  100195:	8d 05 e0 09 10 00    	lea    0x1009e0,%eax
  10019b:	66 87 db             	xchg   %bx,%bx
  10019e:	ff d0                	call   *%eax
  1001a0:	66 87 db             	xchg   %bx,%bx
  1001a3:	58                   	pop    %eax
  1001a4:	0f a9                	pop    %gs
  1001a6:	0f a1                	pop    %fs
  1001a8:	07                   	pop    %es
  1001a9:	1f                   	pop    %ds
  1001aa:	61                   	popa   
  1001ab:	83 c4 08             	add    $0x8,%esp
  1001ae:	cf                   	iret 
now my function is called but it still gets the wrong data

if it helps here is the data that are in the registers when it handles the error:

Code: Select all

pushad

eax 13 0xd
ebx 65536 0x10000
ecx 4 0x4
edx 981 0x3d5
esi 0
edi 0
ebp 0
esp 1079388 0x10785c
eip 1048953 0x100179
eflags 0x200097

cs 0x8
ds 0x10
es 0x10
ss 0x10
fs 0x10
gs 0x10

after push

esp 1079340 0x10782c
eip 1048963 0x100179

after mov

eax 1079340 0x10782c
esp 1079336 0x107828
eip 1048981 0x100195

call
eax 1051104 0x1009e0 <- address of C function
eip 1048990 0x10019e

printing error number
eax 0 0x0
ebx 1048682 0x1006a
esi 1079340 0x10782c
esp 1079304 0x107808
eip 1051129 0x1009f9
eflags 0x200046
and this is my stack before isr_common_stub is called:

Code: Select all

10785C 1048682 0x10006a
107860 3 0x3
107864 0 0x0
107868 1051270 0x100a86
10786C 16 0x10
107870 2097815 0x200297
107874 13 0xd
107878 0 0x0
10787C 0 0x0
107880 0 0x0
107884 0 0x0
107888 0 0x0
10788C 65536 0x10000
107890 1048598 0x100016
107894 1342177283 0x50000003
107898 1183036943 0x4683b60f
10789C 1342177283 0x50000003
1078A0 0 0x0
1078A4 0 0x0
1078A8 0 0x0
1078AC 0 0x0
1078B0 0 0x0
1078B4 1048576 0x100000
1078B8 0 0x0
1078BC 65539 0x10003
1078C0 0 0x0
1078C4 1052470 0x0100f36
1078C8 0 0x0
1078CC 131075 0x20003
1078D0 0 0x0
1078D4 1052908 0x1010ec
1078D8 0 0x0
1078DC 196611 0x30003
1078E0 0 0x0
1078E4 1056768 0x102000
1078E8 0 0x0
1078EC 262147 0x40003
1078F0 0 0x0
1078F4 1060864 0x103000
1078F8 0 0x0
1078FC 327683 0x50003
107900 0 0x0
107904 0 0x0
107908 0 0x0
10790C 393219 0x6003
107910 1 0x1
107914 0 0x0
107918 0 0x0
10791C -983036 0xfff10004
107920 13 0xd
and this is my stack just before the call to the C function:

Code: Select all

107828 1079340 0x10782c
10782C 16 0x10
107830 1048592 0x100010
107834 16 0x10
107838 16 0x10
10783C 0 0x0
107840 0 0x0
107844 0 0x0
107848 1079388 0x10785c
10784C 65536 0x10000
107850 981 0x3d5
107854 4 0x4
107858 13 0xd
10785C 1048682 0x10006a
107860 3 0x3
107864 0 0x0
107868 1051270 0x100a86
10786C 16 0x10
107870 2097815 0x200297
107874 13 0xd
107878 0 0x0
10787C 0 0x0
107880 0 0x0
107884 0 0x0
107888 0 0x0
10788C 65536 0x10000
107890 1048598 0x100016
107894 1342177283 0x50000003
107898 1183036943 0x4683b60f
10789C 1342177283 0x50000003
1078A0 0 0x0
1078A4 0 0x0
1078A8 0 0x0
1078AC 0 0x0
1078B0 0 0x0
1078B4 1048576 0x100000
1078B8 0 0x0
1078BC 65539 0x10003
1078C0 0 0x0
1078C4 1052470 0x0100f36
1078C8 0 0x0
1078CC 131075 0x20003
1078D0 0 0x0
1078D4 1052908 0x1010ec
1078D8 0 0x0
1078DC 196611 0x30003
1078E0 0 0x0
1078E4 1056768 0x102000
1078E8 0 0x0
1078EC 262147 0x40003
Edit: Seems if found out what was causing bad info to be passed to the C was the isr_common_stub was being "called" instead of being "jumped" to :oops: XD ninjad by jnc100
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: [Solved] C++ - Only divide by zero is caught

Post by Bender »

I think from those function names you're following "JamesM's Roll your own UNIX Clone".
If yes, then see: http://wiki.osdev.org/James_Molloy's_Tu ... Known_Bugs
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
User avatar
max9403
Posts: 17
Joined: Sun Feb 09, 2014 3:25 pm

Re: [Solved] C++ - Only divide by zero is caught

Post by max9403 »

Bender wrote:I think from those function names you're following "JamesM's Roll your own UNIX Clone".
If yes, then see: http://wiki.osdev.org/James_Molloy's_Tu ... Known_Bugs
XD no I'm not, I'm using bkerndev by Brandon Friesen and mixing it with the wiki but thanks for the info :D (I used the wiki to setup the basics and looked at his tutorial for setting up the IDTs, GDTs, IRQs and ISRs)

Edit: since I'm home again going to figure out why the IRQs aren't working...
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: [Solved] C++ - Only divide by zero is caught

Post by qw »

max9403 wrote:Thanks I'll look into how to pass it properly, about the esp are you talking about the add %esp 8?
Yes, compare this:

Code: Select all

     push 0x0
     push 0x<Hex value of number>
     call isr_handler
With this:

Code: Select all

     add %esp, 8
User avatar
max9403
Posts: 17
Joined: Sun Feb 09, 2014 3:25 pm

Re: [Solved] C++ - Only divide by zero is caught

Post by max9403 »

Hobbes wrote:
max9403 wrote:Thanks I'll look into how to pass it properly, about the esp are you talking about the add %esp 8?
Yes, compare this:

Code: Select all

     push 0x0
     push 0x<Hex value of number>
     call isr_handler
With this:

Code: Select all

     add %esp, 8
It removes the 0x0 and 0x<value> from the stack so that the stack is restored to the way it was before the function is called/jumped so I'm not sure how it is unbalanced however now I'm stuck with why iret crashes my OS :?
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: [Solved] C++ - Only divide by zero is caught

Post by sortie »

Because the call instruction pushes the return value and jumps, while the jmp instruction just jumps?
User avatar
max9403
Posts: 17
Joined: Sun Feb 09, 2014 3:25 pm

Re: [Solved] C++ - Only divide by zero is caught

Post by max9403 »

sorry, I miss read the code he showed, I'm using jmp in my code instead of call (at least recently) which then ended me up here: General protection fault on return from any interrupt (look at my edit about 6 replies ago :P)
Post Reply