changeset 154:5cb946f323d2 trunk

[svn r160] Added cleaned version of dmd's linux exception runtime
author ChristianK
date Tue, 25 Mar 2008 18:25:24 +0100
parents 2c447715c047
children 7f92f477ff53
files tango/lib/compiler/llvmdc/deh2.d
diffstat 1 files changed, 305 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tango/lib/compiler/llvmdc/deh2.d	Tue Mar 25 18:25:24 2008 +0100
@@ -0,0 +1,305 @@
+/*
+ *  Copyright (C) 1999-2005 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+// Exception handling support for linux
+
+//debug=1;
+
+extern (C)
+{
+    extern void* _deh_beg;
+    extern void* _deh_end;
+
+    int _d_isbaseof(ClassInfo oc, ClassInfo c);
+}
+
+// One of these is generated for each function with try-catch or try-finally
+// all of these structs are located between _deh_beg and _deh_end
+struct FuncTable
+{
+    void *fptr;                 // pointer to start of function
+    DHandlerTable *handlertable; // eh data for this function
+    uint fsize;         // size of function in bytes
+}
+
+// lists all try-catch and try-finally blocks for a given function
+// searched for by eh_finddata()
+struct DHandlerTable
+{
+    void *fptr;                 // pointer to start of function, used but seems redundant
+    uint espoffset;             // offset of ESP from EBP
+    uint retoffset;             // offset from start of function to return code, unused!
+    uint nhandlers;             // dimension of handler_info[]
+    DHandlerInfo handler_info[1];
+}
+
+// information for a single try-finally or try-catch block
+struct DHandlerInfo
+{
+    uint offset;                // offset from function address to start of guarded section
+    uint endoffset;             // offset of end of guarded section
+    int enclosing_index;        // enclosing table index, for nested trys
+    uint cioffset;              // offset to DCatchInfo data from start of DHandlerTable 
+                                // (!=0 if try-catch)
+    void *finally_code;         // pointer to finally code to execute
+                                // (!=0 if try-finally)
+}
+
+// Create one of these for each try-catch
+struct DCatchInfo
+{
+    uint ncatches;                      // number of catch blocks
+    DCatchBlock catch_block[1];         // data for each catch block
+}
+
+// one for each catch in try-catch
+struct DCatchBlock
+{
+    ClassInfo type;             // catch type
+    uint bpoffset;              // EBP offset of catch var
+    void *code;                 // catch handler code
+}
+
+
+alias int (*fp_t)();   // function pointer in ambient memory model
+
+void terminate()
+{
+    asm
+    {
+        hlt ;
+    }
+}
+
+/*******************************************
+ * Given address that is inside a function,
+ * figure out which function it is in.
+ * Return DHandlerTable if there is one, NULL if not.
+ */
+
+DHandlerTable *__eh_finddata(void *address)
+{
+    FuncTable *ft;
+
+//    debug printf("__eh_finddata(address = x%x)\n", address);
+//    debug printf("_deh_beg = x%x, _deh_end = x%x\n", &_deh_beg, &_deh_end);
+    for (ft = cast(FuncTable *)&_deh_beg;
+         ft < cast(FuncTable *)&_deh_end;
+         ft++)
+    {
+//      debug printf("\tfptr = x%x, fsize = x%03x, handlertable = x%x\n",
+//              ft.fptr, ft.fsize, ft.handlertable);
+
+        if (ft.fptr <= address &&
+            address < cast(void *)(cast(char *)ft.fptr + ft.fsize))
+        {
+//          debug printf("\tfound handler table\n");
+            return ft.handlertable;
+        }
+    }
+//    debug printf("\tnot found\n");
+    return null;
+}
+
+
+/******************************
+ * Given EBP, find return address to caller, and caller's EBP.
+ * Input:
+ *   regbp       Value of EBP for current function
+ *   *pretaddr   Return address
+ * Output:
+ *   *pretaddr   return address to caller
+ * Returns:
+ *   caller's EBP
+ */
+
+uint __eh_find_caller(uint regbp, uint *pretaddr)
+{
+    uint bp = *cast(uint *)regbp;
+
+    if (bp)         // if not end of call chain
+    {
+        // Perform sanity checks on new EBP.
+        // If it is screwed up, terminate() hopefully before we do more damage.
+        if (bp <= regbp)
+            // stack should grow to smaller values
+            terminate();
+
+        *pretaddr = *cast(uint *)(regbp + int.sizeof);
+    }
+    return bp;
+}
+
+/***********************************
+ * Throw a D object.
+ */
+
+extern (Windows) void _d_throw(Object *h)
+{
+    uint regebp;
+
+    debug
+    {
+        printf("_d_throw(h = %p, &h = %p)\n", h, &h);
+        printf("\tvptr = %p\n", *cast(void **)h);
+    }
+
+    asm
+    {
+        mov regebp,EBP  ;
+    }
+
+    while (1)           // for each function on the stack
+    {
+        DHandlerTable *handler_table;
+        FuncTable *pfunc;
+        DHandlerInfo *handler;
+        uint calleraddr;
+        uint funcoffset;
+        int index;
+        int dim;
+        int ndx;
+        int enclosing_ndx;
+
+        regebp = __eh_find_caller(regebp,&calleraddr);
+        if (!regebp)
+        {   // if end of call chain
+            debug printf("end of call chain\n");
+            break;
+        }
+        debug printf("found caller, EBP = x%x, calleraddr = x%x\n", regebp, calleraddr);
+        
+        // find DHandlerTable associated with function
+        handler_table = __eh_finddata(cast(void *)calleraddr);
+        if (!handler_table)         // if no static data
+        {
+            debug printf("no handler table\n");
+            continue;
+        }
+        funcoffset = cast(uint)handler_table.fptr;
+
+        debug
+        {
+            printf("calleraddr = x%x\n",cast(uint)calleraddr);
+            printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
+            regebp,funcoffset,handler_table.espoffset,handler_table.retoffset);
+        }
+
+        dim = handler_table.nhandlers;
+
+        debug
+        {
+            printf("handler_info[]:\n");
+            for (int i = 0; i < dim; i++)
+            {
+                handler = &handler_table.handler_info[i];
+                printf("\t[%d]: offset = x%04x, endoffset = x%04x, enclosing_index = %d, cioffset = x%04x, finally_code = %x\n",
+                        i, handler.offset, handler.endoffset, handler.enclosing_index, handler.cioffset, handler.finally_code);
+            }
+        }
+
+        // Find index of DHandlerInfo coresponding to the innermost
+        // try block wrapping calleraddr
+        index = -1;
+        for (int i = 0; i < dim; i++)
+        {
+            handler = &handler_table.handler_info[i];
+
+            debug printf("i = %d, handler.offset = %04x\n", i, funcoffset + handler.offset);
+            if (cast(uint)calleraddr > funcoffset + handler.offset &&
+                cast(uint)calleraddr <= funcoffset + handler.endoffset)
+                index = i; // don't break if found, want innermost try
+        }
+        debug printf("index = %d\n", index);
+
+        // walk through handler infos for all try blocks enclosing the call,
+        // starting with the innermost one we just found
+        for (ndx = index; ndx != -1; ndx = enclosing_ndx)
+        {
+            handler = &handler_table.handler_info[ndx];
+            enclosing_ndx = handler.enclosing_index;
+            
+            if (handler.cioffset)
+            {
+                // this is a catch handler (no finally)
+                DCatchInfo *pci;
+                int ncatches;
+                int i;
+
+                pci = cast(DCatchInfo *)(cast(char *)handler_table + handler.cioffset);
+                ncatches = pci.ncatches;
+                for (i = 0; i < ncatches; i++)
+                {
+                    DCatchBlock *pcb;
+                    ClassInfo ci = **cast(ClassInfo **)h;
+
+                    pcb = &pci.catch_block[i];
+
+                    if (_d_isbaseof(ci, pcb.type))
+                    {   // Matched the catch type, so we've found the handler.
+
+                        // Initialize catch variable
+                        *cast(void **)(regebp + (pcb.bpoffset)) = h;
+
+                        // Jump to catch block. Does not return.
+                        {
+                            uint catch_esp;
+                            fp_t catch_addr;
+
+                            catch_addr = cast(fp_t)(pcb.code);
+                            catch_esp = regebp - handler_table.espoffset - fp_t.sizeof;
+                            asm
+                            {
+                                mov     EAX,catch_esp   ;
+                                mov     ECX,catch_addr  ;
+                                mov     [EAX],ECX       ;
+                                mov     EBP,regebp      ;
+                                mov     ESP,EAX         ; // reset stack
+                                ret                     ; // jump to catch block
+                            }
+                        }
+                    }
+                }
+            }
+            else if (handler.finally_code)
+            {   // Call finally block
+                // Note that it is unnecessary to adjust the ESP, as the finally block
+                // accesses all items on the stack as relative to EBP.
+
+                void *blockaddr = handler.finally_code;
+
+                asm
+                {
+                    push        EBX             ;
+                    mov         EBX,blockaddr   ;
+                    push        EBP             ;
+                    mov         EBP,regebp      ;
+                    call        EBX             ;
+                    pop         EBP             ;
+                    pop         EBX             ;
+                }
+            }
+        }
+    }
+}
+