[PATCH] libdl: Add C++ exception support to loaded modules.

Chris Johns chrisj at rtems.org
Mon Dec 12 00:44:07 UTC 2016


This has been tested on SPARC, i386, PowerPC and ARM.

Closes #2767.
---
 .../sparc/erc32/make/custom/erc32-testsuite.tcfg   |   4 -
 cpukit/libdl/Makefile.am                           |   1 +
 cpukit/libdl/dlfcn.c                               |   2 +-
 cpukit/libdl/rtl-allocator.c                       |  26 ++-
 cpukit/libdl/rtl-allocator.h                       |   7 +-
 cpukit/libdl/rtl-debugger.c                        |  14 +-
 cpukit/libdl/rtl-elf.c                             |  94 +++++++----
 cpukit/libdl/rtl-elf.h                             |  26 ++-
 cpukit/libdl/rtl-error.c                           |  17 +-
 cpukit/libdl/rtl-mdreloc-arm.c                     | 147 +++++++++++++++--
 cpukit/libdl/rtl-mdreloc-bfin.c                    |  29 ++++
 cpukit/libdl/rtl-mdreloc-h8300.c                   |  29 ++++
 cpukit/libdl/rtl-mdreloc-i386.c                    |  29 ++++
 cpukit/libdl/rtl-mdreloc-lm32.c                    |  29 ++++
 cpukit/libdl/rtl-mdreloc-m68k.c                    |  29 ++++
 cpukit/libdl/rtl-mdreloc-mips.c                    |  29 ++++
 cpukit/libdl/rtl-mdreloc-moxie.c                   |  29 ++++
 cpukit/libdl/rtl-mdreloc-powerpc.c                 |  43 +++++
 cpukit/libdl/rtl-mdreloc-sparc.c                   |  43 ++++-
 cpukit/libdl/rtl-mdreloc-v850.c                    |  29 ++++
 cpukit/libdl/rtl-obj.c                             | 178 +++++++++++++--------
 cpukit/libdl/rtl-obj.h                             | 169 +++++++++++--------
 cpukit/libdl/rtl-rap.c                             |  55 ++++---
 cpukit/libdl/rtl-rap.h                             |   7 +
 cpukit/libdl/rtl-unwind-dw2.c                      |  71 ++++++++
 cpukit/libdl/rtl-unwind-dw2.h                      |  83 ++++++++++
 cpukit/libdl/rtl-unwind.h                          |  63 ++++++++
 cpukit/libdl/rtl.c                                 |  33 +++-
 cpukit/libdl/rtl.h                                 |   2 +-
 testsuites/libtests/dl01/init.c                    |   3 +-
 testsuites/libtests/dl02/init.c                    |   2 +
 testsuites/libtests/dl03/init.c                    |   2 +
 testsuites/libtests/dl04/init.c                    |   2 +
 testsuites/libtests/dl05/dl-cpp.cpp                |  24 ++-
 testsuites/libtests/dl05/dl-load.c                 |  34 ++--
 testsuites/libtests/dl05/dl-load.h                 |  30 +++-
 testsuites/libtests/dl05/dl-o5.cpp                 |  15 +-
 testsuites/libtests/dl05/init.c                    |   8 +-
 38 files changed, 1182 insertions(+), 255 deletions(-)
 delete mode 100644 c/src/lib/libbsp/sparc/erc32/make/custom/erc32-testsuite.tcfg
 create mode 100644 cpukit/libdl/rtl-unwind-dw2.c
 create mode 100644 cpukit/libdl/rtl-unwind-dw2.h
 create mode 100644 cpukit/libdl/rtl-unwind.h

diff --git a/c/src/lib/libbsp/sparc/erc32/make/custom/erc32-testsuite.tcfg b/c/src/lib/libbsp/sparc/erc32/make/custom/erc32-testsuite.tcfg
deleted file mode 100644
index cee7ce5..0000000
--- a/c/src/lib/libbsp/sparc/erc32/make/custom/erc32-testsuite.tcfg
+++ /dev/null
@@ -1,4 +0,0 @@
-#
-# Excpected failures.
-#
-expected-fail: dl05
diff --git a/cpukit/libdl/Makefile.am b/cpukit/libdl/Makefile.am
index 5c3cd15..b21c167 100644
--- a/cpukit/libdl/Makefile.am
+++ b/cpukit/libdl/Makefile.am
@@ -25,6 +25,7 @@ libdl_a_SOURCES = \
   rtl-string.c \
   rtl-sym.c \
   rtl-trace.c \
+  rtl-unwind-dw2.c \
   rtl-unresolved.c
 
 libdl_a_SOURCES += rtl-mdreloc- at RTEMS_CPU@.c
diff --git a/cpukit/libdl/dlfcn.c b/cpukit/libdl/dlfcn.c
index 19feaaf..3b31bb2 100644
--- a/cpukit/libdl/dlfcn.c
+++ b/cpukit/libdl/dlfcn.c
@@ -130,7 +130,7 @@ dlerror (void)
 {
   static char msg[64];
   rtems_rtl_get_error (msg, sizeof (msg));
-	return msg;
+  return msg;
 }
 
 int
diff --git a/cpukit/libdl/rtl-allocator.c b/cpukit/libdl/rtl-allocator.c
index 9880940..39b4bcd 100644
--- a/cpukit/libdl/rtl-allocator.c
+++ b/cpukit/libdl/rtl-allocator.c
@@ -152,6 +152,7 @@ rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag,
 bool
 rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
                             void** const_base, size_t const_size,
+                            void** eh_base, size_t eh_size,
                             void** data_base, size_t data_size,
                             void** bss_base, size_t bss_size)
 {
@@ -173,7 +174,20 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
                                        const_size, false);
     if (!*const_base)
     {
-      rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base);
+      rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
+                                  data_base, bss_base);
+      return false;
+    }
+  }
+
+  if (eh_size)
+  {
+    *eh_base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_READ,
+                                    eh_size, false);
+    if (!*eh_base)
+    {
+      rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
+                                  data_base, bss_base);
       return false;
     }
   }
@@ -184,7 +198,8 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
                                       data_size, false);
     if (!*data_base)
     {
-      rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base);
+      rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
+                                  data_base, bss_base);
       return false;
     }
   }
@@ -195,7 +210,8 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
                                      bss_size, false);
     if (!*bss_base)
     {
-      rtems_rtl_alloc_module_del (text_base, const_base, data_base, bss_base);
+      rtems_rtl_alloc_module_del (text_base, const_base, eh_base,
+                                  data_base, bss_base);
       return false;
     }
   }
@@ -206,12 +222,14 @@ rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
 void
 rtems_rtl_alloc_module_del (void** text_base,
                             void** const_base,
+                            void** eh_base,
                             void** data_base,
                             void** bss_base)
 {
   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *bss_base);
   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_WRITE, *data_base);
+  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *eh_base);
   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ, *const_base);
   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_READ_EXEC, *text_base);
-  *text_base = *const_base = *data_base = *bss_base = NULL;
+  *text_base = *const_base = *eh_base = *data_base = *bss_base = NULL;
 }
diff --git a/cpukit/libdl/rtl-allocator.h b/cpukit/libdl/rtl-allocator.h
index 4d996d3..e8044ee 100644
--- a/cpukit/libdl/rtl-allocator.h
+++ b/cpukit/libdl/rtl-allocator.h
@@ -146,6 +146,8 @@ void rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag,
  * @param text_size The size of the read/exec section.
  * @param const_base Pointer to the const base pointer.
  * @param const_size The size of the read only section.
+ * @param eh_base Pointer to the eh base pointer.
+ * @param eh_size The size of the eh section.
  * @param data_base Pointer to the data base pointer.
  * @param data_size The size of the read/write secton.
  * @param bss_base Pointer to the bss base pointer.
@@ -155,6 +157,7 @@ void rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag,
  */
 bool rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
                                  void** const_base, size_t const_size,
+                                 void** eh_base, size_t eh_size,
                                  void** data_base, size_t data_size,
                                  void** bss_base, size_t bss_size);
 
@@ -163,11 +166,13 @@ bool rtems_rtl_alloc_module_new (void** text_base, size_t text_size,
  *
  * @param text_base Pointer to the text base pointer.
  * @param const_base Pointer to the const base pointer.
+ * @param eh_base Pointer to the eh base pointer.
  * @param data_base Pointer to the data base pointer.
  * @param bss_base Pointer to the bss base pointer.
  */
 void rtems_rtl_alloc_module_del (void** text_base, void** const_base,
-                                 void** data_base, void** bss_base);
+                                 void** eh_base, void** data_base,
+                                 void** bss_base);
 
 #ifdef __cplusplus
 }
diff --git a/cpukit/libdl/rtl-debugger.c b/cpukit/libdl/rtl-debugger.c
index 63add59..afbea8a 100644
--- a/cpukit/libdl/rtl-debugger.c
+++ b/cpukit/libdl/rtl-debugger.c
@@ -45,10 +45,10 @@ _rtld_debug_state (void)
 int
 _rtld_linkmap_add (rtems_rtl_obj_t* obj)
 {
-  struct link_map* l = (struct link_map*)obj->detail;
+  struct link_map* l = obj->linkmap;
   struct link_map* prev;
-  uint32_t obj_num = obj->obj_num;
-  int i;
+  uint32_t         obj_num = obj->obj_num;
+  int              i;
 
   if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
     printf ("rtl: linkmap_add\n");
@@ -78,8 +78,10 @@ _rtld_linkmap_add (rtems_rtl_obj_t* obj)
 void
 _rtld_linkmap_delete (rtems_rtl_obj_t* obj)
 {
-  struct link_map* l = (struct link_map*)obj->detail;
-  /* link_maps are allocated together if not 1 */
+  struct link_map* l = obj->linkmap;
+  /*
+   *  link_maps are allocated together if not 1
+   */
   struct link_map* e = l + obj->obj_num - 1;
 
   while (e && e->l_next) e = e->l_next;
@@ -90,7 +92,7 @@ _rtld_linkmap_delete (rtems_rtl_obj_t* obj)
       e->l_next->l_prev = NULL;
     return;
   }
+
   if ((l->l_prev->l_next = e->l_next) != NULL)
     e->l_next->l_prev = l->l_prev;
-  return;
 }
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index b686a48..37775ff 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -30,6 +30,7 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
 #include "rtl-unresolved.h"
 
 /**
@@ -169,6 +170,9 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t*      obj,
                                          &relbuf[0], reloc_size))
       return false;
 
+    /*
+     * Read the symbol details.
+     */
     if (is_rela)
       off = (obj->ooffset + symsect->offset +
              (ELF_R_SYM (rela->r_info) * sizeof (sym)));
@@ -246,7 +250,7 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t*      obj,
       if (is_rela)
       {
         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-          printf ("rtl: rela: sym:%s(%-2d)=%08lx type:%-2d off:%08lx addend:%d\n",
+          printf ("rtl: rela: sym:%s(%d)=%08lx type:%d off:%08lx addend:%d\n",
                   symname, (int) ELF_R_SYM (rela->r_info), symvalue,
                   (int) ELF_R_TYPE (rela->r_info), rela->r_offset, (int) rela->r_addend);
         if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect,
@@ -256,7 +260,7 @@ rtems_rtl_elf_relocator (rtems_rtl_obj_t*      obj,
       else
       {
         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-          printf ("rtl: rel: sym:%s(%-2d)=%08lx type:%-2d off:%08lx\n",
+          printf ("rtl: rel: sym:%s(%d)=%08lx type:%d off:%08lx\n",
                   symname, (int) ELF_R_SYM (rel->r_info), symvalue,
                   (int) ELF_R_TYPE (rel->r_info), rel->r_offset);
         if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect,
@@ -300,7 +304,7 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc_t* reloc,
     rela.r_info = reloc->rel[REL_R_INFO];
     rela.r_addend = reloc->rel[REL_R_ADDEND];
     if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-          printf ("rtl: rela: sym:%-2d type:%-2d off:%08lx addend:%d\n",
+          printf ("rtl: rela: sym:%d type:%d off:%08lx addend:%d\n",
                   (int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info),
                   rela.r_offset, (int) rela.r_addend);
     if (!rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect,
@@ -313,7 +317,7 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc_t* reloc,
     rel.r_offset = reloc->rel[REL_R_OFFSET];
     rel.r_info = reloc->rel[REL_R_INFO];
     if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-      printf ("rtl: rel: sym:%-2d type:%-2d off:%08lx\n",
+      printf ("rtl: rel: sym:%d type:%d off:%08lx\n",
               (int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info),
               rel.r_offset);
     if (!rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect,
@@ -707,9 +711,16 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
         break;
 
       default:
-        if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
-          printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
-                  section, (int) shdr.sh_type, (int) shdr.sh_flags);
+        /*
+         * See there are architecture specific flags?
+         */
+        flags = rtems_rtl_elf_section_flags (obj, &shdr);
+        if (flags == 0)
+        {
+          if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
+            printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
+                    section, (int) shdr.sh_type, (int) shdr.sh_flags);
+        }
         break;
     }
 
@@ -729,6 +740,12 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
       if (strcmp (".dtors", name) == 0)
         flags |= RTEMS_RTL_OBJ_SECT_DTOR;
 
+      if (rtems_rtl_elf_unwind_parse (obj, name, flags))
+      {
+        flags &= ~(RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST);
+        flags |= RTEMS_RTL_OBJ_SECT_EH;
+      }
+
       if (!rtems_rtl_obj_add_section (obj, section, name,
                                       shdr.sh_size, shdr.sh_offset,
                                       shdr.sh_addralign, shdr.sh_link,
@@ -771,16 +788,19 @@ rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd)
   return true;
 }
 
-bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj)
+static bool
+rtems_rtl_elf_load_linkmap (rtems_rtl_obj_t* obj)
 {
   rtems_chain_control* sections = NULL;
   rtems_chain_node*    node = NULL;
   size_t               mask = 0;
-  struct link_map*     l = NULL;
   int                  sec_num = 0;
+  section_detail*      sd;
   int                  i = 0;
 
-  /* caculate the size of sections' name. */
+  /*
+   * Caculate the size of sections' name.
+   */
 
   for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
        mask <= RTEMS_RTL_OBJ_SECT_BSS;
@@ -791,7 +811,6 @@ bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj)
     while (!rtems_chain_is_tail (sections, node))
     {
       rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
-
       if ((sect->size != 0) && ((sect->flags & mask) != 0))
       {
         ++sec_num;
@@ -801,32 +820,31 @@ bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj)
   }
 
   obj->obj_num = 1;
-  obj->detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
-                                     sizeof(struct link_map) +
-                                     sec_num * sizeof (section_detail), true);
-  if (!obj->detail)
+  obj->linkmap = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
+                                      sizeof(struct link_map) +
+                                      sec_num * sizeof (section_detail), true);
+  if (!obj->linkmap)
   {
-    rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
+    rtems_rtl_set_error (ENOMEM, "no memory for obj linkmap");
     return false;
   }
 
-  l = (struct link_map*) obj->detail;
-  l->name = obj->oname;
-  l->sec_num = sec_num;
-  l->sec_detail = (section_detail*) (l + 1);
-  l->rpathlen = 0;
-  l->rpath = NULL;
-  l->l_next = NULL;
-  l->l_prev = NULL;
-  l->sec_addr[rap_text] = obj->text_base;
-  l->sec_addr[rap_const] = obj->const_base;
-  l->sec_addr[rap_data] = obj->data_base;
-  l->sec_addr[rap_bss] = obj->bss_base;
-
-
-  section_detail* sd = l->sec_detail;
+  obj->linkmap->name = obj->oname;
+  obj->linkmap->sec_num = sec_num;
+  obj->linkmap->sec_detail = (section_detail*) (obj->linkmap + 1);
+  obj->linkmap->rpathlen = 0;
+  obj->linkmap->rpath = NULL;
+  obj->linkmap->l_next = NULL;
+  obj->linkmap->l_prev = NULL;
+  obj->linkmap->sec_addr[rap_text] = obj->text_base;
+  obj->linkmap->sec_addr[rap_const] = obj->const_base;
+  obj->linkmap->sec_addr[rap_data] = obj->data_base;
+  obj->linkmap->sec_addr[rap_bss] = obj->bss_base;
+
+  sd = obj->linkmap->sec_detail;
   sections = &obj->sections;
   node = rtems_chain_first (sections);
+
   for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
        mask <= RTEMS_RTL_OBJ_SECT_BSS;
        mask <<= 1)
@@ -948,7 +966,12 @@ rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd)
 
   rtems_rtl_symbol_obj_erase_local (obj);
 
-  if (!rtems_rtl_elf_load_details (obj))
+  if (!rtems_rtl_elf_load_linkmap (obj))
+  {
+    return false;
+  }
+
+  if (!rtems_rtl_elf_unwind_register (obj))
   {
     return false;
   }
@@ -956,6 +979,13 @@ rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd)
   return true;
 }
 
+bool
+rtems_rtl_elf_file_unload (rtems_rtl_obj_t* obj)
+{
+  rtems_rtl_elf_unwind_deregister (obj);
+  return true;
+}
+
 rtems_rtl_loader_format_t*
 rtems_rtl_elf_file_sig (void)
 {
diff --git a/cpukit/libdl/rtl-elf.h b/cpukit/libdl/rtl-elf.h
index 7f6ea30..e3ac07f 100644
--- a/cpukit/libdl/rtl-elf.h
+++ b/cpukit/libdl/rtl-elf.h
@@ -55,6 +55,18 @@ extern "C" {
 #define RTEMS_RTL_ELF_STRING_MAX (256)
 
 /**
+ * Architecture specific handler to translate unknown section flags to RTL
+ * section flags.
+ *
+ * @param obj The object file being relocated.
+ * @param shdr The ELF section header.
+ * @retval 0 Unknown or unsupported flags.
+ * @retval uint32_t RTL object file flags.
+ */
+uint32_t rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                                      const Elf_Shdr*        shdr);
+
+/**
  * Architecture specific handler to check is a relocation record's type is
  * required to resolve a symbol.
  *
@@ -137,13 +149,6 @@ bool rtems_rtl_elf_find_symbol (rtems_rtl_obj_t* obj,
 bool rtems_rtl_elf_file_check (rtems_rtl_obj_t* obj, int fd);
 
 /**
- * The ELF file details handler.
- *
- * @param obj Load the details of the obj.
- */
-bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj);
-
-/**
  * The ELF format load handler.
  *
  * @param obj The object to load.
@@ -152,6 +157,13 @@ bool rtems_rtl_elf_load_details (rtems_rtl_obj_t* obj);
 bool rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd);
 
 /**
+ * The ELF format unload handler.
+ *
+ * @param obj The object to unload.
+ */
+bool rtems_rtl_elf_file_unload (rtems_rtl_obj_t* obj);
+
+/**
  * The ELF format signature handler.
  *
  * @return rtems_rtl_loader_format_t* The format's signature.
diff --git a/cpukit/libdl/rtl-error.c b/cpukit/libdl/rtl-error.c
index 3251fa5..5ec4b26 100644
--- a/cpukit/libdl/rtl-error.c
+++ b/cpukit/libdl/rtl-error.c
@@ -17,6 +17,7 @@
 #include "config.h"
 #endif
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdarg.h>
 
@@ -39,9 +40,15 @@ int
 rtems_rtl_get_error (char* message, size_t max_message)
 {
   rtems_rtl_data_t* rtl = rtems_rtl_lock ();
-  int               last_errno = rtl->last_errno;
-  strncpy (message, rtl->last_error, sizeof (rtl->last_error));
-  rtems_rtl_unlock ();
-  return last_errno;
-}
+  if (rtl != NULL)
+  {
+    int last_errno = rtl->last_errno;
+    strncpy (message, rtl->last_error, sizeof (rtl->last_error));
+    rtems_rtl_unlock ();
+    return last_errno;
+  }
 
+  strncpy(message, "RTL init error", max_message);
+
+  return EIO;
+}
diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c
index 84d58e3..4c55cae 100644
--- a/cpukit/libdl/rtl-mdreloc-arm.c
+++ b/cpukit/libdl/rtl-mdreloc-arm.c
@@ -10,11 +10,14 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <unwind.h>
+#include <unwind-arm-common.h>
 
 #include <rtems/rtl/rtl.h>
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
 
 /*
  * It is possible for the compiler to emit relocations for unaligned data.
@@ -23,6 +26,8 @@
 #define	RELOC_ALIGNED_P(x) \
 	(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
 
+#define SHT_ARM_EXIDX  0x70000001 /* Section holds ARM unwind info. */
+
 static inline Elf_Addr
 load_ptr(void *where)
 {
@@ -56,9 +61,18 @@ static inline Elf_SOff
 sign_extend31(Elf_Addr val)
 {
   if (0x40000000 & val)
-    return ~((Elf_Addr)0x7fffffff) | (0x7fffffff & val);
-  else
-    return 0x7fffffff & val;
+    val =  ~((Elf_Addr)0x7fffffff) | (0x7fffffff & val);
+  return 0x7fffffff & val;
+}
+
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  uint32_t flags = 0;
+  if (shdr->sh_type == SHT_ARM_EXIDX)
+    flags = RTEMS_RTL_OBJ_SECT_EH | RTEMS_RTL_OBJ_SECT_LOAD;
+  return flags;
 }
 
 bool
@@ -96,8 +110,11 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
   where = (Elf_Addr *)(sect->base + rel->r_offset);
 
   switch (ELF_R_TYPE(rel->r_info)) {
-		case R_TYPE(NONE):
-			break;
+    case R_TYPE(NONE):
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
+        printf ("rtl: NONE %p in %s\n", where, rtems_rtl_obj_oname (obj));
+      }
+      break;
 
     case R_TYPE(CALL):    /* BL/BLX */
     case R_TYPE(JUMP24):  /* B/BL<cond> */
@@ -175,29 +192,31 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
     case R_TYPE(ABS32):     /* word32 (S + A) | T */
     case R_TYPE(GLOB_DAT):  /* word32 (S + A) | T */
     case R_TYPE(PREL31):    /* word32 (S + A) | T - P */
-    case R_TYPE(TARGET2):   /* Equivalent to ABS32 */
+    case R_TYPE(TARGET2):   /* Equivalent to REL32 */
       if (__predict_true(RELOC_ALIGNED_P(where))) {
         tmp = *where + symvalue;
         if (isThumb(symvalue))
           tmp |= 1;
-        if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32))
+        if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32) ||
+            ELF_R_TYPE(rel->r_info) == R_TYPE(TARGET2))
           tmp -= (Elf_Addr)where;
         else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
-          tmp -= sign_extend31((Elf_Addr)where);
+          tmp = sign_extend31(tmp - (Elf_Addr)where);
         *where = tmp;
       } else {
         tmp = load_ptr(where) + symvalue;
         if (isThumb(symvalue))
           tmp |= 1;
-        if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32))
+        if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32) ||
+            ELF_R_TYPE(rel->r_info) == R_TYPE(TARGET2))
           tmp -= (Elf_Addr)where;
         else if (ELF_R_TYPE(rel->r_info) == R_TYPE(PREL31))
-          tmp -= sign_extend31((Elf_Addr)where);
+          tmp = sign_extend31(tmp - (Elf_Addr)where);
         store_ptr(where, tmp);
       }
 
       if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-        printf ("rtl: REL32/ABS32/GLOB_DAT/PREL31/TARGET2 %p @ %p in %s",
+        printf ("rtl: REL32/ABS32/GLOB_DAT/PREL31/TARGET2 %p @ %p in %s\n",
                 (void *)tmp, where, rtems_rtl_obj_oname (obj));
       break;
 
@@ -321,7 +340,7 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
                 (void *)*where, where, rtems_rtl_obj_oname (obj));
       break;
 
-		default:
+    default:
       printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
               "contents = %p\n",
               ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
@@ -330,9 +349,109 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
                            "%s: Unsupported relocation type %ld "
                            "in non-PLT relocations",
                            sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
-			return false;
+      return false;
   }
 
-	return true;
+  return true;
 }
 
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  /*
+   * We location the EH sections in section flags.
+   */
+  return false;
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  rtems_chain_control* sections = &obj->sections;
+  rtems_chain_node*    node = rtems_chain_first (sections);
+  while (!rtems_chain_is_tail (sections, node))
+  {
+    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
+    if ((sect->flags & RTEMS_RTL_OBJ_SECT_EH) != 0)
+    {
+      break;
+    }
+    node = rtems_chain_next (node);
+  }
+  return true;
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  obj->loader = NULL;
+  return true;
+}
+
+/* An exception index table entry.  */
+typedef struct __EIT_entry
+{
+  _uw fnoffset;
+  _uw content;
+} __EIT_entry;
+
+/* The exception index table location in the base module */
+extern __EIT_entry __exidx_start;
+extern __EIT_entry __exidx_end;
+
+static inline _uw
+selfrel_offset31 (const _uw *p)
+{
+  _uw offset;
+
+  offset = *p;
+  /* Sign extend to 32 bits.  */
+  if (offset & (1 << 30))
+    offset |= 1u << 31;
+  else
+    offset &= ~(1u << 31);
+
+  return offset + (_uw) p;
+}
+
+/*
+ * A weak reference is in libgcc, provide a real version and provide a way to
+ * manage loaded modules.
+ *
+ * Passed in the return address and a reference to the number of records
+ * found. We set the start of the exidx data and the number of records.
+ */
+_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address,
+                                     int*        nrec) __attribute__ ((__noinline__,
+                                                                       __used__,
+                                                                       __noclone__));
+
+_Unwind_Ptr __gnu_Unwind_Find_exidx (_Unwind_Ptr return_address,
+                                     int*        nrec)
+{
+  rtems_rtl_data_t* rtl;
+  rtems_chain_node* node;
+  __EIT_entry*      exidx_start = &__exidx_start;
+  __EIT_entry*      exidx_end = &__exidx_end;
+
+  rtl = rtems_rtl_lock ();
+
+  node = rtems_chain_first (&rtl->objects);
+  while (!rtems_chain_is_tail (&rtl->objects, node)) {
+    rtems_rtl_obj_t* obj = (rtems_rtl_obj_t*) node;
+    if (rtems_rtl_obj_text_inside (obj, (void*) return_address)) {
+      exidx_start = (__EIT_entry*) obj->eh_base;
+      exidx_end = (__EIT_entry*) (obj->eh_base + obj->eh_size);
+      break;
+    }
+    node = rtems_chain_next (node);
+  }
+
+  rtems_rtl_unlock ();
+
+  *nrec = exidx_end - exidx_start;
+
+  return (_Unwind_Ptr) exidx_start;
+}
diff --git a/cpukit/libdl/rtl-mdreloc-bfin.c b/cpukit/libdl/rtl-mdreloc-bfin.c
index d855d30..5a1fd26 100644
--- a/cpukit/libdl/rtl-mdreloc-bfin.c
+++ b/cpukit/libdl/rtl-mdreloc-bfin.c
@@ -6,6 +6,15 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
+
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
 
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
@@ -113,3 +122,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
   return false;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-mdreloc-h8300.c b/cpukit/libdl/rtl-mdreloc-h8300.c
index 925601b..0ef717b 100644
--- a/cpukit/libdl/rtl-mdreloc-h8300.c
+++ b/cpukit/libdl/rtl-mdreloc-h8300.c
@@ -9,6 +9,15 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
+
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
 
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
@@ -99,3 +108,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
   return false;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-mdreloc-i386.c b/cpukit/libdl/rtl-mdreloc-i386.c
index b6dd9b7..c8f1e11 100644
--- a/cpukit/libdl/rtl-mdreloc-i386.c
+++ b/cpukit/libdl/rtl-mdreloc-i386.c
@@ -15,6 +15,15 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
+
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
 
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
@@ -101,3 +110,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
 
   return true;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-mdreloc-lm32.c b/cpukit/libdl/rtl-mdreloc-lm32.c
index 057d6ce..e7e2a4c 100644
--- a/cpukit/libdl/rtl-mdreloc-lm32.c
+++ b/cpukit/libdl/rtl-mdreloc-lm32.c
@@ -9,6 +9,15 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
+
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
 
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
@@ -118,3 +127,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
   rtems_rtl_set_error (EINVAL, "rela type record not supported");
   return false;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-mdreloc-m68k.c b/cpukit/libdl/rtl-mdreloc-m68k.c
index 36692eb..8a91ebc 100644
--- a/cpukit/libdl/rtl-mdreloc-m68k.c
+++ b/cpukit/libdl/rtl-mdreloc-m68k.c
@@ -15,6 +15,8 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
 
 static inline int overflow_8_check(int value)
 {
@@ -30,6 +32,13 @@ static inline int overflow_16_check(int value)
   return false;
 }
 
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
+
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
 {
@@ -146,3 +155,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
   return false;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-mdreloc-mips.c b/cpukit/libdl/rtl-mdreloc-mips.c
index c17dbc2..7ceac54 100644
--- a/cpukit/libdl/rtl-mdreloc-mips.c
+++ b/cpukit/libdl/rtl-mdreloc-mips.c
@@ -9,6 +9,15 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
+
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
 
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
@@ -188,3 +197,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
 
   return true;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-mdreloc-moxie.c b/cpukit/libdl/rtl-mdreloc-moxie.c
index 1fb05e6..27b0cf6 100644
--- a/cpukit/libdl/rtl-mdreloc-moxie.c
+++ b/cpukit/libdl/rtl-mdreloc-moxie.c
@@ -10,6 +10,15 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
+
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
 
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
@@ -86,3 +95,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
   return false;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-mdreloc-powerpc.c b/cpukit/libdl/rtl-mdreloc-powerpc.c
index 6909167..43c0b83 100644
--- a/cpukit/libdl/rtl-mdreloc-powerpc.c
+++ b/cpukit/libdl/rtl-mdreloc-powerpc.c
@@ -15,11 +15,19 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
 
 #define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
                  ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
 #define l(x) ((u_int32_t)(x) & 0xffff)
 
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
 
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
@@ -158,6 +166,21 @@ rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t*      obj,
                 (void *)*where, where, rtems_rtl_obj_oname (obj));
       break;
 
+    case R_TYPE(SDAREL16):
+      /*
+       * A sign-extended 16 bit value relative to _SDA_BASE_, for use with
+       * small data items.
+       */
+      mask = 0xffff;
+      tmp = *((Elf32_Half*) where);
+      tmp &= ~mask;
+      tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask;
+      *((Elf32_Half*) where) = tmp;
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+        printf ("rtl: SDAREL16 %p @ %p in %s\n",
+                (void *) *((Elf32_Half*) where), where, rtems_rtl_obj_oname (obj));
+      break;
+
     default:
       printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
               "contents = %p\n",
@@ -183,3 +206,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
   printf ("rtl: rel type record not supported; please report\n");
   return false;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-mdreloc-sparc.c b/cpukit/libdl/rtl-mdreloc-sparc.c
index 509b62f..38b3850 100644
--- a/cpukit/libdl/rtl-mdreloc-sparc.c
+++ b/cpukit/libdl/rtl-mdreloc-sparc.c
@@ -41,6 +41,8 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
 
 /*
  * The following table holds for each relocation type:
@@ -128,6 +130,13 @@ static const int reloc_target_bitmask[] = {
 };
 #define RELOC_VALUE_BITMASK(t)  (reloc_target_bitmask[t])
 
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
+
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
 {
@@ -220,21 +229,22 @@ rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t*      obj,
   value &= mask;
 
   if (RELOC_UNALIGNED(type)) {
-    /* Handle unaligned relocations. */
-    char *ptr = (char *)where;
+    /*
+     * Handle unaligned relocations.
+     */
+    char *ptr = (char*) where;
     int i, size = RELOC_TARGET_SIZE (type) / 8;
 
     /* Read it in one byte at a time. */
-    for (i=0; i<size; i++)
+    for (i = size - 1; i >= 0; i--)
       tmp = (tmp << 8) | ptr[i];
 
     tmp &= ~mask;
     tmp |= value;
 
     /* Write it back out. */
-    for (i=0; i<size; i++)
-      ptr[i] = ((tmp >> (8*i)) & 0xff);
-
+    for (i = size - 1; i >= 0; i--, tmp >>= 8)
+      ptr[i] = tmp & 0xff;
   } else {
     *where &= ~mask;
     *where |= value;
@@ -245,7 +255,6 @@ rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t*      obj,
     printf ("rtl: %s %p @ %p in %s\n",
             reloc_names[type], (void *)tmp, where, rtems_rtl_obj_oname (obj));
 
-
   return true;
 }
 
@@ -260,3 +269,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
   printf ("rtl: rel type record not supported; please report\n");
   return false;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-mdreloc-v850.c b/cpukit/libdl/rtl-mdreloc-v850.c
index 5372e81..7f958a5 100644
--- a/cpukit/libdl/rtl-mdreloc-v850.c
+++ b/cpukit/libdl/rtl-mdreloc-v850.c
@@ -10,6 +10,15 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include "rtl-trace.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
+
+uint32_t
+rtems_rtl_elf_section_flags (const rtems_rtl_obj_t* obj,
+                             const Elf_Shdr*        shdr)
+{
+  return 0;
+}
 
 bool
 rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
@@ -95,3 +104,23 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t*      obj,
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
   return false;
 }
+
+bool
+rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                            const char*            name,
+                            uint32_t               flags)
+{
+  return rtems_rtl_elf_unwind_dw2_parse (obj, name, flags);
+}
+
+bool
+rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_register (obj);
+}
+
+bool
+rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_elf_unwind_dw2_deregister (obj);
+}
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c
index bdcebce..b27f28b 100644
--- a/cpukit/libdl/rtl-obj.c
+++ b/cpukit/libdl/rtl-obj.c
@@ -49,14 +49,21 @@
 /**
  * The table of supported loader formats.
  */
-static rtems_rtl_loader_table_t loaders[RTEMS_RTL_ELF_LOADER_COUNT +
-                                        RTEMS_RTL_RAP_LOADER_COUNT] =
+#define RTEMS_RTL_LOADERS (RTEMS_RTL_ELF_LOADER_COUNT + RTEMS_RTL_RAP_LOADER_COUNT)
+static const rtems_rtl_loader_table_t loaders[RTEMS_RTL_LOADERS] =
 {
 #if RTEMS_RTL_RAP_LOADER
-  { rtems_rtl_rap_file_check, rtems_rtl_rap_file_load, rtems_rtl_rap_file_sig },
+  { .check     = rtems_rtl_rap_file_check,
+    .load      = rtems_rtl_rap_file_load,
+    .unload    = rtems_rtl_rap_file_unload,
+    .unload    = rtems_rtl_rap_file_unload,
+    .signature = rtems_rtl_rap_file_sig },
 #endif
 #if RTEMS_RTL_ELF_LOADER
-  { rtems_rtl_elf_file_check, rtems_rtl_elf_file_load, rtems_rtl_elf_file_sig },
+  { .check     = rtems_rtl_elf_file_check,
+    .load      = rtems_rtl_elf_file_load,
+    .unload    = rtems_rtl_elf_file_unload,
+    .signature = rtems_rtl_elf_file_sig },
 #endif
 };
 
@@ -72,6 +79,10 @@ rtems_rtl_obj_alloc (void)
      * Initialise the chains.
      */
     rtems_chain_initialize_empty (&obj->sections);
+    /*
+     * No valid format.
+     */
+    obj->format = -1;
   }
   return obj;
 }
@@ -97,14 +108,14 @@ rtems_rtl_obj_free (rtems_rtl_obj_t* obj)
   }
   if (!rtems_chain_is_node_off_chain (&obj->link))
     rtems_chain_extract (&obj->link);
-  rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
+  rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, &obj->eh_base,
                               &obj->data_base, &obj->bss_base);
   rtems_rtl_symbol_obj_erase (obj);
   rtems_rtl_obj_free_names (obj);
   if (obj->sec_num)
     free (obj->sec_num);
-  if (obj->detail)
-    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*)obj->detail);
+  if (obj->linkmap)
+    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->linkmap);
   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj);
   return true;
 }
@@ -238,7 +249,7 @@ rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
 static size_t
 rtems_rtl_sect_align (size_t offset, uint32_t alignment)
 {
-  if ((alignment > 1) && ((offset & ~alignment) != 0))
+  if ((alignment > 1) && ((offset & (alignment - 1)) != 0))
     offset = (offset + alignment) & ~(alignment - 1);
   return offset;
 }
@@ -264,12 +275,12 @@ rtems_rtl_obj_sect_summer (rtems_chain_node* node, void* data)
 }
 
 static size_t
-rtems_rtl_obj_section_size (rtems_rtl_obj_t* obj, uint32_t mask)
+rtems_rtl_obj_section_size (const rtems_rtl_obj_t* obj, uint32_t mask)
 {
   rtems_rtl_obj_sect_summer_t summer;
   summer.mask = mask;
   summer.size = 0;
-  rtems_rtl_chain_iterate (&obj->sections,
+  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
                            rtems_rtl_obj_sect_summer,
                            &summer);
   return summer.size;
@@ -302,12 +313,12 @@ rtems_rtl_obj_sect_aligner (rtems_chain_node* node, void* data)
 }
 
 static size_t
-rtems_rtl_obj_section_alignment (rtems_rtl_obj_t* obj, uint32_t mask)
+rtems_rtl_obj_section_alignment (const rtems_rtl_obj_t* obj, uint32_t mask)
 {
   rtems_rtl_obj_sect_aligner_t aligner;
   aligner.mask = mask;
   aligner.alignment = 0;
-  rtems_rtl_chain_iterate (&obj->sections,
+  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
                            rtems_rtl_obj_sect_aligner,
                            &aligner);
   return aligner.alignment;
@@ -401,26 +412,30 @@ rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj,
                            int              info,
                            uint32_t         flags)
 {
-  rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
-                                                    sizeof (rtems_rtl_obj_sect_t), true);
-  if (!sect)
+  if (size > 0)
   {
-    rtems_rtl_set_error (ENOMEM, "adding allocated section");
-    return false;
+    rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
+                                                      sizeof (rtems_rtl_obj_sect_t),
+                                                      true);
+    if (!sect)
+    {
+      rtems_rtl_set_error (ENOMEM, "adding allocated section");
+      return false;
+    }
+    sect->section = section;
+    sect->name = rtems_rtl_strdup (name);
+    sect->size = size;
+    sect->offset = offset;
+    sect->alignment = alignment;
+    sect->link = link;
+    sect->info = info;
+    sect->flags = flags;
+    sect->base = NULL;
+    rtems_chain_append (&obj->sections, &sect->node);
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
+      printf ("rtl: sect: %-2d: %s (%zu)\n", section, name, size);
   }
-  sect->section = section;
-  sect->name = rtems_rtl_strdup (name);
-  sect->size = size;
-  sect->offset = offset;
-  sect->alignment = alignment;
-  sect->link = link;
-  sect->info = info;
-  sect->flags = flags;
-  sect->base = NULL;
-  rtems_chain_append (&obj->sections, &sect->node);
-
-  if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
-    printf ("rtl: sect: %-2d: %s\n", section, name);
 
   return true;
 }
@@ -464,12 +479,13 @@ rtems_rtl_obj_sect_match_name (rtems_chain_node* node, void* data)
 }
 
 rtems_rtl_obj_sect_t*
-rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj, const char* name)
+rtems_rtl_obj_find_section (const rtems_rtl_obj_t* obj,
+                            const char*            name)
 {
   rtems_rtl_obj_sect_finder_t match;
   match.sect = NULL;
   match.name = name;
-  rtems_rtl_chain_iterate (&obj->sections,
+  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
                            rtems_rtl_obj_sect_match_name,
                            &match);
   return match.sect;
@@ -489,61 +505,74 @@ rtems_rtl_obj_sect_match_index (rtems_chain_node* node, void* data)
 }
 
 rtems_rtl_obj_sect_t*
-rtems_rtl_obj_find_section_by_index (rtems_rtl_obj_t* obj, int index)
+rtems_rtl_obj_find_section_by_index (const rtems_rtl_obj_t* obj,
+                                     int                    index)
 {
   rtems_rtl_obj_sect_finder_t match;
   match.sect = NULL;
   match.index = index;
-  rtems_rtl_chain_iterate (&obj->sections,
+  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
                            rtems_rtl_obj_sect_match_index,
                            &match);
   return match.sect;
 }
 
 size_t
-rtems_rtl_obj_text_size (rtems_rtl_obj_t* obj)
+rtems_rtl_obj_text_size (const rtems_rtl_obj_t* obj)
 {
   return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_TEXT);
 }
 
 uint32_t
-rtems_rtl_obj_text_alignment (rtems_rtl_obj_t* obj)
+rtems_rtl_obj_text_alignment (const rtems_rtl_obj_t* obj)
 {
   return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_TEXT);
 }
 
 size_t
-rtems_rtl_obj_const_size (rtems_rtl_obj_t* obj)
+rtems_rtl_obj_const_size (const rtems_rtl_obj_t* obj)
 {
   return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_CONST);
 }
 
 uint32_t
-rtems_rtl_obj_const_alignment (rtems_rtl_obj_t* obj)
+rtems_rtl_obj_eh_alignment (const rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_EH);
+}
+
+size_t
+rtems_rtl_obj_eh_size (const rtems_rtl_obj_t* obj)
+{
+  return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_EH);
+}
+
+uint32_t
+rtems_rtl_obj_const_alignment (const rtems_rtl_obj_t* obj)
 {
   return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_CONST);
 }
 
 size_t
-rtems_rtl_obj_data_size (rtems_rtl_obj_t* obj)
+rtems_rtl_obj_data_size (const rtems_rtl_obj_t* obj)
 {
   return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_DATA);
 }
 
 uint32_t
-rtems_rtl_obj_data_alignment (rtems_rtl_obj_t* obj)
+rtems_rtl_obj_data_alignment (const rtems_rtl_obj_t* obj)
 {
   return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_DATA);
 }
 
 size_t
-rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj)
+rtems_rtl_obj_bss_size (const rtems_rtl_obj_t* obj)
 {
   return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_BSS);
 }
 
 uint32_t
-rtems_rtl_obj_bss_alignment (rtems_rtl_obj_t* obj)
+rtems_rtl_obj_bss_alignment (const rtems_rtl_obj_t* obj)
 {
   return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_BSS);
 }
@@ -580,13 +609,17 @@ rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
   if ( !(sect->flags & sync_ctx->mask) || !sect->size)
     return true;
 
-  if (sync_ctx->end_va == sync_ctx->start_va) {
+  if (sync_ctx->end_va == sync_ctx->start_va)
+  {
     sync_ctx->start_va = sect->base;
-  } else {
-    old_end = (uintptr_t)sync_ctx->end_va & ~(sync_ctx->cache_line_size - 1);
-    new_start = (uintptr_t)sect->base & ~(sync_ctx->cache_line_size - 1);
-    if ( (sect->base <  sync_ctx->start_va) ||
-         (new_start - old_end > sync_ctx->cache_line_size) ) {
+  }
+  else
+  {
+    old_end = (uintptr_t) sync_ctx->end_va & ~(sync_ctx->cache_line_size - 1);
+    new_start = (uintptr_t) sect->base & ~(sync_ctx->cache_line_size - 1);
+    if ((sect->base <  sync_ctx->start_va) ||
+        (new_start - old_end > sync_ctx->cache_line_size))
+    {
       rtems_cache_instruction_sync_after_code_change(sync_ctx->start_va,
                              sync_ctx->end_va - sync_ctx->start_va + 1);
       sync_ctx->start_va = sect->base;
@@ -658,8 +691,8 @@ rtems_rtl_obj_sections_loader (uint32_t                     mask,
       sect->base = base + base_offset;
 
       if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
-        printf ("rtl: loading: %s -> %8p (%zi)\n",
-                sect->name, sect->base, sect->size);
+        printf ("rtl: loading: %s -> %8p (l:%zi m:%04lx)\n",
+                sect->name, sect->base, sect->size, sect->flags);
 
       if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
       {
@@ -698,20 +731,30 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t*             obj,
 {
   size_t text_size;
   size_t const_size;
+  size_t eh_size;
   size_t data_size;
   size_t bss_size;
 
   text_size  = rtems_rtl_obj_text_size (obj) + rtems_rtl_obj_const_alignment (obj);
-  const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_data_alignment (obj);
+  const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_eh_alignment (obj);
+  eh_size    = rtems_rtl_obj_eh_size (obj) + rtems_rtl_obj_data_alignment (obj);
   data_size  = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj);
   bss_size   = rtems_rtl_obj_bss_size (obj);
 
   /*
+   * Set the sizes held in the object data. We need this for a fast reference.
+   */
+  obj->text_size = text_size;
+  obj->eh_size   = eh_size;
+  obj->bss_size  = bss_size;
+
+  /*
    * Let the allocator manage the actual allocation. The user can use the
    * standard heap or provide a specific allocator with memory protection.
    */
   if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size,
                                    &obj->const_base, const_size,
+                                   &obj->eh_base, eh_size,
                                    &obj->data_base, data_size,
                                    &obj->bss_base, bss_size))
   {
@@ -728,6 +771,8 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t*             obj,
             obj->text_base, text_size, rtems_rtl_obj_text_alignment (obj));
     printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n",
             obj->const_base, const_size, rtems_rtl_obj_const_alignment (obj));
+    printf ("rtl: load sect: eh    - b:%p s:%zi a:%" PRIu32 "\n",
+            obj->eh_base, eh_size, rtems_rtl_obj_eh_alignment (obj));
     printf ("rtl: load sect: data  - b:%p s:%zi a:%" PRIu32 "\n",
             obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj));
     printf ("rtl: load sect: bss   - b:%p s:%zi a:%" PRIu32 "\n",
@@ -742,12 +787,14 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t*             obj,
                                       obj, fd, obj->text_base, handler, data) ||
       !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST,
                                       obj, fd, obj->const_base, handler, data) ||
+      !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_EH,
+                                      obj, fd, obj->eh_base, handler, data) ||
       !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_DATA,
                                       obj, fd, obj->data_base, handler, data) ||
       !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS,
                                       obj, fd, obj->bss_base, handler, data))
   {
-    rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base,
+    rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, &obj->eh_base,
                                 &obj->data_base, &obj->bss_base);
     obj->exec_size = 0;
     return false;
@@ -972,7 +1019,7 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
              * name from the table and compare with the name we are after.
              */
 #define RTEMS_RTL_MAX_FILE_SIZE (256)
-            char  name[RTEMS_RTL_MAX_FILE_SIZE];
+            char name[RTEMS_RTL_MAX_FILE_SIZE];
 
             if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off,
                                       RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0]))
@@ -1016,7 +1063,7 @@ rtems_rtl_obj_archive_find (rtems_rtl_obj_t* obj, int fd)
   return false;
 }
 
-bool
+static bool
 rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
 {
   int l;
@@ -1024,13 +1071,24 @@ rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd)
   for (l = 0; l < (sizeof (loaders) / sizeof (rtems_rtl_loader_table_t)); ++l)
   {
     if (loaders[l].check (obj, fd))
+    {
+      obj->format = l;
       return loaders[l].load (obj, fd);
+    }
   }
 
   rtems_rtl_set_error (ENOENT, "no format loader found");
   return false;
 }
 
+static bool
+rtems_rtl_obj_file_unload (rtems_rtl_obj_t* obj)
+{
+  if (obj->format >= 0 && obj->format < RTEMS_RTL_LOADERS)
+      return loaders[obj->format].unload (obj);
+  return false;
+}
+
 bool
 rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
 {
@@ -1057,20 +1115,16 @@ rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
   {
     if (!rtems_rtl_obj_archive_find (obj, fd))
     {
-      rtems_rtl_obj_caches_flush ();
       close (fd);
       return false;
     }
   }
 
   /*
-   * Call the format specific loader. Currently this is a call to the ELF
-   * loader. This call could be changed to allow probes then calls if more than
-   * one format is supported.
+   * Call the format specific loader.
    */
   if (!rtems_rtl_obj_file_load (obj, fd))
   {
-    rtems_rtl_obj_caches_flush ();
     close (fd);
     return false;
   }
@@ -1081,8 +1135,6 @@ rtems_rtl_obj_load (rtems_rtl_obj_t* obj)
     return false;
   }
 
-  rtems_rtl_obj_caches_flush ();
-
   close (fd);
 
   return true;
@@ -1092,6 +1144,6 @@ bool
 rtems_rtl_obj_unload (rtems_rtl_obj_t* obj)
 {
   _rtld_linkmap_delete(obj);
-  rtems_rtl_symbol_obj_erase (obj);
-  return rtems_rtl_obj_free (obj);
+  rtems_rtl_obj_file_unload (obj);
+  return true;
 }
diff --git a/cpukit/libdl/rtl-obj.h b/cpukit/libdl/rtl-obj.h
index 80fc60f..9ec184b 100644
--- a/cpukit/libdl/rtl-obj.h
+++ b/cpukit/libdl/rtl-obj.h
@@ -56,14 +56,20 @@ typedef struct rtems_rtl_loader_format_s
 typedef bool (*rtems_rtl_loader_check) (rtems_rtl_obj_t* obj, int fd);
 
 /**
- * The type of the format loader handler. This handler loads the specific
+ * The type of the format loader load handler. This handler loads the specific
  * format.
  */
 typedef bool (*rtems_rtl_loader_load) (rtems_rtl_obj_t* obj, int fd);
 
 /**
- * The type of the format loader handler. This handler loads the specific
- * format.
+ * The type of the format loader unload handler. This handler unloads the
+ * specific format.
+ */
+typedef bool (*rtems_rtl_loader_unload) (rtems_rtl_obj_t* obj);
+
+/**
+ * The type of the format loader signature handler. This handler checks the
+ * format signature.
  */
 typedef rtems_rtl_loader_format_t* (*rtems_rtl_loader_sig) (void);
 
@@ -72,9 +78,10 @@ typedef rtems_rtl_loader_format_t* (*rtems_rtl_loader_sig) (void);
  */
 typedef struct rtems_rtl_loader_table_s
 {
-  rtems_rtl_loader_check check;     /**< The check handler. */
-  rtems_rtl_loader_load  load;      /**< The loader. */
-  rtems_rtl_loader_sig   signature; /**< The loader's signature. */
+  rtems_rtl_loader_check  check;     /**< The check handler. */
+  rtems_rtl_loader_load   load;      /**< The loader. */
+  rtems_rtl_loader_unload unload;    /**< The unloader. */
+  rtems_rtl_loader_sig    signature; /**< The loader's signature. */
 } rtems_rtl_loader_table_t;
 
 /**
@@ -84,18 +91,19 @@ typedef struct rtems_rtl_loader_table_s
 #define RTEMS_RTL_OBJ_SECT_CONST (1 << 1)  /**< Section holds program text. */
 #define RTEMS_RTL_OBJ_SECT_DATA  (1 << 2)  /**< Section holds program data. */
 #define RTEMS_RTL_OBJ_SECT_BSS   (1 << 3)  /**< Section holds program bss. */
-#define RTEMS_RTL_OBJ_SECT_REL   (1 << 4)  /**< Section holds relocation records. */
-#define RTEMS_RTL_OBJ_SECT_RELA  (1 << 5)  /**< Section holds relocation addend
+#define RTEMS_RTL_OBJ_SECT_EH    (1 << 4)  /**< Section holds exception data. */
+#define RTEMS_RTL_OBJ_SECT_REL   (1 << 5)  /**< Section holds relocation records. */
+#define RTEMS_RTL_OBJ_SECT_RELA  (1 << 6)  /**< Section holds relocation addend
                                             *   records. */
-#define RTEMS_RTL_OBJ_SECT_SYM   (1 << 6)  /**< Section holds symbols. */
-#define RTEMS_RTL_OBJ_SECT_STR   (1 << 7)  /**< Section holds strings. */
-#define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 8)  /**< Section allocates runtime memory. */
-#define RTEMS_RTL_OBJ_SECT_LOAD  (1 << 9)  /**< Section is loaded from object file. */
-#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 10) /**< Section is writable, ie data. */
-#define RTEMS_RTL_OBJ_SECT_EXEC  (1 << 11) /**< Section is executable. */
-#define RTEMS_RTL_OBJ_SECT_ZERO  (1 << 12) /**< Section is preset to zero. */
-#define RTEMS_RTL_OBJ_SECT_CTOR  (1 << 13) /**< Section contains constructors. */
-#define RTEMS_RTL_OBJ_SECT_DTOR  (1 << 14) /**< Section contains destructors. */
+#define RTEMS_RTL_OBJ_SECT_SYM   (1 << 7)  /**< Section holds symbols. */
+#define RTEMS_RTL_OBJ_SECT_STR   (1 << 8)  /**< Section holds strings. */
+#define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 9)  /**< Section allocates runtime memory. */
+#define RTEMS_RTL_OBJ_SECT_LOAD  (1 << 10) /**< Section is loaded from object file. */
+#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 11) /**< Section is writable, ie data. */
+#define RTEMS_RTL_OBJ_SECT_EXEC  (1 << 12) /**< Section is executable. */
+#define RTEMS_RTL_OBJ_SECT_ZERO  (1 << 13) /**< Section is preset to zero. */
+#define RTEMS_RTL_OBJ_SECT_CTOR  (1 << 14) /**< Section contains constructors. */
+#define RTEMS_RTL_OBJ_SECT_DTOR  (1 << 15) /**< Section contains destructors. */
 
 /**
  * An object file is made up of sections and the can be more than
@@ -109,7 +117,7 @@ struct rtems_rtl_obj_sect_s
   const char*      name;        /**< The section's name. */
   size_t           size;        /**< The size of the section in memory. */
   off_t            offset;      /**< Offset into the object file. Relative to
-                                 * the start of the object file. */
+                                 *   the start of the object file. */
   uint32_t         alignment;   /**< Alignment of this section. */
   int              link;        /**< Section link field. */
   int              info;        /**< Secfion info field. */
@@ -135,6 +143,7 @@ struct rtems_rtl_obj_s
   rtems_chain_node     link;         /**< The node's link in the chain. */
   uint32_t             flags;        /**< The status of the object file. */
   uint32_t             users;        /**< References to the object file. */
+  int                  format;       /**< The format of the object file. */
   const char*          fname;        /**< The file name for the object. */
   const char*          oname;        /**< The object file name. Can be
                                       *   relative. */
@@ -153,26 +162,27 @@ struct rtems_rtl_obj_s
   size_t               global_size;  /**< Global symbol memory usage. */
   uint32_t             unresolved;   /**< The number of unresolved relocations. */
   void*                text_base;    /**< The base address of the text section
-                                      * in memory. */
+                                      *   in memory. */
+  size_t               text_size;     /**< The size of the text section. */
   void*                const_base;   /**< The base address of the const section
-                                      * in memory. */
+                                      *   in memory. */
+  void*                eh_base;      /**< The base address of the eh section
+                                      *   in memory. */
+  size_t               eh_size;      /**< The size of the eh section. */
   void*                data_base;    /**< The base address of the data section
-                                      * in memory. */
+                                      *   in memory. */
   void*                bss_base;     /**< The base address of the bss section
-                                      * in memory. */
+                                      *   in memory. */
   size_t               bss_size;     /**< The size of the bss section. */
   size_t               exec_size;    /**< The amount of executable memory
-                                      * allocated */
+                                      *   allocated */
   void*                entry;        /**< The entry point of the module. */
   uint32_t             checksum;     /**< The checksum of the text sections. A
-                                      * zero means do not checksum. */
-  void*                detail;       /**< The file details. It contains the elf file
-                                      * detail, mainly including elf file name,
-                                      * section offset, section size, which
-                                      * elf this section belongs to.*/
+                                      *   zero means do not checksum. */
   uint32_t*            sec_num;      /**< The sec nums of each obj. */
   uint32_t             obj_num;      /**< The count of elf files in an rtl obj. */
   struct link_map*     linkmap;      /**< For GDB. */
+  void*                loader;       /**< The file details specific to a loader. */
 };
 
 /**
@@ -258,6 +268,20 @@ static inline bool rtems_rtl_obj_aname_valid (const rtems_rtl_obj_t* obj)
 }
 
 /**
+ * Is the address inside the text section?
+ *
+ * @param obj The object file.
+ * @return bool There is an archive name
+ */
+static inline bool rtems_rtl_obj_text_inside (const rtems_rtl_obj_t* obj,
+                                              const void*            address)
+{
+  return
+    (address >= obj->text_base) &&
+    (address < (obj->text_base + obj->text_size));
+}
+
+/**
  * Allocate an object structure on the heap.
  *
  * @retval NULL No memory for the object.
@@ -300,18 +324,6 @@ bool rtems_rtl_parse_name (const char*  name,
                            off_t*       ooffset);
 
 /**
- * Load the object file.
- *
- * @param obj The object file's descriptor.
- * @param fd The file descriptor.
- * @param load_syms Load symbols.
- * @param load_dep Load dependent object files.
- * @retval true The load was successful.
- * @retval false The load failed. The RTL error has been set.
- */
-bool rtems_rtl_obj_file_load (rtems_rtl_obj_t* obj, int fd);
-
-/**
  * Check of the name matches the object file's object name.
  *
  * @param obj The object file's descriptor.
@@ -371,8 +383,8 @@ void rtems_rtl_obj_erase_sections (rtems_rtl_obj_t* obj);
  * @retval NULL The section was not found.
  * @return rtems_rtl_obj_sect_t* The named section.
  */
-rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj,
-                                                  const char*      name);
+rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section (const rtems_rtl_obj_t* obj,
+                                                  const char*            name);
 
 /**
  * Find a section given a section's index number.
@@ -382,21 +394,21 @@ rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section (rtems_rtl_obj_t* obj,
  * @retval NULL The section was not found.
  * @return rtems_rtl_obj_sect_t* The found section.
  */
-rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section_by_index (rtems_rtl_obj_t* obj,
-                                                           int              index);
+rtems_rtl_obj_sect_t* rtems_rtl_obj_find_section_by_index (const rtems_rtl_obj_t* obj,
+                                                           int                    index);
 
 /**
- * The text size of the object file. Only use once all the sections has been
- * added. It includes alignments between sections that are part of the object's
- * text area. The consts sections are included in this section.
+ * The text section size. Only use once all the sections has been added. It
+ * includes alignments between sections that are part of the object's text
+ * area. The consts sections are included in this section.
  *
  * @param obj The object file's descriptor.
  * @return size_t The size of the text area of the object file.
  */
-size_t rtems_rtl_obj_text_size (rtems_rtl_obj_t* obj);
+size_t rtems_rtl_obj_text_size (const rtems_rtl_obj_t* obj);
 
 /**
- * The text section alignment of the object file. Only use once all the
+ * The text section alignment for the object file. Only use once all the
  * sections has been added. The section alignment is the alignment of the first
  * text type section loaded the text section.
  *
@@ -406,20 +418,20 @@ size_t rtems_rtl_obj_text_size (rtems_rtl_obj_t* obj);
  * @param obj The object file's descriptor.
  * @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
  */
-uint32_t rtems_rtl_obj_text_alignment (rtems_rtl_obj_t* obj);
+uint32_t rtems_rtl_obj_text_alignment (const rtems_rtl_obj_t* obj);
 
 /**
- * The const size of the object file. Only use once all the sections has been
- * added. It includes alignments between sections that are part of the object's
- * const area. The consts sections are included in this section.
+ * The const section size. Only use once all the sections has been added. It
+ * includes alignments between sections that are part of the object's const
+ * area. The consts sections are included in this section.
  *
  * @param obj The object file's descriptor.
  * @return size_t The size of the const area of the object file.
  */
-size_t rtems_rtl_obj_const_size (rtems_rtl_obj_t* obj);
+size_t rtems_rtl_obj_const_size (const rtems_rtl_obj_t* obj);
 
 /**
- * The const section alignment of the object file. Only use once all the
+ * The const section alignment for the object file. Only use once all the
  * sections has been added. The section alignment is the alignment of the first
  * const type section loaded the const section.
  *
@@ -429,20 +441,42 @@ size_t rtems_rtl_obj_const_size (rtems_rtl_obj_t* obj);
  * @param obj The object file's descriptor.
  * @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
  */
-uint32_t rtems_rtl_obj_const_alignment (rtems_rtl_obj_t* obj);
+uint32_t rtems_rtl_obj_const_alignment (const rtems_rtl_obj_t* obj);
+
+/**
+ * The eh section size. Only use once all the sections has been added. It
+ * includes alignments between sections that are part of the object's bss area.
+ *
+ * @param obj The object file's descriptor.
+ * @return size_t The size of the bss area of the object file.
+ */
+size_t rtems_rtl_obj_eh_size (const rtems_rtl_obj_t* obj);
+
+/**
+ * The eh section alignment for the object file. Only use once all the sections
+ * has been added. The section alignment is the alignment of the first bss type
+ * section loaded the bss section.
+ *
+ * You can assume the alignment is a positive integral power of 2 if not 0 or
+ * 1. If 0 or 1 then there is no alignment.
+ *
+ * @param obj The object file's descriptor.
+ * @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
+ */
+uint32_t rtems_rtl_obj_eh_alignment (const rtems_rtl_obj_t* obj);
 
 /**
- * The data size of the object file. Only use once all the sections has been
- * added. It includes alignments between sections that are part of the object's
- * data area.
+ * The data section size. Only use once all the sections has been added. It
+ * includes alignments between sections that are part of the object's data
+ * area.
  *
  * @param obj The object file's descriptor.
  * @return size_t The size of the data area of the object file.
  */
-size_t rtems_rtl_obj_data_size (rtems_rtl_obj_t* obj);
+size_t rtems_rtl_obj_data_size (const rtems_rtl_obj_t* obj);
 
 /**
- * The data section alignment of the object file. Only use once all the
+ * The data section alignment for the object file. Only use once all the
  * sections has been added. The section alignment is the alignment of the first
  * data type section loaded the data section.
  *
@@ -452,20 +486,19 @@ size_t rtems_rtl_obj_data_size (rtems_rtl_obj_t* obj);
  * @param obj The object file's descriptor.
  * @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
  */
-uint32_t rtems_rtl_obj_data_alignment (rtems_rtl_obj_t* obj);
+uint32_t rtems_rtl_obj_data_alignment (const rtems_rtl_obj_t* obj);
 
 /**
- * The bss size of the object file. Only use once all the sections has been
- * added. It includes alignments between sections that are part of the object's
- * bss area.
+ * The bss section size. Only use once all the sections has been added. It
+ * includes alignments between sections that are part of the object's bss area.
  *
  * @param obj The object file's descriptor.
  * @return size_t The size of the bss area of the object file.
  */
-size_t rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj);
+size_t rtems_rtl_obj_bss_size (const rtems_rtl_obj_t* obj);
 
 /**
- * The bss section alignment of the object file. Only use once all the
+ * The bss section alignment for the object file. Only use once all the
  * sections has been added. The section alignment is the alignment of the first
  * bss type section loaded the bss section.
  *
@@ -475,7 +508,7 @@ size_t rtems_rtl_obj_bss_size (rtems_rtl_obj_t* obj);
  * @param obj The object file's descriptor.
  * @return uint32_t The alignment. Can be 0 or 1 for not aligned or the alignment.
  */
-uint32_t rtems_rtl_obj_bss_alignment (rtems_rtl_obj_t* obj);
+uint32_t rtems_rtl_obj_bss_alignment (const rtems_rtl_obj_t* obj);
 
 /**
  * Relocate the object file. The object file's section are parsed for any
diff --git a/cpukit/libdl/rtl-rap.c b/cpukit/libdl/rtl-rap.c
index a7fcb9f..cb7b751 100644
--- a/cpukit/libdl/rtl-rap.c
+++ b/cpukit/libdl/rtl-rap.c
@@ -427,20 +427,22 @@ rtems_rtl_rap_relocate (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
 }
 
 /**
- * The structure of obj->detail is
+ * The structure of obj->linkmap is:
  *
  * |object_detail(0..obj_num)|section_detail(0..sec_num[0..obj_num])|
  * obj_name(0..obj_num)|section_name(0..sec_num[0..obj_num])
  *
  */
 static bool
-rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
+rtems_rtl_rap_load_linkmap (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
 {
+  void*            detail;
   struct link_map* tmp1;
-  section_detail* tmp2;
-  uint32_t obj_detail_size;
-  uint32_t pos = 0;
-  int i,j;
+  section_detail*  tmp2;
+  uint32_t         obj_detail_size;
+  uint32_t         pos = 0;
+  int              i;
+  int              j;
 
   obj_detail_size = sizeof (struct link_map) * obj->obj_num;
 
@@ -449,26 +451,31 @@ rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
     obj_detail_size += (obj->sec_num[i] * sizeof (section_detail));
   }
 
-  obj->detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
-                                     obj_detail_size + rap->strtable_size, true);
+  detail = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
+                                obj_detail_size + rap->strtable_size, true);
 
-  if (!obj->detail)
+  if (!detail)
   {
     rap->strtable_size = 0;
     rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
     return false;
   }
 
-  rap->strtable = obj->detail + obj_detail_size;
+  rap->strtable = detail + obj_detail_size;
 
-  /* Read the obj names and section names */
-  if (!rtems_rtl_obj_comp_read (rap->decomp, rap->strtable,
+  /*
+   *  Read the obj names and section names
+   */
+  if (!rtems_rtl_obj_comp_read (rap->decomp,
+                                rap->strtable,
                                 rap->strtable_size))
   {
-    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj->detail);
+    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, detail);
     return false;
   }
 
+  obj->linkmap = (struct link_map*) detail;
+
   if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
   {
     if (rap->rpathlen > 0)
@@ -489,7 +496,7 @@ rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
 
   for (i = 0; i < obj->obj_num; ++i)
   {
-    tmp1 = (struct link_map*) (obj->detail) + i;
+    tmp1 = obj->linkmap + i;
     tmp1->name = rap->strtable + pos;
     tmp1->sec_num = obj->sec_num[i];
     tmp1->rpathlen = rap->rpathlen;
@@ -509,17 +516,17 @@ rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
     }
   }
 
-  tmp2 =(section_detail*) ((struct link_map*) (obj->detail) + obj->obj_num);
+  tmp2 = (section_detail*) (obj->linkmap + obj->obj_num);
 
   for (i = 0; i < obj->obj_num; ++i)
   {
     if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
     {
-      printf ("File %d: %s\n", i, ((struct link_map*) obj->detail + i)->name);
-      printf ("Section: %d sections\n",(unsigned int) obj->sec_num[i]);
+      printf ("File %d: %s\n", i, (obj->linkmap + i)->name);
+      printf ("Section: %d sections\n", (unsigned int) obj->sec_num[i]);
     }
 
-    ((struct link_map*)obj->detail + i)->sec_detail = tmp2;
+    obj->linkmap[i].sec_detail = tmp2;
 
     for (j = 0; j < obj->sec_num[i]; ++j)
     {
@@ -532,7 +539,8 @@ rtems_rtl_rap_load_details (rtems_rtl_rap_t* rap, rtems_rtl_obj_t* obj)
           !rtems_rtl_rap_read_uint32 (rap->decomp, &offset) ||
           !rtems_rtl_rap_read_uint32 (rap->decomp, &size))
       {
-        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->detail);
+        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->linkmap);
+        obj->linkmap = NULL;
         return false;
       }
 
@@ -907,7 +915,7 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
     if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
       printf ("rtl: rap: details: obj_num=%lu\n", obj->obj_num);
 
-    if (!rtems_rtl_rap_load_details (&rap, obj))
+    if (!rtems_rtl_rap_load_linkmap (&rap, obj))
       return false;
   }
 
@@ -975,6 +983,13 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
   return true;
 }
 
+bool
+rtems_rtl_rap_file_unload (rtems_rtl_obj_t* obj)
+{
+  (void) obj;
+  return true;
+}
+
 rtems_rtl_loader_format_t*
 rtems_rtl_rap_file_sig (void)
 {
diff --git a/cpukit/libdl/rtl-rap.h b/cpukit/libdl/rtl-rap.h
index f828b1f..eca6e9e 100644
--- a/cpukit/libdl/rtl-rap.h
+++ b/cpukit/libdl/rtl-rap.h
@@ -41,6 +41,13 @@ bool rtems_rtl_rap_file_check (rtems_rtl_obj_t* obj, int fd);
 bool rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd);
 
 /**
+ * The RAP format unload handler.
+ *
+ * @param obj The object to unload.
+ */
+bool rtems_rtl_rap_file_unload (rtems_rtl_obj_t* obj);
+
+/**
  * The RAP format signature handler.
  *
  * @return rtems_rtl_loader_format_t* The format's signature.
diff --git a/cpukit/libdl/rtl-unwind-dw2.c b/cpukit/libdl/rtl-unwind-dw2.c
new file mode 100644
index 0000000..d9237c5
--- /dev/null
+++ b/cpukit/libdl/rtl-unwind-dw2.c
@@ -0,0 +1,71 @@
+/*
+ *  COPYRIGHT (c) 2012-2016 Chris Johns <chrisj at rtems.org>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rtld
+ *
+ * @brief RTEMS Run-Time Link Editor
+ *
+ * This is the RTL implementation.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+
+#include <rtems/rtl/rtl.h>
+#include "rtl-elf.h"
+#include "rtl-error.h"
+#include "rtl-unwind.h"
+#include "rtl-unwind-dw2.h"
+
+/*
+ * These interfaces are not exported outside the GCC source.
+ */
+void __register_frame (void *begin);
+void __deregister_frame (void *begin);
+
+bool
+rtems_rtl_elf_unwind_dw2_parse (const rtems_rtl_obj_t* obj,
+                                const char*            name,
+                                uint32_t               flags)
+{
+  return
+    ((flags & RTEMS_RTL_OBJ_SECT_CONST) != 0) &&
+    ((strcmp(name, ".eh_frame") == 0) ||
+     (strncmp(name, ".gcc_except_table.", sizeof (".gcc_except_table.") - 1) == 0));
+}
+
+bool
+rtems_rtl_elf_unwind_dw2_register (const rtems_rtl_obj_t* obj)
+{
+  rtems_rtl_obj_sect_t* sect = rtems_rtl_obj_find_section (obj, ".eh_frame");
+
+  if (sect != NULL && sect->size > 0 && sect->base != NULL)
+  {
+    __register_frame (sect->base);
+  }
+
+  return true;
+}
+
+bool rtems_rtl_elf_unwind_dw2_deregister (const rtems_rtl_obj_t* obj)
+{
+  rtems_rtl_obj_sect_t* sect = rtems_rtl_obj_find_section (obj, ".eh_frame");
+
+  if (sect != NULL && sect->size > 0 && sect->base != NULL)
+  {
+    __deregister_frame (sect->base);
+  }
+
+  return true;
+}
diff --git a/cpukit/libdl/rtl-unwind-dw2.h b/cpukit/libdl/rtl-unwind-dw2.h
new file mode 100644
index 0000000..55b9797
--- /dev/null
+++ b/cpukit/libdl/rtl-unwind-dw2.h
@@ -0,0 +1,83 @@
+/*
+ *  COPYRIGHT (c) 2016 Chris Johns <chrisj at rtems.org>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rtl
+ *
+ * @brief RTEMS Run-Time Linker Unwind DWARF  Support.
+ */
+
+#if !defined (_RTEMS_RTL_UNWIND_DW2_H_)
+#define _RTEMS_RTL_UNWIND_DW2_H_
+
+#include "rtl-elf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if __SIZEOF_LONG__ >= __SIZEOF_POINTER__
+  typedef long rtems_rtl_elf_unwind_dw2_sleb128;
+  typedef unsigned long rtems_rtl_elf_unwind_dw2_uleb128;
+#elif __SIZEOF_LONG_LONG__ >= __SIZEOF_POINTER__
+  typedef long long rtems_rtl_elf_unwind_dw2_sleb128;
+  typedef unsigned long long rtems_rtl_elf_unwind_dw2_uleb128;
+#else
+  #error No DW2 type available.
+#endif
+
+/**
+ * Architecture specific handler to check if a section contains exception
+ * handler data..
+ *
+ * @param obj The object file.
+ * @param name The section's name.
+ * @param uint32 flags The object file's flags.
+ * @retval true The section contains unwind information.
+ * @retval false The section does not contain unwind information.
+ */
+bool rtems_rtl_elf_unwind_dw2_parse (const rtems_rtl_obj_t* obj,
+				     const char*            name,
+				     uint32_t               flags);
+
+/**
+ * Architecture specific handler to add an object file's unwind information to
+ * the base image.
+ *
+ * @param obj The object file.
+ * @retval true The unwind information has been registered.
+ * @retval false The unwind information could not be registered.
+ */
+bool rtems_rtl_elf_unwind_dw2_register (const rtems_rtl_obj_t* obj);
+
+/**
+ * Architecture specific handler to remove an object file's unwind information
+ * from the base image.
+ *
+ * @param obj The object file.
+ * @retval true The unwind information has been deregistered.
+ * @retval false The unwind information could not be deregistered.
+ */
+bool rtems_rtl_elf_unwind_dw2_deregister (const rtems_rtl_obj_t* obj);
+
+/**
+ * Read signed and unsigned LEB128 values.
+ */
+const uint8_t* rtems_rtl_elf_unwind_dw2_read_uleb128 (const uint8_t*                    data,
+						      rtems_rtl_elf_unwind_dw2_uleb128* val);
+const uint8_t* rtems_rtl_elf_unwind_dw2_read_sleb128 (const uint8_t*                    data,
+						      rtems_rtl_elf_unwind_dw2_sleb128* val);
+
+bool rtems_rtl_elf_unwind_dw2_relocate (const Elf_Addr* where, Elf_Word value, Elf_Word mask);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/cpukit/libdl/rtl-unwind.h b/cpukit/libdl/rtl-unwind.h
new file mode 100644
index 0000000..f88787e
--- /dev/null
+++ b/cpukit/libdl/rtl-unwind.h
@@ -0,0 +1,63 @@
+/*
+ *  COPYRIGHT (c) 2016 Chris Johns <chrisj at rtems.org>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rtl
+ *
+ * @brief RTEMS Run-Time Linker Unwind Support.
+ */
+
+#if !defined (_RTEMS_RTL_UNWIND_H_)
+#define _RTEMS_RTL_UNWIND_H_
+
+#include "rtl-elf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Architecture specific handler to check if a section contains exception
+ * handler data..
+ *
+ * @param obj The object file.
+ * @param name The section's name.
+ * @param uint32 flags The object file's flags.
+ * @retval true The section contains unwind information.
+ * @retval false The section does not contain unwind information.
+ */
+bool rtems_rtl_elf_unwind_parse (const rtems_rtl_obj_t* obj,
+                                 const char*            name,
+                                 uint32_t               flags);
+
+/**
+ * Architecture specific handler to add an object file's unwind information to
+ * the base image.
+ *
+ * @param obj The object file.
+ * @retval true The unwind information has been registered.
+ * @retval false The unwind information could not be registered.
+ */
+bool rtems_rtl_elf_unwind_register (rtems_rtl_obj_t* obj);
+
+/**
+ * Architecture specific handler to remove an object file's unwind information
+ * from the base image.
+ *
+ * @param obj The object file.
+ * @retval true The unwind information has been deregistered.
+ * @retval false The unwind information could not be deregistered.
+ */
+bool rtems_rtl_elf_unwind_deregister (rtems_rtl_obj_t* obj);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c
index abfcf25..5052251 100644
--- a/cpukit/libdl/rtl.c
+++ b/cpukit/libdl/rtl.c
@@ -62,6 +62,7 @@
  * Static RTL data is returned to the user when the linker is locked.
  */
 static rtems_rtl_data_t* rtl;
+static bool              rtl_data_init;
 
 /**
  * Define a default base global symbol loader function that is weak
@@ -95,11 +96,25 @@ rtems_rtl_data_init (void)
       rtems_id          lock;
 
       /*
+       * We cannot set an error in this code because there is no RTL data to
+       * hold it.
+       */
+
+      if (rtl_data_init)
+      {
+        rtems_libio_unlock ();
+        return false;
+      }
+
+      rtl_data_init = true;
+
+      /*
        * Always in the heap.
        */
       rtl = malloc (sizeof (rtems_rtl_data_t));
       if (!rtl)
       {
+        rtems_libio_unlock ();
         errno = ENOMEM;
         return false;
       }
@@ -120,6 +135,7 @@ rtems_rtl_data_init (void)
       if (sc != RTEMS_SUCCESSFUL)
       {
         free (rtl);
+        rtems_libio_unlock ();
         return false;
       }
 
@@ -128,6 +144,7 @@ rtems_rtl_data_init (void)
       {
         rtems_semaphore_delete (lock);
         free (rtl);
+        rtems_libio_unlock ();
         return false;
       }
 
@@ -143,6 +160,7 @@ rtems_rtl_data_init (void)
       {
         rtems_semaphore_delete (lock);
         free (rtl);
+        rtems_libio_unlock ();
         return false;
       }
 
@@ -152,6 +170,7 @@ rtems_rtl_data_init (void)
         rtems_rtl_symbol_table_close (&rtl->globals);
         rtems_semaphore_delete (lock);
         free (rtl);
+        rtems_libio_unlock ();
         return false;
       }
 
@@ -162,6 +181,7 @@ rtems_rtl_data_init (void)
         rtems_rtl_unresolved_table_close (&rtl->unresolved);
         rtems_semaphore_delete (lock);
         free (rtl);
+        rtems_libio_unlock ();
         return false;
       }
 
@@ -173,6 +193,7 @@ rtems_rtl_data_init (void)
         rtems_rtl_symbol_table_close (&rtl->globals);
         rtems_semaphore_delete (lock);
         free (rtl);
+        rtems_libio_unlock ();
         return false;
       }
 
@@ -185,6 +206,7 @@ rtems_rtl_data_init (void)
         rtems_rtl_symbol_table_close (&rtl->globals);
         rtems_semaphore_delete (lock);
         free (rtl);
+        rtems_libio_unlock ();
         return false;
       }
 
@@ -198,6 +220,7 @@ rtems_rtl_data_init (void)
         rtems_rtl_symbol_table_close (&rtl->globals);
         rtems_semaphore_delete (lock);
         free (rtl);
+        rtems_libio_unlock ();
         return false;
       }
 
@@ -212,6 +235,7 @@ rtems_rtl_data_init (void)
         rtems_rtl_symbol_table_close (&rtl->globals);
         rtems_semaphore_delete (lock);
         free (rtl);
+        rtems_libio_unlock ();
         return false;
       }
 
@@ -288,7 +312,7 @@ rtems_rtl_obj_caches (rtems_rtl_obj_cache_t** symbols,
 }
 
 void
-rtems_rtl_obj_caches_flush ()
+rtems_rtl_obj_caches_flush (void)
 {
   if (rtl)
   {
@@ -438,6 +462,7 @@ rtems_rtl_load_object (const char* name, int mode)
     if (!rtems_rtl_obj_find_file (obj, name))
     {
       rtems_rtl_obj_free (obj);
+      rtems_rtl_obj_caches_flush ();
       return NULL;
     }
 
@@ -446,9 +471,12 @@ rtems_rtl_load_object (const char* name, int mode)
     if (!rtems_rtl_obj_load (obj))
     {
       rtems_rtl_obj_free (obj);
+      rtems_rtl_obj_caches_flush ();
       return NULL;
     }
 
+    rtems_rtl_obj_caches_flush ();
+
     rtems_rtl_unresolved_resolve ();
   }
 
@@ -514,6 +542,9 @@ rtems_rtl_unload_object (rtems_rtl_obj_t* obj)
     obj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
 
     ok = rtems_rtl_obj_unload (obj);
+
+    rtems_rtl_obj_free (obj);
+    rtems_rtl_obj_caches_flush ();
   }
 
   return ok;
diff --git a/cpukit/libdl/rtl.h b/cpukit/libdl/rtl.h
index 234fc32..fe9a7df 100644
--- a/cpukit/libdl/rtl.h
+++ b/cpukit/libdl/rtl.h
@@ -112,7 +112,7 @@ struct rtems_rtl_data_s
 };
 
 /**
- * Get the RTL data with out locking. This call assmes the RTL is locked.
+ * Get the RTL data with out locking. This call assumes the RTL is locked.
  *
  * @return rtems_rtl_data_t* The RTL data after being locked.
  * @retval NULL The RTL data is not initialised.
diff --git a/testsuites/libtests/dl01/init.c b/testsuites/libtests/dl01/init.c
index 9fbdaa5..e9c7a1a 100644
--- a/testsuites/libtests/dl01/init.c
+++ b/testsuites/libtests/dl01/init.c
@@ -73,6 +73,8 @@ static void Init(rtems_task_argument arg)
 
 #define CONFIGURE_EXTRA_TASK_STACKS (8 * 1024)
 
+#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+
 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
 
 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
@@ -80,4 +82,3 @@ static void Init(rtems_task_argument arg)
 #define CONFIGURE_INIT
 
 #include <rtems/confdefs.h>
-
diff --git a/testsuites/libtests/dl02/init.c b/testsuites/libtests/dl02/init.c
index f761b46..bf2d1a9 100644
--- a/testsuites/libtests/dl02/init.c
+++ b/testsuites/libtests/dl02/init.c
@@ -73,6 +73,8 @@ static void Init(rtems_task_argument arg)
 
 #define CONFIGURE_EXTRA_TASK_STACKS (8 * 1024)
 
+#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+
 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
 
 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
diff --git a/testsuites/libtests/dl03/init.c b/testsuites/libtests/dl03/init.c
index 68f8150..ae82722 100644
--- a/testsuites/libtests/dl03/init.c
+++ b/testsuites/libtests/dl03/init.c
@@ -55,6 +55,8 @@ static void Init(rtems_task_argument arg)
 
 #define CONFIGURE_EXTRA_TASK_STACKS (8 * 1024)
 
+#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+
 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
 
 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
diff --git a/testsuites/libtests/dl04/init.c b/testsuites/libtests/dl04/init.c
index 566752b..6e48864 100644
--- a/testsuites/libtests/dl04/init.c
+++ b/testsuites/libtests/dl04/init.c
@@ -73,6 +73,8 @@ static void Init(rtems_task_argument arg)
 
 #define CONFIGURE_EXTRA_TASK_STACKS (8 * 1024)
 
+#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+
 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
 
 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
diff --git a/testsuites/libtests/dl05/dl-cpp.cpp b/testsuites/libtests/dl05/dl-cpp.cpp
index fcb9e0a..0e20057 100644
--- a/testsuites/libtests/dl05/dl-cpp.cpp
+++ b/testsuites/libtests/dl05/dl-cpp.cpp
@@ -4,11 +4,27 @@
 #include <cstdio>
 #include <stdexcept>
 #include "dl-load.h"
-void exception_base(bool istrue)
+void exception_base(bool throw_runtime)
 {
-  printf("exception_base called\n");
-  if (istrue)
+  printf("%s: begin\n", __func__);
+  try
   {
-    throw std::runtime_error("dummy call to link in symbols");
+    if (throw_runtime)
+      throw std::runtime_error("eb: throw std::runtime_error");
+    else
+      throw dl_test_throw_me("eb: throw me");
   }
+  catch (std::exception const& e)
+  {
+    printf("%s: caught: %s\n", __func__, e.what());
+  }
+  catch (dl_test_throw_me const& e)
+  {
+    printf("%s: caught: %s\n", __func__, e.what());
+  }
+  catch (...)
+  {
+    printf("%s: caught: unknown\n", __func__);
+  }
+  printf("%s: end\n", __func__);
 }
diff --git a/testsuites/libtests/dl05/dl-load.c b/testsuites/libtests/dl05/dl-load.c
index f94317d..c7d5698 100644
--- a/testsuites/libtests/dl05/dl-load.c
+++ b/testsuites/libtests/dl05/dl-load.c
@@ -24,22 +24,38 @@ int dl_load_test(void)
 {
   void*       handle;
   const char* err;
-  void        (*func)(void);
+  void        (*func)(bool );
+#if __i386__
+  /*
+   * std::runtime_error destructor locks up in atomics.
+   */
+  bool        throw_runtime = false;
+#else
+  bool        throw_runtime = true;
+#endif
 
   rtems_rtl_trace_set_mask(RTEMS_RTL_TRACE_ALL);
+
   handle = dlopen("/dl-o5.o", RTLD_GLOBAL | RTLD_NOW);
-  err = dlerror();
-  if (err != NULL)
-    printf("dlopen: %s\n", err);
+  if (handle == NULL)
+  {
+    err = dlerror();
+    if (err != NULL)
+      printf("dlopen: %s\n", err);
+  }
   rtems_test_assert(handle != NULL);
+
   func = dlsym(handle, "exception_dl");
-  err = dlerror ();
-  if (err)
-    printf ("dlsym: %s\n", err);
+  if (func == NULL) {
+    err = dlerror ();
+    if (err)
+      printf ("dlsym: %s\n", err);
+  }
   rtems_test_assert(func != NULL);
 
-  exception_base(false);
-  func();
+  exception_base(throw_runtime);
+
+  func(throw_runtime);
 
   rtems_test_assert(dlclose(handle) == 0);
 
diff --git a/testsuites/libtests/dl05/dl-load.h b/testsuites/libtests/dl05/dl-load.h
index 98f4154..7a9e138 100644
--- a/testsuites/libtests/dl05/dl-load.h
+++ b/testsuites/libtests/dl05/dl-load.h
@@ -13,12 +13,38 @@
 extern "C" {
 #endif
 
-void exception_base(bool istrue);
-void exception_dl(void);
+void exception_base(bool throw_runtime);
+void exception_dl(bool throw_runtime);
 
 int dl_load_test(void);
 
 #ifdef __cplusplus
+  class dl_test_throw_me
+  {
+  public:
+    dl_test_throw_me(const char* message) :
+      message (message) {
+    }
+    dl_test_throw_me(const dl_test_throw_me& orig) :
+      message (orig.message) {
+    }
+    dl_test_throw_me() :
+      message (0) {
+    }
+
+    ~dl_test_throw_me() {
+    }
+
+    const char* what() const {
+      return message;
+    }
+
+  private:
+    const char* message;
+  };
+#endif
+
+#ifdef __cplusplus
 }
 #endif
 
diff --git a/testsuites/libtests/dl05/dl-o5.cpp b/testsuites/libtests/dl05/dl-o5.cpp
index 6e8476d..5918e8f 100644
--- a/testsuites/libtests/dl05/dl-o5.cpp
+++ b/testsuites/libtests/dl05/dl-o5.cpp
@@ -1,12 +1,20 @@
 #include <cstdio>
 #include <stdexcept>
 #include "dl-load.h" /* make the symbol a C linkage */
-void exception_dl(void)
+void exception_dl(bool throw_runtime)
 {
+  printf("exception_dl: begin\n");
   try
   {
-    printf("exception_dl: throwing\n");
-    throw std::runtime_error("exception_dl throw");
+    printf("exception_dl: throwing...\n");
+    if (throw_runtime)
+      throw std::runtime_error("throw std::runtime_error object");
+    else
+      throw dl_test_throw_me("throw dl_test_throw_me object");
+  }
+  catch (dl_test_throw_me const& e)
+  {
+    printf("%s: caught: %s\n", __func__, e.what());
   }
   catch (std::exception const& e)
   {
@@ -16,4 +24,5 @@ void exception_dl(void)
   {
     printf("%s: caught: unknown\n", __func__);
   }
+  printf("exception_dl: end\n");
 }
diff --git a/testsuites/libtests/dl05/init.c b/testsuites/libtests/dl05/init.c
index f6e0c20..9c7f006 100644
--- a/testsuites/libtests/dl05/init.c
+++ b/testsuites/libtests/dl05/init.c
@@ -69,9 +69,13 @@ static void Init(rtems_task_argument arg)
 
 #define CONFIGURE_MAXIMUM_TASKS 1
 
-#define CONFIGURE_MINIMUM_TASK_STACK_SIZE (8U * 1024U)
+#define CONFIGURE_MINIMUM_TASK_STACK_SIZE (32U * 1024U)
 
-#define CONFIGURE_EXTRA_TASK_STACKS (8 * 1024)
+#define CONFIGURE_EXTRA_TASK_STACKS (64 * 1024)
+
+#define CONFIGURE_MAXIMUM_POSIX_KEYS 2
+
+#define CONFIGURE_MAXIMUM_SEMAPHORES 1
 
 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
 
-- 
2.9.0



More information about the devel mailing list