[Wine-patches] eterbug_1990 Ловля программных исключений

Anton Rudnev =?iso-8859-1?q?mibori_=CE=C1_etersoft=2Eru?=
Сб Окт 11 14:08:35 MSD 2008


http://bugs.etersoft.ru/show_bug.cgi?id=1990#c11
----------- следующая часть -----------
From 0014db107ff300014f33f0ba0691e542a8d1abb9 Mon Sep 17 00:00:00 2001
From: Anton Rudnev <mibori на etersoft.ru>
Date: Fri, 19 Sep 2008 16:21:11 +0400
Subject: [PATCH] eterbug-1990

---
 dlls/kernel32/except.c |   38 ++++-
 dlls/ntdll/exception.c |  472 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 508 insertions(+), 2 deletions(-)

diff --git a/dlls/kernel32/except.c b/dlls/kernel32/except.c
index 21d3584..a753cd5 100644
--- a/dlls/kernel32/except.c
+++ b/dlls/kernel32/except.c
@@ -366,7 +366,7 @@ static	int	start_debugger_atomic(PEXCEPTION_POINTERS epointers)
 	/* ask for manual reset, so that once the debugger is started,
 	 * every thread will know it */
 	NtCreateEvent( &hEvent, EVENT_ALL_ACCESS, &attr, TRUE, FALSE );
-	if (InterlockedCompareExchangePointer( (PVOID)&hRunOnce, hEvent, 0 ) == 0)
+    if (InterlockedCompareExchangePointer( (PVOID)&hRunOnce, hEvent, 0 ) == 0)
 	{
 	    /* ok, our event has been set... we're the winning thread */
 	    BOOL	ret = start_debugger( epointers, hRunOnce );
@@ -466,7 +466,41 @@ LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
                                           LPTOP_LEVEL_EXCEPTION_FILTER filter )
 {
     LPTOP_LEVEL_EXCEPTION_FILTER old = top_filter;
-    top_filter = filter;
+
+
+
+    /*MIB: check WINESEHBLOCK */
+    if(!getenv("WINESEHBLOCK")){
+        top_filter = filter; // normal behaviour
+    } else {
+        char c;
+        printf(
+            "Call SetUnhandledExceptionFilter."
+            " Current filter - %x, new filter - %x.\n"
+            "[A]llow, [i]gnore(default)?:",
+            (DWORD)top_filter,
+            (DWORD)filter
+        );
+        while(1){
+            switch(c = fgetc(stdin)){
+            case 'A': c = 'a';
+            case 'a':
+                top_filter = filter;
+                printf("Allowed.\n");
+                break;
+            case '\n': c = 'i';
+            case 'I': c = 'i';
+            case 'i':
+                printf("Ignored.\n");
+                break;
+            default:
+                continue;
+            }
+            fgetc(stdin);
+            break;
+        }
+    }
+
     return old;
 }
 
diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c
index 8aa906e..e91079e 100644
--- a/dlls/ntdll/exception.c
+++ b/dlls/ntdll/exception.c
@@ -26,6 +26,8 @@
 #include <errno.h>
 #include <signal.h>
 #include <stdarg.h>
+/* MIB: for WINESEHBLOCK */
+#include <stdio.h>
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -296,6 +298,188 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
     return STATUS_UNHANDLED_EXCEPTION;
 }
 
+/*
+    table of filters, pointer to memory block:
+        item \n
+        item \n
+        ...  ...
+        item \n
+        item \0
+*/
+
+/* filters table */
+char *filters = NULL;
+        //example "code=345 addr=434534\nparameters[0]=223f4\ncode=456";
+
+char /* command */
+        *sCode        = "code",
+        *sFlag        = "flags",
+        *sParameters  = "parameters",
+        *sAddr        = "addr";
+
+
+void show_filters(){
+    char *pos = filters;
+    if(!pos)
+        printf("NULL");
+
+    for(;*pos; pos++)
+        switch(*pos){
+            case '\n': printf("\\n"); break;
+            default: printf("%c", *pos);
+        }
+    printf("\\0\n");
+}
+
+
+
+#define MAXTOKEN 32
+
+char *check_arg(EXCEPTION_RECORD *rec, CONTEXT *context, char *pos){
+    char *cur;
+    char key[MAXTOKEN], value[MAXTOKEN], ind[MAXTOKEN];
+    int i;
+    DWORD v;
+
+    /* key */
+    cur = pos;
+    for(i = 0; i < MAXTOKEN; i++, cur++){
+        if(!*cur){
+            printf("Invalid `sym-name'.\n");
+            return NULL;
+        }
+        if((*cur == '=') || (*cur == '[')) break;
+        if(isalpha(*cur)) key[i] = *cur;
+        else{
+            printf("Invalid `sym-name'.\n");
+            return NULL;
+        }
+    }
+    if(i == MAXTOKEN){
+        printf("Out of range in `sym-name'.\n");
+        return NULL;
+    }
+    key[i] = (char)0;
+
+
+    /* ind */
+    if(*cur == '['){
+        cur++;
+        for(i = 0; i < 32; cur++, i++){
+            if(!*cur){
+                printf("Invalid `index'.\n");
+                return NULL;
+            }
+            if(*cur == ']') {
+                cur++;
+                break;
+            }
+            if(isdigit(*cur)) ind[i] = *cur;
+            else {
+                printf("Invalid `index'.\n");
+                return NULL;
+            }
+        }
+        if(i == MAXTOKEN){
+            printf("Out of range in `index'.\n");
+            return NULL;
+        }
+        ind[i] = 0;
+    }
+
+
+    /* value */
+    if(*cur = '='){
+        cur++;
+        for(i = 0; i < MAXTOKEN; i++, cur++){
+            if((!*cur) && (i == 0)){
+                printf("Invalid `value'.\n");
+                return NULL;
+            }
+            if((!*cur) || (*cur == '\n') || (*cur == ' ')) break;
+            if(isxdigit(*cur)) value[i] = *cur;
+            else {
+                printf("Invalid `value'.\n");
+                return NULL;
+            }
+        }
+        if(i == MAXTOKEN){
+            printf("Out of range in `value'.\n");
+            return NULL;
+        }
+        value[i] = 0;
+    }
+
+    v = strtoul(value, (char**)NULL, 16);
+
+    if(!strcmp(key, sCode))
+        if(rec->ExceptionCode == v) return cur;
+        else return NULL;
+
+    if(!strcmp(key, sFlag))
+        if(rec->ExceptionFlags == v) return cur;
+        else return NULL;
+
+
+    if(!strcmp(key, sParameters)){
+        int idx;
+        idx = atoi(ind);
+
+        if(idx < rec->NumberParameters)
+            if(v == (rec-> ExceptionInformation)[idx]) return cur;
+            else return NULL;
+        else return NULL;
+    }
+
+    if(!strcmp(key, sAddr))
+        if(((DWORD)(rec->ExceptionAddress)) == v) return cur;
+        else return NULL;
+
+    printf("Invalid `key' name.\n");
+
+    return NULL;
+}
+
+
+char *check_string(EXCEPTION_RECORD *rec, CONTEXT *context, char *pos){
+    char *cur;
+
+    for(cur = pos; (*cur != '\n') && (*cur != '\0');){
+        char *arg;
+
+        if(*cur == ' '){
+            cur++;
+            continue;
+        }
+        arg = check_arg(rec, context, cur);
+
+        if(!arg){
+            while(!((*cur == 0) || (*cur == '\n'))) cur++;
+            return  cur;
+        } else
+            cur = arg;
+    }
+
+    return NULL;
+}
+
+BOOL auto_continue(EXCEPTION_RECORD *rec, CONTEXT *context){
+    char *pos;
+
+    if(!filters) return FALSE;
+
+    for(pos = filters; *pos;){
+        if(*pos == '\n'){
+            pos++;
+            continue;
+        }
+        pos = check_string(rec, context, pos);
+        if(!pos) return TRUE;
+    }
+
+    return FALSE;
+}
+
 
 /*******************************************************************
  *		raise_exception
@@ -348,6 +532,294 @@ static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL f
         if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
             return STATUS_SUCCESS;
 
+        { /* check $WINESEHBLOCK: */
+            char *sehBlock, command[2048];
+            int iteratorExceptionInformation;
+
+            if(sehBlock = getenv("WINESEHBLOCK"))
+                if(!strcmp(sehBlock, "all")){
+                    //char c;
+                    int loop;
+
+                    //Exception information output
+                    printf("Handled exception code=%x, flags=%x, addr=%p, parameters[%i]={",
+                        rec->ExceptionCode,
+                        rec->ExceptionFlags,
+                        rec->ExceptionAddress,
+                        rec->NumberParameters
+                    );
+
+
+
+                    for ( iteratorExceptionInformation = 0
+                        ; iteratorExceptionInformation < rec->NumberParameters
+                        ; iteratorExceptionInformation ++ )
+                        printf("%x%s",
+                            (rec->ExceptionInformation)[iteratorExceptionInformation],
+                            (iteratorExceptionInformation != rec->NumberParameters - 1)?", ": ""
+                        );
+                    printf("}\n");
+
+                    loop = !auto_continue(rec, context);
+                    if(!loop) printf("Skip.\n");
+
+
+                    while(loop){
+                        int i;
+
+                        printf("[d]ebugger, [c]ontinue, [e]xit, [h]elp:");
+                        fgets(command, 256, stdin);
+                        for(i = 0; i < 256; i++)
+                            if(command[i] == '\n')
+                                command[i] = '\x00';
+
+                        if(!strcmp("h", command)){
+                            printf(
+                                "d    Debugger\n"
+                                "c    Continue\n"
+                                "e    Exit\n"
+                                "s    List of skippers\n"
+                                "s+ SkipperString     Add new skipper\n"
+                                "s- Number            Delete skipper by number\n"
+                                "s.   Add new skipper for current handled exception\n"
+                                "s=   Add new skipper for current handled exception with parameters\n"
+                            );
+                            continue;
+                        }
+
+
+                        if(!strcmp("c", command)){
+                            break;
+                        }
+                        if(!strcmp("e", command)){
+                            exit(1);
+                        }
+                        /* Filters */
+                        if(!strcmp("s", command)){
+                            int i;
+                            char *current, *begin;
+                            if(!filters){
+                                printf("Empty list.\n");
+                                continue;
+                            }
+                            printf("Actual skippers:\n");
+                            for(i = 0, current = begin = filters; *current; current++ ){
+                                if(current == begin){
+                                    printf("  (%i)", i++);
+                                }
+                                if((*current) == '\n'){
+                                    begin = current;
+                                    begin++;
+                                    printf("\n");
+                                    continue;
+                                }
+                                printf("%c", *current);
+                            }
+                            MESSAGE("\n");
+                            continue;
+                        }
+
+                        /* add new filter */
+                        if((command[0] == 's') && (command[1] == '+')){
+                            char *pos, *begin;
+                            int l = 0;
+                            pos = &(command[2]);
+
+
+                            while(*pos == ' ')pos ++; /* skip spaces from begin */
+                            begin = pos;
+
+                            while(*pos) pos ++; /* to end */
+                            for(; *pos == ' '; pos --)
+                                *pos = (char)0; /* delete spaces from end */
+                            l = strlen(begin);
+
+                            if(filters){
+                                int lf = strlen(filters);
+                                char *p;
+
+                                filters = (char *) realloc((void *)filters, lf + l + 2);
+
+                                p = filters + lf;
+                                *p = '\n';
+                                strcpy(++p, begin);
+                            } else {
+                                filters = (char *) malloc(l + 1);
+                                strcpy(filters, begin);
+                            }
+                            continue;
+                        }
+
+                        if((command[0] == 's') && (command[1] == '=')){
+                            char f[2048];
+
+                            sprintf(f, "code=%x flags=%x addr=%x",
+                                rec->ExceptionCode,
+                                rec->ExceptionFlags,
+                                rec->ExceptionAddress
+                            );
+
+                            if(rec->NumberParameters){
+                                int i;
+
+                                for(i = 0; i < rec->NumberParameters; i++){
+                                    char arg[32];
+                                    sprintf(arg, " parameters[%i]=%x", i, (rec->ExceptionInformation)[i]);
+                                    strcat(f, arg);
+                                }
+                            }
+
+                            if(filters){
+                                int lf = strlen(filters);
+                                char *p;
+
+                                filters = (char*) realloc((void *)filters, lf + strlen(f) + 2);
+                                p = filters + lf;
+                                *p = '\n';
+                                strcpy(++p, f);
+                            } else {
+                                filters = (char *) malloc (strlen(f) + 1);
+                                strcpy(filters, f);
+                            }
+                            continue;
+                        }
+
+
+
+                        if((command[0] == 's') && (command[1] == '.')){
+                            char f[128];
+
+                            sprintf(f, "code=%x flags=%x addr=%x",
+                                rec->ExceptionCode,
+                                rec->ExceptionFlags,
+                                rec->ExceptionAddress
+                            );
+
+                            if(filters){
+                                int lf = strlen(filters);
+                                char *p;
+
+                                filters = (char*) realloc((void *)filters, lf + strlen(f) + 2);
+                                p = filters + lf;
+                                *p = '\n';
+                                strcpy(++p, f);
+                            } else {
+                                filters = (char *) malloc (strlen(f) + 1);
+                                strcpy(filters, f);
+                            }
+                            continue;
+                        }
+
+
+
+                        /* delete skipper from table */
+                        if((command[0] == 's') && (command[1]=='-')){
+                            int filtN = -1;
+
+                            /* if filter list is empty */
+                            if(!filters) continue;
+
+                                /* parse argument */
+                            {   char *pos = command + 2, *begin;
+
+                                while(*pos == ' ') pos ++; /* skip spaces from begin */
+                                begin = pos;
+                                while(*pos == ' ') pos ++; /* to end */
+                                for(; *pos == ' '; pos --)
+                                    *pos = (char)0;        /* delete spaces from end */
+
+                                filtN = atoi(begin);       /* convert string to number */
+                                if(filtN < 0){
+                                    printf("Invalid argument.\n");
+                                    continue;
+                                }
+                            }
+                                /* delete skipper */
+                            {   char *pos;
+                                int count = 0;
+
+                                for(pos = filters; *pos; pos ++)
+                                    if(*pos == '\n')
+                                        count ++;
+                                count ++;
+
+                                if (filtN >= count){
+                                    printf("Filter not found.\n");
+                                    continue;
+                                }
+
+                                if ((filtN == 0) && (count == 1)){ /* delete all memory block */
+                                    free((void *)filters);
+                                    filters = NULL;
+
+                                    continue;
+                                } /* delete all memory block */
+
+                                if ((filtN == 0) && (count != 1)){ /* delete first skipper */
+                                    char *new_filters, *begin;
+
+                                    pos = filters;
+                                    while(*pos != '\n') pos ++;     /* to first `/n` */
+                                    begin = pos ++;
+                                    while(*pos)pos ++;              /* to end        */
+
+                                    new_filters = (char *) malloc((size_t)pos - (size_t)begin + 1);
+                                    memcpy((void *) new_filters, (void *) (begin + 1), (size_t)pos - (size_t)begin);
+                                    free(filters);
+                                    filters = new_filters;
+                                    continue;
+                                } /* delete first skipper */
+
+                                if(filtN == count - 1){           /* delete last skipper */
+                                    int i;
+                                    for(i = 0, pos = filters; i < filtN; pos ++)
+                                        if(*pos == '\n') i++;
+                                    /* *pos = '\n'  */
+                                    pos--;
+                                    *pos = (char)0;
+                                    filters = (char *) realloc((void *)filters, (size_t)(pos + 1) - (size_t) filters);
+                                    continue;
+                                } /* delete last skipper */
+
+                                /* delete skipper by number */
+                                {   int i;
+                                    char *second, *new_filters;
+
+                                    for(i = 0, pos = filters; i < filtN; pos ++)
+                                        if(*pos == '\n') i++;
+                                    pos --;
+                                    /* *pos == '\n' */
+
+                                    second = pos + 1;
+                                    while(*second != '\n') second ++;
+                                    /* *second == '\n' */
+                                    new_filters = (char *) malloc((size_t)pos - (size_t)filters + strlen(second) + 1);
+                                    memcpy((void *)new_filters, (void *)filters, (size_t)pos - (size_t)filters + 1);
+                                    strcpy(new_filters + ((size_t)pos - (size_t)filters)+1, second + 1);
+
+                                    free(filters);
+                                    filters = new_filters;
+                                    continue;
+                                } /*delete skipper by number */
+                            } /* delete skipper */
+                        }
+
+                        if(!strcmp("d", command)){ /* call debugger */
+                            EXCEPTION_POINTERS pointers;
+
+                            pointers.ExceptionRecord = rec;
+                            pointers.ContextRecord = context;
+
+                            (*unhandled_exception_filter) (&pointers);
+
+                            return STATUS_UNHANDLED_EXCEPTION;
+                        } /* call debugger */
+
+                        printf("Parse command error. Try again...\n");
+                    }
+                }
+        } /* check $WINESEHBLOCK */
+
         if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
             return status;
     }
-- 
1.5.6.GIT



Подробная информация о списке рассылки Wine-patches