(Logical change 1.45)
diff --git a/doc/libunwind-setjmp.man b/doc/libunwind-setjmp.man
index e69de29..3c112cd 100644
--- a/doc/libunwind-setjmp.man
+++ b/doc/libunwind-setjmp.man
@@ -0,0 +1,136 @@
+'\" t
+.\" Manual page created with latex2man on Sat Feb  8 01:31:56 PST 2003
+.\" NOTE: This file is generated, DO NOT EDIT.
+.de Vb
+.ft CW
+.nf
+..
+.de Ve
+.ft R
+
+.fi
+..
+.TH "LIBUNWIND\-SETJMP" "3" "08 February 2003" "Programming Library " "Programming Library "
+.SH NAME
+
+libunwind\-setjmp \-\- libunwind\-based non\-local gotos 
+.PP
+.SH SYNOPSIS
+
+.PP
+#include <setjmp.h>
+.br
+.PP
+int
+setjmp(jmp_buf env);
+.br
+void
+longjmp(jmp_buf env,
+int val);
+.br
+int
+_setjmp(jmp_buf env);
+.br
+void
+_longjmp(jmp_buf env,
+int val);
+.br
+int
+setjmp(sigjmp_buf env,
+int savemask);
+.br
+void
+siglongjmp(sigjmp_buf env,
+int val);
+.br
+.PP
+.SH DESCRIPTION
+
+.PP
+The unwind\-setjmp
+library offers a libunwind\-based
+implementation of non\-local gotos. This implementation is intended to 
+be a drop\-in replacement for the normal, system\-provided routines of 
+the same name. The main advantage of using the unwind\-setjmp
+library is that setting up a non\-local goto via one of the 
+setjmp()
+routines is very fast. Typically, just 2 or 3 words 
+need to be saved in the jump\-buffer (plus one call to 
+sigprocmask(2),
+in the case of sigsetjmp).
+On the 
+other hand, executing a non\-local goto by calling one of the 
+longjmp()
+routines tends to be much slower than with the 
+system\-provided routines. In fact, the time spent on a 
+longjmp()
+will be proportional to the number of call frames 
+that exist between the points where setjmp()
+and 
+longjmp()
+were called. For this reason, the 
+unwind\-setjmp
+library is beneficial primarily in applications 
+that frequently call setjmp()
+but only rarely call 
+longjmp().
+.PP
+.SH CAVEATS
+
+.PP
+.TP
+.B *
+The correct operation of this library depends on the presence of 
+correct unwind information. On newer platforms, this is rarely an 
+issue. On older platforms, care needs to be taken to 
+ensure that each of the functions whose stack frames may have to be 
+unwound during a longjmp()
+have correct unwind information 
+(on those platforms, there is usually a compiler\-switch, such as 
+\fB\-funwind\-tables\fP,
+to request the generation of unwind 
+information). 
+.TP
+.B *
+The contents of jmp_buf and sigjmp_buf as setup
+and used by these routines is completely different from the ones 
+used by the system\-provided routines. Thus, a jump\-buffer created 
+by the libunwind\-based setjmp()/_setjmp
+may only be 
+used in a call to the libunwind\-based 
+longjmp()/_longjmp().
+The analogous applies for 
+sigjmp_buf
+with sigsetjmp()
+and siglongjmp().
+.PP
+.SH FILES
+
+.PP
+.TP
+\fB\-l\fPunwind\-setjmp
+ The library an application should 
+be linked against to ensure it uses the libunwind\-based non\-local 
+goto routines. 
+.PP
+.SH SEE ALSO
+
+.PP
+libunwind(3),
+setjmp(3), longjmp(3), 
+_setjmp(3), _longjmp(3), 
+sigsetjmp(3), siglongjmp(3) 
+.PP
+.SH AUTHOR
+
+.PP
+David Mosberger\-Tang
+.br 
+Hewlett\-Packard Labs
+.br 
+Palo\-Alto, CA 94304
+.br 
+Email: \fBdavidm@hpl.hp.com\fP
+.br
+WWW: \fBhttp://www.hpl.hp.com/research/linux/libunwind/\fP\&.
+.\" NOTE: This file is generated, DO NOT EDIT.
diff --git a/doc/libunwind-setjmp.tex b/doc/libunwind-setjmp.tex
index e69de29..efaf957 100644
--- a/doc/libunwind-setjmp.tex
+++ b/doc/libunwind-setjmp.tex
@@ -0,0 +1,90 @@
+\documentclass{article}
+\usepackage[fancyhdr,pdf]{latex2man}
+
+\input{common.tex}
+
+\begin{document}
+
+\begin{Name}{3}{libunwind-setjmp}{David Mosberger-Tang}{Programming Library}{libunwind-based non-local gotos}
+  libunwind-setjmp -- libunwind-based non-local gotos
+\end{Name}
+
+\section{Synopsis}
+
+\File{\#include $<$setjmp.h$>$}\\
+
+\noindent
+\Type{int} \Func{setjmp}(\Type{jmp\_buf}~\Var{env});\\
+\Type{void} \Func{longjmp}(\Type{jmp\_buf}~\Var{env}, \Type{int}~\Var{val});\\
+\Type{int} \Func{\_setjmp}(\Type{jmp\_buf}~\Var{env});\\
+\Type{void} \Func{\_longjmp}(\Type{jmp\_buf}~\Var{env}, \Type{int}~\Var{val});\\
+\Type{int} \Func{setjmp}(\Type{sigjmp\_buf}~\Var{env}, \Type{int}~\Var{savemask});\\
+\Type{void} \Func{siglongjmp}(\Type{sigjmp\_buf}~\Var{env}, \Type{int}~\Var{val});\\
+
+\section{Description}
+
+The \Prog{unwind-setjmp} library offers a \Prog{libunwind}-based
+implementation of non-local gotos.  This implementation is intended to
+be a drop-in replacement for the normal, system-provided routines of
+the same name.  The main advantage of using the \Prog{unwind-setjmp}
+library is that setting up a non-local goto via one of the
+\Func{setjmp}() routines is very fast.  Typically, just 2 or 3 words
+need to be saved in the jump-buffer (plus one call to
+\Func{sigprocmask}(2), in the case of \Func{sigsetjmp}).  On the
+other hand, executing a non-local goto by calling one of the
+\Func{longjmp}() routines tends to be much slower than with the
+system-provided routines.  In fact, the time spent on a
+\Func{longjmp}() will be proportional to the number of call frames
+that exist between the points where \Func{setjmp}() and
+\Func{longjmp}() were called.  For this reason, the
+\Prog{unwind-setjmp} library is beneficial primarily in applications
+that frequently call \Func{setjmp}() but only rarely call
+\Func{longjmp}().
+
+\section{Caveats}
+
+\begin{itemize}
+\item The correct operation of this library depends on the presence of
+  correct unwind information.  On newer platforms, this is rarely an
+  issue.  On older platforms, care needs to be taken to
+  ensure that each of the functions whose stack frames may have to be
+  unwound during a \Func{longjmp}() have correct unwind information
+  (on those platforms, there is usually a compiler-switch, such as
+  \Opt{-funwind-tables}, to request the generation of unwind
+  information).
+\item The contents of \Type{jmp\_buf} and \Type{sigjmp\_buf} as setup
+  and used by these routines is completely different from the ones
+  used by the system-provided routines.  Thus, a jump-buffer created
+  by the libunwind-based \Func{setjmp}()/\Func{\_setjmp} may only be
+  used in a call to the libunwind-based
+  \Func{longjmp}()/\Func{\_longjmp}().  The analogous applies for
+  \Type{sigjmp\_buf} with \Func{sigsetjmp}() and \Func{siglongjmp}().
+\end{itemize}
+
+\section{Files}
+
+\begin{Description}
+\item[\Opt{-l}\File{unwind-setjmp}] The library an application should
+  be linked against to ensure it uses the libunwind-based non-local
+  goto routines.
+\end{Description}
+
+
+\section{See Also}
+
+\SeeAlso{libunwind(3)},
+setjmp(3), longjmp(3),
+\_setjmp(3), \_longjmp(3),
+sigsetjmp(3), siglongjmp(3)
+
+\section{Author}
+
+\noindent
+David Mosberger-Tang\\
+Hewlett-Packard Labs\\
+Palo-Alto, CA 94304\\
+Email: \Email{davidm@hpl.hp.com}\\
+WWW: \URL{http://www.hpl.hp.com/research/linux/libunwind/}.
+\LatexManEnd
+
+\end{document}
diff --git a/doc/unw_resume.man b/doc/unw_resume.man
index e69de29..4adf8da 100644
--- a/doc/unw_resume.man
+++ b/doc/unw_resume.man
@@ -0,0 +1,107 @@
+'\" t
+.\" Manual page created with latex2man on Sat Feb  8 01:21:05 PST 2003
+.\" NOTE: This file is generated, DO NOT EDIT.
+.de Vb
+.ft CW
+.nf
+..
+.de Ve
+.ft R
+
+.fi
+..
+.TH "UNW\\_RESUME" "3" "08 February 2003" "Programming Library " "Programming Library "
+.SH NAME
+
+.PP
+unw_resume \-\- resume execution in a particular stack frame 
+.PP
+.SH SYNOPSIS
+
+.PP
+#include <libunwind.h>
+.br
+.PP
+int
+unw_resume(unw_cursor_t *cursor);
+.br
+.PP
+.SH DESCRIPTION
+
+.PP
+The unw_resume()
+routine resumes execution at the stack frame 
+identified by cursor\&.
+Normally, this is accomplished by 
+restoring the ``preserved\&'' (callee\-saved) machine state. However, if 
+execution in any of the stack frames younger (more deeply nested) than 
+the one identified by cursor
+was interrupted by a signal, then 
+unw_resume()
+will restore the entire machine state, including 
+the ``preserved\&'' and ``scratch\&'' (caller\-saved) registers, as well as 
+the signal mask. 
+.PP
+Most platforms reserve some registers to pass arguments to exception 
+handlers (e.g., IA\-64 uses r15\-r18
+for this 
+purpose). These registers are normally treated like ``scratch\&'' 
+registers. However, if libunwind
+is used to define an 
+exception argument register, e.g., by calling unw_set_reg(),
+then unw_resume()
+will always install the new value as the 
+contents of that register. In other words, the exception handling 
+arguments are installed even in cases where normally only the 
+``preserved\&'' registers are restored. 
+.PP
+.SH RETURN VALUE
+
+.PP
+For local unwinding, unw_resume()
+does not return on success. 
+For remote unwinding, it returns 0 on success. On failure, the 
+negative value of one of the errors below is returned. 
+.PP
+.SH ERRORS
+
+.PP
+.TP
+UNW_EUNSPEC
+ An unspecified error occurred. 
+.TP
+UNW_EBADREG
+ A register needed by unw_resume()
+wasn\&'t 
+accessible. 
+.TP
+UNW_EINVALIDIP
+ The instruction pointer identified by 
+cursor
+is not valid. 
+.TP
+UNW_BADFRAME
+ The stack frame identified by 
+cursor
+is not valid. 
+.PP
+.SH SEE ALSO
+
+.PP
+libunwind(3),
+unw_set_reg(3),
+sigprocmask(2) 
+.PP
+.SH AUTHOR
+
+.PP
+David Mosberger\-Tang
+.br 
+Hewlett\-Packard Labs
+.br 
+Palo\-Alto, CA 94304
+.br 
+Email: \fBdavidm@hpl.hp.com\fP
+.br
+WWW: \fBhttp://www.hpl.hp.com/research/linux/libunwind/\fP\&.
+.\" NOTE: This file is generated, DO NOT EDIT.
diff --git a/doc/unw_resume.tex b/doc/unw_resume.tex
index e69de29..f7f458a 100644
--- a/doc/unw_resume.tex
+++ b/doc/unw_resume.tex
@@ -0,0 +1,74 @@
+\documentclass{article}
+\usepackage[fancyhdr,pdf]{latex2man}
+
+\input{common.tex}
+
+\begin{document}
+
+\begin{Name}{3}{unw\_resume}{David Mosberger-Tang}{Programming Library}{unw\_resume}
+
+  unw\_resume -- resume execution in a particular stack frame
+\end{Name}
+
+\section{Synopsis}
+
+\File{\#include $<$libunwind.h$>$}\\
+
+\Type{int} \Func{unw\_resume}(\Type{unw\_cursor\_t~*}\Var{cursor});\\
+
+\section{Description}
+
+The \Func{unw\_resume}() routine resumes execution at the stack frame
+identified by \Var{cursor}.  Normally, this is accomplished by
+restoring the ``preserved'' (callee-saved) machine state.  However, if
+execution in any of the stack frames younger (more deeply nested) than
+the one identified by \Var{cursor} was interrupted by a signal, then
+\Func{unw\_resume}() will restore the entire machine state, including
+the ``preserved'' and ``scratch'' (caller-saved) registers, as well as
+the signal mask.
+
+Most platforms reserve some registers to pass arguments to exception
+handlers (e.g., IA-64 uses \texttt{r15}-\texttt{r18} for this
+purpose).  These registers are normally treated like ``scratch''
+registers.  However, if \Prog{libunwind} is used to define an
+exception argument register, e.g., by calling \Func{unw\_set\_reg}(),
+then \Func{unw\_resume}() will always install the new value as the
+contents of that register.  In other words, the exception handling
+arguments are installed even in cases where normally only the
+``preserved'' registers are restored.
+
+\section{Return Value}
+
+For local unwinding, \Func{unw\_resume}() does not return on success.
+For remote unwinding, it returns 0 on success.  On failure, the
+negative value of one of the errors below is returned.
+
+\section{Errors}
+
+\begin{Description}
+\item[\Const{UNW\_EUNSPEC}] An unspecified error occurred.
+\item[\Const{UNW\_EBADREG}] A register needed by \Func{unw\_resume}() wasn't
+  accessible.
+\item[\Const{UNW\_EINVALIDIP}] The instruction pointer identified by
+  \Var{cursor} is not valid.
+\item[\Const{UNW\_BADFRAME}] The stack frame identified by
+  \Var{cursor} is not valid.
+\end{Description}
+
+\section{See Also}
+
+\SeeAlso{libunwind(3)},
+\SeeAlso{unw\_set\_reg(3)},
+sigprocmask(2)
+
+\section{Author}
+
+\noindent
+David Mosberger-Tang\\
+Hewlett-Packard Labs\\
+Palo-Alto, CA 94304\\
+Email: \Email{davidm@hpl.hp.com}\\
+WWW: \URL{http://www.hpl.hp.com/research/linux/libunwind/}.
+\LatexManEnd
+
+\end{document}
diff --git a/src/elf32.c b/src/elf32.c
index e69de29..f1c21e6 100644
--- a/src/elf32.c
+++ b/src/elf32.c
@@ -0,0 +1,2 @@
+#include "elf32.h"
+#include "elfxx.c"
diff --git a/src/elf32.h b/src/elf32.h
index e69de29..d27646c 100644
--- a/src/elf32.h
+++ b/src/elf32.h
@@ -0,0 +1,7 @@
+#ifndef elf32_h
+#define elf32_h
+
+#define ELF_CLASS	ELFCLASS32
+#include "elfxx.h"
+
+#endif /* elf32_h */
diff --git a/src/elf64.c b/src/elf64.c
index e69de29..1154179 100644
--- a/src/elf64.c
+++ b/src/elf64.c
@@ -0,0 +1,2 @@
+#include "elf64.h"
+#include "elfxx.c"
diff --git a/src/elf64.h b/src/elf64.h
index e69de29..8f22384 100644
--- a/src/elf64.h
+++ b/src/elf64.h
@@ -0,0 +1,7 @@
+#ifndef elf64_h
+#define elf64_h
+
+#define ELF_CLASS	ELFCLASS64
+#include "elfxx.h"
+
+#endif /* elf64_h */
diff --git a/src/elfxx.c b/src/elfxx.c
index e69de29..68985b5 100644
--- a/src/elfxx.c
+++ b/src/elfxx.c
@@ -0,0 +1,168 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+
+
+extern HIDDEN int
+elfW (valid_object) (struct elf_image *ei)
+{
+  if (ei->size <= EI_CLASS)
+    return 0;
+
+  return (memcmp (ei->image, ELFMAG, SELFMAG) == 0
+	  && ((uint8_t *) ei->image)[EI_CLASS] == ELF_CLASS);
+}
+
+
+static int
+elfW (lookup_symbol) (unw_word_t ip, struct elf_image *ei,
+		      ElfW (Addr) load_offset,
+		      char *buf, size_t buf_len, unw_word_t *offp)
+{
+  size_t syment_size, str_size;
+  ElfW (Ehdr) *ehdr = ei->image;
+  ElfW (Sym) *sym, *symtab, *symtab_end;
+  ElfW (Off) soff, str_soff;
+  ElfW (Shdr) *shdr, *str_shdr;
+  ElfW (Addr) val, min_dist = ~(ElfW (Addr))0;
+  char *strtab;
+  int i;
+
+  if (!elfW (valid_object) (ei))
+    return -1;
+
+  soff = ehdr->e_shoff;
+  if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->size)
+    {
+      debug (1, "%s: section table outside of image? (%lu > %lu)\n",
+	     __FUNCTION__, soff + ehdr->e_shnum * ehdr->e_shentsize,
+	     ei->size);
+      return -1;
+    }
+
+  shdr = (ElfW (Shdr) *) ((char *) ei->image + soff);
+
+  for (i = 0; i < ehdr->e_shnum; ++i)
+    {
+      switch (shdr->sh_type)
+	{
+	case SHT_SYMTAB:
+	case SHT_DYNSYM:
+	  symtab = (ElfW (Sym) *) ((char *) ei->image + shdr->sh_offset);
+	  symtab_end = (ElfW (Sym) *) ((char *) symtab + shdr->sh_size);
+	  syment_size = shdr->sh_entsize;
+
+	  str_soff = soff + (shdr->sh_link * ehdr->e_shentsize);
+	  if (str_soff + ehdr->e_shentsize >= ei->size)
+	    {
+	      debug (1, "%s: string table outside of image? (%lu >= %lu)\n",
+		     __FUNCTION__, str_soff + ehdr->e_shentsize, ei->size);
+	      break;
+	    }
+	  str_shdr = (ElfW (Shdr) *) ((char *) ei->image + str_soff);
+	  str_size = str_shdr->sh_size;
+	  strtab = (char *) ei->image + str_shdr->sh_offset;
+
+	  debug (10, "symtab=0x%lx[%d], strtab=0x%lx\n", shdr->sh_offset,
+		 shdr->sh_type, str_shdr->sh_offset);
+
+	  for (sym = symtab;
+	       sym < symtab_end;
+	       sym = (ElfW (Sym) *) ((char *) sym + syment_size))
+	    {
+	      if (ELFW (ST_TYPE) (sym->st_info) == STT_FUNC
+		  && sym->st_shndx != SHN_UNDEF)
+		{
+		  val = sym->st_value;
+		  if (sym->st_shndx != SHN_ABS)
+		    val += load_offset;
+		  debug (100, "0x%016lx info=0x%02x %s\n",
+			 val, sym->st_info, strtab + sym->st_name);
+
+		  if ((ElfW (Addr)) (ip - val) < min_dist)
+		    {
+		      min_dist = (ElfW (Addr)) (ip - val);
+		      buf[buf_len - 1] = 'x';
+		      strncpy (buf, strtab + sym->st_name, buf_len);
+		      buf[buf_len - 1] = '\0';
+		    }
+		}
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+      shdr = (Elf64_Shdr *) (((char *) shdr) + ehdr->e_shentsize);
+    }
+  if (min_dist >= ei->size)
+    return -1;			/* not found */
+  if (offp)
+    *offp = min_dist;
+  return 0;
+}
+
+/* Find the ELF image that contains IP and return the "closest"
+   procedure name, if there is one.  With some caching, this could be
+   sped up greatly, but until an application materializes that's
+   sensitive to the performance of this routine, why bother...  */
+
+HIDDEN int
+elfW (get_proc_name) (unw_word_t ip, char *buf, size_t buf_len,
+		      unw_word_t *offp)
+{
+  unsigned long segbase, mapoff;
+  ElfW (Addr) load_offset = 0;
+  struct elf_image ei;
+  ElfW (Ehdr) *ehdr;
+  ElfW (Phdr) *phdr;
+  int i, ret;
+
+  ret = tdep_get_elf_image (&ei, getpid (), ip, &segbase, &mapoff);
+  if (ret < 0)
+    return ret;
+
+  ehdr = ei.image;
+  phdr = (Elf64_Phdr *) ((char *) ei.image + ehdr->e_phoff);
+
+  for (i = 0; i < ehdr->e_phnum; ++i)
+    if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff)
+      {
+	load_offset = segbase - phdr[i].p_vaddr;
+	break;
+      }
+
+  ret = elfW (lookup_symbol) (ip, &ei, load_offset, buf, buf_len, offp);
+
+  munmap (ei.image, ei.size);
+  ei.image = NULL;
+
+  return ret;
+}
diff --git a/src/elfxx.h b/src/elfxx.h
index e69de29..b92253b 100644
--- a/src/elfxx.h
+++ b/src/elfxx.h
@@ -0,0 +1,71 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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 <elf.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#include "internal.h"
+
+#if ELF_CLASS == ELFCLASS32
+# define ELFW(x)	ELF32_##x
+# define ElfW(x)	Elf32_##x
+# define elfW(x)	_Uelf32_##x
+#else
+# define ELFW(x)	ELF64_##x
+# define ElfW(x)	Elf64_##x
+# define elfW(x)	_Uelf64_##x
+#endif
+
+static inline int
+elf_map_image (struct elf_image *ei, char *path)
+{
+  struct stat stat;
+  int fd;
+
+  fd = open (path, O_RDONLY);
+  if (fd < 0)
+    return -1;
+
+  if (fstat (fd, &stat) < 0)
+    {
+      close (fd);
+      return -1;
+    }
+
+  ei->size = stat.st_size;
+  ei->image = mmap (NULL, ei->size, PROT_READ, MAP_PRIVATE, fd, 0);
+  close (fd);
+  if (ei->image == MAP_FAILED)
+    return -1;
+
+  return 0;
+}
+
+extern HIDDEN int elfW (valid_object) (struct elf_image *ei);
+extern HIDDEN int elfW (get_proc_name) (unw_word_t ip, char *buf, size_t len,
+					unw_word_t *offp);
diff --git a/src/ia64/mk_cursor_i-ia64.c b/src/ia64/mk_cursor_i-ia64.c
index e69de29..aa70a27 100644
--- a/src/ia64/mk_cursor_i-ia64.c
+++ b/src/ia64/mk_cursor_i-ia64.c
@@ -0,0 +1,104 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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.  */
+
+/* Utility to generate cursor_i.h.  */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "internal.h"
+
+#ifdef offsetof
+# undef offsetof
+#endif
+
+#define offsetof(type,field)	((char *) &((type *) 0)->field - (char *) 0)
+
+struct
+  {
+    const char name[256];
+    unsigned long value;
+  }
+tab[] =
+  {
+    { "IP_OFF",			offsetof (struct cursor, ip) },
+    { "PR_OFF",			offsetof (struct cursor, pr) },
+    { "BSP_OFF",		offsetof (struct cursor, bsp) },
+    { "PSP_OFF",		offsetof (struct cursor, psp) },
+    { "PFS_LOC_OFF",		offsetof (struct cursor, pfs_loc) },
+    { "RNAT_LOC_OFF",		offsetof (struct cursor, rnat_loc) },
+    { "UNAT_LOC_OFF",		offsetof (struct cursor, unat_loc) },
+    { "LC_LOC_OFF",		offsetof (struct cursor, lc_loc) },
+    { "FPSR_LOC_OFF",		offsetof (struct cursor, fpsr_loc) },
+    { "B1_LOC_OFF",		offsetof (struct cursor, b1_loc) },
+    { "B2_LOC_OFF",		offsetof (struct cursor, b2_loc) },
+    { "B3_LOC_OFF",		offsetof (struct cursor, b3_loc) },
+    { "B4_LOC_OFF",		offsetof (struct cursor, b4_loc) },
+    { "B5_LOC_OFF",		offsetof (struct cursor, b5_loc) },
+    { "F2_LOC_OFF",		offsetof (struct cursor, f2_loc) },
+    { "F3_LOC_OFF",		offsetof (struct cursor, f3_loc) },
+    { "F4_LOC_OFF",		offsetof (struct cursor, f4_loc) },
+    { "F5_LOC_OFF",		offsetof (struct cursor, f5_loc) },
+    { "FR_LOC_OFF",		offsetof (struct cursor, fr_loc) },
+    { "SIGCONTEXT_LOC_OFF",	offsetof (struct cursor, sigcontext_loc) },
+};
+
+static const char *tabs = "\t\t\t\t\t\t\t\t\t\t";
+
+int
+main (int argc, char **argv)
+{
+  const char *space;
+  int i, num_tabs;
+  size_t len;
+
+  printf ("#ifndef cursor_i_h\n");
+  printf ("#define cursor_i_h\n\n");
+
+  printf ("/*\n * DO NOT MODIFY\n *\n * This file was generated by "
+	  "print_offsets.\n *\n */\n\n");
+
+  for (i = 0; i < (int) (sizeof (tab) / sizeof (tab[0])); ++i)
+    {
+      if (tab[i].name[0] == '\0')
+	printf ("\n");
+      else
+	{
+	  len = strlen (tab[i].name);
+
+	  num_tabs = (40 - len) / 8;
+	  if (num_tabs <= 0)
+	    space = " ";
+	  else
+	    space = strchr(tabs, '\0') - (40 - len) / 8;
+
+	  printf ("#define %s%s%lu\t/* 0x%lx */\n",
+		  tab[i].name, space, tab[i].value, tab[i].value);
+	}
+    }
+
+  printf ("\n#endif /* cursor_i_h */\n");
+  return 0;
+}
diff --git a/src/ia64/setjmp-ia64.S b/src/ia64/setjmp-ia64.S
index e69de29..52ecd53 100644
--- a/src/ia64/setjmp-ia64.S
+++ b/src/ia64/setjmp-ia64.S
@@ -0,0 +1,45 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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.  */
+
+	.align 32
+
+	.global _setjmp
+
+	.proc _setjmp
+
+_setjmp:
+	mov r2 = ar.bsp
+	st8 [r32] = r12		// jmp_buf[0] = sp
+	mov r3 = rp
+
+	adds r16 = 8, r32
+	adds r17 = 16, r32
+	mov r8 = 0
+	;;
+	st8 [r16] = r3		// jmp_buf[1] = rp
+	st8 [r17] = r2		// jmp_buf[2] = bsp
+	br.ret.sptk.many rp
+
+	.endp _setjmp
diff --git a/src/ia64/siglongjmp-ia64.S b/src/ia64/siglongjmp-ia64.S
index e69de29..3feccf2 100644
--- a/src/ia64/siglongjmp-ia64.S
+++ b/src/ia64/siglongjmp-ia64.S
@@ -0,0 +1,64 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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.  */
+
+#define SIG_SETMASK	2
+
+	.globl _UI_siglongjmp_cont
+
+	.align 32
+	.proc siglongjmp_continuation
+siglongjmp_continuation:
+_UI_siglongjmp_cont:		// non-function label for {sig,}longjmp.c
+	.prologue
+	.save rp, r15
+	.body
+	nop 0
+	nop 0
+	br.call.sptk.many b6 = 1f
+	;;
+	.prologue
+	.save ar.pfs, r33
+1:	alloc loc1 = ar.pfs, 0, 3, 3, 0
+	/*
+	 * Note: we can use the scratch stack are because the caller
+	 * of sigsetjmp() by definition is not a leaf-procedure.
+	 */
+	st8 [sp] = r17			// store signal mask
+	.save rp, loc0
+	mov loc0 = r15			// final continuation point
+	;;
+	.body
+	mov loc2 = r16			// value to return in r8
+
+	mov out0 = SIG_SETMASK
+	mov out1 = sp
+	mov out2 = r0
+	br.call.sptk.many rp = sigprocmask
+	;;
+	mov rp = loc0
+	mov ar.pfs = loc1
+	mov r8 = loc2
+	br.ret.sptk.many rp
+	.endp siglongjmp_continuation
diff --git a/src/ia64/sigsetjmp-ia64.S b/src/ia64/sigsetjmp-ia64.S
index e69de29..271d29d 100644
--- a/src/ia64/sigsetjmp-ia64.S
+++ b/src/ia64/sigsetjmp-ia64.S
@@ -0,0 +1,64 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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.  */
+
+#define SIG_BLOCK 0
+
+	.align 32
+
+	.global __sigsetjmp
+
+	.proc __sigsetjmp
+
+__sigsetjmp:
+	.prologue
+	.save ar.pfs, r35
+	alloc loc1 = ar.pfs, 2, 3, 3, 0
+	add r16 = 16, in0
+	add out2 = 24, in0
+
+	st8 [in0] = sp, 8		// sigjmp_buf[0] = sp
+	mov out0 = SIG_BLOCK
+	.save rp, loc0
+	mov loc0 = rp
+	.body
+	;;
+	st8 [in0] = loc0, 24		// sigjmp_buf[1] = rp
+	st8 [r16] = in1			// sigjmp_buf[2] = savemask
+	cmp.ne p6, p0 = in1, r0
+
+	mov out1 = r0
+	mov loc2 = ar.bsp
+(p6)	br.call.sptk.many rp = sigprocmask	// sigjmp_buf[3] = sigmask
+	;;
+
+	st8 [in0] = loc2		// sigjmp_buf[4] = bsp
+	mov rp = loc0
+	nop 0
+
+	mov r8 = 0
+	mov.i ar.pfs = loc1
+	br.ret.sptk.many rp
+
+	.endp __sigsetjmp
diff --git a/src/longjmp.c b/src/longjmp.c
index e69de29..69bfeba 100644
--- a/src/longjmp.c
+++ b/src/longjmp.c
@@ -0,0 +1,109 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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.  */
+
+#define UNW_LOCAL_ONLY
+
+#include <libunwind.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#if UNW_TARGET_IA64
+# include "ia64/rse.h"
+#endif
+
+void
+_longjmp (jmp_buf env, int val)
+{
+  extern int _UI_siglongjmp_cont;
+  sigset_t current_mask;
+  unw_context_t uc;
+  unw_cursor_t c;
+  unw_word_t sp;
+  unw_word_t *wp = (unw_word_t *) env;
+
+  if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0)
+    abort ();
+
+  do
+    {
+      if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0)
+	abort ();
+      if (sp != wp[0])
+	continue;
+
+#if UNW_TARGET_IA64
+      {
+	unw_word_t bsp, pfs, sol;
+
+	if (unw_get_reg (&c, UNW_IA64_BSP, &bsp) < 0
+	    || unw_get_reg (&c, UNW_IA64_AR_PFS, &pfs) < 0)
+	  abort ();
+
+	/* simulate the effect of "br.call setjmp" on ar.bsp: */
+	sol = (pfs >> 7) & 0x7f;
+	bsp = ia64_rse_skip_regs (bsp, sol);
+
+	if (bsp != wp[2])
+	  continue;
+      }
+#endif
+
+      /* found the right frame: */
+
+      if (sigprocmask (SIG_BLOCK, NULL, &current_mask) < 0)
+	abort ();
+
+      if (unw_set_reg (&c, UNW_REG_EH_ARG0, wp[1]) < 0
+	  || unw_set_reg (&c, UNW_REG_EH_ARG1, val) < 0
+	  || unw_set_reg (&c, UNW_REG_EH_ARG2,
+			  ((unw_word_t *) &current_mask)[0]) < 0
+	  || unw_set_reg (&c, UNW_REG_IP,
+			  (unw_word_t) &_UI_siglongjmp_cont))
+	abort ();
+
+      if (_NSIG > 8 * sizeof (unw_word_t))
+	{
+	  if (_NSIG > 16 * sizeof (unw_word_t))
+	    abort ();
+	  if (unw_set_reg (&c, UNW_REG_EH_ARG3,
+			   ((unw_word_t *) &current_mask)[1]) < 0)
+	    abort ();
+	}
+
+      unw_resume (&c);
+
+      abort ();
+    }
+  while (unw_step (&c) >= 0);
+
+  abort ();
+}
+
+void
+longjmp (jmp_buf env, int val)
+{
+  _longjmp (env, val);
+}
diff --git a/src/os-linux.c b/src/os-linux.c
index e69de29..b4b8d71 100644
--- a/src/os-linux.c
+++ b/src/os-linux.c
@@ -0,0 +1,63 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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.  */
+
+#ifndef UNW_REMOTE_ONLY
+
+#include <limits.h>
+#include <stdio.h>
+
+#include "internal.h"
+#include "os-linux.h"
+
+/* Here, it doesn't matter whether we include elf64.h or elf32.h.
+   Both define "struct elf_image" and elf_map_image() in an identical
+   fashion.  */
+#include "elf64.h"
+
+HIDDEN int
+tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
+		    unsigned long *segbase, unsigned long *mapoff)
+{
+  struct map_iterator mi;
+  char path[PATH_MAX];
+  int found = 0;
+  unsigned long hi;
+
+  maps_init (&mi, pid);
+  while (maps_next (&mi, segbase, &hi, mapoff, path))
+    if (ip >= *segbase && ip < hi)
+      {
+	found = 1;
+	break;
+      }
+  maps_close (&mi);
+
+  if (!found)
+    return -1;
+
+  return elf_map_image (ei, path);
+}
+
+#endif /* UNW_REMOTE_ONLY */
diff --git a/src/os-linux.h b/src/os-linux.h
index e69de29..88ba4ac 100644
--- a/src/os-linux.h
+++ b/src/os-linux.h
@@ -0,0 +1,69 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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.  */
+
+#ifndef os_linux_h
+#define os_linux_h
+
+struct map_iterator
+  {
+    FILE *fp;
+  };
+
+static inline void
+maps_init (struct map_iterator *mi, pid_t pid)
+{
+  char path[PATH_MAX];
+
+  snprintf (path, sizeof (path), "/proc/%d/maps", pid);
+  mi->fp = fopen (path, "r");
+}
+
+static inline int
+maps_next (struct map_iterator *mi,
+	   unsigned long *low, unsigned long *high, unsigned long *offset,
+	   char *path)
+{
+  char line[256+PATH_MAX];
+
+  if (!mi->fp)
+    return 0;
+
+  while (fgets (line, sizeof (line), mi->fp))
+    {
+      if (sscanf (line, "%lx-%lx %*4c %lx %*x:%*x %*d %s\n",
+		  low, high, offset, path) == 4)
+	return 1;
+    }
+  return 0;
+}
+
+static inline void
+maps_close (struct map_iterator *mi)
+{
+  fclose (mi->fp);
+  mi->fp = NULL;
+}
+
+#endif /* os_linux_h */
diff --git a/src/setjmp.c b/src/setjmp.c
index e69de29..8901071 100644
--- a/src/setjmp.c
+++ b/src/setjmp.c
@@ -0,0 +1,52 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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 <libunwind.h>
+#include <setjmp.h>
+
+/* Why use K&R syntax here?  setjmp() is often a macro and that
+   expands into a call to, say, __setjmp() and we need to define the
+   libunwind-version of setjmp() with the name of the actual function.
+   Using K&R syntax lets us keep the setjmp() macro while keeping the
+   syntax valid...  This trick works provided setjmp() doesn't do
+   anything other than a function call.  */
+
+int
+setjmp (env)
+     jmp_buf env;
+{
+  void **wp = (void **) env;
+
+#if UNW_TARGET_IA64
+  wp[0] = __builtin_dwarf_cfa () - 16;
+  wp[1] = __builtin_ia64_bsp ();
+#else
+  /* this should work on most platforms, but may not be
+     performance-optimal; check the code! */
+  wp[0] = __builtin_frame_address (0);
+  wp[1] = (void *) (uintptr_t) 0;
+#endif
+  return 0;
+}
diff --git a/src/siglongjmp.c b/src/siglongjmp.c
index e69de29..9762410 100644
--- a/src/siglongjmp.c
+++ b/src/siglongjmp.c
@@ -0,0 +1,108 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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.  */
+
+#define UNW_LOCAL_ONLY
+
+#include <libunwind.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#if UNW_TARGET_IA64
+# include "ia64/rse.h"
+#endif
+
+void
+siglongjmp (sigjmp_buf env, int val)
+{
+  unw_word_t *mp, *wp = (unw_word_t *) env;
+  extern int _UI_siglongjmp_cont;
+  sigset_t current_mask;
+  unw_context_t uc;
+  unw_cursor_t c;
+  unw_word_t sp;
+
+  if (unw_getcontext (&uc) < 0 || unw_init_local (&c, &uc) < 0)
+    abort ();
+
+  do
+    {
+      if (unw_get_reg (&c, UNW_REG_SP, &sp) < 0)
+	abort ();
+      if (sp != wp[0])
+	continue;
+
+#if UNW_TARGET_IA64
+      {
+	unw_word_t bsp, pfs, sol;
+
+	if (unw_get_reg (&c, UNW_IA64_BSP, &bsp) < 0
+	    || unw_get_reg (&c, UNW_IA64_AR_PFS, &pfs) < 0)
+	  abort ();
+
+	/* simulate the effect of "br.call sigsetjmp" on ar.bsp: */
+	sol = (pfs >> 7) & 0x7f;
+	bsp = ia64_rse_skip_regs (bsp, sol);
+
+	if (bsp != wp[4])
+	  continue;
+      }
+#endif
+
+      /* found the right frame: */
+
+      if (wp[2])
+	mp = wp + 3;
+      else
+	{
+	  /* sigmask wasn't saved; get it now so we can leave it unchanged.  */
+	  if (sigprocmask (SIG_BLOCK, NULL, &current_mask) < 0)
+	    abort ();
+	  mp = (unw_word_t *) &current_mask;
+	}
+
+      if (unw_set_reg (&c, UNW_REG_EH_ARG0, wp[1]) < 0
+	  || unw_set_reg (&c, UNW_REG_EH_ARG1, val) < 0
+	  || unw_set_reg (&c, UNW_REG_EH_ARG2, mp[0]) < 0
+	  || unw_set_reg (&c, UNW_REG_IP,
+			  (unw_word_t) &_UI_siglongjmp_cont))
+	abort ();
+
+      if (_NSIG > 8 * sizeof (unw_word_t))
+	{
+	  if (_NSIG > 16 * sizeof (unw_word_t))
+	    abort ();
+	  if (unw_set_reg (&c, UNW_REG_EH_ARG3, mp[1]) < 0)
+	    abort ();
+	}
+
+      unw_resume (&c);
+
+      abort ();
+    }
+  while (unw_step (&c) >= 0);
+
+  abort ();
+}
diff --git a/src/sigsetjmp.c b/src/sigsetjmp.c
index e69de29..7378287 100644
--- a/src/sigsetjmp.c
+++ b/src/sigsetjmp.c
@@ -0,0 +1,47 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 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 <libunwind.h>
+#include <setjmp.h>
+#include <stdlib.h>
+
+int
+sigsetjmp (sigjmp_buf env, int savemask)
+{
+  unw_word_t *wp = (unw_word_t *) env;
+
+  /* This should work on most platforms, but may not be
+     performance-optimal; check the code! */
+
+  wp[0] = (unw_word_t) __builtin_frame_address (0);
+  wp[1] = (unw_word_t) __builtin_return_address (0);
+  wp[2] = savemask;
+
+  /* Note: we assume here that "wp" has same or better alignment as
+     sigset_t.  */
+  if (savemask && sigprocmask (SIG_BLOCK, NULL, (sigset_t *) (wp + 3)) < 0)
+    abort ();
+  return 0;
+}
diff --git a/tests/test-setjmp.c b/tests/test-setjmp.c
index e69de29..7a3ddb4 100644
--- a/tests/test-setjmp.c
+++ b/tests/test-setjmp.c
@@ -0,0 +1,278 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 Hewlett-Packard Co
+	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+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.  */
+
+/* The setjmp()/longjmp(), sigsetjmp()/siglongjmp().  */
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int nerrors;
+int verbose;
+
+static jmp_buf jbuf;
+static sigjmp_buf sigjbuf;
+static sigset_t sigset4;
+
+void
+raise_longjmp (jmp_buf jbuf, int i, int n)
+{
+  while (i < n)
+    raise_longjmp (jbuf, i + 1, n);
+
+  longjmp (jbuf, n);
+}
+
+void
+test_setjmp (void)
+{
+  volatile int i;
+  jmp_buf jbuf;
+  int ret;
+
+  for (i = 0; i < 10; ++i)
+    {
+      if ((ret = setjmp (jbuf)))
+	{
+	  if (verbose)
+	    printf ("%s: secondary setjmp () return, ret=%d\n",
+		    __FUNCTION__, ret);
+	  if (ret != i + 1)
+	    {
+	      fprintf (stderr, "%s: setjmp() returned %d, expected %d\n",
+		       __FUNCTION__, ret, i + 1);
+	      ++nerrors;
+	    }
+	  continue;
+	}
+      if (verbose)
+	printf ("%s.%d: done with setjmp(); calling children\n",
+		__FUNCTION__, i + 1);
+
+      raise_longjmp (jbuf, 0, i + 1);
+
+      fprintf (stderr, "%s: raise_longjmp() returned unexpected\n",
+	       __FUNCTION__);
+      ++nerrors;
+    }
+}
+
+
+void
+raise_siglongjmp (sigjmp_buf jbuf, int i, int n)
+{
+  while (i < n)
+    raise_siglongjmp (jbuf, i + 1, n);
+
+  siglongjmp (jbuf, n);
+}
+
+void
+test_sigsetjmp (void)
+{
+  sigjmp_buf jbuf;
+  int i, ret;
+
+  for (i = 0; i < 10; ++i)
+    {
+      if ((ret = sigsetjmp (jbuf, 1)))
+	{
+	  if (verbose)
+	    printf ("%s: secondary sigsetjmp () return, ret=%d\n",
+		    __FUNCTION__, ret);
+	  if (ret != i + 1)
+	    {
+	      fprintf (stderr, "%s: sigsetjmp() returned %d, expected %d\n",
+		       __FUNCTION__, ret, i + 1);
+	      ++nerrors;
+	    }
+	  continue;
+	}
+      if (verbose)
+	printf ("%s.%d: done with sigsetjmp(); calling children\n",
+		__FUNCTION__, i + 1);
+
+      raise_siglongjmp (jbuf, 0, i + 1);
+
+      fprintf (stderr, "%s: raise_siglongjmp() returned unexpected\n",
+	       __FUNCTION__);
+      ++nerrors;
+    }
+}
+
+void
+sighandler (int signal)
+{
+  if (verbose)
+    printf ("%s: got signal %d\n", __FUNCTION__, signal);
+
+  sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset4);
+  siglongjmp (sigjbuf, 1);
+}
+
+int
+main (int argc, char **argv)
+{
+  volatile sigset_t sigset1, sigset2, sigset3;
+  volatile struct sigaction act;
+
+  if (argc > 1)
+    verbose = 1;
+
+  sigemptyset ((sigset_t *) &sigset1);
+  sigaddset ((sigset_t *) &sigset1, SIGUSR1);
+  sigemptyset ((sigset_t *) &sigset2);
+  sigaddset ((sigset_t *) &sigset2, SIGUSR2);
+
+  memset ((void *) &act, 0, sizeof (act));
+  act.sa_handler = sighandler;
+  sigaction (SIGTERM, (struct sigaction *) &act, NULL);
+
+  test_setjmp ();
+  test_sigsetjmp ();
+
+  /* _setjmp() MUST NOT change signal mask: */
+  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
+  if (_setjmp (jbuf))
+    {
+      sigemptyset ((sigset_t *) &sigset3);
+      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
+      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2,
+		  sizeof (sigset_t)) != 0)
+	{
+	  fprintf (stderr, "FAILURE: _longjmp() manipulated signal mask!\n");
+	  ++nerrors;
+	}
+      else if (verbose)
+	printf ("OK: _longjmp() seems not to change signal mask\n");
+    }
+  else
+    {
+      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
+      _longjmp (jbuf, 1);
+    }
+
+  /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */
+  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
+  if (sigsetjmp (sigjbuf, 1))
+    {
+      sigemptyset ((sigset_t *) &sigset3);
+      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
+      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1,
+		  sizeof (sigset_t)) != 0)
+	{
+	  fprintf (stderr,
+		   "FAILURE: siglongjmp() didn't restore signal mask!\n");
+	  ++nerrors;
+	}
+      else if (verbose)
+	printf ("OK: siglongjmp() restores signal mask when asked to\n");
+    }
+  else
+    {
+      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
+      siglongjmp (sigjbuf, 1);
+    }
+
+  /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */
+  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
+  if (sigsetjmp (sigjbuf, 0))
+    {
+      sigemptyset ((sigset_t *) &sigset3);
+      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
+      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2,
+		  sizeof (sigset_t)) != 0)
+	{
+	  fprintf (stderr,
+		   "FAILURE: siglongjmp() changed signal mask!\n");
+	  ++nerrors;
+	}
+      else if (verbose)
+	printf ("OK: siglongjmp() leaves signal mask along when asked to\n");
+    }
+  else
+    {
+      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
+      siglongjmp (sigjbuf, 1);
+    }
+
+  /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */
+  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
+  if (sigsetjmp (sigjbuf, 1))
+    {
+      sigemptyset ((sigset_t *) &sigset3);
+      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
+      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1,
+		  sizeof (sigset_t)) != 0)
+	{
+	  fprintf (stderr,
+		   "FAILURE: siglongjmp() didn't restore signal mask!\n");
+	  ++nerrors;
+	}
+      else if (verbose)
+	printf ("OK: siglongjmp() restores signal mask when asked to\n");
+    }
+  else
+    {
+      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
+      kill (getpid (), SIGTERM);
+      fprintf (stderr, "FAILURE: unexpected return from kill()\n");
+      ++nerrors;
+    }
+
+  /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */
+  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
+  if (sigsetjmp (sigjbuf, 0))
+    {
+      sigemptyset ((sigset_t *) &sigset3);
+      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
+      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset4,
+		  sizeof (sigset_t)) != 0)
+	{
+	  fprintf (stderr,
+		   "FAILURE: siglongjmp() changed signal mask!\n");
+	  ++nerrors;
+	}
+      else if (verbose)
+	printf ("OK: siglongjmp() leaves signal mask along when asked to\n");
+    }
+  else
+    {
+      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
+      kill (getpid (), SIGTERM);
+      fprintf (stderr, "FAILURE: unexpected return from kill()\n");
+      ++nerrors;
+    }
+
+  if (nerrors > 0)
+    {
+      fprintf (stderr, "FAILURE: detected %d failures\n", nerrors);
+      exit (-1);
+    }
+  if (verbose)
+    printf ("SUCCESS\n");
+  return 0;
+}