1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2025-01-09 02:43:42 +01:00

(Logical change 1.45)

This commit is contained in:
mostang.com!davidm 2003-02-08 10:10:59 +00:00
parent 5f94e2d488
commit 824d6619b5
21 changed files with 1667 additions and 0 deletions

View file

@ -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.

View file

@ -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}

View file

@ -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.

View file

@ -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}

View file

@ -0,0 +1,2 @@
#include "elf32.h"
#include "elfxx.c"

View file

@ -0,0 +1,7 @@
#ifndef elf32_h
#define elf32_h
#define ELF_CLASS ELFCLASS32
#include "elfxx.h"
#endif /* elf32_h */

View file

@ -0,0 +1,2 @@
#include "elf64.h"
#include "elfxx.c"

View file

@ -0,0 +1,7 @@
#ifndef elf64_h
#define elf64_h
#define ELF_CLASS ELFCLASS64
#include "elfxx.h"
#endif /* elf64_h */

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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 */

View file

@ -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 */

View file

@ -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;
}

View file

@ -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 ();
}

View file

@ -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;
}

View file

@ -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;
}