diff --git a/src/dyn-common.h b/src/dyn-common.h
index e69de29b..c3dd7355 100644
--- a/src/dyn-common.h
+++ b/src/dyn-common.h
@@ -0,0 +1,52 @@
+static int
+find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
+		void *arg, unw_dyn_info_list_t *list)
+{
+  unw_dyn_info_t *di;
+
+  for (di = list->first; di; di = di->next)
+    {
+      if (ip >= di->start_ip && ip < di->end_ip)
+	{
+	  pi->start_ip = di->start_ip;
+	  pi->end_ip = di->end_ip;
+	  pi->gp = di->gp;
+	  pi->format = di->format;
+	  switch (di->format)
+	    {
+	    case UNW_INFO_FORMAT_DYNAMIC:
+	      pi->proc_name = di->u.pi.name;
+	      pi->handler = di->u.pi.handler;
+	      pi->flags = di->u.pi.flags;
+	      pi->unwind_info = di;
+	      return 0;
+
+	    case UNW_INFO_FORMAT_TABLE:
+#ifdef unw_search_unwind_table
+	      /* call platform-specific search routine: */
+	      return sysdep_search_unwind_table (as, ip, &di->u.ti, pi, arg);
+#endif
+
+	    default:
+	      break;
+	    }
+	}
+    }
+  return -UNW_ENOINFO;
+}
+
+static int
+remote_find_proc_info (unw_addr_space_t as, unw_word_t ip,
+		       unw_proc_info_t *pi, void *arg)
+{
+  unw_dyn_info_list_t *list = NULL;
+
+  fprintf (stderr, "remote_find_proc_info: not implemented yet\n");
+  /* use as.accessors to locate _U_dyn_info_list.  */
+  /* check _U_dyn_info_list.generation to see if cached info is stale */
+  /* if cached info is stale, use as.accessors to read new info */
+  /* internalize the data */
+  /* re-check _U_dyn_info_list.generation to verify that read-in info
+     is consistent */
+  return find_proc_info (as, ip, pi, arg, list);
+}
diff --git a/src/dyn-local.c b/src/dyn-local.c
index e69de29b..7ab0805b 100644
--- a/src/dyn-local.c
+++ b/src/dyn-local.c
@@ -0,0 +1,33 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002 Hewlett-Packard Co
+	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+/* This gets linked in only when UNW_REMOTE_ONLY is not defined.  It
+   must be a separate file to ensure registering dynamic info doesn't
+   automatically drag in the lookup code and vice versa.  */
+
+#include <libunwind.h>
+
+unw_dyn_info_list_t _U_dyn_info_list
+	__attribute__ ((section (".data.unwind_dynamic")));
diff --git a/src/dyn-register.c b/src/dyn-register.c
index e69de29b..835a79b6 100644
--- a/src/dyn-register.c
+++ b/src/dyn-register.c
@@ -0,0 +1,52 @@
+#include <libunwind.h>
+
+#ifndef HAVE_CMP8XCHG16
+
+#include <pthread.h>
+
+/* Make it easy to write thread-safe code which may or may not be
+   linked against libpthread.  The macros below can be used
+   unconditionally and if -lpthread is around, they'll call the
+   corresponding routines otherwise, they do nothing.  */
+
+#pragma weak pthread_rwlock_rdlock
+#pragma weak pthread_rwlock_wrlock
+#pragma weak pthread_rwlock_unlock
+
+#define rw_rdlock(l)    (pthread_rwlock_rdlock ? pthread_rwlock_rdlock (l) : 0)
+#define rw_wrlock(l)    (pthread_rwlock_wrlock ? pthread_rwlock_wrlock (l) : 0)
+#define rw_unlock(l)    (pthread_rwlock_unlock ? pthread_rwlock_unlock (l) : 0)
+
+static pthread_rwlock_t registration_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+#endif
+
+extern unw_dyn_info_list_t _U_dyn_info_list;
+
+int
+_U_dyn_register (unw_dyn_info_t *di)
+{
+#ifdef HAVE_CMP8XCHG16
+  unw_dyn_info_t *old_list_head, *new_list_head;
+  unsigned long old_gen, new_gen;
+
+  do
+    {
+      old_gen = _U_dyn_info_list.generation;
+      old_list_head = _U_dyn_info_list.first;
+
+      new_gen = old_gen + 1;
+      new_list_head = di;
+      di->next = old_list_head;
+    }
+  while (cmp8xchg16 (&_U_dyn_info_list, new_gen, new_list_head) != old_gen);
+#else
+  rw_wrlock (&registration_lock);
+  {
+    ++_U_dyn_info_list.generation;
+    di->next = _U_dyn_info_list.first;
+    _U_dyn_info_list.first = di;
+  }
+  rw_unlock (&registration_lock);
+#endif
+}
diff --git a/src/ia64/Lunw_find_dynamic_proc_info.c b/src/ia64/Lunw_find_dynamic_proc_info.c
index e69de29b..85f23e50 100644
--- a/src/ia64/Lunw_find_dynamic_proc_info.c
+++ b/src/ia64/Lunw_find_dynamic_proc_info.c
@@ -0,0 +1,4 @@
+#ifndef UNW_REMOTE_ONLY
+#define UNW_LOCAL_ONLY
+#include "unw_find_dynamic_proc_info.c"
+#endif
diff --git a/src/ia64/Lunw_get_accessors.c b/src/ia64/Lunw_get_accessors.c
index e69de29b..921848bb 100644
--- a/src/ia64/Lunw_get_accessors.c
+++ b/src/ia64/Lunw_get_accessors.c
@@ -0,0 +1,4 @@
+#ifndef UNW_REMOTE_ONLY
+#define UNW_LOCAL_ONLY
+#include "unw_get_accessors.c"
+#endif
diff --git a/src/ia64/Lunw_get_proc_info.c b/src/ia64/Lunw_get_proc_info.c
index e69de29b..2ab1bf9e 100644
--- a/src/ia64/Lunw_get_proc_info.c
+++ b/src/ia64/Lunw_get_proc_info.c
@@ -0,0 +1,4 @@
+#ifndef UNW_REMOTE_ONLY
+#define UNW_LOCAL_ONLY
+#include "unw_get_proc_info.c"
+#endif
diff --git a/src/ia64/unw_find_dynamic_proc_info.c b/src/ia64/unw_find_dynamic_proc_info.c
index e69de29b..44f1eea7 100644
--- a/src/ia64/unw_find_dynamic_proc_info.c
+++ b/src/ia64/unw_find_dynamic_proc_info.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+
+#include <libunwind.h>
+
+#include "dyn-common.h"
+
+int
+unw_find_dynamic_proc_info (unw_addr_space_t as, unw_word_t ip,
+			    unw_proc_info_t *pi, void *arg)
+{
+  extern unw_dyn_info_list_t _U_dyn_info_list;
+
+#ifdef UNW_LOCAL_ONLY
+  return find_proc_info (as, ip, pi, arg, &_U_dyn_info_list);
+#else
+# ifdef UNW_REMOTE_ONLY
+  return remote_find_proc_info (as, ip, pi, arg);
+# else
+  if (as == unw_local_addr_space)
+    return find_proc_info (as, ip, pi, arg, &_U_dyn_info_list);
+  else
+    return remote_find_proc_info (as, ip, pi, arg);
+# endif
+#endif
+}
diff --git a/src/ia64/unw_get_accessors.c b/src/ia64/unw_get_accessors.c
index e69de29b..f116ea2a 100644
--- a/src/ia64/unw_get_accessors.c
+++ b/src/ia64/unw_get_accessors.c
@@ -0,0 +1,32 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002 Hewlett-Packard Co
+	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+unw_accessors_t *
+unw_get_accessors (unw_addr_space_t as)
+{
+  return &as->acc;
+}
diff --git a/src/ia64/unw_get_proc_info.c b/src/ia64/unw_get_proc_info.c
index e69de29b..8982e1bc 100644
--- a/src/ia64/unw_get_proc_info.c
+++ b/src/ia64/unw_get_proc_info.c
@@ -0,0 +1,34 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2002 Hewlett-Packard Co
+	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include "unwind_i.h"
+
+int
+unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
+{
+  struct ia64_cursor *c = (struct ia64_cursor *) cursor;
+  *pi = c->pi;
+  return 0;
+}
diff --git a/tests/test-dyn1.c b/tests/test-dyn1.c
index e69de29b..b5484c16 100644
--- a/tests/test-dyn1.c
+++ b/tests/test-dyn1.c
@@ -0,0 +1,146 @@
+#include <libunwind.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#define panic(args...)				\
+	{ fprintf (stderr, args); exit (-1); }
+
+typedef void (*template_t) (int, void (*)(),
+			    int (*)(const char *, ...), const char *,
+			    const char **);
+
+static const char *strarr[] =
+  {
+    "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", NULL
+  };
+
+#ifdef __ia64__
+struct fdesc
+  {
+    long code;
+    long gp;
+  };
+# define get_fdesc(fdesc,func)	(fdesc = *(struct fdesc *) &(func))
+# define get_funcp(fdesc)	((template_t) &(fdesc))
+#else
+struct fdesc
+  {
+    long code;
+  };
+# define get_fdesc(fdesc,func)	(fdesc.code = (long) &(func))
+# define get_funcp(fdesc)	((template_t) (fdesc).code)
+#endif
+
+static void
+flush_cache (void *addr, unsigned long len)
+{
+  void *end = (char *) addr + len;
+
+#ifdef __ia64__
+  while (addr < end)
+    {
+      asm volatile ("fc %0" :: "r"(addr));
+      addr = (char *) addr + 32;
+    }
+  asm volatile (";;sync.i;;srlz.i;;");
+#endif
+}
+
+void
+template (int i, template_t self,
+	  int (*printer)(const char *, ...), const char *fmt, const char **arr)
+{
+  (*printer) (fmt, arr[11 - i][0], arr[11 - i] + 1);
+  if (i > 0)
+    (*self) (i - 1, self, printer, fmt, arr);
+}
+
+static void
+sighandler (int signal)
+{
+  unw_cursor_t cursor;
+  unw_word_t ip;
+  unw_context_t uc;
+  int count = 0;
+
+  printf ("caught signal %d\n", signal);
+
+  unw_getcontext (&uc);
+  unw_init_local (&cursor, &uc);
+
+  while (!unw_is_signal_frame (&cursor))
+    if (unw_step (&cursor) < 0)
+      panic ("failed to find signal frame!\n");
+  unw_step (&cursor);
+
+  do
+    {
+      unw_get_reg (&cursor, UNW_REG_IP, &ip);
+      printf ("ip = %lx\n", (long) ip);
+      ++count;
+    }
+  while (unw_step (&cursor) > 0);
+
+  if (count != 13)
+    panic ("FAILURE: expected 13, not %d frames below signal frame\n", count);
+
+  printf ("SUCCESS\n");
+  exit (0);
+}
+
+int
+main (int argc, char *argv[])
+{
+  unw_dyn_region_info_t *region;
+  unw_dyn_info_t di;
+  struct fdesc fdesc;
+  template_t funcp;
+  void *mem;
+  int ret;
+
+  mem = malloc (getpagesize ());
+
+  get_fdesc (fdesc, template);
+
+  printf ("old code @ %p, new code @ %p\n", (void *) fdesc.code, mem);
+
+  memcpy (mem, (void *) fdesc.code, 256);
+  mprotect ((void *) ((long) mem & ~(getpagesize () - 1)),
+	    2*getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC);
+  flush_cache (mem, 256);
+
+  signal (SIGSEGV, sighandler);
+
+  /* register the new function: */
+  region = alloca (_U_dyn_region_info_size (2));
+  region->next = NULL;
+  region->insn_count = 256;
+  region->op_count = 2;
+  _U_dyn_op_alias (&region->op[0], 0, -1, fdesc.code);
+  _U_dyn_op_stop (&region->op[1]);
+
+  di.start_ip = (long) mem;
+  di.end_ip = (long) mem + 256;
+  di.gp = fdesc.gp;
+  di.format = UNW_INFO_FORMAT_DYNAMIC;
+  di.u.pi.name = "<copy of template()>";
+  di.u.pi.handler = 0;
+  di.u.pi.flags = 0;
+  di.u.pi.regions = region;
+
+  ret = _U_dyn_register (&di);
+  if (ret < 0)
+    panic ("call to _U_dyn_register() failed: ret=%d\n", ret);
+
+  /* call new function: */
+  fdesc.code = (long) mem;
+  funcp = get_funcp (fdesc);
+
+  (*funcp) (10, funcp, printf, "iteration %c%s\n", strarr);
+  return -1;
+}