2

I have seen all the exception "IDs" in the Intel Manuals, and just came across sandpile's exception guide, which actually shows some hexcodes. For example, "divide by zero error":

00h         #DE

Questions:

  1. What are these IDs for, just for use in the manuals for easy reference?
  2. Where do these hexcodes (or machine codes) pop up in running code?
  3. How do you test for these in your code?
  4. How do you handle them generally?

What would be an example to demonstrate their usage, essentially, like this divide by zero error? I am looking for something I could run with NASM, and a general approach to how to debug it if possible.

From my reading of the table, there are two "type types": rIP and B/C. A B is a "benign" error, meaning it can't cause a "double fault", an error in an error handler. A C is a "contributory" error, which can cause a double fault (error in an error handler). There are 3 types of rIP (what does that stand for?): trap, fault, and abort. Divide by zero is a fault rIP type, so how do you generate this error, and how do you handle it, in some example x86 assembly code?

2

Those are vectors for interrupt like int1....intn

here is sample c code that generates and a handles int0 (#DE) ,int1 (#DB) ,int3 (#BP) and int6 (#UD)

#include <stdio.h>
#include <windows.h>
unsigned int Exec_Search(unsigned int code) {
    printf("unknown Exception %x\n",code);
    return EXCEPTION_CONTINUE_SEARCH;
}
unsigned int  ExceHandler(unsigned int code ){
    printf("caught %x\n" , code);
    return EXCEPTION_EXECUTE_HANDLER;
}
int filter(unsigned int code, struct _EXCEPTION_POINTERS *){
    if( code == EXCEPTION_BREAKPOINT ) { 
        return ExceHandler(code); 
    }else if( code == EXCEPTION_ACCESS_VIOLATION  ) { 
        return ExceHandler(code); 
    }else if( code == EXCEPTION_ILLEGAL_INSTRUCTION  ) { 
        return ExceHandler(code); 
    }else { 
        return Exec_Search(code); 
    }    
}
void testint0(void){
    printf("Testing int 0\n");
    __try {
        __asm {
            int 0
        }
    } __except(filter(GetExceptionCode(), GetExceptionInformation())) {
        printf("Handler for #DE %x\n",GetExceptionCode() );
    }
}

void testint1(void){
    printf("Testing int 1\n");
    __try {
        __asm {
            int 1
        }
    } __except(filter(GetExceptionCode(), GetExceptionInformation())) {
        printf("Handler for #DB %x\n",GetExceptionCode() );
    }
}
void testint3(void){
    printf("Testing int 3\n");
    __try {
        __asm {
            int 3
        }
    } __except(filter(GetExceptionCode(), GetExceptionInformation())) {
        printf("Handler for #BP %x\n",GetExceptionCode() );
    }
}

void testint6(void){
    printf("Testing int 6\n");
    __try {
        __asm {
            ud2
        }
    } __except(filter(GetExceptionCode(), GetExceptionInformation())) {
        printf("Handler for #UD %x\n",GetExceptionCode() );
    }
}
int main (void) {    
    testint1(); 
    testint3();
    testint0();
    testint6();    
    printf("normal program continuation\n");
} 

compiled and executed

:\>cl /Zi /W4 /analyze /Od /EHsc /nologo inthash.cpp /link /release
inthash.cpp

:\>inthash.exe
Testing int 1
caught c0000005
Handler for #DB c0000005
Testing int 3
caught 80000003
Handler for #BP 80000003
Testing int 0
caught c0000005
Handler for #DE c0000005
Testing int 6
caught c000001d
Handler for #UD c000001d
normal program continuation

for generating and handling divide_by_zero
one could add a testcase like this

void testdiv0(void){
    printf("Testing integer divided by 0\n");
    __try {
        __asm {
            mov edx,0 // remainder
            mov eax,0 // dividend
            mov ecx,0 // divisor
            div ecx   // doing 0/0
        }
    } __except(filter(GetExceptionCode(), GetExceptionInformation())) {
        printf("Handler for #DE %x\n",GetExceptionCode() );
    }
}

Add a filter clause like this

else if( code == EXCEPTION_INT_DIVIDE_BY_ZERO  ) { 
        return ExceHandler(code); 

and execute it in main with

testdiv0();

resulting in

Testing integer divided by 0
caught c0000094
Handler for #DE c0000094
normal program continuation
1
  • How do you do this entirely in assembly? Jan 30 at 23:15
2

The CPU exceptions are reported to the OS fault handler which then may either terminate the program or notify it via an OS specific mechanism. On Windows this is Structured Exception Handling (SEH), on Unix-like systems usually signals. Check your OS documentation for more info.

If you want to learn how to handle the raw exceptions yourself, you basically need to write an OS. Osdev wiki may be a start, otherwise see the processor manuals (system programming volume).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.