Raise an exception when a stub entry point is called.

diff --git a/debugger/winedbg.c b/debugger/winedbg.c
index 45dde5c..ec649cf 100644
--- a/debugger/winedbg.c
+++ b/debugger/winedbg.c
@@ -444,6 +444,16 @@
 		return TRUE;
 	    }
             break;
+        case EXCEPTION_WINE_STUB:
+            {
+                char dll[32], name[64];
+                DEBUG_ProcessGetString( dll, sizeof(dll), DEBUG_CurrThread->process->handle,
+                                        (char *)rec->ExceptionInformation[0] );
+                DEBUG_ProcessGetString( name, sizeof(name), DEBUG_CurrThread->process->handle,
+                                        (char *)rec->ExceptionInformation[1] );
+                DEBUG_Printf(DBG_CHN_MESG, "unimplemented function %s.%s called", dll, name );
+            }
+            break;
         case EXCEPTION_VM86_INTx:
             DEBUG_Printf(DBG_CHN_MESG, "interrupt %02lx in vm86 mode",
                          rec->ExceptionInformation[0]);
diff --git a/include/windef.h b/include/windef.h
index 192eff9..f1e8517 100644
--- a/include/windef.h
+++ b/include/windef.h
@@ -117,14 +117,12 @@
 # if defined(__GNUC__) && ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7)))
 #  define __stdcall __attribute__((__stdcall__))
 #  define __cdecl   __attribute__((__cdecl__))
-#  define __RESTORE_ES  __asm__ __volatile__("pushl %ds\n\tpopl %es")
 # else
 #  error You need gcc >= 2.7 to build Wine on a 386
 # endif  /* __GNUC__ */
 #else  /* __i386__ */
 # define __stdcall
 # define __cdecl
-# define __RESTORE_ES
 #endif  /* __i386__ */
 
 #define CALLBACK    __stdcall
diff --git a/include/wine/exception.h b/include/wine/exception.h
index c8d6bdd..41d0757 100644
--- a/include/wine/exception.h
+++ b/include/wine/exception.h
@@ -168,6 +168,8 @@
 
 /* Wine-specific exceptions codes */
 
+#define EXCEPTION_WINE_STUB       0x80000100  /* stub entry point called */
+
 /* unhandled return status from vm86 mode */
 #define EXCEPTION_VM86_INTx       0x80000101
 #define EXCEPTION_VM86_STI        0x80000102
diff --git a/relay32/builtin32.c b/relay32/builtin32.c
index 1ff7a98..cdb288c 100644
--- a/relay32/builtin32.c
+++ b/relay32/builtin32.c
@@ -356,21 +356,3 @@
     builtin_dlls[nb_dlls].filename = filename;
     nb_dlls++;
 }
-
-/***********************************************************************
- *           BUILTIN32_Unimplemented
- *
- * This function is called for unimplemented 32-bit entry points (declared
- * as 'stub' in the spec file).
- */
-void BUILTIN32_Unimplemented( const char *dllname, const char *funcname )
-{
-    __RESTORE_ES;  /* Just in case */
-
-    MESSAGE( "FATAL: No handler for Win32 routine %s.%s", dllname, funcname );
-#ifdef __GNUC__
-    MESSAGE( " (called from %p)", __builtin_return_address(1) );
-#endif
-    MESSAGE( "\n" );
-    ExitProcess(1);
-}
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index a8b02d2..79c75a0 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -12,6 +12,7 @@
 #include <unistd.h>
 
 #include "winbase.h"
+#include "wine/exception.h"
 #include "build.h"
 
 
@@ -155,7 +156,8 @@
             fprintf( outfile, "%s", odp->u.func.link_name);
             break;
         case TYPE_STUB:
-            fprintf( outfile, "__stub_%d", i );
+            if (odp->name[0]) fprintf( outfile, "__stub_%s", odp->name );
+            else fprintf( outfile, "__stub_%d", i );
             break;
         case TYPE_REGISTER:
             fprintf( outfile, "__regs_%d", i );
@@ -294,7 +296,6 @@
 
     fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n\n",
              input_file_name );
-    fprintf( outfile, "extern void BUILTIN32_Unimplemented( const char *dllname, const char *funcname );\n\n" );
 
     /* Reserve some space for the PE header */
 
@@ -303,7 +304,38 @@
     fprintf( outfile, "    \".align %ld\\n\"\n", page_size );
     fprintf( outfile, "    \"pe_header:\\t.fill %ld,1,0\\n\\t\");\n", page_size );
 
-    fprintf( outfile, "static const char dllname[] = \"%s\";\n", DLLName );
+    fprintf( outfile, "static const char dllname[] = \"%s\";\n\n", DLLName );
+
+    /* Output the stub function if necessary */
+
+    for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++)
+    {
+        if (odp->type != TYPE_STUB) continue;
+        fprintf( outfile, "#ifdef __GNUC__\n" );
+        fprintf( outfile, "static void __wine_unimplemented( const char *func ) __attribute__((noreturn));\n" );
+        fprintf( outfile, "#endif\n" );
+        fprintf( outfile, "static void __wine_unimplemented( const char *func )\n{\n" );
+        fprintf( outfile, "  struct exc_record {\n" );
+        fprintf( outfile, "    unsigned int code, flags;\n" );
+        fprintf( outfile, "    void *rec, *addr;\n" );
+        fprintf( outfile, "    unsigned int params;\n" );
+        fprintf( outfile, "    const void *info[15];\n" );
+        fprintf( outfile, "  } rec;\n" );
+        fprintf( outfile, "  extern void RtlRaiseException( struct exc_record * );\n\n" );
+        fprintf( outfile, "  rec.code    = 0x%08x;\n", EXCEPTION_WINE_STUB );
+        fprintf( outfile, "  rec.flags   = %d;\n", EH_NONCONTINUABLE );
+        fprintf( outfile, "  rec.rec     = 0;\n" );
+        fprintf( outfile, "  rec.params  = 2;\n" );
+        fprintf( outfile, "  rec.info[0] = dllname;\n" );
+        fprintf( outfile, "  rec.info[1] = func;\n" );
+        fprintf( outfile, "#ifdef __GNUC__\n" );
+        fprintf( outfile, "  rec.addr = __builtin_return_address(1);\n" );
+        fprintf( outfile, "#else\n" );
+        fprintf( outfile, "  rec.addr = 0;\n" );
+        fprintf( outfile, "#endif\n" );
+        fprintf( outfile, "  for (;;) RtlRaiseException( &rec );\n}\n\n" );
+        break;
+    }
 
     /* Output the DLL functions prototypes */
 
@@ -330,13 +362,12 @@
         case TYPE_STUB:
             if (odp->name[0])
                 fprintf( outfile,
-                         "static void __stub_%d() { BUILTIN32_Unimplemented(dllname,\"%s\"); }\n",
-                         odp->ordinal, odp->name );
+                         "static void __stub_%s() { __wine_unimplemented(\"%s\"); }\n",
+                         odp->name, odp->name );
             else
                 fprintf( outfile,
-                         "static void __stub_%d() { BUILTIN32_Unimplemented(dllname,\"%d\"); }\n",
+                         "static void __stub_%d() { __wine_unimplemented(\"%d\"); }\n",
                          odp->ordinal, odp->ordinal );
-            
             break;
         default:
             fprintf(stderr,"build: function type %d not available for Win32\n",
diff --git a/win32/except.c b/win32/except.c
index 6ff1219..ecfe933 100644
--- a/win32/except.c
+++ b/win32/except.c
@@ -27,7 +27,7 @@
 #include "winerror.h"
 #include "ntddk.h"
 #include "wine/exception.h"
-#include "ldt.h"
+#include "selectors.h"
 #include "callback.h"
 #include "process.h"
 #include "thread.h"
@@ -64,6 +64,81 @@
 
 
 /*******************************************************************
+ *         format_exception_msg
+ */
+static void format_exception_msg( const EXCEPTION_POINTERS *ptr, char *buffer )
+{
+    const EXCEPTION_RECORD *rec = ptr->ExceptionRecord;
+
+    switch(rec->ExceptionCode)
+    {
+    case EXCEPTION_INT_DIVIDE_BY_ZERO:
+        sprintf( buffer, "Unhandled division by zero" );
+        break;
+    case EXCEPTION_INT_OVERFLOW:
+        sprintf( buffer, "Unhandled overflow" );
+        break;
+    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+        sprintf( buffer, "Unhandled array bounds" );
+        break;
+    case EXCEPTION_ILLEGAL_INSTRUCTION:
+        sprintf( buffer, "Unhandled illegal instruction" );
+        break;
+    case EXCEPTION_STACK_OVERFLOW:
+        sprintf( buffer, "Unhandled stack overflow" );
+        break;
+    case EXCEPTION_PRIV_INSTRUCTION:
+        sprintf( buffer, "Unhandled priviledged instruction" );
+        break;
+    case EXCEPTION_ACCESS_VIOLATION:
+        if (rec->NumberParameters == 2)
+            sprintf( buffer, "Unhandled page fault on %s access to 0x%08lx",
+                     rec->ExceptionInformation[0] ? "write" : "read",
+                     rec->ExceptionInformation[1]);
+        else
+            sprintf( buffer, "Unhandled page fault");
+        break;
+    case EXCEPTION_DATATYPE_MISALIGNMENT:
+        sprintf( buffer, "Unhandled alignment" );
+        break;
+    case CONTROL_C_EXIT:
+        sprintf( buffer, "Unhandled ^C");
+        break;
+    case EXCEPTION_CRITICAL_SECTION_WAIT:
+        sprintf( buffer, "Critical section %08lx wait failed",
+                 rec->ExceptionInformation[0]);
+        break;
+    case EXCEPTION_WINE_STUB:
+        sprintf( buffer, "Unimplemented function %s.%s called",
+                 (char *)rec->ExceptionInformation[0], (char *)rec->ExceptionInformation[1] );
+        break;
+    case EXCEPTION_VM86_INTx:
+        sprintf( buffer, "Unhandled interrupt %02lx in vm86 mode",
+                 rec->ExceptionInformation[0]);
+        break;
+    case EXCEPTION_VM86_STI:
+        sprintf( buffer, "Unhandled sti in vm86 mode");
+        break;
+    case EXCEPTION_VM86_PICRETURN:
+        sprintf( buffer, "Unhandled PIC return in vm86 mode");
+        break;
+    default:
+        sprintf( buffer, "Unhandled exception 0x%08lx", rec->ExceptionCode);
+        break;
+    }
+#ifdef __i386__
+    if (ptr->ContextRecord->SegCs != __get_cs())
+        sprintf( buffer+strlen(buffer), " at address 0x%04lx:0x%08lx.\n",
+                 ptr->ContextRecord->SegCs, (DWORD)ptr->ExceptionRecord->ExceptionAddress );
+    else
+#endif
+    sprintf( buffer+strlen(buffer), " at address 0x%08lx.\n",
+             (DWORD)ptr->ExceptionRecord->ExceptionAddress );
+    strcat( buffer, "Do you wish to debug it ?" );
+}
+
+
+/*******************************************************************
  *         UnhandledExceptionFilter   (KERNEL32.537)
  */
 DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
@@ -133,11 +208,7 @@
     }
 
     if (!bAuto && Callout.MessageBoxA) {
-       sprintf( buffer, "Unhandled exception 0x%08lx at address 0x%04lx:0x%08lx.\n"
-	                "Do you wish to debug it ?",
-		epointers->ExceptionRecord->ExceptionCode,
-		epointers->ContextRecord->SegCs,
-		(DWORD)epointers->ExceptionRecord->ExceptionAddress );
+        format_exception_msg( epointers, buffer );
        if (Callout.MessageBoxA( 0, buffer, "Error", MB_YESNO | MB_ICONHAND ) == IDNO) {
 	  TRACE("Killing process\n");
 	  return EXCEPTION_EXECUTE_HANDLER;