(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, ¤t_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 *) ¤t_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 *) ¤t_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, ¤t_mask) < 0)
+ abort ();
+ mp = (unw_word_t *) ¤t_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;
+}