view tango-0.99.9.patch @ 1651:cb960b882ca3 tip

bindings were moved to dsource.org/projects/bindings/
author Moritz Warning <moritzwarning@web.de>
date Thu, 20 May 2010 20:05:03 +0200
parents 40bd4a0d4870
children
line wrap: on
line source
Index: tango/core/rt/compiler/ldc/rt/lifetime.d
===================================================================
--- tango/core/rt/compiler/ldc/rt/lifetime.d	(revision 5462)
+++ tango/core/rt/compiler/ldc/rt/lifetime.d	(working copy)
@@ -786,6 +786,7 @@
     return *cast(long*)px;
 }
 
++/
 
 /**
  *
@@ -849,10 +850,11 @@
 
 
 /**
- *
+ * Appends a single element to an array.
  */
-extern (C) byte[] _d_arrayappendcT(TypeInfo ti, ref byte[] x, ...)
+extern (C) byte[] _d_arrayappendcT(TypeInfo ti, void* array, void* element)
 {
+    auto x = cast(byte[]*)array;
     auto sizeelem = ti.next.tsize();            // array element size
     auto info = gc_query(x.ptr);
     auto length = x.length;
@@ -879,16 +881,16 @@
         assert(newcap >= newlength * sizeelem);
         newdata = cast(byte *)gc_malloc(newcap + 1, info.attr);
         memcpy(newdata, x.ptr, length * sizeelem);
-        (cast(void**)(&x))[1] = newdata;
+        (cast(void**)x)[1] = newdata;
     }
   L1:
-    byte *argp = cast(byte *)(&ti + 2);
+    byte *argp = cast(byte *)element;
 
-    *cast(size_t *)&x = newlength;
+    *cast(size_t *)x = newlength;
     x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
     assert((cast(size_t)x.ptr & 15) == 0);
     assert(gc_sizeOf(x.ptr) > x.length * sizeelem);
-    return x;
+    return *x;
 }
 
 
@@ -1128,6 +1130,7 @@
     return result;
 }
 
+/+
 
 /**
  *
Index: tango/core/rt/compiler/ldc/rt/eh.d
===================================================================
--- tango/core/rt/compiler/ldc/rt/eh.d	(revision 5462)
+++ tango/core/rt/compiler/ldc/rt/eh.d	(working copy)
@@ -1,38 +1,34 @@
 /**
  * This module contains functions and structures required for
- * exception handling.
+ * dwarf exception handling with llvm
  */
 module rt.eh;
 
-import ldc.cstdarg;
-import rt.compiler.util.console;
+//debug = EH_personality;
 
-// debug = EH_personality;
-
 // current EH implementation works on x86
 // if it has a working unwind runtime
 version(X86) {
     version(linux) version=X86_UNWIND;
     version(darwin) version=X86_UNWIND;
     version(solaris) version=X86_UNWIND;
-    version(freebsd) version=X86_UNWIND;
 }
 version(X86_64) {
     version(linux) version=X86_UNWIND;
     version(darwin) version=X86_UNWIND;
     version(solaris) version=X86_UNWIND;
-    version(freebsd) version=X86_UNWIND;
 }
 
 //version = HP_LIBUNWIND;
 
 private extern(C) void abort();
 private extern(C) int printf(char*, ...);
-private extern(C) int vprintf(char*, va_list va);
+//private extern(C) int vprintf(char*, va_list va);
 
 // D runtime functions
 extern(C) {
-    int _d_isbaseof(ClassInfo oc, ClassInfo c);
+//    int _d_isbaseof(ClassInfo oc, ClassInfo c);
+    Object _d_dynamic_cast(Object o, ClassInfo c);
 }
 
 // libunwind headers
@@ -74,16 +70,19 @@
 // interface to HP's libunwind from http://www.nongnu.org/libunwind/
 version(HP_LIBUNWIND)
 {
+    // Haven't checked whether and how it has _Unwind_Get{Text,Data}RelBase
+    pragma (msg, "HP_LIBUNWIND interface is out of date and untested");
+
     void __libunwind_Unwind_Resume(_Unwind_Exception *);
     _Unwind_Reason_Code __libunwind_Unwind_RaiseException(_Unwind_Exception *);
     ptrdiff_t __libunwind_Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr
             context);
-    ptrdiff_t __libunwind_Unwind_GetIP(_Unwind_Context_Ptr context);
+    size_t __libunwind_Unwind_GetIP(_Unwind_Context_Ptr context);
     ptrdiff_t __libunwind_Unwind_SetIP(_Unwind_Context_Ptr context,
             ptrdiff_t new_value);
     ptrdiff_t __libunwind_Unwind_SetGR(_Unwind_Context_Ptr context, int index,
             ptrdiff_t new_value);
-    ptrdiff_t __libunwind_Unwind_GetRegionStart(_Unwind_Context_Ptr context);
+    size_t __libunwind_Unwind_GetRegionStart(_Unwind_Context_Ptr context);
 
     alias __libunwind_Unwind_Resume _Unwind_Resume;
     alias __libunwind_Unwind_RaiseException _Unwind_RaiseException;
@@ -94,27 +93,30 @@
     alias __libunwind_Unwind_SetGR _Unwind_SetGR;
     alias __libunwind_Unwind_GetRegionStart _Unwind_GetRegionStart;
 }
-else version(X86_UNWIND) 
+else version(X86_UNWIND)
 {
     void _Unwind_Resume(_Unwind_Exception*);
     _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*);
     ptrdiff_t _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context);
-    ptrdiff_t _Unwind_GetIP(_Unwind_Context_Ptr context);
+    size_t _Unwind_GetIP(_Unwind_Context_Ptr context);
     ptrdiff_t _Unwind_SetIP(_Unwind_Context_Ptr context, ptrdiff_t new_value);
     ptrdiff_t _Unwind_SetGR(_Unwind_Context_Ptr context, int index,
             ptrdiff_t new_value);
-    ptrdiff_t _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
+    size_t _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
+
+    size_t _Unwind_GetTextRelBase(_Unwind_Context_Ptr);
+    size_t _Unwind_GetDataRelBase(_Unwind_Context_Ptr);
 }
 else
 {
     // runtime calls these directly
     void _Unwind_Resume(_Unwind_Exception*)
     {
-        console("_Unwind_Resume is not implemented on this platform.\n");
+        printf("_Unwind_Resume is not implemented on this platform.\n");
     }
     _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*)
     {
-        console("_Unwind_RaiseException is not implemented on this platform.\n");
+        printf("_Unwind_RaiseException is not implemented on this platform.\n");
         return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
     }
 }
@@ -122,14 +124,161 @@
 }
 
 // error and exit
-extern(C) private void fatalerror(char[] format)
+extern(C) private void fatalerror(char* format, ...)
 {
-  printf("Fatal error in EH code: %.*s\n", format.length, format.ptr);
+//  va_list args;
+//  va_start(args, format);
+  printf("Fatal error in EH code: ");
+//  vprintf(format, args);
+  printf("\n");
   abort();
 }
 
 
-// helpers for reading certain DWARF data
+// DWARF EH encoding enum
+// See e.g. http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/dwarfext.html
+private enum : ubyte {
+  DW_EH_PE_omit    = 0xff, // value is not present
+
+  // value format
+  DW_EH_PE_absptr  = 0x00, // literal pointer
+  DW_EH_PE_uleb128 = 0x01,
+  DW_EH_PE_udata2  = 0x02, // unsigned 2-byte
+  DW_EH_PE_udata4  = 0x03,
+  DW_EH_PE_udata8  = 0x04,
+  DW_EH_PE_sleb128 = 0x09,
+  DW_EH_PE_sdata2  = 0x0a,
+  DW_EH_PE_sdata4  = 0x0b,
+  DW_EH_PE_sdata8  = 0x0c,
+
+  // value meaning
+  DW_EH_PE_pcrel    = 0x10, // relative to program counter
+  DW_EH_PE_textrel  = 0x20, // relative to .text
+  DW_EH_PE_datarel  = 0x30, // relative to .got or .eh_frame_hdr
+  DW_EH_PE_funcrel  = 0x40, // relative to beginning of function
+  DW_EH_PE_aligned  = 0x50, // is an aligned void*
+
+  // value is a pointer to the actual value
+  // this is a mask on top of one of the above
+  DW_EH_PE_indirect = 0x80
+}
+
+// Helpers for reading DWARF data
+
+// Given an encoding and a context, return the base to which the encoding is
+// relative
+private size_t base_of_encoded(_Unwind_Context_Ptr context, ubyte encoding)
+{
+  if (encoding == DW_EH_PE_omit)
+    return 0;
+
+  switch (encoding & 0x70) // ignore DW_EH_PE_indirect
+  {
+    case DW_EH_PE_absptr, DW_EH_PE_pcrel, DW_EH_PE_aligned:
+      return 0;
+
+    case DW_EH_PE_textrel: return _Unwind_GetTextRelBase(context);
+    case DW_EH_PE_datarel: return _Unwind_GetDataRelBase(context);
+    case DW_EH_PE_funcrel: return _Unwind_GetRegionStart(context);
+
+    default: fatalerror("Unrecognized base for DWARF value");
+  }
+}
+
+// Only defined for fixed-size encodings
+private size_t size_of_encoded(ubyte encoding)
+{
+  if (encoding == DW_EH_PE_omit)
+    return 0;
+
+  switch (encoding & 0x07) // ignore leb128
+  {
+    case DW_EH_PE_absptr: return (void*).sizeof;
+    case DW_EH_PE_udata2: return 2;
+    case DW_EH_PE_udata4: return 4;
+    case DW_EH_PE_udata8: return 8;
+
+    default: fatalerror("Unrecognized fixed-size DWARF value encoding");
+  }
+}
+
+// Actual value readers below: read a value from the given ubyte* into the
+// output parameter and return the pointer incremented past the value.
+
+// Like read_encoded_with_base but gets the base from the given context
+private ubyte* read_encoded(_Unwind_Context_Ptr context, ubyte encoding, ubyte* p, out size_t val)
+{
+  return read_encoded_with_base(encoding, base_of_encoded(context, encoding), p, val);
+}
+
+private ubyte* read_encoded_with_base(ubyte encoding, size_t base, ubyte* p, out size_t val)
+{
+  if (encoding == DW_EH_PE_aligned)
+  {
+    auto a = cast(size_t)p;
+    a = (a + (void*).sizeof - 1) & -(void*).sizeof;
+    val = *cast(size_t*)a;
+    return cast(ubyte*)(a + (void*).sizeof);
+  }
+
+  union U
+  {
+    size_t ptr;
+    ushort udata2;
+    uint   udata4;
+    ulong  udata8;
+    short  sdata2;
+    int    sdata4;
+    long   sdata8;
+  }
+
+  auto u = cast(U*)p;
+
+  size_t result;
+
+  switch (encoding & 0x0f)
+  {
+    case DW_EH_PE_absptr:
+      result = u.ptr;
+      p += (void*).sizeof;
+      break;
+
+    case DW_EH_PE_uleb128:
+    {
+      p = get_uleb128(p, result);
+      break;
+    }
+    case DW_EH_PE_sleb128:
+    {
+      ptrdiff_t sleb128;
+      p = get_sleb128(p, sleb128);
+      result = cast(size_t)sleb128;
+      break;
+    }
+
+    case DW_EH_PE_udata2: result = cast(size_t)u.udata2; p += 2; break;
+    case DW_EH_PE_udata4: result = cast(size_t)u.udata4; p += 4; break;
+    case DW_EH_PE_udata8: result = cast(size_t)u.udata8; p += 8; break;
+    case DW_EH_PE_sdata2: result = cast(size_t)u.sdata2; p += 2; break;
+    case DW_EH_PE_sdata4: result = cast(size_t)u.sdata4; p += 4; break;
+    case DW_EH_PE_sdata8: result = cast(size_t)u.sdata8; p += 8; break;
+
+    default: fatalerror("Unrecognized DWARF value encoding format");
+  }
+  if (result)
+  {
+    if ((encoding & 0x70) == DW_EH_PE_pcrel)
+      result += cast(size_t)u;
+    else
+      result += base;
+
+    if (encoding & DW_EH_PE_indirect)
+      result = *cast(size_t*)result;
+  }
+  val = result;
+  return p;
+}
+
 private ubyte* get_uleb128(ubyte* addr, ref size_t res)
 {
   res = 0;
@@ -137,7 +286,7 @@
 
   // read as long as high bit is set
   while(*addr & 0x80) {
-    res |= (*addr & 0x7f) << bitsize;
+    res |= (*addr & 0x7fU) << bitsize;
     bitsize += 7;
     addr += 1;
     if(bitsize >= size_t.sizeof*8)
@@ -153,12 +302,12 @@
 
 private ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res)
 {
-  res = 0;
+  size_t tres = 0;
   size_t bitsize = 0;
 
   // read as long as high bit is set
   while(*addr & 0x80) {
-    res |= (*addr & 0x7f) << bitsize;
+    tres |= (*addr & 0x7fU) << bitsize;
     bitsize += 7;
     addr += 1;
     if(bitsize >= size_t.sizeof*8)
@@ -167,12 +316,14 @@
   // read last
   if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
     fatalerror("tried to read sleb128 that exceeded size of size_t");
-  res |= (*addr) << bitsize;
+  tres |= (*addr) << bitsize;
 
   // take care of sign
-  if(bitsize < size_t.sizeof*8 && ((*addr) & 0x40))
-    res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1);
+  if(bitsize < size_t.sizeof*8 && (*addr & 0x40U) != 0)
+    tres |= cast(size_t)(-1) ^ ((1 << (bitsize+7)) - 1);
 
+  res = cast(ptrdiff_t)tres;
+
   return addr + 1;
 }
 
@@ -190,8 +341,7 @@
 
 // the 8-byte string identifying the type of exception
 // the first 4 are for vendor, the second 4 for language
-//TODO: This may be the wrong way around
-const char[8] _d_exception_class = "LLDCD1\0\0";
+const char[8] _d_exception_class = "LDC_D_10";
 
 
 //
@@ -201,118 +351,174 @@
 version(X86_UNWIND)
 {
 
+// Various stuff we need
+struct Region
+{
+  ubyte* callsite_table;
+  ubyte* action_table;
+
+  // Note: classinfo_table points past the end of the table
+  ubyte* classinfo_table;
+
+  size_t start;
+  size_t lpStart_base; // landing pad base
+
+  ubyte ttypeEnc;
+  size_t ttype_base; // typeinfo base
+
+  ubyte callSiteEnc;
+}
+
 // the personality routine gets called by the unwind handler and is responsible for
 // reading the EH tables and deciding what to do
 extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context)
 {
+  debug(EH_personality) printf("Entering personality routine, context=%p\n", context);
   // check ver: the C++ Itanium ABI only allows ver == 1
   if(ver != 1)
+  {
+    debug(EH_personality) printf("eh version mismatch\n");
     return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+  }
 
   // check exceptionClass
   //TODO: Treat foreign exceptions with more respect
-  if((cast(char*)&exception_class)[0..8] != _d_exception_class)
+  auto wanted_ec = *cast(ulong*)_d_exception_class.ptr;
+  if(exception_class != wanted_ec)
+  {
+    debug(EH_personality) printf("exception class mismatch %p vs %p\n", exception_class, wanted_ec);
     return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+  }
 
   // find call site table, action table and classinfo table
   // Note: callsite and action tables do not contain static-length
   // data and will be parsed as needed
-  // Note: classinfo_table points past the end of the table
-  ubyte* callsite_table;
-  ubyte* action_table;
-  ClassInfo* classinfo_table;
-  _d_getLanguageSpecificTables(context, callsite_table, action_table, classinfo_table);
-  if (!callsite_table)
+
+  Region region;
+
+  _d_getLanguageSpecificTables(context, region);
+
+  // workaround. this should not happen
+  if (!region.callsite_table)
+  {
+    debug(EH_personality) printf("callsite_table is null\n");
     return _Unwind_Reason_Code.CONTINUE_UNWIND;
+  }
 
+  debug(EH_personality) printf("yay, checking\n");
+  debug(EH_personality) printf("region.start = %p\n", region.start);
+
   /*
     find landing pad and action table index belonging to ip by walking
     the callsite_table
   */
-  ubyte* callsite_walker = callsite_table;
+  ubyte* callsite_walker = region.callsite_table;
+  debug(EH_personality) printf("callsite table at: %p\n", region.callsite_table);
+  debug(EH_personality) printf("action table at: %p\n", region.action_table);
+  debug(EH_personality) printf("rtti table at %p\n", region.classinfo_table);
 
   // get the instruction pointer
   // will be used to find the right entry in the callsite_table
   // -1 because it will point past the last instruction
-  ptrdiff_t ip = _Unwind_GetIP(context) - 1;
+  debug(EH_personality) printf("check1\n");
+  size_t ip = _Unwind_GetIP(context) - 1;
+  debug(EH_personality) printf("check2\n");
 
-  // address block_start is relative to
-  ptrdiff_t region_start = _Unwind_GetRegionStart(context);
-
   // table entries
-  uint block_start_offset, block_size;
-  ptrdiff_t landing_pad;
+  size_t landing_pad;
   size_t action_offset;
 
   while(true) {
     // if we've gone through the list and found nothing...
-    if(callsite_walker >= action_table)
+    if(callsite_walker >= region.action_table)
+    {
+      debug(EH_personality) printf("found nothing\n");
       return _Unwind_Reason_Code.CONTINUE_UNWIND;
+    }
 
-    block_start_offset = *cast(uint*)callsite_walker;
-    block_size = *(cast(uint*)callsite_walker + 1);
-    landing_pad = *(cast(uint*)callsite_walker + 2);
-    if(landing_pad)
-      landing_pad += region_start;
-    callsite_walker = get_uleb128(callsite_walker + 3*uint.sizeof, action_offset);
+    size_t block_start, block_size;
 
-    debug(EH_personality_verbose) printf("ip=%llx %d %d %llx\n", ip, block_start_offset, block_size, landing_pad);
+    callsite_walker = read_encoded(null, region.callSiteEnc, callsite_walker, block_start);
+    callsite_walker = read_encoded(null, region.callSiteEnc, callsite_walker, block_size);
+    callsite_walker = read_encoded(null, region.callSiteEnc, callsite_walker, landing_pad);
+    callsite_walker = get_uleb128(callsite_walker, action_offset);
 
+    debug(EH_personality) printf("*block start offset = %p\n", block_start);
+    debug(EH_personality) printf(" block size = %p\n", block_size);
+    debug(EH_personality) printf(" landing pad = %p\n", landing_pad);
+    debug(EH_personality) printf(" ip=%p %p %p %p\n", ip, block_start, block_size, landing_pad);
+
     // since the list is sorted, as soon as we're past the ip
     // there's no handler to be found
-    if(ip < region_start + block_start_offset)
+    if(ip < region.start + block_start)
+    {
+      debug(EH_personality) printf("found nothing2\n");
       return _Unwind_Reason_Code.CONTINUE_UNWIND;
+    }
 
+    if(landing_pad)
+      landing_pad += region.lpStart_base;
+
     // if we've found our block, exit
-    if(ip < region_start + block_start_offset + block_size)
+    if(ip < region.start + block_start + block_size)
       break;
   }
 
-  debug(EH_personality) printf("Found correct landing pad and actionOffset %d\n", action_offset);
+  debug(EH_personality) printf("Found correct landing pad %p and actionOffset %p\n", landing_pad, action_offset);
 
   // now we need the exception's classinfo to find a handler
   // the exception_info is actually a member of a larger _d_exception struct
   // the runtime allocated. get that now
-  _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof);
+  _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - size_t.sizeof); //_d_exception.unwind_info.offsetof);
 
   // if there's no action offset and no landing pad, continue unwinding
   if(!action_offset && !landing_pad)
     return _Unwind_Reason_Code.CONTINUE_UNWIND;
 
   // if there's no action offset but a landing pad, this is a cleanup handler
-  else if(!action_offset && landing_pad)
-    return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
+  else if(!action_offset && landing_pad != 0)
+  {
+    debug(EH_personality) printf("installing finally context\n");
+    return _d_eh_install_finally_context(actions, cast(ptrdiff_t)landing_pad, exception_struct, context);
+  }
 
   /*
    walk action table chain, comparing classinfos using _d_isbaseof
   */
-  ubyte* action_walker = action_table + action_offset - 1;
+  ubyte* action_walker = region.action_table + action_offset - 1;
 
-  ptrdiff_t ti_offset, next_action_offset;
   while(true) {
+    ptrdiff_t ti_offset, next_action_offset;
+
     action_walker = get_sleb128(action_walker, ti_offset);
     // it is intentional that we not modify action_walker here
     // next_action_offset is from current action_walker position
     get_sleb128(action_walker, next_action_offset);
 
     // negative are 'filters' which we don't use
-    if(!(ti_offset >= 0))
+    if(ti_offset < 0)
       fatalerror("Filter actions are unsupported");
 
     // zero means cleanup, which we require to be the last action
     if(ti_offset == 0) {
-      if(!(next_action_offset == 0))
+      if(next_action_offset != 0)
         fatalerror("Cleanup action must be last in chain");
-      return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
+      return _d_eh_install_finally_context(actions, cast(ptrdiff_t)landing_pad, exception_struct, context);
     }
 
     // get classinfo for action and check if the one in the
     // exception structure is a base
-    ClassInfo catch_ci = *(classinfo_table - ti_offset);
-    debug(EH_personality) printf("Comparing catch %s to exception %s\n", catch_ci.name.ptr, exception_struct.exception_object.classinfo.name.ptr);
-    if(_d_isbaseof(exception_struct.exception_object.classinfo, catch_ci))
-      return _d_eh_install_catch_context(actions, ti_offset, landing_pad, exception_struct, context);
+    size_t typeinfo;
+    auto filter = cast(size_t)ti_offset * size_of_encoded(region.ttypeEnc);
+    read_encoded_with_base(region.ttypeEnc, region.ttype_base, region.classinfo_table - filter, typeinfo);
 
+    debug(EH_personality)
+      printf("classinfo at %zx (enc %zx (size %zx) base %zx ptr %zx)\n", typeinfo, region.ttypeEnc, size_of_encoded(region.ttypeEnc), region.ttype_base, region.classinfo_table - filter);
+
+    auto catch_ci = *cast(ClassInfo*)&typeinfo;
+    if(_d_dynamic_cast(exception_struct.exception_object, catch_ci) !is null)
+      return _d_eh_install_catch_context(actions, ti_offset, cast(ptrdiff_t)landing_pad, exception_struct, context);
+
     // we've walked through all actions and found nothing...
     if(next_action_offset == 0)
       return _Unwind_Reason_Code.CONTINUE_UNWIND;
@@ -356,6 +562,7 @@
   }
 
   fatalerror("reached unreachable");
+
   return _Unwind_Reason_Code.FATAL_PHASE2_ERROR;
 }
 
@@ -370,56 +577,78 @@
   _Unwind_SetGR(context, eh_exception_regno, cast(ptrdiff_t)exception_struct);
   _Unwind_SetGR(context, eh_selector_regno, 0);
   _Unwind_SetIP(context, landing_pad);
+
   return _Unwind_Reason_Code.INSTALL_CONTEXT;
 }
 
-private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, ref ubyte* callsite, ref ubyte* action, ref ClassInfo* ci)
+private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, out Region region)
 {
-  ubyte* data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
+  auto data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
+
+  // workaround. this should not be 0...
   if (!data)
   {
-    callsite = null;
-    action = null;
-    ci = null;
-    return;
+      //printf("language specific data is null\n");
+      return;
   }
 
-  //TODO: Do proper DWARF reading here
-  if(*data++ != 0xff)
-    fatalerror("DWARF header has unexpected format 1");
+  region.start = _Unwind_GetRegionStart(context);
 
-  if(*data++ != 0x00)
-    fatalerror("DWARF header has unexpected format 2");
-  size_t cioffset;
-  data = get_uleb128(data, cioffset);
-  ci = cast(ClassInfo*)(data + cioffset);
+  // Read the C++-style LSDA: this is implementation-defined by GCC but LLVM
+  // outputs the same kind of table
 
-  if(*data++ != 0x03)
-    fatalerror("DWARF header has unexpected format 3");
-  size_t callsitelength;
-  data = get_uleb128(data, callsitelength);
-  action = data + callsitelength;
+  // Get @LPStart: landing pad offsets are relative to it
+  auto lpStartEnc = *data++;
+  if (lpStartEnc == DW_EH_PE_omit)
+    region.lpStart_base = region.start;
+  else
+    data = read_encoded(context, lpStartEnc, data, region.lpStart_base);
 
-  callsite = data;
+  // Get @TType: the offset to the handler and typeinfo
+  region.ttypeEnc = *data++;
+  if (region.ttypeEnc == DW_EH_PE_omit)
+    // Not sure about this one...
+    fatalerror("@TType must not be omitted from DWARF header");
+
+  size_t ciOffset;
+  data = get_uleb128(data, ciOffset);
+  region.classinfo_table = data + ciOffset;
+
+  region.ttype_base = base_of_encoded(context, region.ttypeEnc);
+
+  // Get encoding and length of the call site table, which precedes the action
+  // table.
+  region.callSiteEnc = *data++;
+  if (region.callSiteEnc == DW_EH_PE_omit)
+    fatalerror("Call site table encoding must not be omitted from DWARF header");
+
+  size_t callSiteLength;
+  region.callsite_table = get_uleb128(data, callSiteLength);
+  region.action_table = region.callsite_table + callSiteLength;
 }
 
 } // end of x86 Linux specific implementation
 
-
-extern(C) void _d_throw_exception(Object e)
+// called to throw object
+extern(C)
+void _d_throw_exception(Object e)
 {
+    //printf("throwing %p, rtti = %p\n", e, **cast(ClassRTTI***)e);
     if (e !is null)
     {
         _d_exception* exc_struct = new _d_exception;
         exc_struct.unwind_info.exception_class = *cast(ulong*)_d_exception_class.ptr;
         exc_struct.exception_object = e;
         _Unwind_Reason_Code ret = _Unwind_RaiseException(&exc_struct.unwind_info);
-        console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
+        printf("Error: returned %d from raise exception.\n", ret);
+        //console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
     }
     abort();
 }
 
-extern(C) void _d_eh_resume_unwind(_d_exception* exception_struct)
+// called to resume unwinding
+extern(C)
+void _d_eh_resume_unwind(void* exception_struct)
 {
-  _Unwind_Resume(&exception_struct.unwind_info);
+    _Unwind_Resume(&(cast(_d_exception*)exception_struct).unwind_info);
 }