1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-05-11 17:05:18 +02:00

(Logical change 1.3)

This commit is contained in:
mostang.com!davidm 2002-02-15 23:22:05 +00:00
parent 63669f7ad4
commit 7fbfe0a255
36 changed files with 5984 additions and 0 deletions

View file

@ -0,0 +1 @@
davidm@panda.mostang.com

340
COPYING
View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View file

@ -0,0 +1,39 @@
2002-01-18 David Mosberger-Tang <David.Mosberger@acm.org>
* src/ia64/parser.c (__ia64_unw_create_state_record): Set
IA64_FLAG_HAS_HANDLER if the unwind info descriptors indicate that
there a handler.
* src/ia64/regs.c (__ia64_access_reg): Return zero for UNW_REG_HANDLER
in frames that don't have a personality routine.
* src/ia64/unwind_i.h (IA64_FLAG_HAS_HANDLER): New flag.
* src/ia64/regs.c (__ia64_access_reg): When reading UNW_REG_HANDLER,
account for the fact that the personality address is gp-relative.
* src/ia64/parser.c (__ia64_unw_create_state_record): Fix
initialization of segbase and len.
2002-01-17 David Mosberger-Tang <David.Mosberger@acm.org>
* include/unwind-ia64.h: Include via "unwind.h" to ensure
the file is picked up from same directory.
2002-01-16 David Mosberger-Tang <David.Mosberger@acm.org>
* include/unwind.h: Define UNW_ESTOPUNWIND. This error code may
be returned by acquire_unwind_info() to force termination of
unwinding. An application may want to do this when encountering a
call frame for dynamically generated code, for example.
* unwind.h: Pass opaque argument pointer to acquire_unwind_info()
and release_unwind_info() like we do for access_mem() etc.
2002-01-14 David Mosberger-Tang <David.Mosberger@acm.org>
* Version 0.0 released.
2002-01-11 David Mosberger-Tang <David.Mosberger@acm.org>
* ChangeLog created.

74
NOTES
View file

@ -0,0 +1,74 @@
The central data structure of the unwind API is the unwind cursor.
This structure tracks the frame registers and the preserved registers.
The distinction between frame registers and preserved registers is
important: the former represent the *current* value of a register (as
it existed at the current IP); the latter represent the *saved* value
of a register (i.e., the value that existed on entry to the current
procedure). The unwind API defines a handful of well-known frame
"registers":
- ip: the instruction pointer (pc)
- rp: the return pointer (rp, aka "return address" or "return link")
- sp: the stack pointer (memory stack pointer, in the case of ia64)
- fp: the frame pointer
- first_ip: the starting address of the current "procedure"
- handler: a pointer to an architecture & language-specific
"personality" routine
- lsda: a pointer to an architecture & language-specific
data-area
The API defines no well-known preserved registers. Each architecture
can define additional registers as needed. Of course, a portable
application may only rely on well-known registers. The names for
preserved registers are defined in the architecture-specific header
file <unwind-ARCH.h>. For example, to get the IA-64-specific register
names, an application would do:
#include <unwind-ia64.h>
The API is designed to handle two primary cases: unwinding within the
current (local) process and unwinding of another ("remote") process
(e.g., through ptrace()). In the local case, the initial machine
state is captured by an unwind context (currently the same as
ucontext_t). In the remote case, the initial machine state is
captured by an unwind accessor structure, which provides callback
routines for reading/writing memory and registers and for obtaining
unwind information.
Once a cursor has been initialized, you can step through the call
chain with the unw_step() routine. The frame registers and the
preserved state can then be accessed with unw_get_reg() or modified
with unw_set_reg(). For floating-point registers, there are separate
unw_get_fpreg() and unw_set_fpreg() routines (on some arches, e.g.,
Alpha, these could be just aliases for unw_{g,s}et_reg()). The
unw_resume() routine can be used to resume execution at an arbitrary
point in the call-chain (as identified by an unwind cursor). This is
intended for exception handling and, at least for now, the intention
is to support this routine only for the local case. Kevin, if you
feel gdb could benefit from such a routine, I'd be interested to hear
about it.
Note that it is perfectly legal to make copies of the unwind cursor.
This makes it possible, e.g., to obtain an unwind context, modify the
state in an earlier call frame, and then resume execution at the point
at which the unwind context was captured.
Here is a quick example of how to use the unwind API to do a simple
stack trace:
unw_cursor_t cursor;
unw_word_t ip, sp;
ucontext_t uc;
getcontext(&uc);
unw_init_local(&cursor, &uc);
do
{
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
printf ("ip=%016lx sp=%016lx\n", ip, sp);
}
while (unw_step (&cursor) > 0);
Note that this particular example should work on pretty much any
architecture, as it doesn't rely on any arch-specific registers.

46
README
View file

@ -0,0 +1,46 @@
This is version 0.0 of the unwind library. At the moment, only the
IA-64 Linux (IPF Linux) platform is supported and even that support
has received only light testing. Consequently, this release is
intended primarily to expose the unwind API to more developers and to
collect feedback on what does and does not work. Having said that,
backtracing through gcc-generated code might work reasonably well.
There is virtually no documentation at the moment. A brief outline of
the unwind API is in file NOTES. To get a feel for how things are
intended to work, you may also want to take a look at include/unwind.h
and include/unwind-ia64.h. Finally, the test program in
src/tests/bt.c shows two ways of how to do a simple backtrace: one
uses libunwind directly, the other uses a libunwind-based
implementation of the backtrace() function. The test program in
src/tests/exc.c shows the basics of how to do exception handling with
this library.
The following steps should be used to compile and install this library:
$ cd src
$ make dep
$ make
$ make install prefix=PREFIX
where PREFIX is the installation prefix. By default, a prefix of /usr
is used, such that libunwind.a is installed in /usr/lib and unwind.h
is installed in /usr/include. For testing, you may want to use a
prefix of /usr/local instead.
Please direct all questions regarding this library to:
libunwind@linux.hpl.hp.com
For spam protection, you'll have to subscribe to this list before
posting a question. You can do this by sending a mail to
libunwind-request@linux.hpl.hp.com with a body of:
subscribe libunwind
Note: the host that is running this list is behind a firewall, so
you'll not be able to use the Web interface to manage your
subscription. Send a mail containing "help" to
libunwind-request@linux.hpl.hp.com for information on how to manage
your subscription via email.
--david

View file

@ -0,0 +1 @@
#undef SIGCONTEXT_HAS_AR25_AND_AR26

View file

@ -0,0 +1,2 @@
#define UNW_TARGET_IA64
#undef UNW_LOCAL_ONLY

View file

@ -0,0 +1,99 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include <ucontext.h>
typedef enum
{
/* Note: general registers are excepted to start with index 0.
This convention facilitates architecture-independent
implementation of the C++ exception handling ABI. See
_Unwind_SetGR() and _Unwind_GetGR() for details. */
UNW_IA64_GR = 0, /* general registers (r0..r127) */
UNW_IA64_GP = UNW_IA64_GR + 1,
UNW_IA64_SP = UNW_IA64_GR + 12,
UNW_IA64_TP = UNW_IA64_GR + 13,
UNW_IA64_NAT = UNW_IA64_GR + 128, /* NaT registers (nat0..nat127) */
UNW_IA64_FR = UNW_IA64_NAT + 128, /* fp registers (f0..f127) */
UNW_IA64_AR = UNW_IA64_FR + 128, /* application registers (ar0..r127) */
UNW_IA64_AR_RSC = UNW_IA64_AR + 16,
UNW_IA64_AR_BSP = UNW_IA64_AR + 17,
UNW_IA64_AR_BSPSTORE = UNW_IA64_AR + 18,
UNW_IA64_AR_RNAT = UNW_IA64_AR + 19,
UNW_IA64_AR_25 = UNW_IA64_AR + 25, /* reserved (scratch) */
UNW_IA64_AR_26 = UNW_IA64_AR + 26, /* reserved (scratch) */
UNW_IA64_AR_CCV = UNW_IA64_AR + 32,
UNW_IA64_AR_UNAT = UNW_IA64_AR + 36,
UNW_IA64_AR_FPSR = UNW_IA64_AR + 40,
UNW_IA64_AR_PFS = UNW_IA64_AR + 64,
UNW_IA64_AR_LC = UNW_IA64_AR + 65,
UNW_IA64_AR_EC = UNW_IA64_AR + 66,
UNW_IA64_BR = UNW_IA64_AR + 128, /* branch registers (b0..p7) */
UNW_IA64_PR = UNW_IA64_BR + 8, /* predicate registers (p0..p63) */
UNW_IA64_CFM,
/* frame info (read-only): */
UNW_IA64_CURRENT_BSP, /* read-only */
UNW_TDEP_LAST_REG = UNW_IA64_CURRENT_BSP
}
ia64_regnum_t;
/* Info needed for a single IA-64 unwind. A pointer to this structure
is expected in the acquire/release callbacks of the unwind
accessors. */
typedef struct unw_ia64_table
{
const char *name; /* table name (or NULL if none) */
unw_word_t gp; /* global pointer for this load-module */
unw_word_t segbase; /* base for offsets in the unwind table */
unw_word_t length; /* number of entries in unwind table array */
/* Local copy of the unwind descriptor table: */
const struct ia64_unwind_table_entry *array;
/* Local copy of the unwind descriptor information. This is
initialized such that adding the unwind entry's info_offset
yields the address at which the corresponding descriptors can
be found. */
const unsigned char *unwind_info_base;
}
unw_ia64_table_t;
/* On IA-64, we can directly use ucontext_t as the unwind context. */
typedef ucontext_t unw_tdep_context_t;
/* XXX this is not ideal: an application should not be prevented from
using the "getcontext" name just because it's using libunwind. We
can't just use __getcontext() either, because that isn't exported
by glibc... */
#define unw_tdep_getcontext(uc) getcontext(uc)

View file

@ -0,0 +1,189 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#ifndef LIBUNWIND_H
#define LIBUNWIND_H
#include "libunwind-config.h"
#ifdef UNW_LOCAL_ONLY
# define UNW_PREFIX _Ul_
#else /* !UNW_LOCAL_ONLY */
# define UNW_PREFIX _U_
#endif /* !UNW_LOCAL_ONLY */
#define UNW_PASTE2(x,y) x##y
#define UNW_PASTE(x,y) UNW_PASTE2(x,y)
#define UNW_OBJ(fn) UNW_PASTE(UNW_PREFIX, fn)
typedef unsigned long unw_word_t;
#if defined(UNW_TARGET_IA64)
# include "libunwind-ia64.h"
#else
# error Sorry, target architecture is not yet supported.
#endif
/* This needs to be big enough to accommodate the unwind state of any
architecture, while leaving some slack for future expansion.
Changing this value will require recompiling all users of this
library. */
#define UNW_STATE_LEN 127
/* Error codes. The unwind routines return the *negated* values of
these error codes on error and a non-negative value on success. */
typedef enum
{
UNW_ESUCCESS = 0, /* no error */
UNW_EUNSPEC, /* unspecified (general) error */
UNW_ENOMEM, /* out of memory */
UNW_EBADREG, /* bad register number */
UNW_EREADONLYREG, /* attempt to write read-only register */
UNW_ESTOPUNWIND, /* stop unwinding */
UNW_EINVALIDIP, /* invalid IP */
UNW_EBADFRAME /* bad frame */
}
unw_error_t;
/* The following enum defines the indices for a couple of
(pseudo-)registers which have the same meaning across all
platforms. (RO) means read-only. (RW) means read-write. General
registers (aka "integer registers") are expected to start with
index 0. The number of such registers is architecture-dependent.
The remaining indices can be used as an architecture sees fit. The
last valid register index is given by UNW_REG_LAST. */
typedef enum
{
UNW_REG_IP = -1, /* (rw) instruction pointer (pc) */
UNW_REG_SP = -2, /* (ro) stack pointer */
UNW_REG_PROC_START = -3, /* (ro) starting addr. of procedure */
UNW_REG_HANDLER = -4, /* (ro) addr. of "personality routine" */
UNW_REG_LSDA = -5, /* (ro) addr. of language-specific data area */
UNW_REG_LAST = UNW_TDEP_LAST_REG
}
unw_frame_regnum_t;
typedef int unw_regnum_t;
/* The unwind cursor starts at the youngest (most deeply nested) frame
and is used to track the frame state as the unwinder steps from
frame to frame. It is safe to make (shallow) copies of variables
of this type. */
typedef struct unw_cursor
{
unw_word_t opaque[UNW_STATE_LEN];
}
unw_cursor_t;
/* This type encapsulates the entire (preserved) machine-state. */
typedef unw_tdep_context_t unw_context_t;
/* unw_getcontext() fills the unw_context_t pointed to by UC with the
machine state as it exists at the call-site. For implementation
reasons, this needs to be a target-dependent macro. It's easiest
to think of unw_getcontext() as being identical to getcontext(). */
#define unw_getcontext(uc) unw_tdep_getcontext(uc)
/* We will assume that "long double" is sufficiently large and aligned
to hold the contents of a floating-point register. Note that the
fp register format is not usually the same format as a "long
double". Instead, the content of unw_fpreg_t should be manipulated
only through the "raw.bits" member. */
typedef union
{
struct { unsigned long bits[1]; } raw;
long double dummy; /* dummy to force 16-byte alignment */
}
unw_fpreg_t;
/* These are backend callback routines that provide access to the
state of a "remote" process. This can be used, for example, to
unwind another process through the ptrace() interface. */
typedef struct unw_accessors
{
/* Lock for unwind info for address IP. The architecture specific
UNWIND_INFO is updated as necessary. */
int (*acquire_unwind_info) (unw_word_t ip, void *unwind_info, void *arg);
int (*release_unwind_info) (void *unwind_info, void *arg);
/* Access aligned word at address ADDR. */
int (*access_mem) (unw_word_t addr, unw_word_t *val, int write, void *arg);
/* Access register number REG at address ADDR. */
int (*access_reg) (unw_regnum_t reg, unw_word_t *val, int write,
void *arg);
/* Access register number REG at address ADDR. */
int (*access_fpreg) (unw_regnum_t reg, unw_fpreg_t *val, int write,
void *arg);
int (*resume) (unw_cursor_t *c, void *arg);
void *arg; /* application-specific data */
}
unw_accessors_t;
/* These routines work both for local and remote unwinding. */
extern int UNW_OBJ(init_local) (unw_cursor_t *c, ucontext_t *u);
extern int UNW_OBJ(init_remote) (unw_cursor_t *c, unw_accessors_t *a);
extern int UNW_OBJ(step) (unw_cursor_t *c);
extern int UNW_OBJ(resume) (unw_cursor_t *c);
extern int UNW_OBJ(get_reg) (unw_cursor_t *c, int regnum, unw_word_t *valp);
extern int UNW_OBJ(set_reg) (unw_cursor_t *c, int regnum, unw_word_t val);
extern int UNW_OBJ(get_fpreg) (unw_cursor_t *c, int regnum, unw_fpreg_t *val);
extern int UNW_OBJ(set_fpreg) (unw_cursor_t *c, int regnum, unw_fpreg_t val);
extern int UNW_OBJ(is_signal_frame) (unw_cursor_t *c);
/* Initialize cursor C such that unwinding starts at the point
represented by the context U. Returns zero on success, negative
value on failure. */
#define unw_init_local(c,u) UNW_OBJ(init_local)(c, u)
/* Initialize cursor C such that it accesses the unwind target through
accessors A. */
#define unw_init_remote(c,a) UNW_OBJ(init_remote)(c, a)
/* Move cursor up by one step (up meaning toward earlier, less deeply
nested frames). Returns positive number if there are more frames
to unwind, 0 if last frame has been reached, negative number in
case of an error. */
#define unw_step(c) UNW_OBJ(step)(c)
/* Resume execution at the point identified by the cursor. */
#define unw_resume(c) UNW_OBJ(resume)(c)
/* Register accessor routines. Return zero on success, negative value
on failure. */
#define unw_get_reg(c,r,v) UNW_OBJ(get_reg)(c,r,v)
#define unw_set_reg(c,r,v) UNW_OBJ(set_reg)(c,r,v)
/* Floating-point accessor routines. Return zero on success, negative
value on failure. */
#define unw_get_fpreg(c,r,v) UNW_OBJ(get_fpreg)(c,r,v)
#define unw_set_fpreg(c,r,v) UNW_OBJ(set_fpreg)(c,r,v)
/* Returns non-zero value if the cursor points to a signal frame. */
#define unw_is_signal_frame(c) UNW_OBJ(is_signal_frame)(c)
#endif /* LIBUNWIND_H */

View file

@ -0,0 +1,342 @@
prefix = /usr
libdir = $(prefix)/lib
includedir = $(prefix)/include
# XXX fix for cross-compilation:
ARCH = $(shell uname -m)
CPPFLAGS = -I$(ARCH) -I../include -D_GNU_SOURCE -DIA64_UNW_ACCESSORS
CFLAGS = -Wall -g -O
SUBDIRS = tests
ia64_OBJS = \
__ia64_install_context.o \
init.o parser.o regs.o script.o tables-glibc.o \
unw_get_reg.o unw_resume.o unw_set_reg.o \
unw_init_local.o unw_init_remote.o unw_step.o
OBJS = backtrace.o $(patsubst %,$(ARCH)/%,$($(ARCH)_OBJS))
LIBUNWIND = libunwind.a
all: $(LIBUNWIND) all-recursive
clean: clean-recursive
rm -f $(LIBUNWIND) *.o $(ARCH)/*.o
distclean: clean distclean-recursive
rm -f *.bak *~ $(ARCH)/*~ ../include/*~
install:
install -m 644 libunwind.a $(libdir)
install -m 644 ../include/libunwind-config.h $(includedir)
install -m 644 ../include/libunwind.h $(includedir)
install -m 644 ../include/libunwind-$(ARCH).h $(includedir)
%-recursive:
@for subdir in $(SUBDIRS); do \
make -C $$subdir $*; \
done
libunwind.a: libunwind.a($(OBJS))
$(ARCH)/%.o: $(ARCH)/%.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(ARCH)/%.o: $(ARCH)/%.S
$(COMPILE.S) $(OUTPUT_OPTION) $<
dep:
makedepend $(CPPFLAGS) *.c $(ARCH)/*.c
.PHONY: clean distclean SUBDIRS
# DO NOT DELETE
backtrace.o: ../include/libunwind.h ../include/libunwind-config.h
backtrace.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
backtrace.o: /usr/include/features.h /usr/include/sys/cdefs.h
backtrace.o: /usr/include/gnu/stubs.h /usr/include/sys/ucontext.h
backtrace.o: /usr/include/signal.h /usr/include/bits/sigset.h
backtrace.o: /usr/include/bits/types.h
backtrace.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
backtrace.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
backtrace.o: /usr/include/bits/signum.h /usr/include/time.h
backtrace.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
backtrace.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
backtrace.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
backtrace.o: /usr/include/bits/sigthread.h
ia64/init.o: ia64/unwind_i.h /usr/include/memory.h /usr/include/features.h
ia64/init.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
ia64/init.o: /usr/include/string.h
ia64/init.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/init.o: /usr/include/xlocale.h /usr/include/stdint.h
ia64/init.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
ia64/init.o: ../include/libunwind.h ../include/libunwind-config.h
ia64/init.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
ia64/init.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/init.o: /usr/include/bits/sigset.h /usr/include/bits/types.h
ia64/init.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
ia64/init.o: /usr/include/bits/signum.h /usr/include/time.h
ia64/init.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
ia64/init.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/init.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/init.o: /usr/include/bits/sigthread.h /usr/include/stdio.h
ia64/init.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/init.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/init.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/init.o: /usr/include/bits/stdio_lim.h ia64/script.h
ia64/parser.o: /usr/include/assert.h /usr/include/features.h
ia64/parser.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
ia64/parser.o: /usr/include/stdio.h
ia64/parser.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/parser.o: /usr/include/bits/types.h /usr/include/bits/pthreadtypes.h
ia64/parser.o: /usr/include/bits/sched.h /usr/include/libio.h
ia64/parser.o: /usr/include/_G_config.h /usr/include/wchar.h
ia64/parser.o: /usr/include/bits/wchar.h /usr/include/gconv.h
ia64/parser.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/parser.o: /usr/include/bits/stdio_lim.h /usr/include/stdlib.h
ia64/parser.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
ia64/parser.o: /usr/include/endian.h /usr/include/bits/endian.h
ia64/parser.o: /usr/include/xlocale.h /usr/include/sys/types.h
ia64/parser.o: /usr/include/time.h /usr/include/sys/select.h
ia64/parser.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
ia64/parser.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
ia64/parser.o: /usr/include/alloca.h /usr/include/string.h ia64/unwind_i.h
ia64/parser.o: /usr/include/memory.h /usr/include/stdint.h
ia64/parser.o: /usr/include/bits/wordsize.h ../include/libunwind.h
ia64/parser.o: ../include/libunwind-config.h ../include/libunwind-ia64.h
ia64/parser.o: /usr/include/ucontext.h /usr/include/sys/ucontext.h
ia64/parser.o: /usr/include/signal.h /usr/include/bits/signum.h
ia64/parser.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
ia64/parser.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/parser.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/parser.o: /usr/include/bits/sigthread.h ia64/script.h
ia64/parser.o: ia64/unwind_decoder.c
ia64/regs.o: ../include/config.h /usr/include/assert.h
ia64/regs.o: /usr/include/features.h /usr/include/sys/cdefs.h
ia64/regs.o: /usr/include/gnu/stubs.h ia64/unwind_i.h /usr/include/memory.h
ia64/regs.o: /usr/include/string.h
ia64/regs.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/regs.o: /usr/include/xlocale.h /usr/include/stdint.h
ia64/regs.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
ia64/regs.o: ../include/libunwind.h ../include/libunwind-config.h
ia64/regs.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
ia64/regs.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/regs.o: /usr/include/bits/sigset.h /usr/include/bits/types.h
ia64/regs.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
ia64/regs.o: /usr/include/bits/signum.h /usr/include/time.h
ia64/regs.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
ia64/regs.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/regs.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/regs.o: /usr/include/bits/sigthread.h /usr/include/stdio.h
ia64/regs.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/regs.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/regs.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/regs.o: /usr/include/bits/stdio_lim.h ia64/script.h ia64/rse.h
ia64/script.o: ia64/rse.h ia64/unwind_i.h /usr/include/memory.h
ia64/script.o: /usr/include/features.h /usr/include/sys/cdefs.h
ia64/script.o: /usr/include/gnu/stubs.h /usr/include/string.h
ia64/script.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/script.o: /usr/include/xlocale.h /usr/include/stdint.h
ia64/script.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
ia64/script.o: ../include/libunwind.h ../include/libunwind-config.h
ia64/script.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
ia64/script.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/script.o: /usr/include/bits/sigset.h /usr/include/bits/types.h
ia64/script.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
ia64/script.o: /usr/include/bits/signum.h /usr/include/time.h
ia64/script.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
ia64/script.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/script.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/script.o: /usr/include/bits/sigthread.h /usr/include/stdio.h
ia64/script.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/script.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/script.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/script.o: /usr/include/bits/stdio_lim.h ia64/script.h
ia64/tables-glibc.o: /usr/include/link.h /usr/include/features.h
ia64/tables-glibc.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
ia64/tables-glibc.o: /usr/include/elf.h /usr/include/stdint.h
ia64/tables-glibc.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/tables-glibc.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
ia64/tables-glibc.o: /usr/include/dlfcn.h /usr/include/bits/dlfcn.h
ia64/tables-glibc.o: /usr/include/sys/types.h /usr/include/bits/types.h
ia64/tables-glibc.o: /usr/include/bits/pthreadtypes.h
ia64/tables-glibc.o: /usr/include/bits/sched.h /usr/include/time.h
ia64/tables-glibc.o: /usr/include/endian.h /usr/include/bits/endian.h
ia64/tables-glibc.o: /usr/include/sys/select.h /usr/include/bits/select.h
ia64/tables-glibc.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
ia64/tables-glibc.o: /usr/include/sys/sysmacros.h
ia64/tables-glibc.o: /usr/include/bits/elfclass.h /usr/include/stdlib.h
ia64/tables-glibc.o: /usr/include/bits/waitflags.h
ia64/tables-glibc.o: /usr/include/bits/waitstatus.h /usr/include/xlocale.h
ia64/tables-glibc.o: /usr/include/alloca.h ia64/unwind_i.h
ia64/tables-glibc.o: /usr/include/memory.h /usr/include/string.h
ia64/tables-glibc.o: ../include/libunwind.h ../include/libunwind-config.h
ia64/tables-glibc.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
ia64/tables-glibc.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/tables-glibc.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
ia64/tables-glibc.o: /usr/include/bits/sigaction.h
ia64/tables-glibc.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/tables-glibc.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/tables-glibc.o: /usr/include/bits/sigthread.h /usr/include/stdio.h
ia64/tables-glibc.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/tables-glibc.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/tables-glibc.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/tables-glibc.o: /usr/include/bits/stdio_lim.h ia64/script.h
ia64/tables-glibc.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
ia64/tables-glibc.o: /usr/include/bits/environments.h
ia64/tables-glibc.o: /usr/include/bits/confname.h /usr/include/getopt.h
ia64/tables-glibc.o: /usr/include/sys/syscall.h /usr/include/asm/unistd.h
ia64/tables-glibc.o: /usr/include/asm/break.h /usr/include/bits/syscall.h
ia64/unw_get_reg.o: ia64/unwind_i.h /usr/include/memory.h
ia64/unw_get_reg.o: /usr/include/features.h /usr/include/sys/cdefs.h
ia64/unw_get_reg.o: /usr/include/gnu/stubs.h /usr/include/string.h
ia64/unw_get_reg.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/unw_get_reg.o: /usr/include/xlocale.h /usr/include/stdint.h
ia64/unw_get_reg.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
ia64/unw_get_reg.o: ../include/libunwind.h ../include/libunwind-config.h
ia64/unw_get_reg.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
ia64/unw_get_reg.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/unw_get_reg.o: /usr/include/bits/sigset.h /usr/include/bits/types.h
ia64/unw_get_reg.o: /usr/include/bits/pthreadtypes.h
ia64/unw_get_reg.o: /usr/include/bits/sched.h /usr/include/bits/signum.h
ia64/unw_get_reg.o: /usr/include/time.h /usr/include/bits/siginfo.h
ia64/unw_get_reg.o: /usr/include/bits/sigaction.h
ia64/unw_get_reg.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/unw_get_reg.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/unw_get_reg.o: /usr/include/bits/sigthread.h /usr/include/stdio.h
ia64/unw_get_reg.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/unw_get_reg.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/unw_get_reg.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/unw_get_reg.o: /usr/include/bits/stdio_lim.h ia64/script.h
ia64/unw_init_local.o: /usr/include/string.h /usr/include/features.h
ia64/unw_init_local.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
ia64/unw_init_local.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/unw_init_local.o: /usr/include/xlocale.h ia64/rse.h ia64/unwind_i.h
ia64/unw_init_local.o: /usr/include/memory.h /usr/include/stdint.h
ia64/unw_init_local.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
ia64/unw_init_local.o: ../include/libunwind.h ../include/libunwind-config.h
ia64/unw_init_local.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
ia64/unw_init_local.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/unw_init_local.o: /usr/include/bits/sigset.h /usr/include/bits/types.h
ia64/unw_init_local.o: /usr/include/bits/pthreadtypes.h
ia64/unw_init_local.o: /usr/include/bits/sched.h /usr/include/bits/signum.h
ia64/unw_init_local.o: /usr/include/time.h /usr/include/bits/siginfo.h
ia64/unw_init_local.o: /usr/include/bits/sigaction.h
ia64/unw_init_local.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/unw_init_local.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/unw_init_local.o: /usr/include/bits/sigthread.h /usr/include/stdio.h
ia64/unw_init_local.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/unw_init_local.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/unw_init_local.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/unw_init_local.o: /usr/include/bits/stdio_lim.h ia64/script.h
ia64/unw_init_remote.o: ia64/rse.h ia64/unwind_i.h /usr/include/memory.h
ia64/unw_init_remote.o: /usr/include/features.h /usr/include/sys/cdefs.h
ia64/unw_init_remote.o: /usr/include/gnu/stubs.h /usr/include/string.h
ia64/unw_init_remote.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/unw_init_remote.o: /usr/include/xlocale.h /usr/include/stdint.h
ia64/unw_init_remote.o: /usr/include/bits/wchar.h
ia64/unw_init_remote.o: /usr/include/bits/wordsize.h ../include/libunwind.h
ia64/unw_init_remote.o: ../include/libunwind-config.h
ia64/unw_init_remote.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
ia64/unw_init_remote.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/unw_init_remote.o: /usr/include/bits/sigset.h /usr/include/bits/types.h
ia64/unw_init_remote.o: /usr/include/bits/pthreadtypes.h
ia64/unw_init_remote.o: /usr/include/bits/sched.h /usr/include/bits/signum.h
ia64/unw_init_remote.o: /usr/include/time.h /usr/include/bits/siginfo.h
ia64/unw_init_remote.o: /usr/include/bits/sigaction.h
ia64/unw_init_remote.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/unw_init_remote.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/unw_init_remote.o: /usr/include/bits/sigthread.h /usr/include/stdio.h
ia64/unw_init_remote.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/unw_init_remote.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/unw_init_remote.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/unw_init_remote.o: /usr/include/bits/stdio_lim.h ia64/script.h
ia64/unw_is_signal_frame.o: ia64/unwind_i.h /usr/include/memory.h
ia64/unw_is_signal_frame.o: /usr/include/features.h /usr/include/sys/cdefs.h
ia64/unw_is_signal_frame.o: /usr/include/gnu/stubs.h /usr/include/string.h
ia64/unw_is_signal_frame.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/unw_is_signal_frame.o: /usr/include/xlocale.h /usr/include/stdint.h
ia64/unw_is_signal_frame.o: /usr/include/bits/wchar.h
ia64/unw_is_signal_frame.o: /usr/include/bits/wordsize.h
ia64/unw_is_signal_frame.o: ../include/libunwind.h
ia64/unw_is_signal_frame.o: ../include/libunwind-config.h
ia64/unw_is_signal_frame.o: ../include/libunwind-ia64.h
ia64/unw_is_signal_frame.o: /usr/include/ucontext.h
ia64/unw_is_signal_frame.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/unw_is_signal_frame.o: /usr/include/bits/sigset.h
ia64/unw_is_signal_frame.o: /usr/include/bits/types.h
ia64/unw_is_signal_frame.o: /usr/include/bits/pthreadtypes.h
ia64/unw_is_signal_frame.o: /usr/include/bits/sched.h
ia64/unw_is_signal_frame.o: /usr/include/bits/signum.h /usr/include/time.h
ia64/unw_is_signal_frame.o: /usr/include/bits/siginfo.h
ia64/unw_is_signal_frame.o: /usr/include/bits/sigaction.h
ia64/unw_is_signal_frame.o: /usr/include/bits/sigcontext.h
ia64/unw_is_signal_frame.o: /usr/include/asm/fpu.h /usr/include/asm/types.h
ia64/unw_is_signal_frame.o: /usr/include/bits/sigstack.h
ia64/unw_is_signal_frame.o: /usr/include/bits/sigthread.h
ia64/unw_is_signal_frame.o: /usr/include/stdio.h /usr/include/libio.h
ia64/unw_is_signal_frame.o: /usr/include/_G_config.h /usr/include/wchar.h
ia64/unw_is_signal_frame.o: /usr/include/gconv.h
ia64/unw_is_signal_frame.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/unw_is_signal_frame.o: /usr/include/bits/stdio_lim.h ia64/script.h
ia64/unw_resume.o: ia64/unwind_i.h /usr/include/memory.h
ia64/unw_resume.o: /usr/include/features.h /usr/include/sys/cdefs.h
ia64/unw_resume.o: /usr/include/gnu/stubs.h /usr/include/string.h
ia64/unw_resume.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/unw_resume.o: /usr/include/xlocale.h /usr/include/stdint.h
ia64/unw_resume.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
ia64/unw_resume.o: ../include/libunwind.h ../include/libunwind-config.h
ia64/unw_resume.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
ia64/unw_resume.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/unw_resume.o: /usr/include/bits/sigset.h /usr/include/bits/types.h
ia64/unw_resume.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
ia64/unw_resume.o: /usr/include/bits/signum.h /usr/include/time.h
ia64/unw_resume.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
ia64/unw_resume.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/unw_resume.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/unw_resume.o: /usr/include/bits/sigthread.h /usr/include/stdio.h
ia64/unw_resume.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/unw_resume.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/unw_resume.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/unw_resume.o: /usr/include/bits/stdio_lim.h ia64/script.h
ia64/unw_set_reg.o: ia64/unwind_i.h /usr/include/memory.h
ia64/unw_set_reg.o: /usr/include/features.h /usr/include/sys/cdefs.h
ia64/unw_set_reg.o: /usr/include/gnu/stubs.h /usr/include/string.h
ia64/unw_set_reg.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/unw_set_reg.o: /usr/include/xlocale.h /usr/include/stdint.h
ia64/unw_set_reg.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
ia64/unw_set_reg.o: ../include/libunwind.h ../include/libunwind-config.h
ia64/unw_set_reg.o: ../include/libunwind-ia64.h /usr/include/ucontext.h
ia64/unw_set_reg.o: /usr/include/sys/ucontext.h /usr/include/signal.h
ia64/unw_set_reg.o: /usr/include/bits/sigset.h /usr/include/bits/types.h
ia64/unw_set_reg.o: /usr/include/bits/pthreadtypes.h
ia64/unw_set_reg.o: /usr/include/bits/sched.h /usr/include/bits/signum.h
ia64/unw_set_reg.o: /usr/include/time.h /usr/include/bits/siginfo.h
ia64/unw_set_reg.o: /usr/include/bits/sigaction.h
ia64/unw_set_reg.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/unw_set_reg.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/unw_set_reg.o: /usr/include/bits/sigthread.h /usr/include/stdio.h
ia64/unw_set_reg.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/unw_set_reg.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/unw_set_reg.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/unw_set_reg.o: /usr/include/bits/stdio_lim.h ia64/script.h
ia64/unw_step.o: /usr/include/signal.h /usr/include/features.h
ia64/unw_step.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
ia64/unw_step.o: /usr/include/bits/sigset.h /usr/include/bits/types.h
ia64/unw_step.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stddef.h
ia64/unw_step.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
ia64/unw_step.o: /usr/include/bits/signum.h /usr/include/time.h
ia64/unw_step.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
ia64/unw_step.o: /usr/include/bits/sigcontext.h /usr/include/asm/fpu.h
ia64/unw_step.o: /usr/include/asm/types.h /usr/include/bits/sigstack.h
ia64/unw_step.o: /usr/include/ucontext.h /usr/include/sys/ucontext.h
ia64/unw_step.o: /usr/include/bits/sigthread.h ia64/rse.h ia64/unwind_i.h
ia64/unw_step.o: /usr/include/memory.h /usr/include/string.h
ia64/unw_step.o: /usr/include/xlocale.h /usr/include/stdint.h
ia64/unw_step.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
ia64/unw_step.o: ../include/libunwind.h ../include/libunwind-config.h
ia64/unw_step.o: ../include/libunwind-ia64.h /usr/include/stdio.h
ia64/unw_step.o: /usr/include/libio.h /usr/include/_G_config.h
ia64/unw_step.o: /usr/include/wchar.h /usr/include/gconv.h
ia64/unw_step.o: /usr/lib/gcc-lib/ia64-redhat-linux/2.96/include/stdarg.h
ia64/unw_step.o: /usr/include/bits/stdio_lim.h ia64/script.h

View file

@ -0,0 +1,50 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include <libunwind.h>
/* See glibc manual for a description of this function. */
int
backtrace (void **buffer, int size)
{
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip;
int n = 0;
unw_getcontext (&uc);
if (unw_init_local (&cursor, &uc) < 0)
return 0;
while (unw_step (&cursor) > 0)
{
if (n >= size)
return n;
if (unw_get_reg (&cursor, UNW_REG_IP, &ip) < 0)
return n;
buffer[n++] = (void *) ip;
}
return n;
}

View file

@ -0,0 +1,62 @@
- the frame state consists of the following:
- ip current instruction pointer
- sp current stack pointer value
- bsp current backing store pointer
- cfm current frame mask
these are derived from the next younger (more deeply nested) frame
as follows:
- ip == saved return-link (may be b0 or an alternate branch-reg)
- sp == if younger frame has a fixed-sized frame, sp + size-of-frame,
else saved sp
- cfm == saved ar.pfs
- bsp == if ar.bsp has been saved, saved ar.bsp, otherwise,
ar.bsp \ominus saved ar.pfs.pfm.sol
The unwind cursor should represent the machine state as it existed at
the address contained in register ip. This state consists of the
*current* frame state and the save locations in the next younger
frame.
An unwind script current takes the old save locations and updates them
for the next older frame. With the new setup, we need to update the
frame state first, without updating the other save locations. For this
to work, we need the following info:
- save location of return-link
- save location of ar.pfs
- save location of bsp (if it has been saved)
- size of stack frame (fixed case) or save location of sp
setup:
func: ...
...
...
br.call foo <-- call site
... <-- ip
...
initial state:
The unwind cursor represents the (preserved) machine state
as it existed at "ip".
Evaluating the unwind descriptors for "ip" yields the following
info:
- frame size at call site (or previous sp)
- what registers where saved where by func before
the call site was reached
Problem: there is some procedure info that needs to be obtained
for the new "ip" which is contained in the unwind
descriptors. Specifically, the following is needed:
- procedure's start address
- personality address
- pointer to language-specific data area

View file

@ -0,0 +1,3 @@
- c->prev_script is redundant now that we have c->script
- finish & test unwinding across signal frame (pay attention that signal
frame gets updated)

View file

@ -0,0 +1,146 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include "ucontext_i.h"
/* __ia64_install_context (const ucontext_t *ucp,
long r15, long r16, long r17, long r18)
Restores the machine context in UCP and thereby resumes execution
in that context.
This implementation in intended to be used for *synchronous* context
switches only. Therefore, it does not have to restore anything
other than the PRESERVED state. */
.global __ia64_install_context
.proc __ia64_install_context
__ia64_install_context:
alloc r16 = ar.pfs, 5, 0, 0, 0
invala
add r2 = SC_NAT, r32
;;
ld8 rNAT = [r2], (SC_BSP-SC_NAT)
add r3 = SC_RNAT, r32 // r3 <- &sc_ar_rnat
add rPOS = SC_GR, r32 // rPOS <- &sc_gr[0]
;;
ld8 rBSP = [r2], (SC_UNAT-SC_BSP)
ld8 rRNAT = [r3], (SC_FPSR-SC_RNAT)
extr.u rPOS = rPOS, 3, 6 // get NaT bit number for r0
;;
ld8 rUNAT = [r2], (SC_PFS-SC_UNAT)
ld8 rFPSR = [r3], (SC_LC-SC_FPSR)
/*
* Rotate NaT bits by rPOS positions to the left:
*/
sub rCPOS = 64, rPOS
;;
ld8 rPFS = [r2], (SC_PR-SC_PFS)
ld8 rLC = [r3], (SC_BR+0*8-SC_LC)
shl rTMP = rNAT, rPOS
;;
ld8 rPR = [r2], (SC_BR+1*8-SC_PR)
ld8 rB0 = [r3], 16
shr.u rNAT = rNAT, rCPOS
;;
ld8 rB1 = [r2], 16
ld8 rB2 = [r3], 16
or rNAT = rNAT, rTMP
;;
mov.m ar.unat = rNAT
mov.m rRSC = ar.rsc
;;
ld8 rB3 = [r2], 16
ld8 rB4 = [r3], (SC_GR+1*8-(SC_BR+4*8))
mov r15 = in1
;;
ld8 rB5 = [r2], (SC_GR+4*8-(SC_BR+5*8))
ld8.fill r1 = [r3], (5*8 - 1*8)
mov r16 = in2
;;
ld8.fill r4 = [r2], 16
ld8.fill r5 = [r3], 16
mov b0 = rB0
;;
ld8.fill r6 = [r2], 48
ld8.fill r7 = [r3], (SC_FR+2*16-(SC_GR+7*8))
mov r17 = in3
;;
ld8.fill sp = [r2], (SC_FR+3*16-(SC_GR+12*8))
mov.m ar.fpsr = rFPSR
mov.i ar.pfs = rPFS
;;
ldf.fill f3 = [r2], 16
ldf.fill f2 = [r3], 48
mov b1 = rB1
;;
ldf.fill f4 = [r2], (16*16-4*16)
ldf.fill f5 = [r3], (17*16-5*16)
mov b2 = rB2
;;
ldf.fill f16 = [r2], 32
ldf.fill f17 = [r3], 32
mov b3 = rB3
;;
ldf.fill f18 = [r2], 32
ldf.fill f19 = [r3], 32
mov b4 = rB4
;;
ldf.fill f20 = [r2], 32
ldf.fill f21 = [r3], 32
mov b5 = rB5
;;
ldf.fill f22 = [r2], 32
ldf.fill f23 = [r3], 32
mov r8 = 0
;;
ldf.fill f24 = [r2], 32
ldf.fill f25 = [r3], 32
mov r9 = 0
;;
ldf.fill f26 = [r2], 32
ldf.fill f27 = [r3], 32
dep rTMP = 0, rRSC, 16, 14 // clear ar.rsc.loadrs
;;
ldf.fill f28 = [r2], 32
ldf.fill f29 = [r3], 32
and rTMP = ~0x3, rTMP // clear ar.rsc.mode
;;
ldf.fill f30 = [r2], 32
ldf.fill f31 = [r3], 32
mov pr = rPR, -1
;;
mov.m ar.rsc = rTMP // put RSE into enforced lazy mode
;;
loadrs // drop dirty partition
mov r18 = in4
;;
mov.m ar.bspstore = rBSP
mov.m ar.unat = rUNAT
mov.i ar.lc = rLC
;;
mov.m ar.rnat = rRNAT
mov.m ar.rsc = rRSC
br.ret.sptk rp
.endp __ia64_install_context

View file

@ -0,0 +1,250 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include "unwind_i.h"
struct ia64_global_unwind_state unw =
{
first_time: 1,
// tables: &unw.kernel_table,
// lock: SPIN_LOCK_UNLOCKED,
save_order: {
IA64_REG_RP, IA64_REG_PFS, IA64_REG_PSP, IA64_REG_PR,
IA64_REG_UNAT, IA64_REG_LC, IA64_REG_FPSR, IA64_REG_PRI_UNAT_GR
},
preg_index: {
struct_offset(struct ia64_cursor, pri_unat_loc)/8, /* PRI_UNAT_GR */
struct_offset(struct ia64_cursor, pri_unat_loc)/8, /* PRI_UNAT_MEM */
struct_offset(struct ia64_cursor, bsp_loc)/8,
struct_offset(struct ia64_cursor, bspstore_loc)/8,
struct_offset(struct ia64_cursor, pfs_loc)/8,
struct_offset(struct ia64_cursor, rnat_loc)/8,
struct_offset(struct ia64_cursor, psp)/8,
struct_offset(struct ia64_cursor, rp_loc)/8,
struct_offset(struct ia64_cursor, r4_loc)/8,
struct_offset(struct ia64_cursor, r5_loc)/8,
struct_offset(struct ia64_cursor, r6_loc)/8,
struct_offset(struct ia64_cursor, r7_loc)/8,
struct_offset(struct ia64_cursor, nat4_loc)/8,
struct_offset(struct ia64_cursor, nat5_loc)/8,
struct_offset(struct ia64_cursor, nat6_loc)/8,
struct_offset(struct ia64_cursor, nat7_loc)/8,
struct_offset(struct ia64_cursor, unat_loc)/8,
struct_offset(struct ia64_cursor, pr_loc)/8,
struct_offset(struct ia64_cursor, lc_loc)/8,
struct_offset(struct ia64_cursor, fpsr_loc)/8,
struct_offset(struct ia64_cursor, b1_loc)/8,
struct_offset(struct ia64_cursor, b2_loc)/8,
struct_offset(struct ia64_cursor, b3_loc)/8,
struct_offset(struct ia64_cursor, b4_loc)/8,
struct_offset(struct ia64_cursor, b5_loc)/8,
struct_offset(struct ia64_cursor, f2_loc)/8,
struct_offset(struct ia64_cursor, f3_loc)/8,
struct_offset(struct ia64_cursor, f4_loc)/8,
struct_offset(struct ia64_cursor, f5_loc)/8,
struct_offset(struct ia64_cursor, fr_loc[16 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[17 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[18 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[19 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[20 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[21 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[22 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[23 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[24 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[25 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[26 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[27 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[28 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[29 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[30 - 16])/8,
struct_offset(struct ia64_cursor, fr_loc[31 - 16])/8,
},
hash : { [0 ... IA64_UNW_HASH_SIZE - 1] = -1 },
#if IA64_UNW_DEBUG
debug_level: 0,
preg_name: {
"pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat",
"psp", "rp",
"r4", "r5", "r6", "r7",
"ar.unat", "pr", "ar.lc", "ar.fpsr",
"b1", "b2", "b3", "b4", "b5",
"f2", "f3", "f4", "f5",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
}
#endif
};
#ifdef IA64_UNW_DEBUG
static const char *regname[] = {
"<lsda>",
"<handler>",
"<first-ip>",
"<fp>",
"<sp>",
"<rp>",
"<ip>",
"r0", "gp", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "sp", "tp", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
"r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
"r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
"r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
"r56", "r57", "r58", "r59", "r60", "r61", "r62", "r63",
"r64", "r65", "r66", "r67", "r68", "r69", "r70", "r71",
"r72", "r73", "r74", "r75", "r76", "r77", "r78", "r79",
"r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87",
"r88", "r89", "r90", "r91", "r92", "r93", "r94", "r95",
"r96", "r97", "r98", "r99", "r100", "r101", "r102", "r103",
"r104", "r105", "r106", "r107", "r108", "r109", "r110", "r111",
"r112", "r113", "r114", "r115", "r116", "r117", "r118", "r119",
"r120", "r121", "r122", "r123", "r124", "r125", "r126", "r127",
"nat0", "nat1", "nat2", "nat3", "nat4", "nat5", "nat6", "nat7",
"nat8", "nat9", "nat10", "nat11", "nat12", "nat13", "nat14", "nat15",
"nat16", "nat17", "nat18", "nat19", "nat20", "nat21", "nat22", "nat23",
"nat24", "nat25", "nat26", "nat27", "nat28", "nat29", "nat30", "nat31",
"nat32", "nat33", "nat34", "nat35", "nat36", "nat37", "nat38", "nat39",
"nat40", "nat41", "nat42", "nat43", "nat44", "nat45", "nat46", "nat47",
"nat48", "nat49", "nat50", "nat51", "nat52", "nat53", "nat54", "nat55",
"nat56", "nat57", "nat58", "nat59", "nat60", "nat61", "nat62", "nat63",
"nat64", "nat65", "nat66", "nat67", "nat68", "nat69", "nat70", "nat71",
"nat72", "nat73", "nat74", "nat75", "nat76", "nat77", "nat78", "nat79",
"nat80", "nat81", "nat82", "nat83", "nat84", "nat85", "nat86", "nat87",
"nat88", "nat89", "nat90", "nat91", "nat92", "nat93", "nat94", "nat95",
"nat96", "nat97", "nat98", "nat99", "nat100", "nat101", "nat102", "nat103",
"nat104","nat105","nat106", "nat107", "nat108", "nat109", "nat110", "nat111",
"nat112","nat113","nat114", "nat115", "nat116", "nat117", "nat118", "nat119",
"nat120","nat121","nat122", "nat123", "nat124", "nat125", "nat126", "nat127",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
"f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
"f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
"f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
"f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
"f64", "f65", "f66", "f67", "f68", "f69", "f70", "f71",
"f72", "f73", "f74", "f75", "f76", "f77", "f78", "f79",
"f80", "f81", "f82", "f83", "f84", "f85", "f86", "f87",
"f88", "f89", "f90", "f91", "f92", "f93", "f94", "f95",
"f96", "f97", "f98", "f99", "f100", "f101", "f102", "f103",
"f104", "f105", "f106", "f107", "f108", "f109", "f110", "f111",
"f112", "f113", "f114", "f115", "f116", "f117", "f118", "f119",
"f120", "f121", "f122", "f123", "f124", "f125", "f126", "f127",
"ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7",
"ar8", "ar9", "ar10", "ar11", "ar12", "ar13", "ar14", "ar15",
"rsc", "bsp", "bspstore", "rnat", "ar20", "ar21", "ar22", "ar23",
"ar24", "ar25", "ar26", "ar27", "ar28", "ar29", "ar30", "ar31",
"ccv", "ar33", "ar34", "ar35", "unat", "ar37", "ar38", "ar39",
"fpsr", "ar41", "ar42", "ar43", "ar44", "ar45", "ar46", "ar47",
"ar48", "ar49", "ar50", "ar51", "ar52", "ar53", "ar54", "ar55",
"ar56", "ar57", "ar58", "ar59", "ar60", "ar61", "ar62", "ar63",
"pfs", "lc", "ec", "ar67", "ar68", "ar69", "ar70", "ar71",
"ar72", "ar73", "ar74", "ar75", "ar76", "ar77", "ar78", "ar79",
"ar80", "ar81", "ar82", "ar83", "ar84", "ar85", "ar86", "ar87",
"ar88", "ar89", "ar90", "ar91", "ar92", "ar93", "ar94", "ar95",
"ar96", "ar97", "ar98", "ar99", "ar100", "ar101", "ar102", "ar103",
"ar104", "ar105", "ar106", "ar107", "ar108", "ar109", "ar110", "ar111",
"ar112", "ar113", "ar114", "ar115", "ar116", "ar117", "ar118", "ar119",
"ar120", "ar121", "ar122", "ar123", "ar124", "ar125", "ar126", "ar127",
"rp", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
"pr",
"cfm",
"current-bsp"
};
const char *
_U_ia64_regname (unw_regnum_t reg)
{
if ((unsigned) (reg + 7) < sizeof (regname) / sizeof (regname[0]))
return regname[reg + 7];
else
return "???";
}
#endif /* IA64_UNW_DEBUG */
void
ia64_init (void)
{
extern void unw_hash_index_t_is_too_narrow (void);
extern void unw_cursor_t_is_too_small (void);
uint8_t f1_bytes[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint8_t nat_val_bytes[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint8_t int_val_bytes[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint8_t *lep, *bep;
long i;
unw.f0.raw.bits[0] = 0;
unw.f0.raw.bits[1] = 0;
lep = (uint8_t *) &unw.f1_le + 16;
bep = (uint8_t *) &unw.f1_be;
for (i = 0; i < 16; ++i)
{
*--lep = f1_bytes[i];
*bep++ = f1_bytes[i];
}
lep = (uint8_t *) &unw.nat_val_le + 16;
bep = (uint8_t *) &unw.nat_val_be;
for (i = 0; i < 16; ++i)
{
*--lep = nat_val_bytes[i];
*bep++ = nat_val_bytes[i];
}
lep = (uint8_t *) &unw.int_val_le + 16;
bep = (uint8_t *) &unw.int_val_be;
for (i = 0; i < 16; ++i)
{
*--lep = int_val_bytes[i];
*bep++ = int_val_bytes[i];
}
if (sizeof (struct ia64_cursor) > sizeof (unw_cursor_t))
unw_cursor_t_is_too_small();
if (8*sizeof(unw_hash_index_t) < IA64_LOG_UNW_HASH_SIZE)
unw_hash_index_t_is_too_narrow();
for (i = 0; i < IA64_UNW_CACHE_SIZE; ++i) {
if (i > 0)
unw.cache[i].lru_chain = (i - 1);
unw.cache[i].coll_chain = -1;
// unw.cache[i].lock = RW_LOCK_UNLOCKED;
}
unw.lru_head = IA64_UNW_CACHE_SIZE - 1;
unw.lru_tail = 0;
}

View file

@ -0,0 +1,875 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unwind_i.h"
typedef unsigned long unw_word;
#define alloc_reg_state() (malloc (sizeof(struct ia64_state_record)))
#define free_reg_state(usr) (free (usr))
/* Unwind decoder routines */
static inline void
push (struct ia64_state_record *sr)
{
struct ia64_reg_state *rs;
rs = alloc_reg_state ();
if (!rs)
{
fprintf (stderr, "unwind: cannot stack reg state!\n");
return;
}
memcpy (rs, &sr->curr, sizeof (*rs));
rs->next = sr->stack;
sr->stack = rs;
}
static void
pop (struct ia64_state_record *sr)
{
struct ia64_reg_state *rs;
if (!sr->stack)
{
fprintf (stderr, "unwind: stack underflow!\n");
return;
}
rs = sr->stack;
sr->stack = rs->next;
free_reg_state (rs);
}
static enum ia64_pregnum __attribute__ ((const))
decode_abreg (unsigned char abreg, int memory)
{
switch (abreg)
{
case 0x04 ... 0x07:
return IA64_REG_R4 + (abreg - 0x04);
case 0x22 ... 0x25:
return IA64_REG_F2 + (abreg - 0x22);
case 0x30 ... 0x3f:
return IA64_REG_F16 + (abreg - 0x30);
case 0x41 ... 0x45:
return IA64_REG_B1 + (abreg - 0x41);
case 0x60:
return IA64_REG_PR;
case 0x61:
return IA64_REG_PSP;
case 0x62:
return memory ? IA64_REG_PRI_UNAT_MEM : IA64_REG_PRI_UNAT_GR;
case 0x63:
return IA64_REG_RP;
case 0x64:
return IA64_REG_BSP;
case 0x65:
return IA64_REG_BSPSTORE;
case 0x66:
return IA64_REG_RNAT;
case 0x67:
return IA64_REG_UNAT;
case 0x68:
return IA64_REG_FPSR;
case 0x69:
return IA64_REG_PFS;
case 0x6a:
return IA64_REG_LC;
default:
break;
}
dprintf ("unwind: bad abreg=0x%x\n", abreg);
return IA64_REG_LC;
}
static void
set_reg (struct ia64_reg_info *reg, enum ia64_where where, int when,
unsigned long val)
{
reg->val = val;
reg->where = where;
if (reg->when == IA64_WHEN_NEVER)
reg->when = when;
}
static void
alloc_spill_area (unsigned long *offp, unsigned long regsize,
struct ia64_reg_info *lo, struct ia64_reg_info *hi)
{
struct ia64_reg_info *reg;
for (reg = hi; reg >= lo; --reg)
{
if (reg->where == IA64_WHERE_SPILL_HOME)
{
reg->where = IA64_WHERE_PSPREL;
reg->val = 0x10 - *offp;
*offp += regsize;
}
}
}
static inline void
spill_next_when (struct ia64_reg_info **regp, struct ia64_reg_info *lim,
unw_word t)
{
struct ia64_reg_info *reg;
for (reg = *regp; reg <= lim; ++reg)
{
if (reg->where == IA64_WHERE_SPILL_HOME)
{
reg->when = t;
*regp = reg + 1;
return;
}
}
dprintf ("unwind: excess spill!\n");
}
static inline void
finish_prologue (struct ia64_state_record *sr)
{
struct ia64_reg_info *reg;
unsigned long off;
int i;
/* First, resolve implicit register save locations (see Section
"11.4.2.3 Rules for Using Unwind Descriptors", rule 3). */
for (i = 0; i < (int) sizeof (unw.save_order) / sizeof (unw.save_order[0]);
++i)
{
reg = sr->curr.reg + unw.save_order[i];
if (reg->where == IA64_WHERE_GR_SAVE)
{
reg->where = IA64_WHERE_GR;
reg->val = sr->gr_save_loc++;
}
}
/* Next, compute when the fp, general, and branch registers get
saved. This must come before alloc_spill_area() because we need
to know which registers are spilled to their home locations. */
if (sr->imask)
{
unsigned char kind, mask = 0, *cp = sr->imask;
unsigned long t;
static const unsigned char limit[3] =
{
IA64_REG_F31, IA64_REG_R7, IA64_REG_B5
};
struct ia64_reg_info *(regs[3]);
regs[0] = sr->curr.reg + IA64_REG_F2;
regs[1] = sr->curr.reg + IA64_REG_R4;
regs[2] = sr->curr.reg + IA64_REG_B1;
for (t = 0; t < sr->region_len; ++t)
{
if ((t & 3) == 0)
mask = *cp++;
kind = (mask >> 2 * (3 - (t & 3))) & 3;
if (kind > 0)
spill_next_when (&regs[kind - 1], sr->curr.reg + limit[kind - 1],
sr->region_start + t);
}
}
/* Next, lay out the memory stack spill area. */
if (sr->any_spills)
{
off = sr->spill_offset;
alloc_spill_area (&off, 16, sr->curr.reg + IA64_REG_F2,
sr->curr.reg + IA64_REG_F31);
alloc_spill_area (&off, 8, sr->curr.reg + IA64_REG_B1,
sr->curr.reg + IA64_REG_B5);
alloc_spill_area (&off, 8, sr->curr.reg + IA64_REG_R4,
sr->curr.reg + IA64_REG_R7);
}
}
/* Region header descriptors. */
static void
desc_prologue (int body, unw_word rlen, unsigned char mask,
unsigned char grsave, struct ia64_state_record *sr)
{
int i;
if (!(sr->in_body || sr->first_region))
finish_prologue (sr);
sr->first_region = 0;
/* check if we're done: */
if (body && sr->when_target < sr->region_start + sr->region_len)
{
sr->done = 1;
return;
}
for (i = 0; i < sr->epilogue_count; ++i)
pop (sr);
sr->epilogue_count = 0;
sr->epilogue_start = IA64_WHEN_NEVER;
if (!body)
push (sr);
sr->region_start += sr->region_len;
sr->region_len = rlen;
sr->in_body = body;
if (!body)
{
for (i = 0; i < 4; ++i)
{
if (mask & 0x8)
set_reg (sr->curr.reg + unw.save_order[i], IA64_WHERE_GR,
sr->region_start + sr->region_len - 1, grsave++);
mask <<= 1;
}
sr->gr_save_loc = grsave;
sr->any_spills = 0;
sr->imask = 0;
sr->spill_offset = 0x10; /* default to psp+16 */
}
}
/* Prologue descriptors. */
static inline void
desc_abi (unsigned char abi, unsigned char context,
struct ia64_state_record *sr)
{
if (abi == 0 && context == 's')
sr->flags |= IA64_FLAG_SIGTRAMP;
else
dprintf ("unwind: ignoring unwabi(abi=0x%x,context=0x%x)\n", abi, context);
}
static inline void
desc_br_gr (unsigned char brmask, unsigned char gr,
struct ia64_state_record *sr)
{
int i;
for (i = 0; i < 5; ++i)
{
if (brmask & 1)
set_reg (sr->curr.reg + IA64_REG_B1 + i, IA64_WHERE_GR,
sr->region_start + sr->region_len - 1, gr++);
brmask >>= 1;
}
}
static inline void
desc_br_mem (unsigned char brmask, struct ia64_state_record *sr)
{
int i;
for (i = 0; i < 5; ++i)
{
if (brmask & 1)
{
set_reg (sr->curr.reg + IA64_REG_B1 + i, IA64_WHERE_SPILL_HOME,
sr->region_start + sr->region_len - 1, 0);
sr->any_spills = 1;
}
brmask >>= 1;
}
}
static inline void
desc_frgr_mem (unsigned char grmask, unw_word frmask,
struct ia64_state_record *sr)
{
int i;
for (i = 0; i < 4; ++i)
{
if ((grmask & 1) != 0)
{
set_reg (sr->curr.reg + IA64_REG_R4 + i, IA64_WHERE_SPILL_HOME,
sr->region_start + sr->region_len - 1, 0);
sr->any_spills = 1;
}
grmask >>= 1;
}
for (i = 0; i < 20; ++i)
{
if ((frmask & 1) != 0)
{
set_reg (sr->curr.reg + IA64_REG_F2 + i, IA64_WHERE_SPILL_HOME,
sr->region_start + sr->region_len - 1, 0);
sr->any_spills = 1;
}
frmask >>= 1;
}
}
static inline void
desc_fr_mem (unsigned char frmask, struct ia64_state_record *sr)
{
int i;
for (i = 0; i < 4; ++i)
{
if ((frmask & 1) != 0)
{
set_reg (sr->curr.reg + IA64_REG_F2 + i, IA64_WHERE_SPILL_HOME,
sr->region_start + sr->region_len - 1, 0);
sr->any_spills = 1;
}
frmask >>= 1;
}
}
static inline void
desc_gr_gr (unsigned char grmask, unsigned char gr,
struct ia64_state_record *sr)
{
int i;
for (i = 0; i < 4; ++i)
{
if ((grmask & 1) != 0)
set_reg (sr->curr.reg + IA64_REG_R4 + i, IA64_WHERE_GR,
sr->region_start + sr->region_len - 1, gr++);
grmask >>= 1;
}
}
static inline void
desc_gr_mem (unsigned char grmask, struct ia64_state_record *sr)
{
int i;
for (i = 0; i < 4; ++i)
{
if ((grmask & 1) != 0)
{
set_reg (sr->curr.reg + IA64_REG_R4 + i, IA64_WHERE_SPILL_HOME,
sr->region_start + sr->region_len - 1, 0);
sr->any_spills = 1;
}
grmask >>= 1;
}
}
static inline void
desc_mem_stack_f (unw_word t, unw_word size, struct ia64_state_record *sr)
{
set_reg (sr->curr.reg + IA64_REG_PSP, IA64_WHERE_NONE,
sr->region_start + MIN ((int) t, sr->region_len - 1), 16 * size);
}
static inline void
desc_mem_stack_v (unw_word t, struct ia64_state_record *sr)
{
sr->curr.reg[IA64_REG_PSP].when =
sr->region_start + MIN ((int) t, sr->region_len - 1);
}
static inline void
desc_reg_gr (unsigned char reg, unsigned char dst,
struct ia64_state_record *sr)
{
set_reg (sr->curr.reg + reg, IA64_WHERE_GR,
sr->region_start + sr->region_len - 1, dst);
}
static inline void
desc_reg_psprel (unsigned char reg, unw_word pspoff,
struct ia64_state_record *sr)
{
set_reg (sr->curr.reg + reg, IA64_WHERE_PSPREL,
sr->region_start + sr->region_len - 1, 0x10 - 4 * pspoff);
}
static inline void
desc_reg_sprel (unsigned char reg, unw_word spoff,
struct ia64_state_record *sr)
{
set_reg (sr->curr.reg + reg, IA64_WHERE_SPREL,
sr->region_start + sr->region_len - 1, 4 * spoff);
}
static inline void
desc_rp_br (unsigned char dst, struct ia64_state_record *sr)
{
sr->return_link_reg = dst;
}
static inline void
desc_reg_when (unsigned char regnum, unw_word t, struct ia64_state_record *sr)
{
struct ia64_reg_info *reg = sr->curr.reg + regnum;
if (reg->where == IA64_WHERE_NONE)
reg->where = IA64_WHERE_GR_SAVE;
reg->when = sr->region_start + MIN ((int) t, sr->region_len - 1);
}
static inline void
desc_spill_base (unw_word pspoff, struct ia64_state_record *sr)
{
sr->spill_offset = 0x10 - 4 * pspoff;
}
static inline unsigned char *
desc_spill_mask (unsigned char *imaskp, struct ia64_state_record *sr)
{
sr->imask = imaskp;
return imaskp + (2 * sr->region_len + 7) / 8;
}
/* Body descriptors. */
static inline void
desc_epilogue (unw_word t, unw_word ecount, struct ia64_state_record *sr)
{
sr->epilogue_start = sr->region_start + sr->region_len - 1 - t;
sr->epilogue_count = ecount + 1;
}
static inline void
desc_copy_state (unw_word label, struct ia64_state_record *sr)
{
struct ia64_reg_state *rs;
for (rs = sr->reg_state_list; rs; rs = rs->next)
{
if (rs->label == label)
{
memcpy (&sr->curr, rs, sizeof (sr->curr));
return;
}
}
fprintf (stderr, "unwind: failed to find state labelled 0x%lx\n", label);
}
static inline void
desc_label_state (unw_word label, struct ia64_state_record *sr)
{
struct ia64_reg_state *rs;
rs = alloc_reg_state ();
if (!rs)
{
fprintf (stderr, "unwind: cannot stack!\n");
return;
}
memcpy (rs, &sr->curr, sizeof (*rs));
rs->label = label;
rs->next = sr->reg_state_list;
sr->reg_state_list = rs;
}
/** General descriptors. */
static inline int
desc_is_active (unsigned char qp, unw_word t, struct ia64_state_record *sr)
{
if (sr->when_target <= sr->region_start + MIN ((int) t, sr->region_len - 1))
return 0;
if (qp > 0)
{
if ((sr->pr_val & (1UL << qp)) == 0)
return 0;
sr->pr_mask |= (1UL << qp);
}
return 1;
}
static inline void
desc_restore_p (unsigned char qp, unw_word t, unsigned char abreg,
struct ia64_state_record *sr)
{
struct ia64_reg_info *r;
if (!desc_is_active (qp, t, sr))
return;
r = sr->curr.reg + decode_abreg (abreg, 0);
r->where = IA64_WHERE_NONE;
r->when = IA64_WHEN_NEVER;
r->val = 0;
}
static inline void
desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg,
unsigned char x, unsigned char ytreg,
struct ia64_state_record *sr)
{
enum ia64_where where = IA64_WHERE_GR;
struct ia64_reg_info *r;
if (!desc_is_active (qp, t, sr))
return;
if (x)
where = IA64_WHERE_BR;
else if (ytreg & 0x80)
where = IA64_WHERE_FR;
r = sr->curr.reg + decode_abreg (abreg, 0);
r->where = where;
r->when = sr->region_start + MIN ((int) t, sr->region_len - 1);
r->val = (ytreg & 0x7f);
}
static inline void
desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg,
unw_word pspoff, struct ia64_state_record *sr)
{
struct ia64_reg_info *r;
if (!desc_is_active (qp, t, sr))
return;
r = sr->curr.reg + decode_abreg (abreg, 1);
r->where = IA64_WHERE_PSPREL;
r->when = sr->region_start + MIN ((int) t, sr->region_len - 1);
r->val = 0x10 - 4 * pspoff;
}
static inline void
desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg,
unw_word spoff, struct ia64_state_record *sr)
{
struct ia64_reg_info *r;
if (!desc_is_active (qp, t, sr))
return;
r = sr->curr.reg + decode_abreg (abreg, 1);
r->where = IA64_WHERE_SPREL;
r->when = sr->region_start + MIN ((int) t, sr->region_len - 1);
r->val = 4 * spoff;
}
#define UNW_DEC_BAD_CODE(code) fprintf (stderr, "unwind: unknown code 0x%02x\n", code);
/* Register names. */
#define UNW_REG_BSP IA64_REG_BSP
#define UNW_REG_BSPSTORE IA64_REG_BSPSTORE
#define UNW_REG_FPSR IA64_REG_FPSR
#define UNW_REG_LC IA64_REG_LC
#define UNW_REG_PFS IA64_REG_PFS
#define UNW_REG_PR IA64_REG_PR
#define UNW_REG_RNAT IA64_REG_RNAT
#define UNW_REG_PSP IA64_REG_PSP
#define UNW_REG_RP IA64_REG_RP
#define UNW_REG_UNAT IA64_REG_UNAT
/* Region headers. */
#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg)
#define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg)
/* Prologue descriptors. */
#define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg)
#define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg)
#define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg)
#define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg)
#define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg)
#define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg)
#define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg)
#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg)
#define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg)
#define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg)
#define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg)
#define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg)
#define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg)
#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) \
desc_reg_when(IA64_REG_PRI_UNAT_GR,t,arg)
#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) \
desc_reg_when(IA64_REG_PRI_UNAT_MEM,t,arg)
#define UNW_DEC_PRIUNAT_GR(fmt,r,arg) \
desc_reg_gr(IA64_REG_PRI_UNAT_GR,r,arg)
#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) \
desc_reg_psprel(IA64_REG_PRI_UNAT_MEM,o,arg)
#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) \
desc_reg_sprel(IA64_REG_PRI_UNAT_MEM,o,arg)
#define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg)
#define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg)
#define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg))
/* Body descriptors. */
#define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg)
#define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg)
#define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg)
/* General unwind descriptors. */
#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg)
#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg)
#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) \
desc_spill_psprel_p(p,t,a,o,arg)
#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) \
desc_spill_psprel_p(0,t,a,o,arg)
#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg)
#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg)
#define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg)
#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg)
#include "unwind_decoder.c"
static inline const struct ia64_unwind_table_entry *
lookup (struct ia64_unwind_table *table, unw_word_t rel_ip)
{
const struct ia64_unwind_table_entry *e = 0;
unsigned long lo, hi, mid;
/* do a binary search for right entry: */
for (lo = 0, hi = table->info.length; lo < hi;)
{
mid = (lo + hi) / 2;
e = &table->info.array[mid];
if (rel_ip < e->start_offset)
hi = mid;
else if (rel_ip >= e->end_offset)
lo = mid + 1;
else
break;
}
return e;
}
static int
get_proc_info (struct ia64_cursor *c)
{
const struct ia64_unwind_table_entry *e = 0;
struct ia64_unwind_table *table;
unw_word_t segbase, len;
uint8_t *dp, *desc_end;
unw_ia64_table_t info;
unw_word_t ip = c->ip;
uint64_t hdr;
int ret;
/* search the kernels and the modules' unwind tables for IP: */
for (table = unw.tables; table; table = table->next)
if (ip >= table->start && ip < table->end)
break;
if (!table)
{
ret = ia64_acquire_unwind_info (c, ip, &info);
if (ret < 0)
return ret;
segbase = info.segbase;
len = info.length;
/* XXX avoid malloc: */
table = malloc (sizeof (struct ia64_unwind_table));
if (!table)
{
dprintf ("%s: out of memory\n", __FUNCTION__);
return -1;
}
memset (table, 0, sizeof (*table));
table->info = info;
table->start = segbase + table->info.array[0].start_offset;
table->end = segbase + table->info.array[len - 1].end_offset;
/* XXX LOCK { */
table->next = unw.tables;
unw.tables = table;
/* XXX LOCK } */
}
assert (ip >= table->start && ip < table->end);
e = lookup (table, ip - table->info.segbase);
hdr = *(uint64_t *) (table->info.unwind_info_base + e->info_offset);
dp = (uint8_t *) (table->info.unwind_info_base + e->info_offset + 8);
desc_end = dp + 8 * IA64_UNW_LENGTH (hdr);
c->pi.flags = 0;
c->pi.gp = table->info.gp;
c->pi.proc_start = table->info.segbase + e->start_offset;
c->pi.pers_addr = (uint64_t *) desc_end;
c->pi.desc = dp;
/* XXX Perhaps check UNW_VER / UNW_FLAG_OSMASK ? */
if (IA64_UNW_FLAG_EHANDLER (hdr) | IA64_UNW_FLAG_UHANDLER (hdr))
c->pi.flags |= IA64_FLAG_HAS_HANDLER;
return 0;
}
int
ia64_create_state_record (struct ia64_cursor *c, struct ia64_state_record *sr)
{
unw_word_t ip = c->ip, predicates = c->pr;
struct ia64_reg_info *r;
uint8_t *dp, *desc_end;
int ret;
STAT(unsigned long start;)
STAT(++unw.stat.parse.calls; start = ia64_get_itc ());
/* build state record */
memset (sr, 0, sizeof (*sr));
for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r)
r->when = IA64_WHEN_NEVER;
sr->pr_val = predicates;
ret = get_proc_info (c);
if (ret < 0)
return ret;
if (!c->pi.desc)
{
/* No info, return default unwinder (leaf proc, no mem stack, no
saved regs). */
dprintf ("unwind: no unwind info for ip=0x%lx\n", ip);
sr->curr.reg[IA64_REG_RP].where = IA64_WHERE_BR;
sr->curr.reg[IA64_REG_RP].when = -1;
sr->curr.reg[IA64_REG_RP].val = 0;
STAT(unw.stat.parse.time += ia64_get_itc () - start);
return 0;
}
sr->when_target = (3 * ((ip & ~0xfUL) - c->pi.proc_start)
/ 16 + (ip & 0xfUL));
dp = c->pi.desc;
desc_end = (uint8_t *) c->pi.pers_addr;
while (!sr->done && dp < desc_end)
dp = unw_decode (dp, sr->in_body, sr);
c->pi.flags |= sr->flags;
if (sr->when_target > sr->epilogue_start)
{
/* sp has been restored and all values on the memory stack below
psp also have been restored. */
sr->curr.reg[IA64_REG_PSP].val = 0;
sr->curr.reg[IA64_REG_PSP].where = IA64_WHERE_NONE;
sr->curr.reg[IA64_REG_PSP].when = IA64_WHEN_NEVER;
for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r)
if ((r->where == IA64_WHERE_PSPREL && r->val <= 0x10)
|| r->where == IA64_WHERE_SPREL)
{
r->val = 0;
r->where = IA64_WHERE_NONE;
r->when = IA64_WHEN_NEVER;
}
}
/* If RP did't get saved, generate entry for the return link
register. */
if (sr->curr.reg[IA64_REG_RP].when >= sr->when_target)
{
sr->curr.reg[IA64_REG_RP].where = IA64_WHERE_BR;
sr->curr.reg[IA64_REG_RP].when = -1;
sr->curr.reg[IA64_REG_RP].val = sr->return_link_reg;
}
#if IA64_UNW_DEBUG
if (unw.debug_level > 0)
{
printf ("unwind: state record for func 0x%lx, t=%u:\n",
c->pi.proc_start, sr->when_target);
for (r = sr->curr.reg; r < sr->curr.reg + IA64_NUM_PREGS; ++r)
{
if (r->where != IA64_WHERE_NONE || r->when != IA64_WHEN_NEVER)
{
printf (" %s <- ", unw.preg_name[r - sr->curr.reg]);
switch (r->where)
{
case IA64_WHERE_GR:
printf ("r%lu", r->val);
break;
case IA64_WHERE_FR:
printf ("f%lu", r->val);
break;
case IA64_WHERE_BR:
printf ("b%lu", r->val);
break;
case IA64_WHERE_SPREL:
printf ("[sp+0x%lx]", r->val);
break;
case IA64_WHERE_PSPREL:
printf ("[psp+0x%lx]", r->val);
break;
case IA64_WHERE_NONE:
printf ("%s+0x%lx", unw.preg_name[r - sr->curr.reg], r->val);
break;
default:
printf ("BADWHERE(%d)", r->where);
break;
}
printf ("\t\t%d\n", r->when);
}
}
}
#endif
return 0;
}
int
ia64_free_state_record (struct ia64_state_record *sr)
{
struct ia64_reg_state *rs, *next;
/* free labelled register states & stack: */
STAT(parse_start = ia64_get_itc ());
for (rs = sr->reg_state_list; rs; rs = next)
{
next = rs->next;
free_reg_state (rs);
}
while (sr->stack)
pop (sr);
STAT(unw.stat.script.parse_time += ia64_get_itc () - parse_start);
return 0;
}
int
ia64_get_proc_info (struct ia64_cursor *c)
{
#ifdef IA64_UNW_SCRIPT_CACHE
struct ia64_script *script = ia64_script_lookup (c);
if (script)
{
c->pi = script->pi;
return 0;
}
#endif
return get_proc_info (c);
}

View file

@ -0,0 +1,590 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include "config.h"
#include <assert.h>
#include "unwind_i.h"
#include "rse.h"
/* The first three 64-bit words in a signal frame contain the signal
number, siginfo pointer, and sigcontext pointer passed to the
signal handler. We use this to locate the sigcontext pointer. */
#define SIGFRAME_ARG2_OFF 0x10
unw_word_t
ia64_get_sigcontext_addr (struct ia64_cursor *c)
{
unw_word_t addr;
if (!(c->pi.flags & IA64_FLAG_SIGTRAMP))
return 0;
if (ia64_get (c, c->sp + 0x10 + SIGFRAME_ARG2_OFF, &addr) < 0)
return 0;
return addr;
}
/* Apply rotation to a general register. The number REG must be in
the range of 0-127. */
static inline int
rotate_gr (struct ia64_cursor *c, int reg)
{
unsigned int rrb_gr, sor;
unw_word_t cfm;
int preg, ret;
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
sor = 8 * ((cfm >> 14) & 0xf);
rrb_gr = (cfm >> 18) & 0x7f;
if ((unsigned) (reg - 32) > sor)
preg = reg; /* register not part of the rotating partition */
else
{
preg = reg + rrb_gr; /* apply rotation */
if (preg > 32 + sor)
preg -= sor; /* wrap around */
}
debug (100, "%s: sor=%u rrb.gr=%u, r%d -> r%d\n", __FUNCTION__, sor, rrb_gr,
reg, preg);
return preg;
}
/* Apply rotation to a floating-point register. The number REG must
be in the range of 0-127. */
static inline int
rotate_fr (struct ia64_cursor *c, int reg)
{
unsigned int rrb_fr;
unw_word_t cfm;
int preg, ret;
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
rrb_fr = (cfm >> 25) & 0x7f;
if (reg < 32)
preg = reg; /* register not part of the rotating partition */
else
{
preg = reg + rrb_fr; /* apply rotation */
if (preg > 127)
preg -= 96; /* wrap around */
}
debug (100, "%s: rrb.fr=%u, f%d -> f%d\n", __FUNCTION__, rrb_fr, reg, preg);
return preg;
}
/* Apply logical-to-physical rotation. */
static inline unw_word_t
pr_ltop (struct ia64_cursor *c, unw_word_t pr)
{
unw_word_t rrb_pr, mask, rot, cfm;
int ret;
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
rrb_pr = (cfm >> 32) & 0x3f;
rot = pr >> 16;
mask = ((unw_word_t) 1 << rrb_pr) - 1;
rot = ((pr & mask) << (48 - rrb_pr)) | ((pr >> rrb_pr) & mask);
return (pr & 0xffff) | (rot << 16);
}
/* Apply physical-to-logical rotation. */
static inline unw_word_t
pr_ptol (struct ia64_cursor *c, unw_word_t pr)
{
unw_word_t rrb_pr, mask, rot, cfm;
int ret;
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
rrb_pr = 48 - ((cfm >> 32) & 0x3f);
rot = pr >> 16;
mask = ((unw_word_t) 1 << rrb_pr) - 1;
rot = ((pr & mask) << (48 - rrb_pr)) | ((pr >> rrb_pr) & mask);
return (pr & 0xffff) | (rot << 16);
}
static inline int
update_nat (struct ia64_cursor *c, unw_word_t nat_loc, unw_word_t mask,
unw_word_t *valp, int write)
{
unw_word_t nat_word;
int ret;
ret = ia64_get (c, nat_loc, &nat_word);
if (ret < 0)
return ret;
if (write)
{
if (*valp)
nat_word |= mask;
else
nat_word &= ~mask;
ret = ia64_put (c, nat_loc, nat_word);
}
else
*valp = (nat_word & mask) != 0;
return ret;
}
static int
access_nat (struct ia64_cursor *c, unw_word_t loc, unw_word_t reg_loc,
unw_word_t *valp, int write)
{
unw_word_t nat_loc = -8, mask = 0, sc_addr;
unw_fpreg_t tmp;
int ret;
if (IA64_IS_FP_LOC (reg_loc))
{
/* NaT bit is saved as a NaTVal. This happens when a general
register is saved to a floating-point register. */
if (write)
{
if (*valp)
{
if (c->pi.flags & IA64_FLAG_BIG_ENDIAN)
ret = ia64_putfp (c, reg_loc, unw.nat_val_be);
else
ret = ia64_putfp (c, reg_loc, unw.nat_val_le);
}
else
{
unw_fpreg_t tmp;
ret = ia64_getfp (c, reg_loc, &tmp);
if (ret < 0)
return ret;
/* Reset the exponent to 0x1003e so that the significand
will be interpreted as an integer value. */
if (c->pi.flags & IA64_FLAG_BIG_ENDIAN)
tmp.raw.bits[0] = unw.int_val_be.raw.bits[0];
else
tmp.raw.bits[1] = unw.int_val_le.raw.bits[1];
ret = ia64_putfp (c, reg_loc, tmp);
}
}
else
{
ret = ia64_getfp (c, reg_loc, &tmp);
if (ret < 0)
return ret;
if (c->pi.flags & IA64_FLAG_BIG_ENDIAN)
*valp = (memcmp (&tmp, &unw.nat_val_be, sizeof (tmp)) == 0);
else
*valp = (memcmp (&tmp, &unw.nat_val_le, sizeof (tmp)) == 0);
}
return ret;
}
if (IA64_IS_MEMSTK_NAT (loc))
{
nat_loc = IA64_GET_LOC (loc) << 3;
mask = (unw_word_t) 1 << ia64_rse_slot_num ((unsigned long *) reg_loc);
}
else
{
loc = IA64_GET_LOC (loc);
assert (loc >= 0 && loc < 128);
if (!loc)
{
/* NaT bit is not saved. This happens if a general register
is saved to a branch register. Since the NaT bit gets
lost, we need to drop it here, too. Note that if the NaT
bit had been set when the save occurred, it would have
caused a NaT consumption fault. */
if (write)
{
if (*valp)
return -UNW_EBADREG; /* can't set NaT bit */
}
else
*valp = 0;
return 0;
}
if (loc >= 4 && loc <= 7)
{
/* NaT bit is saved in a NaT register. This happens when a
general register is saved to another general
register. */
if (write)
ret = ia64_put (c, UNW_IA64_NAT + loc, *valp);
else
ret = ia64_get (c, UNW_IA64_NAT + loc, valp);
return ret;
}
else if (loc >= 32)
{
/* NaT bit is saved in a stacked register. */
nat_loc = (unw_word_t) ia64_rse_rnat_addr ((unsigned long *)
reg_loc);
if (nat_loc > c->rbs_top)
nat_loc = c->top_rnat_loc;
mask = (unw_word_t) 1 << ia64_rse_slot_num ((unsigned long *)
reg_loc);
}
else
{
/* NaT bit is saved in a scratch register. */
if (!(c->pi.flags & IA64_FLAG_SIGTRAMP))
return -UNW_EBADREG;
sc_addr = ia64_get_sigcontext_addr (c);
if (!sc_addr)
return -UNW_EBADREG;
nat_loc = sc_addr + struct_offset (struct sigcontext, sc_nat);
mask = (unw_word_t) 1 << loc;
}
}
return update_nat (c, nat_loc, mask, valp, write);
}
int
ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
int write)
{
unw_word_t loc = -8, reg_loc, sc_off = 0, nat, nat_loc, cfm, mask, pr;
int ret, readonly = 0;
switch (reg)
{
/* frame registers: */
case UNW_IA64_CURRENT_BSP:
if (write)
return -UNW_EREADONLYREG;
*valp = c->bsp;
return 0;
case UNW_REG_SP:
case UNW_REG_PROC_START:
case UNW_REG_HANDLER:
case UNW_REG_LSDA:
if (write)
return -UNW_EREADONLYREG;
switch (reg)
{
case UNW_REG_SP: *valp = c->sp; break;
case UNW_REG_PROC_START:*valp = c->pi.proc_start; break;
case UNW_REG_LSDA:
*valp = (unw_word_t) (c->pi.pers_addr + 1);
break;
case UNW_REG_HANDLER:
if (c->pi.flags & IA64_FLAG_HAS_HANDLER)
/* *c->pers_addr is the linkage-table offset of the word
that stores the address of the personality routine's
function descriptor. */
*valp = *(unw_word_t *) (*c->pi.pers_addr + c->pi.gp);
else
*valp = 0;
break;
}
return 0;
case UNW_REG_IP:
loc = c->rp_loc;
break;
/* preserved registers: */
case UNW_IA64_GR + 4: loc = c->r4_loc; break;
case UNW_IA64_GR + 5: loc = c->r5_loc; break;
case UNW_IA64_GR + 6: loc = c->r6_loc; break;
case UNW_IA64_GR + 7: loc = c->r7_loc; break;
case UNW_IA64_AR_BSP: loc = c->bsp_loc; break;
case UNW_IA64_AR_BSPSTORE: loc = c->bspstore_loc; break;
case UNW_IA64_AR_PFS: loc = c->pfs_loc; break;
case UNW_IA64_AR_RNAT: loc = c->rnat_loc; break;
case UNW_IA64_AR_UNAT: loc = c->unat_loc; break;
case UNW_IA64_AR_LC: loc = c->lc_loc; break;
case UNW_IA64_AR_FPSR: loc = c->fpsr_loc; break;
case UNW_IA64_BR + 1: loc = c->b1_loc; break;
case UNW_IA64_BR + 2: loc = c->b2_loc; break;
case UNW_IA64_BR + 3: loc = c->b3_loc; break;
case UNW_IA64_BR + 4: loc = c->b4_loc; break;
case UNW_IA64_BR + 5: loc = c->b5_loc; break;
case UNW_IA64_CFM: loc = c->cfm_loc; break;
case UNW_IA64_PR:
if (write)
{
pr = pr_ltop (c, *valp);
return ia64_put (c, c->pr_loc, pr);
}
else
{
ret = ia64_get (c, c->pr_loc, &pr);
if (ret < 0)
return ret;
*valp = pr_ptol (c, pr);
}
return 0;
case UNW_IA64_GR + 32 ... UNW_IA64_GR + 127: /* stacked reg */
reg = rotate_gr (c, reg - UNW_IA64_GR) + UNW_IA64_GR;
loc = (unw_word_t) ia64_rse_skip_regs ((unsigned long *) c->bsp,
reg - (UNW_IA64_GR + 32));
break;
case UNW_IA64_NAT + 32 ... UNW_IA64_NAT + 127: /* stacked reg */
reg = rotate_gr (c, reg - UNW_IA64_NAT) + UNW_IA64_NAT;
loc = (unw_word_t) ia64_rse_skip_regs ((unsigned long *) c->bsp,
reg - (UNW_IA64_NAT + 32));
nat_loc = (unw_word_t) ia64_rse_rnat_addr ((unsigned long *) loc);
if (nat_loc > c->rbs_top)
nat_loc = c->top_rnat_loc;
mask = (unw_word_t) 1 << ia64_rse_slot_num ((unsigned long *) loc);
return update_nat (c, nat_loc, mask, valp, write);
case UNW_IA64_AR_EC:
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
if (write)
ret = ia64_put (c, c->cfm_loc, ((cfm & ~((unw_word_t) 0x3f << 52))
| (*valp & 0x3f) << 52));
else
*valp = (cfm >> 52) & 0x3f;
return ret;
/* scratch & special registers: */
case UNW_IA64_GR + 0:
if (write)
return -UNW_EREADONLYREG;
*valp = 0;
return 0;
case UNW_IA64_GR + 1: /* global pointer */
if (write)
return -UNW_EREADONLYREG;
*valp = c->pi.gp;
return 0;
case UNW_IA64_GR + 15 ... UNW_IA64_GR + 18:
if (!(c->pi.flags & IA64_FLAG_SIGTRAMP))
{
if (write)
c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp;
else
*valp = c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp;
return 0;
}
else
sc_off = struct_offset (struct sigcontext, sc_gr[reg]);
break;
case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3:
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 14:
case UNW_IA64_GR + 19 ... UNW_IA64_GR + 31:
sc_off = struct_offset (struct sigcontext, sc_gr[reg]);
break;
case UNW_IA64_NAT + 0:
case UNW_IA64_NAT + 1: /* global pointer */
if (write)
return -UNW_EREADONLYREG;
*valp = 0;
return 0;
case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3:
case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31:
mask = (unw_word_t) 1 << (reg - UNW_IA64_NAT);
loc = ia64_get_sigcontext_addr (c);
if (!loc)
return -UNW_EBADREG;
loc += struct_offset (struct sigcontext, sc_nat);
ret = ia64_get (c, loc, &nat);
if (ret < 0)
return ret;
if (write)
{
if (*valp)
nat |= mask;
else
nat &= ~mask;
ret = ia64_put (c, loc, nat);
}
else
*valp = (nat & mask) != 0;
return ret;
case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7:
loc = (&c->nat4_loc)[reg - (UNW_IA64_NAT + 4)];
reg_loc = (&c->r4_loc)[reg - (UNW_IA64_NAT + 4)];
return access_nat (c, loc, reg_loc, valp, write);
case UNW_IA64_AR_RSC:
sc_off = struct_offset (struct sigcontext, sc_ar_rsc);
break;
#ifdef SIGCONTEXT_HAS_AR25_AND_AR26
case UNW_IA64_AR_25:
sc_off = struct_offset (struct sigcontext, sc_ar25);
break;
case UNW_IA64_AR_26:
sc_off = struct_offset (struct sigcontext, sc_ar26);
break;
#endif
case UNW_IA64_AR_CCV:
sc_off = struct_offset (struct sigcontext, sc_ar_ccv);
break;
default:
dprintf ("%s: bad register number %d\n", __FUNCTION__, reg);
return -UNW_EBADREG;
}
if (sc_off)
{
loc = ia64_get_sigcontext_addr (c);
if (!loc)
return -UNW_EBADREG;
loc += sc_off;
}
if (write)
{
if (readonly)
return -UNW_EREADONLYREG;
return ia64_put (c, loc, *valp);
}
else
return ia64_get (c, loc, valp);
}
int
ia64_access_fpreg (struct ia64_cursor *c, int reg, unw_fpreg_t *valp,
int write)
{
unw_word_t loc = -8, flags, tmp_loc;
int ret, i;
switch (reg)
{
case UNW_IA64_FR + 0:
if (write)
return -UNW_EREADONLYREG;
*valp = unw.f0;
return 0;
case UNW_IA64_FR + 1:
if (write)
return -UNW_EREADONLYREG;
if (c->pi.flags & IA64_FLAG_BIG_ENDIAN)
*valp = unw.f1_be;
else
*valp = unw.f1_le;
return 0;
case UNW_IA64_FR + 2: loc = c->f2_loc; break;
case UNW_IA64_FR + 3: loc = c->f3_loc; break;
case UNW_IA64_FR + 4: loc = c->f4_loc; break;
case UNW_IA64_FR + 5: loc = c->f5_loc; break;
case UNW_IA64_FR + 16 ... UNW_IA64_FR + 31:
loc = c->fr_loc[reg - (UNW_IA64_FR + 16)];
break;
case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15:
loc = ia64_get_sigcontext_addr (c);
if (!loc)
return -UNW_EBADREG;
loc += struct_offset (struct sigcontext, sc_fr[reg - UNW_IA64_FR]);
break;
case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127:
reg = rotate_fr (c, reg - UNW_IA64_FR) + UNW_IA64_FR;
loc = ia64_get_sigcontext_addr (c);
if (!loc)
return -UNW_EBADREG;
ret = ia64_get (c, loc + struct_offset (struct sigcontext, sc_flags),
&flags);
if (ret < 0)
return ret;
if (!(flags & IA64_SC_FLAG_FPH_VALID))
{
if (write)
{
/* initialize fph partition: */
tmp_loc = loc + struct_offset (struct sigcontext, sc_fr[32]);
for (i = 32; i < 128; ++i, tmp_loc += 16)
{
ret = ia64_putfp (c, tmp_loc, unw.f0);
if (ret < 0)
return ret;
}
/* mark fph partition as being valid: */
ret = ia64_put (c, loc + struct_offset (struct sigcontext,
sc_flags),
flags | IA64_SC_FLAG_FPH_VALID);
if (ret < 0)
return ret;
}
else
{
*valp = unw.f0;
return 0;
}
}
loc += struct_offset (struct sigcontext, sc_fr[reg - UNW_IA64_FR]);
break;
}
if (write)
return ia64_putfp (c, loc, *valp);
else
return ia64_getfp (c, loc, valp);
}

View file

@ -0,0 +1,66 @@
#ifndef _ASM_IA64_RSE_H
#define _ASM_IA64_RSE_H
/*
* Copyright (C) 1998, 1999 Hewlett-Packard Co
* Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
*
* Register stack engine related helper functions. This file may be
* used in applications, so be careful about the name-space and give
* some consideration to non-GNU C compilers (though __inline__ is
* fine).
*/
static __inline__ unsigned long
ia64_rse_slot_num (unsigned long *addr)
{
return (((unsigned long) addr) >> 3) & 0x3f;
}
/*
* Return TRUE if ADDR is the address of an RNAT slot.
*/
static __inline__ unsigned long
ia64_rse_is_rnat_slot (unsigned long *addr)
{
return ia64_rse_slot_num(addr) == 0x3f;
}
/*
* Returns the address of the RNAT slot that covers the slot at
* address SLOT_ADDR.
*/
static __inline__ unsigned long *
ia64_rse_rnat_addr (unsigned long *slot_addr)
{
return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3));
}
/*
* Calcuate the number of registers in the dirty partition starting at
* BSPSTORE with a size of DIRTY bytes. This isn't simply DIRTY
* divided by eight because the 64th slot is used to store ar.rnat.
*/
static __inline__ unsigned long
ia64_rse_num_regs (unsigned long *bspstore, unsigned long *bsp)
{
unsigned long slots = (bsp - bspstore);
return slots - (ia64_rse_slot_num(bspstore) + slots)/0x40;
}
/*
* The inverse of the above: given bspstore and the number of
* registers, calculate ar.bsp.
*/
static __inline__ unsigned long *
ia64_rse_skip_regs (unsigned long *addr, long num_regs)
{
long delta = ia64_rse_slot_num(addr) + num_regs;
if (num_regs < 0)
delta -= 0x3e;
return addr + num_regs + delta/0x3f;
}
#endif /* _ASM_IA64_RSE_H */

View file

@ -0,0 +1,469 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include "rse.h"
#include "unwind_i.h"
static inline unw_hash_index_t
hash (unw_word_t ip)
{
# define magic 0x9e3779b97f4a7c16 /* based on (sqrt(5)/2-1)*2^64 */
return (ip >> 4) * magic >> (64 - IA64_LOG_UNW_HASH_SIZE);
}
static inline long
cache_match (struct ia64_script *script, unw_word_t ip, unw_word_t pr)
{
/* XXX lock script cache */
if (ip == script->ip && ((pr ^ script->pr_val) & script->pr_mask) == 0)
/* keep the lock... */
return 1;
/* XXX unlock script cache */
return 0;
}
inline struct ia64_script *
ia64_script_lookup (struct ia64_cursor *c)
{
struct ia64_script *script = unw.cache + c->hint;
unsigned short index;
unw_word_t ip, pr;
STAT(++unw.stat.cache.lookups);
ip = c->ip;
pr = c->pr;
if (cache_match (script, ip, pr))
{
STAT(++unw.stat.cache.hinted_hits);
return script;
}
index = unw.hash[hash (ip)];
if (index >= IA64_UNW_CACHE_SIZE)
return 0;
script = unw.cache + index;
while (1)
{
if (cache_match (script, ip, pr))
{
/* update hint; no locking needed: single-word writes are atomic */
STAT(++unw.stat.cache.normal_hits);
c->hint = unw.cache[c->prev_script].hint = script - unw.cache;
return script;
}
if (script->coll_chain >= IA64_UNW_HASH_SIZE)
return 0;
script = unw.cache + script->coll_chain;
STAT(++unw.stat.cache.collision_chain_traversals);
}
}
/* On returning, the lock for the SCRIPT is still being held. */
static inline struct ia64_script *
script_new (unw_word_t ip)
{
struct ia64_script *script, *prev, *tmp;
unw_hash_index_t index;
unsigned short head;
STAT(++unw.stat.script.news);
/* XXX lock hash table */
{
head = unw.lru_head;
script = unw.cache + head;
unw.lru_head = script->lru_chain;
}
/* XXX unlock hash table */
/* XXX We'll deadlock here if we interrupt a thread that is holding
the script->lock. */
/* XXX lock script */
/* XXX lock unwind data lock */
{
/* re-insert script at the tail of the LRU chain: */
unw.cache[unw.lru_tail].lru_chain = head;
unw.lru_tail = head;
/* remove the old script from the hash table (if it's there): */
if (script->ip)
{
index = hash (script->ip);
tmp = unw.cache + unw.hash[index];
prev = 0;
while (1)
{
if (tmp == script)
{
if (prev)
prev->coll_chain = tmp->coll_chain;
else
unw.hash[index] = tmp->coll_chain;
break;
}
else
prev = tmp;
if (tmp->coll_chain >= IA64_UNW_CACHE_SIZE)
/* old script wasn't in the hash-table */
break;
tmp = unw.cache + tmp->coll_chain;
}
}
/* enter new script in the hash table */
index = hash (ip);
script->coll_chain = unw.hash[index];
unw.hash[index] = script - unw.cache;
script->ip = ip; /* set new IP while we're holding the locks */
STAT(if (script->coll_chain < IA64_UNW_CACHE_SIZE)
++unw.stat.script.collisions);
}
/* XXX unlock unwind data lock */
script->hint = 0;
script->count = 0;
return script;
}
static void
script_finalize (struct ia64_script *script, struct ia64_state_record *sr)
{
script->pr_mask = sr->pr_mask;
script->pr_val = sr->pr_val;
}
static inline void
script_emit (struct ia64_script *script, struct ia64_script_insn insn)
{
if (script->count >= IA64_MAX_SCRIPT_LEN)
{
dprintf ("%s: script exceeds maximum size of %u instructions!\n",
__FUNCTION__, IA64_MAX_SCRIPT_LEN);
return;
}
script->insn[script->count++] = insn;
}
static inline void
emit_nat_info (struct ia64_state_record *sr, int i, struct ia64_script *script)
{
struct ia64_reg_info *r = sr->curr.reg + i;
struct ia64_script_insn insn;
enum ia64_script_insn_opcode opc = IA64_INSN_SET;
unsigned long val = 0;
switch (r->where)
{
case IA64_WHERE_GR:
val = IA64_LOC (r->val, 0);
break;
case IA64_WHERE_FR:
val = 0; /* value doesn't matter... */
break;
case IA64_WHERE_BR:
val = IA64_LOC (0, 0); /* no NaT bit */
break;
case IA64_WHERE_PSPREL:
case IA64_WHERE_SPREL:
opc = IA64_INSN_SETNAT_MEMSTK;
break;
default:
dprintf ("%s: don't know how to emit nat info for where = %u\n",
__FUNCTION__, r->where);
return;
}
insn.opc = opc;
insn.dst = unw.preg_index[i];
insn.val = val;
script_emit (script, insn);
}
static void
compile_reg (struct ia64_state_record *sr, int i, struct ia64_script *script)
{
struct ia64_reg_info *r = sr->curr.reg + i;
enum ia64_script_insn_opcode opc;
unsigned long val, rval;
struct ia64_script_insn insn;
long is_preserved_gr;
if (r->where == IA64_WHERE_NONE || r->when >= sr->when_target)
return;
opc = IA64_INSN_MOVE;
val = rval = r->val;
is_preserved_gr = (i >= IA64_REG_R4 && i <= IA64_REG_R7);
switch (r->where)
{
case IA64_WHERE_GR:
if (rval >= 32)
{
/* register got spilled to a stacked register */
opc = IA64_INSN_MOVE_STACKED;
val = rval - 32;
}
else if (rval >= 4 && rval <= 7)
/* register got spilled to a preserved register */
val = unw.preg_index[IA64_REG_R4 + (rval - 4)];
else
{
/* register got spilled to a scratch register */
opc = IA64_INSN_MOVE_SIGCONTEXT;
val = struct_offset (struct sigcontext, sc_gr[rval]);
}
break;
case IA64_WHERE_FR:
if (rval <= 5)
val = unw.preg_index[IA64_REG_F2 + (rval - 1)];
else if (rval >= 16 && rval <= 31)
val = unw.preg_index[IA64_REG_F16 + (rval - 16)];
else
{
opc = IA64_INSN_MOVE_SIGCONTEXT;
val = struct_offset (struct sigcontext, sc_fr[rval]);
}
break;
case IA64_WHERE_BR:
if (rval >= 1 && rval <= 5)
val = unw.preg_index[IA64_REG_B1 + (rval - 1)];
else
{
opc = IA64_INSN_MOVE_SIGCONTEXT;
val = struct_offset (struct sigcontext, sc_br[rval]);
}
break;
case IA64_WHERE_SPREL:
opc = IA64_INSN_ADD_SP;
if (i >= IA64_REG_F2 && i <= IA64_REG_F31)
val |= IA64_LOC_TYPE_FP;
break;
case IA64_WHERE_PSPREL:
opc = IA64_INSN_ADD_PSP;
if (i >= IA64_REG_F2 && i <= IA64_REG_F31)
val |= IA64_LOC_TYPE_FP;
break;
default:
dprintf ("%s: register %u has unexpected `where' value of %u\n",
__FUNCTION__, i, r->where);
break;
}
insn.opc = opc;
insn.dst = unw.preg_index[i];
insn.val = val;
script_emit (script, insn);
if (is_preserved_gr)
emit_nat_info (sr, i, script);
if (i == IA64_REG_PSP)
{
/* info->psp must contain the _value_ of the previous sp, not
it's save location. We get this by dereferencing the value
we just stored in info->psp: */
insn.opc = IA64_INSN_LOAD;
insn.dst = insn.val = unw.preg_index[IA64_REG_PSP];
script_emit (script, insn);
}
}
/* Build an unwind script that unwinds from state OLD_STATE to the
entrypoint of the function that called OLD_STATE. */
static inline int
build_script (struct ia64_cursor *c, struct ia64_script **scriptp)
{
struct ia64_script *script;
struct ia64_state_record sr;
struct ia64_script_insn insn;
int i, ret;
STAT(unsigned long start, parse_start;)
STAT(++unw.stat.script.builds; start = ia64_get_itc ());
STAT(unw.stat.script.parse_time += ia64_get_itc () - parse_start);
script = script_new (c->ip);
if (!script)
{
dprintf ("%s: failed to create unwind script\n", __FUNCTION__);
STAT(unw.stat.script.build_time += ia64_get_itc() - start);
return -UNW_EUNSPEC;
}
unw.cache[c->prev_script].hint = script - unw.cache;
ret = ia64_create_state_record (c, &sr);
if (ret < 0)
return ret;
/* First, set psp if we're dealing with a fixed-size frame;
subsequent instructions may depend on this value. */
if (sr.when_target > sr.curr.reg[IA64_REG_PSP].when
&& (sr.curr.reg[IA64_REG_PSP].where == IA64_WHERE_NONE)
&& sr.curr.reg[IA64_REG_PSP].val != 0)
{
/* new psp is psp plus frame size */
insn.opc = IA64_INSN_ADD;
insn.dst = struct_offset (struct ia64_cursor, psp) / 8;
insn.val = sr.curr.reg[IA64_REG_PSP].val; /* frame size */
script_emit (script, insn);
}
/* determine where the primary UNaT is: */
if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_GR].when)
i = IA64_REG_PRI_UNAT_MEM;
else if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when)
i = IA64_REG_PRI_UNAT_GR;
else if (sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when >
sr.curr.reg[IA64_REG_PRI_UNAT_GR].when)
i = IA64_REG_PRI_UNAT_MEM;
else
i = IA64_REG_PRI_UNAT_GR;
compile_reg (&sr, i, script);
for (i = IA64_REG_BSP; i < IA64_NUM_PREGS; ++i)
compile_reg (&sr, i, script);
script_finalize (script, &sr);
script->pi = c->pi;
ia64_free_state_record (&sr);
STAT(unw.stat.script.build_time += ia64_get_itc () - start);
*scriptp = script;
return 0;
}
/* Apply the unwinding actions represented by OPS and update SR to
reflect the state that existed upon entry to the function that this
unwinder represents. */
static inline int
run_script (struct ia64_script *script, struct ia64_cursor *c)
{
struct ia64_script_insn *ip, *limit, next_insn;
unw_word_t val, unat_addr, *s = (unw_word_t *) c;
unsigned long opc, dst;
int ret;
STAT(unsigned long start;)
STAT(++unw.stat.script.runs; start = ia64_get_itc ());
c->pi = script->pi;
ip = script->insn;
limit = script->insn + script->count;
next_insn = *ip;
while (ip++ < limit)
{
opc = next_insn.opc;
dst = next_insn.dst;
val = next_insn.val;
next_insn = *ip;
switch (opc)
{
case IA64_INSN_SET:
s[dst] = val;
break;
case IA64_INSN_ADD:
s[dst] += val;
break;
case IA64_INSN_ADD_PSP:
s[dst] = c->psp + val;
break;
case IA64_INSN_ADD_SP:
s[dst] = c->sp + val;
break;
case IA64_INSN_MOVE:
s[dst] = s[val];
break;
case IA64_INSN_MOVE_SIGCONTEXT:
s[dst] = ia64_get_sigcontext_addr (c);
break;
case IA64_INSN_MOVE_STACKED:
s[dst] = (unsigned long) ia64_rse_skip_regs ((unsigned long *)
c->bsp, val);
break;
case IA64_INSN_SETNAT_MEMSTK:
ret = ia64_get (c, c->pri_unat_loc, &unat_addr);
if (ret < 0)
return ret;
s[dst] = IA64_LOC (unat_addr >> 3, IA64_LOC_TYPE_MEMSTK_NAT);
break;
case IA64_INSN_LOAD:
ret = ia64_get (c, s[val], &s[dst]);
if (ret < 0)
return ret;
break;
}
}
STAT(unw.stat.script.run_time += ia64_get_itc () - start);
return 0;
}
int
ia64_find_save_locs (struct ia64_cursor *c)
{
struct ia64_script *script = ia64_script_lookup (c);
int ret;
if (!script)
{
ret = build_script (c, &script);
if (ret < 0)
{
if (ret != UNW_ESTOPUNWIND)
dprintf ("%s: failed to locate/build unwind script for ip %lx\n",
__FUNCTION__, c->ip);
return ret;
}
}
c->hint = script->hint;
c->prev_script = script - unw.cache;
run_script (script, c);
return 0;
}

View file

@ -0,0 +1,73 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#define IA64_LOG_UNW_CACHE_SIZE 7
#define IA64_UNW_CACHE_SIZE (1 << IA64_LOG_UNW_CACHE_SIZE)
#define IA64_LOG_UNW_HASH_SIZE (IA64_LOG_UNW_CACHE_SIZE + 1)
#define IA64_UNW_HASH_SIZE (1 << IA64_LOG_UNW_HASH_SIZE)
typedef unsigned char unw_hash_index_t;
enum ia64_script_insn_opcode
{
IA64_INSN_SET, /* s[dst] = val */
IA64_INSN_ADD, /* s[dst] += val */
IA64_INSN_ADD_PSP, /* s[dst] = (s.psp + val) */
IA64_INSN_ADD_SP, /* s[dst] = (s.sp + val) */
IA64_INSN_MOVE, /* s[dst] = s[val] */
IA64_INSN_MOVE_STACKED, /* s[dst] = ia64_rse_skip(*s.bsp_loc, val) */
IA64_INSN_MOVE_SIGCONTEXT, /* s[dst] = sigcontext + val */
IA64_INSN_SETNAT_MEMSTK, /* s[dst].nat.type = s.pri_unat_loc | MEMSTK */
IA64_INSN_LOAD /* s[dst] = *s[val] */
};
struct ia64_script_insn
{
unsigned int opc;
unsigned int dst;
unw_word_t val;
};
/* Preserved general static registers (r4-r7) give rise to two script
instructions; everything else yields at most one instruction; at
the end of the script, the psp gets popped, accounting for one more
instruction. */
#define IA64_MAX_SCRIPT_LEN (IA64_NUM_PREGS + 5)
struct ia64_script
{
unw_word_t ip; /* ip this script is for */
unw_word_t pr_mask; /* mask of predicates script depends on */
unw_word_t pr_val; /* predicate values this script is for */
struct ia64_proc_info pi; /* info about underlying procedure */
unsigned short lru_chain; /* used for least-recently-used chain */
unsigned short coll_chain; /* used for hash collisions */
unsigned short hint; /* hint for next script to try (or -1) */
unsigned short count; /* number of instructions in script */
struct ia64_script_insn insn[IA64_MAX_SCRIPT_LEN];
};
#define ia64_script_lookup UNW_OBJ(ia64_script_lookup)
extern struct ia64_script *ia64_script_lookup (struct ia64_cursor *c);

View file

@ -0,0 +1,197 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
/* This file is bsed on gcc/config/ia64/fde-glibc.c, which is copyright
by:
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@cygnus.com>. */
#include <link.h>
#include <stddef.h>
#include <stdlib.h>
#include "unwind_i.h"
#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \
|| (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG))
# error You need GLIBC 2.2.4 or later on IA-64 Linux
#endif
#if 0
extern unsigned long getunwind (void *buf, size_t len);
#else
/* XXX fix me */
#include <unistd.h>
#include <sys/syscall.h>
# ifndef __NR_getunwind
# define __NR_getunwind 1215
# endif
static unsigned long
getunwind (void *buf, size_t len)
{
return syscall (SYS_getunwind, buf, len);
}
#endif
static int
get_kernel_table (void *ptr)
{
struct ia64_unwind_table_entry *ktab, *etab;
unw_ia64_table_t *info = ptr;
size_t size;
debug (100, "unwind: checking kernel unwind table");
size = getunwind (NULL, 0);
ktab = malloc (size);
if (!ktab)
{
dprintf (__FILE__".%s: failed to allocated %Zu bytes",
__FUNCTION__, size);
return -1;
}
getunwind (ktab, size);
/* Determine length of kernel's unwind table. */
for (etab = ktab; etab->start_offset; ++etab);
if (info->segbase < ktab->start_offset || info->segbase >= ktab->end_offset)
{
free (ktab);
return -1;
}
info->name = "<kernel>";
info->gp = 0;
info->segbase = 0;
info->length = etab - ktab;
info->array = ktab;
info->unwind_info_base = (const u_int8_t *) ktab;
debug (100, "unwind: found table `%s': segbase=%lx, length=%lu, gp=%lx\n",
info->name, info->segbase, info->length, info->gp);
return 0;
}
static int
callback (struct dl_phdr_info *info, size_t size, void *ptr)
{
unw_ia64_table_t *data = ptr;
const Elf64_Phdr *phdr, *p_unwind, *p_dynamic;
long n, match;
Elf64_Addr load_base, segbase;
/* Make sure struct dl_phdr_info is at least as big as we need. */
if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
+ sizeof (info->dlpi_phnum))
return -1;
debug (100, "unwind: checking `%s'\n", info->dlpi_name);
match = 0;
phdr = info->dlpi_phdr;
load_base = info->dlpi_addr;
p_unwind = NULL;
p_dynamic = NULL;
segbase = ~(Elf64_Addr) 0;
/* See if PC falls into one of the loaded segments. Find the unwind
segment at the same time. */
for (n = info->dlpi_phnum; --n >= 0; phdr++)
{
if (phdr->p_type == PT_LOAD)
{
Elf64_Addr vaddr = phdr->p_vaddr + load_base;
if (data->segbase >= vaddr && data->segbase < vaddr + phdr->p_memsz)
match = 1;
if (vaddr < segbase)
segbase = vaddr;
}
else if (phdr->p_type == PT_IA_64_UNWIND)
p_unwind = phdr;
else if (phdr->p_type == PT_DYNAMIC)
p_dynamic = phdr;
}
if (!match || !p_unwind)
return 0;
if (p_dynamic)
{
/* For dynamicly linked executables and shared libraries,
DT_PLTGOT is the gp value for that object. */
Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base);
for (; dyn->d_tag != DT_NULL ; dyn++)
if (dyn->d_tag == DT_PLTGOT)
{
/* On IA-64, _DYNAMIC is writable and GLIBC has relocated it. */
data->gp = dyn->d_un.d_ptr;
break;
}
}
else
{
/* Otherwise this is a static executable with no _DYNAMIC.
The gp is constant program-wide. */
register unsigned long gp __asm__("gp");
data->gp = gp;
}
data->name = info->dlpi_name;
data->array
= (const struct ia64_unwind_table_entry *) (p_unwind->p_vaddr + load_base);
data->length = p_unwind->p_memsz / sizeof (struct ia64_unwind_table_entry);
data->segbase = segbase;
data->unwind_info_base = (const u_int8_t *) segbase;
debug (100, "unwind: found table `%s': segbase=%lx, length=%lu, gp=%lx, "
"array=%p\n", data->name, data->segbase, data->length, data->gp,
data->array);
return 1;
}
int
ia64_glibc_acquire_unwind_info (unw_word_t ip, void *info, void *arg)
{
((unw_ia64_table_t *) info)->segbase = ip; /* this is cheap... */
if (dl_iterate_phdr (callback, info) >= 0)
return 0;
return get_kernel_table (info);
}
int
ia64_glibc_release_unwind_info (void *info, void *arg)
{
/* nothing to do */
return 0;
}

View file

@ -0,0 +1,59 @@
/* Copyright (C) 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* Constants shared between setcontext() and getcontext(). Don't
install this header file. */
#define SIG_BLOCK 0
#define SIG_UNBLOCK 1
#define SIG_SETMASK 2
#define SC_NAT 0x008
#define SC_BSP 0x048
#define SC_RNAT 0x050
#define SC_UNAT 0x060
#define SC_FPSR 0x068
#define SC_PFS 0x070
#define SC_LC 0x078
#define SC_PR 0x080
#define SC_BR 0x088
#define SC_GR 0x0c8
#define SC_FR 0x1d0
#define SC_MASK 0x9d0
#define rTMP r14
#define rPOS r14
#define rCPOS r17
#define rNAT r18
#define rB5 r18
#define rB4 r19
#define rB3 r20
#define rB2 r21
#define rB1 r22
#define rB0 r23
#define rRSC r24
#define rBSP r25
#define rRNAT r26
#define rUNAT r27
#define rFPSR r28
#define rPFS r29
#define rLC r30
#define rPR r31

View file

@ -0,0 +1,32 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include "unwind_i.h"
int
unw_get_reg (unw_cursor_t *cursor, int regnum, unw_word_t *valp)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
return ia64_access_reg (c, regnum, valp, 0);
}

View file

@ -0,0 +1,279 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include <string.h>
#include "rse.h"
#include "unwind_i.h"
#ifdef IA64_UNW_ACCESSORS
static int
access_mem (unw_word_t addr, unw_word_t *val, int write, void *arg)
{
if (write)
{
debug (100, "%s: mem[%lx] <- %lx\n", __FUNCTION__, addr, *val);
*(unw_word_t *) addr = *val;
}
else
{
*val = *(unw_word_t *) addr;
debug (100, "%s: mem[%lx] -> %lx\n", __FUNCTION__, addr, *val);
}
return 0;
}
static int
access_reg (unw_regnum_t reg, unw_word_t *val, int write, void *arg)
{
ucontext_t *uc = arg;
unw_word_t *addr, mask;
switch (reg)
{
case UNW_IA64_SP: addr = &uc->uc_mcontext.sc_gr[12]; break;
case UNW_IA64_AR_PFS: addr = &uc->uc_mcontext.sc_ar_pfs; break;
case UNW_IA64_AR_RNAT: addr = &uc->uc_mcontext.sc_ar_rnat; break;
case UNW_IA64_AR_UNAT: addr = &uc->uc_mcontext.sc_ar_unat; break;
case UNW_IA64_AR_LC: addr = &uc->uc_mcontext.sc_ar_lc; break;
case UNW_IA64_AR_FPSR: addr = &uc->uc_mcontext.sc_ar_fpsr; break;
case UNW_IA64_PR: addr = &uc->uc_mcontext.sc_pr; break;
case UNW_IA64_AR_BSP:
/* bsp and bspstore are equal after a flushrs: */
addr = &uc->uc_mcontext.sc_ar_bsp;
break;
case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7:
addr = &uc->uc_mcontext.sc_gr[reg - UNW_IA64_GR];
break;
case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7:
mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT);
if (write)
{
if (*val)
uc->uc_mcontext.sc_nat |= mask;
else
uc->uc_mcontext.sc_nat &= ~mask;
}
else
*val = (uc->uc_mcontext.sc_nat & mask) != 0;
if (write)
debug (100, "%s: %s <- %lx\n", __FUNCTION__, _U_ia64_regname(reg),
*val);
else
debug (100, "%s: %s -> %lx\n", __FUNCTION__, _U_ia64_regname(reg),
*val);
return 0;
case UNW_IA64_BR + 0 ... UNW_IA64_BR + 5:
addr = &uc->uc_mcontext.sc_br[reg - UNW_IA64_BR];
break;
default:
debug (1, "%s: bad register number %u\n", __FUNCTION__, reg);
return -1; /* attempt to access a non-preserved register */
}
if (write)
{
*(unw_word_t *) addr = *val;
debug (100, "%s: %s <- %lx\n", __FUNCTION__, _U_ia64_regname(reg), *val);
}
else
{
*val = *(unw_word_t *) addr;
debug (100, "%s: %s -> %lx\n", __FUNCTION__, _U_ia64_regname(reg), *val);
}
return 0;
}
static int
access_fpreg (unw_regnum_t reg, unw_fpreg_t *val, int write, void *arg)
{
ucontext_t *uc = arg;
unw_fpreg_t *addr;
switch (reg)
{
case UNW_IA64_FR+ 2 ... UNW_IA64_FR+ 5:
case UNW_IA64_FR+16 ... UNW_IA64_FR+31:
addr = (unw_fpreg_t *) &uc->uc_mcontext.sc_fr[reg - UNW_IA64_FR]; break;
default:
debug (1, "%s: bad register number %u\n", __FUNCTION__, reg);
return -1; /* attempt to access a non-preserved register */
}
if (write)
{
debug (100, "%s: %s <- %016lx.%016lx\n", __FUNCTION__,
_U_ia64_regname(reg), val->raw.bits[1], val->raw.bits[0]);
*(unw_fpreg_t *) addr = *val;
}
else
{
*val = *(unw_fpreg_t *) addr;
debug (100, "%s: %s -> %016lx.%016lx\n", __FUNCTION__,
_U_ia64_regname(reg), val->raw.bits[1], val->raw.bits[0]);
}
return 0;
}
static int
resume (unw_cursor_t *cursor, void *arg)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
unsigned long *bsp, sol;
unw_fpreg_t fpval;
ucontext_t *uc = arg;
unw_word_t val;
int i, ret;
# define SET_NAT(n, r) \
do \
{ \
ret = ia64_get (c, c->r, &val); \
if (ret < 0) \
return ret; \
if (val) \
uc->uc_mcontext.sc_nat |= (unw_word_t) 1 << n; \
} \
while (0)
# define SET_REG(f, r) \
do \
{ \
ret = ia64_get (c, c->r, &val); \
if (ret < 0) \
return ret; \
uc->uc_mcontext.f = val; \
} \
while (0)
# define SET_FPREG(f, r) \
do \
{ \
ret = ia64_getfp (c, c->r, &fpval); \
if (ret < 0) \
return ret; \
uc->uc_mcontext.f.u.bits[0] = fpval.raw.bits[0]; \
uc->uc_mcontext.f.u.bits[1] = fpval.raw.bits[1]; \
} \
while (0)
SET_REG (sc_ar_pfs, pfs_loc);
SET_REG (sc_br[0], rp_loc);
SET_REG (sc_pr, pr_loc);
SET_REG (sc_ar_rnat, rnat_loc);
SET_REG (sc_ar_lc, lc_loc);
SET_REG (sc_ar_fpsr, fpsr_loc);
SET_REG (sc_gr[4], r4_loc); SET_REG(sc_gr[5], r5_loc);
SET_REG (sc_gr[6], r6_loc); SET_REG(sc_gr[7], r7_loc);
uc->uc_mcontext.sc_nat = 0;
SET_NAT (4, nat4_loc); SET_NAT(5, nat5_loc);
SET_NAT (6, nat6_loc); SET_NAT(7, nat7_loc);
SET_REG (sc_br[1], b1_loc);
SET_REG (sc_br[2], b2_loc);
SET_REG (sc_br[3], b3_loc);
SET_REG (sc_br[4], b4_loc);
SET_REG (sc_br[5], b5_loc);
SET_FPREG (sc_fr[2], f2_loc);
SET_FPREG (sc_fr[3], f3_loc);
SET_FPREG (sc_fr[4], f4_loc);
SET_FPREG (sc_fr[5], f5_loc);
for (i = 16; i < 32; ++i)
SET_FPREG (sc_fr[i], fr_loc[i - 16]);
if ((c->pi.flags & IA64_FLAG_SIGTRAMP) != 0)
fprintf (stderr, "%s: fix me!!\n", __FUNCTION__);
/* Account for the fact that __ia64_install_context() returns via
br.ret, which will decrement bsp by size-of-locals. */
bsp = (unsigned long *) c->bsp;
sol = (uc->uc_mcontext.sc_ar_pfs >> 7) & 0x7f;
bsp = ia64_rse_skip_regs (bsp, sol);
uc->uc_mcontext.sc_ar_bsp = (unsigned long) bsp;
uc->uc_mcontext.sc_flags = 0;
uc->uc_mcontext.sc_gr[1] = c->pi.gp;
uc->uc_mcontext.sc_gr[12] = c->psp;
__ia64_install_context (uc, c->eh_args[0], c->eh_args[1], c->eh_args[2],
c->eh_args[3]);
}
#endif /* IA64_UNW_ACCESSORS */
int
unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
{
STAT(unsigned long start, flags; ++unw.stat.api.inits;
start = ia64_get_itc ();)
int ret;
if (unw.first_time)
{
unw.first_time = 0;
ia64_init ();
}
#ifdef IA64_UNW_ACCESSORS
{
unw_accessors_t a;
a.arg = uc;
a.acquire_unwind_info = ia64_glibc_acquire_unwind_info;
a.release_unwind_info = ia64_glibc_release_unwind_info;
a.access_mem = access_mem;
a.access_reg = access_reg;
a.access_fpreg = access_fpreg;
a.resume = resume;
ret = ia64_init_remote (cursor, &a);
}
#else
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
unw_word_t bsp, sol;
c->uc = uc;
/* What we do here is initialize the unwind cursor so unwinding
starts at parent of the function that created the ucontext_t. */
c->sp = c->psp = uc->uc_mcontext.sc_gr[12];
c->cfm_loc = &uc->uc_mcontext.sc_ar_pfs;
bsp = uc->uc_mcontext.sc_ar_bsp;
sol = (*c->cfm_loc >> 7) & 0x7f;
c->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) bsp, -sol);
c->ip = uc->uc_mcontext.sc_br[0];
c->pr = uc->uc_mcontext.sc_pr;
ret = ia64_find_save_locs (c);
}
#endif
STAT(unw.stat.api.init_time += ia64_get_itc() - start;)
return ret;
}

View file

@ -0,0 +1,98 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include "rse.h"
#include "unwind_i.h"
int
ia64_init_remote (unw_cursor_t *cursor, unw_accessors_t *a)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
int i;
if (unw.first_time)
{
unw.first_time = 0;
ia64_init ();
}
c->acc = *a;
c->cfm_loc = IA64_REG_LOC (UNW_IA64_AR_PFS);
c->top_rnat_loc = IA64_REG_LOC (UNW_IA64_AR_RNAT);
c->bsp_loc = IA64_REG_LOC (UNW_IA64_AR_BSP);
c->bspstore_loc = IA64_REG_LOC (UNW_IA64_AR_BSP);
c->pfs_loc = IA64_REG_LOC (UNW_IA64_AR_PFS);
c->rnat_loc = IA64_REG_LOC (UNW_IA64_AR_RNAT);
c->rp_loc = IA64_REG_LOC (UNW_IA64_BR + 0);
c->pri_unat_loc = 0; /* no primary UNaT location */
c->unat_loc = IA64_REG_LOC (UNW_IA64_AR_UNAT);
c->pr_loc = IA64_REG_LOC (UNW_IA64_PR);
c->lc_loc = IA64_REG_LOC (UNW_IA64_AR_LC);
c->fpsr_loc = IA64_REG_LOC (UNW_IA64_AR_FPSR);
c->r4_loc = IA64_REG_LOC (UNW_IA64_GR + 4);
c->r5_loc = IA64_REG_LOC (UNW_IA64_GR + 5);
c->r6_loc = IA64_REG_LOC (UNW_IA64_GR + 6);
c->r7_loc = IA64_REG_LOC (UNW_IA64_GR + 7);
c->nat4_loc = IA64_REG_LOC (UNW_IA64_NAT + 4);
c->nat5_loc = IA64_REG_LOC (UNW_IA64_NAT + 5);
c->nat6_loc = IA64_REG_LOC (UNW_IA64_NAT + 6);
c->nat7_loc = IA64_REG_LOC (UNW_IA64_NAT + 7);
c->b1_loc = IA64_REG_LOC (UNW_IA64_BR + 1);
c->b2_loc = IA64_REG_LOC (UNW_IA64_BR + 2);
c->b3_loc = IA64_REG_LOC (UNW_IA64_BR + 3);
c->b4_loc = IA64_REG_LOC (UNW_IA64_BR + 4);
c->b5_loc = IA64_REG_LOC (UNW_IA64_BR + 5);
c->f2_loc = IA64_FPREG_LOC (UNW_IA64_FR + 2);
c->f3_loc = IA64_FPREG_LOC (UNW_IA64_FR + 3);
c->f4_loc = IA64_FPREG_LOC (UNW_IA64_FR + 4);
c->f5_loc = IA64_FPREG_LOC (UNW_IA64_FR + 5);
for (i = 16; i <= 31; ++i)
c->fr_loc[i - 16] = IA64_FPREG_LOC (UNW_IA64_FR + i);
if (ia64_get (c, IA64_REG_LOC (UNW_IA64_SP), &c->psp) < 0)
return -1;
if (ia64_get (c, c->bsp_loc, &c->bsp) < 0)
return -1;
c->rbs_top = c->bsp;
c->pi.flags = 0;
c->eh_args[0] = 0;
c->eh_args[1] = 0;
c->eh_args[2] = 0;
c->eh_args[3] = 0;
#ifdef IA64_UNW_SCRIPT_CACHE
c->hint = 0;
c->prev_script = 0;
#endif
return ia64_get_frame_state (c);
}
alias (ia64_init_remote, UNW_OBJ(init_remote))

View file

@ -0,0 +1,32 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include "unwind_i.h"
int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
return (c->flags & IA64_FLAG_SIGTRAMP) != 0;
}

View file

@ -0,0 +1,36 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include "unwind_i.h"
int
unw_resume (unw_cursor_t *cursor)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
#ifdef IA64_UNW_ACCESSORS
return (*c->acc.resume) (cursor, c->acc.arg);
#else
# error fix me.
#endif
}

View file

@ -0,0 +1,32 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include "unwind_i.h"
int
unw_set_reg (unw_cursor_t *cursor, int regnum, unw_word_t valp)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
return ia64_access_reg (c, regnum, &valp, 1);
}

View file

@ -0,0 +1,134 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#include <signal.h>
#include "rse.h"
#include "unwind_i.h"
int
ia64_get_frame_state (struct ia64_cursor *c)
{
unw_word_t prev_ip, prev_sp, prev_bsp, ip, pr, num_regs, cfm;
int ret;
prev_ip = c->ip;
prev_sp = c->sp;
prev_bsp = c->bsp;
/* restore the ip */
ret = ia64_get (c, c->rp_loc, &ip);
if (ret < 0)
return ret;
c->ip = ip;
if ((ip & 0xf) != 0)
{
/* don't let obviously bad addresses pollute the cache */
debug (1, "%s: rejecting bad ip=0x%lx\n", __FUNCTION__, c->ip);
c->rp_loc = 0;
return -UNW_EINVALIDIP;
}
/* restore the cfm: */
c->cfm_loc = c->pfs_loc;
/* restore the bsp: */
pr = c->pr;
num_regs = 0;
if ((c->pi.flags & IA64_FLAG_SIGTRAMP))
{
unw_word_t sigcontext_addr, sigcontext_flags;
ret = ia64_get (c, c->sp + 0x10, &sigcontext_addr);
if (ret < 0)
return ret;
ret = ia64_get (c, (sigcontext_addr
+ struct_offset (struct sigcontext, sc_flags)),
&sigcontext_flags);
if (ret < 0)
return ret;
if ((sigcontext_flags & IA64_SC_FLAG_IN_SYSCALL_BIT) == 0)
{
unw_word_t cfm;
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
num_regs = cfm & 0x7f; /* size of frame */
}
c->pfs_loc = (c->sp + 0x10 + struct_offset (struct sigcontext,
sc_ar_pfs));
}
else
{
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
num_regs = (cfm >> 7) & 0x7f; /* size of locals */
}
c->bsp = (unsigned long) ia64_rse_skip_regs ((unsigned long *) c->bsp,
-num_regs);
/* restore the sp: */
c->sp = c->psp;
if (c->ip == prev_ip && c->sp == prev_sp && c->bsp == prev_bsp)
{
dprintf ("%s: ip, sp, bsp remain unchanged; stopping here (ip=0x%lx)\n",
__FUNCTION__, ip);
STAT(unw.stat.api.unwind_time += ia64_get_itc () - start);
return -UNW_EBADFRAME;
}
/* as we unwind, the saved ar.unat becomes the primary unat: */
c->pri_unat_loc = c->unat_loc;
/* restore the predicates: */
ret = ia64_get (c, c->pr_loc, &c->pr);
if (ret < 0)
return ret;
return ia64_get_proc_info (c);
}
int
unw_step (unw_cursor_t *cursor)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
int ret;
ret = ia64_find_save_locs (c);
if (ret < 0)
return ret;
ret = ia64_get_frame_state (c);
if (ret < 0)
return ret;
return (c->ip == 0) ? 0 : 1;
}

View file

@ -0,0 +1,482 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
/*
* Copyright (C) 2000 Hewlett-Packard Co
* Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
*
* Generic IA-64 unwind info decoder.
*
* This file is used both by the Linux kernel and objdump. Please keep
* the two copies of this file in sync.
*
* You need to customize the decoder by defining the following
* macros/constants before including this file:
*
* Types:
* unw_word Unsigned integer type with at least 64 bits
*
* Register names:
* UNW_REG_BSP
* UNW_REG_BSPSTORE
* UNW_REG_FPSR
* UNW_REG_LC
* UNW_REG_PFS
* UNW_REG_PR
* UNW_REG_RNAT
* UNW_REG_PSP
* UNW_REG_RP
* UNW_REG_UNAT
*
* Decoder action macros:
* UNW_DEC_BAD_CODE(code)
* UNW_DEC_ABI(fmt,abi,context,arg)
* UNW_DEC_BR_GR(fmt,brmask,gr,arg)
* UNW_DEC_BR_MEM(fmt,brmask,arg)
* UNW_DEC_COPY_STATE(fmt,label,arg)
* UNW_DEC_EPILOGUE(fmt,t,ecount,arg)
* UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg)
* UNW_DEC_FR_MEM(fmt,frmask,arg)
* UNW_DEC_GR_GR(fmt,grmask,gr,arg)
* UNW_DEC_GR_MEM(fmt,grmask,arg)
* UNW_DEC_LABEL_STATE(fmt,label,arg)
* UNW_DEC_MEM_STACK_F(fmt,t,size,arg)
* UNW_DEC_MEM_STACK_V(fmt,t,arg)
* UNW_DEC_PRIUNAT_GR(fmt,r,arg)
* UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg)
* UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg)
* UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg)
* UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg)
* UNW_DEC_PROLOGUE(fmt,body,rlen,arg)
* UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg)
* UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg)
* UNW_DEC_REG_REG(fmt,src,dst,arg)
* UNW_DEC_REG_SPREL(fmt,reg,spoff,arg)
* UNW_DEC_REG_WHEN(fmt,reg,t,arg)
* UNW_DEC_RESTORE(fmt,t,abreg,arg)
* UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg)
* UNW_DEC_SPILL_BASE(fmt,pspoff,arg)
* UNW_DEC_SPILL_MASK(fmt,imaskp,arg)
* UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg)
* UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg)
* UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg)
* UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg)
* UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg)
* UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg)
*/
static unw_word
unw_decode_uleb128 (unsigned char **dpp)
{
unsigned shift = 0;
unw_word byte, result = 0;
unsigned char *bp = *dpp;
while (1)
{
byte = *bp++;
result |= (byte & 0x7f) << shift;
if ((byte & 0x80) == 0)
break;
shift += 7;
}
*dpp = bp;
return result;
}
static unsigned char *
unw_decode_x1 (unsigned char *dp, unsigned char code, void *arg)
{
unsigned char byte1, abreg;
unw_word t, off;
byte1 = *dp++;
t = unw_decode_uleb128 (&dp);
off = unw_decode_uleb128 (&dp);
abreg = (byte1 & 0x7f);
if (byte1 & 0x80)
UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg);
else
UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg);
return dp;
}
static unsigned char *
unw_decode_x2 (unsigned char *dp, unsigned char code, void *arg)
{
unsigned char byte1, byte2, abreg, x, ytreg;
unw_word t;
byte1 = *dp++; byte2 = *dp++;
t = unw_decode_uleb128 (&dp);
abreg = (byte1 & 0x7f);
ytreg = byte2;
x = (byte1 >> 7) & 1;
if ((byte1 & 0x80) == 0 && ytreg == 0)
UNW_DEC_RESTORE(X2, t, abreg, arg);
else
UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg);
return dp;
}
static unsigned char *
unw_decode_x3 (unsigned char *dp, unsigned char code, void *arg)
{
unsigned char byte1, byte2, abreg, qp;
unw_word t, off;
byte1 = *dp++; byte2 = *dp++;
t = unw_decode_uleb128 (&dp);
off = unw_decode_uleb128 (&dp);
qp = (byte1 & 0x3f);
abreg = (byte2 & 0x7f);
if (byte1 & 0x80)
UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg);
else
UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg);
return dp;
}
static unsigned char *
unw_decode_x4 (unsigned char *dp, unsigned char code, void *arg)
{
unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg;
unw_word t;
byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
t = unw_decode_uleb128 (&dp);
qp = (byte1 & 0x3f);
abreg = (byte2 & 0x7f);
x = (byte2 >> 7) & 1;
ytreg = byte3;
if ((byte2 & 0x80) == 0 && byte3 == 0)
UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg);
else
UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg);
return dp;
}
static unsigned char *
unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg)
{
int body = (code & 0x20) != 0;
unw_word rlen;
rlen = (code & 0x1f);
UNW_DEC_PROLOGUE(R1, body, rlen, arg);
return dp;
}
static unsigned char *
unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg)
{
unsigned char byte1, mask, grsave;
unw_word rlen;
byte1 = *dp++;
mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
grsave = (byte1 & 0x7f);
rlen = unw_decode_uleb128 (&dp);
UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg);
return dp;
}
static unsigned char *
unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg)
{
unw_word rlen;
rlen = unw_decode_uleb128 (&dp);
UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg);
return dp;
}
static unsigned char *
unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg)
{
unsigned char brmask = (code & 0x1f);
UNW_DEC_BR_MEM(P1, brmask, arg);
return dp;
}
static unsigned char *
unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg)
{
if ((code & 0x10) == 0)
{
unsigned char byte1 = *dp++;
UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1),
(byte1 & 0x7f), arg);
}
else if ((code & 0x08) == 0)
{
unsigned char byte1 = *dp++, r, dst;
r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
dst = (byte1 & 0x7f);
switch (r)
{
case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break;
case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break;
case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break;
case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break;
case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break;
case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break;
case 6: UNW_DEC_RP_BR(P3, dst, arg); break;
case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break;
case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break;
case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break;
case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break;
case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break;
default: UNW_DEC_BAD_CODE(r); break;
}
}
else if ((code & 0x7) == 0)
UNW_DEC_SPILL_MASK(P4, dp, arg);
else if ((code & 0x7) == 1)
{
unw_word grmask, frmask, byte1, byte2, byte3;
byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
grmask = ((byte1 >> 4) & 0xf);
frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3;
UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg);
}
else
UNW_DEC_BAD_CODE(code);
return dp;
}
static unsigned char *
unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg)
{
int gregs = (code & 0x10) != 0;
unsigned char mask = (code & 0x0f);
if (gregs)
UNW_DEC_GR_MEM(P6, mask, arg);
else
UNW_DEC_FR_MEM(P6, mask, arg);
return dp;
}
static unsigned char *
unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg)
{
unsigned char r, byte1, byte2;
unw_word t, size;
if ((code & 0x10) == 0)
{
r = (code & 0xf);
t = unw_decode_uleb128 (&dp);
switch (r)
{
case 0:
size = unw_decode_uleb128 (&dp);
UNW_DEC_MEM_STACK_F(P7, t, size, arg);
break;
case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break;
case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break;
case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break;
case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break;
case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break;
case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break;
case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break;
case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break;
case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break;
case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break;
case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break;
case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break;
case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break;
case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break;
case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break;
default: UNW_DEC_BAD_CODE(r); break;
}
}
else
{
switch (code & 0xf)
{
case 0x0: /* p8 */
{
r = *dp++;
t = unw_decode_uleb128 (&dp);
switch (r)
{
case 1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break;
case 2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break;
case 3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break;
case 4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break;
case 5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break;
case 6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break;
case 7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break;
case 8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break;
case 9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break;
case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break;
case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break;
case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break;
case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break;
case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break;
case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break;
case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break;
case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break;
default: UNW_DEC_BAD_CODE(r); break;
}
}
break;
case 0x1:
byte1 = *dp++; byte2 = *dp++;
UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg);
break;
case 0xf: /* p10 */
byte1 = *dp++; byte2 = *dp++;
UNW_DEC_ABI(P10, byte1, byte2, arg);
break;
case 0x9:
return unw_decode_x1 (dp, code, arg);
case 0xa:
return unw_decode_x2 (dp, code, arg);
case 0xb:
return unw_decode_x3 (dp, code, arg);
case 0xc:
return unw_decode_x4 (dp, code, arg);
default:
UNW_DEC_BAD_CODE(code);
break;
}
}
return dp;
}
static unsigned char *
unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg)
{
unw_word label = (code & 0x1f);
if ((code & 0x20) != 0)
UNW_DEC_COPY_STATE(B1, label, arg);
else
UNW_DEC_LABEL_STATE(B1, label, arg);
return dp;
}
static unsigned char *
unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg)
{
unw_word t;
t = unw_decode_uleb128 (&dp);
UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg);
return dp;
}
static unsigned char *
unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg)
{
unw_word t, ecount, label;
if ((code & 0x10) == 0)
{
t = unw_decode_uleb128 (&dp);
ecount = unw_decode_uleb128 (&dp);
UNW_DEC_EPILOGUE(B3, t, ecount, arg);
}
else if ((code & 0x07) == 0)
{
label = unw_decode_uleb128 (&dp);
if ((code & 0x08) != 0)
UNW_DEC_COPY_STATE(B4, label, arg);
else
UNW_DEC_LABEL_STATE(B4, label, arg);
}
else
switch (code & 0x7)
{
case 1: return unw_decode_x1 (dp, code, arg);
case 2: return unw_decode_x2 (dp, code, arg);
case 3: return unw_decode_x3 (dp, code, arg);
case 4: return unw_decode_x4 (dp, code, arg);
default: UNW_DEC_BAD_CODE(code); break;
}
return dp;
}
typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *);
static unw_decoder unw_decode_table[2][8] =
{
/* prologue table: */
{
unw_decode_r1, /* 0 */
unw_decode_r1,
unw_decode_r2,
unw_decode_r3,
unw_decode_p1, /* 4 */
unw_decode_p2_p5,
unw_decode_p6,
unw_decode_p7_p10
},
{
unw_decode_r1, /* 0 */
unw_decode_r1,
unw_decode_r2,
unw_decode_r3,
unw_decode_b1, /* 4 */
unw_decode_b1,
unw_decode_b2,
unw_decode_b3_x4
}
};
/*
* Decode one descriptor and return address of next descriptor.
*/
static inline unsigned char *
unw_decode (unsigned char *dp, int inside_body, void *arg)
{
unw_decoder decoder;
unsigned char code;
code = *dp++;
decoder = unw_decode_table[inside_body][code >> 5];
dp = (*decoder) (dp, code, arg);
return dp;
}

View file

@ -0,0 +1,485 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
As a special exception, if you link this library with other files to
produce an executable, this library does not by itself cause the
resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public
License. */
#define IA64_UNW_SCRIPT_CACHE
#include <memory.h>
#include <stdint.h>
#include <libunwind.h>
#define struct_offset(str,fld) ((char *)&((str *)NULL)->fld - (char *) 0)
#define IA64_UNW_VER(x) ((x) >> 48)
#define IA64_UNW_FLAG_MASK 0x0000ffff00000000
#define IA64_UNW_FLAG_OSMASK 0x0000f00000000000
#define IA64_UNW_FLAG_EHANDLER(x) ((x) & 0x0000000100000000L)
#define IA64_UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000L)
#define IA64_UNW_LENGTH(x) ((x) & 0x00000000ffffffffL)
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define IA64_UNW_DEBUG 1
#define IA64_UNW_STATS 0
#if IA64_UNW_DEBUG
# include <stdio.h>
# define debug(level,format...) \
do { if (unw.debug_level > level) printf (format); } while (0)
# define dprintf(format...) \
printf (format)
# define inline __attribute__ ((unused))
extern const char *_U_ia64_regname (unw_regnum_t reg);
#else
# define debug(level,format...)
# define dprintf(format...)
#endif
#if IA64_UNW_STATS
# define STAT(x...) x
#else
# define STAT(x...)
#endif
enum ia64_pregnum
{
/* primary unat: */
IA64_REG_PRI_UNAT_GR,
IA64_REG_PRI_UNAT_MEM,
/* register stack */
IA64_REG_BSP, /* register stack pointer */
IA64_REG_BSPSTORE,
IA64_REG_PFS, /* previous function state */
IA64_REG_RNAT,
/* memory stack */
IA64_REG_PSP, /* previous memory stack pointer */
/* return pointer: */
IA64_REG_RP,
/* preserved registers: */
IA64_REG_R4, IA64_REG_R5, IA64_REG_R6, IA64_REG_R7,
IA64_REG_NAT4, IA64_REG_NAT5, IA64_REG_NAT6, IA64_REG_NAT7,
IA64_REG_UNAT, IA64_REG_PR, IA64_REG_LC, IA64_REG_FPSR,
IA64_REG_B1, IA64_REG_B2, IA64_REG_B3, IA64_REG_B4, IA64_REG_B5,
IA64_REG_F2, IA64_REG_F3, IA64_REG_F4, IA64_REG_F5,
IA64_REG_F16, IA64_REG_F17, IA64_REG_F18, IA64_REG_F19,
IA64_REG_F20, IA64_REG_F21, IA64_REG_F22, IA64_REG_F23,
IA64_REG_F24, IA64_REG_F25, IA64_REG_F26, IA64_REG_F27,
IA64_REG_F28, IA64_REG_F29, IA64_REG_F30, IA64_REG_F31,
IA64_NUM_PREGS
};
#define IA64_FLAG_SIGTRAMP (1 << 0) /* signal trampoline? */
#define IA64_FLAG_BIG_ENDIAN (1 << 1) /* big-endian? */
#define IA64_FLAG_HAS_HANDLER (1 << 2) /* has personality routine? */
struct ia64_proc_info
{
unsigned int flags; /* see IA64_FLAG_* above */
unw_word_t gp; /* global pointer value */
unw_word_t proc_start; /* start address of procedure */
uint64_t *pers_addr; /* address of personality routine pointer */
uint8_t *desc; /* encoded unwind descriptors (or NULL) */
};
struct ia64_cursor
{
#ifdef IA64_UNW_ACCESSORS
struct unw_accessors acc;
#else
ucontext_t *uc; /* pointer to struct of preserved registers */
#endif
/* current frame info: */
unw_word_t bsp; /* backing store pointer value */
unw_word_t sp; /* stack pointer value */
unw_word_t psp; /* previous sp value */
unw_word_t ip; /* instruction pointer value */
struct ia64_proc_info pi; /* info about current procedure */
unw_word_t pr; /* current predicate values */
unw_word_t cfm_loc; /* cfm save location (or NULL) */
unw_word_t rbs_top; /* address of end of register backing store */
unw_word_t top_rnat_loc; /* location of final (topmost) RNaT word */
/* preserved state: */
unw_word_t bsp_loc; /* previous bsp save location */
unw_word_t bspstore_loc;
unw_word_t pfs_loc;
unw_word_t rnat_loc;
unw_word_t rp_loc;
unw_word_t pri_unat_loc;
unw_word_t unat_loc;
unw_word_t pr_loc;
unw_word_t lc_loc;
unw_word_t fpsr_loc;
unw_word_t r4_loc, r5_loc, r6_loc, r7_loc;
unw_word_t nat4_loc, nat5_loc, nat6_loc, nat7_loc;
unw_word_t b1_loc, b2_loc, b3_loc, b4_loc, b5_loc;
unw_word_t f2_loc, f3_loc, f4_loc, f5_loc, fr_loc[16];
unw_word_t eh_args[4]; /* exception handler arguments */
#ifdef IA64_UNW_SCRIPT_CACHE
short hint;
short prev_script;
#endif
};
#ifdef IA64_UNW_SCRIPT_CACHE
# include "script.h"
#endif
/* Bits 0 to 2 of an location are used to encode its type:
bit 0: set if location uses floating-point format.
bit 1: set if location is a NaT bit on memory stack
bit 2: set if location is a register. */
#define IA64_LOC_TYPE_FP (1 << 0)
#define IA64_LOC_TYPE_MEMSTK_NAT (1 << 1)
#define IA64_LOC_TYPE_REG (1 << 2)
#define IA64_LOC(l,t) (((l) << 3) | (t))
#define IA64_GET_LOC(l) ((l) >> 3)
#define IA64_MASK_LOC_TYPE(l) ((l) & ~0x7)
#define IA64_IS_FP_LOC(loc) (((loc) & IA64_LOC_TYPE_FP) != 0)
#define IA64_IS_MEMSTK_NAT(loc) (((loc) & IA64_LOC_TYPE_MEMSTK_NAT) != 0)
#define IA64_IS_REG_LOC(r) (((r) & IA64_LOC_TYPE_REG) != 0)
#define IA64_REG_LOC(r) IA64_LOC((r), IA64_LOC_TYPE_REG)
#define IA64_FPREG_LOC(r) IA64_LOC((r), (IA64_LOC_TYPE_REG \
| IA64_LOC_TYPE_FP))
#if 0
#define IA64_FP_LOC(l) ((l) | 0x1)
#define IA64_NAT_TYPE_LOC(t,l) ((l) | ((t) << 2))
#define IA64_GET_REG_LOC(r) ((r) >> 3)
#define IA64_GET_NAT_LOC(loc) ((loc) >> 3)
#endif
#ifdef IA64_UNW_ACCESSORS
# define ia64_acquire_unwind_info(c,ip,i) \
(*(c)->acc.acquire_unwind_info)((ip), (i), (c)->acc.arg)
# define ia64_release_unwind_info(c,ip,i) \
(*(c)->acc.release_unwind_info)((i), (c)->acc.arg)
static inline int
ia64_getfp (struct ia64_cursor *c, unw_word_t loc, unw_fpreg_t *val)
{
int ret;
if (IA64_IS_REG_LOC (loc))
return (*c->acc.access_fpreg) (IA64_GET_LOC (loc), val, 0, c->acc.arg);
loc = IA64_MASK_LOC_TYPE(loc);
ret = (*c->acc.access_mem) (loc + 0, &val->raw.bits[0], 0, c->acc.arg);
if (ret < 0)
return ret;
return (*c->acc.access_mem) (loc + 8, &val->raw.bits[1], 0, c->acc.arg);
}
static inline int
ia64_putfp (struct ia64_cursor *c, unw_word_t loc, unw_fpreg_t val)
{
int ret;
if (IA64_IS_REG_LOC (loc))
return (*c->acc.access_fpreg) (IA64_GET_LOC (loc), &val, 1, c->acc.arg);
loc = IA64_MASK_LOC_TYPE(loc);
ret = (*c->acc.access_mem) (loc + 0, &val.raw.bits[0], 1, c->acc.arg);
if (ret < 0)
return ret;
return (*c->acc.access_mem) (loc + 8, &val.raw.bits[1], 1, c->acc.arg);
}
/* Get the 64 data bits from location LOC. If bit 0 is cleared, LOC
is a memory address, otherwise it is a register number. If the
register is a floating-point register, the 64 bits are read from
the significand bits. */
static inline int
ia64_get (struct ia64_cursor *c, unw_word_t loc, unw_word_t *val)
{
if (IA64_IS_FP_LOC (loc))
{
unw_fpreg_t tmp;
int ret;
ret = ia64_getfp (c, loc, &tmp);
if (ret < 0)
return ret;
if (c->pi.flags & IA64_FLAG_BIG_ENDIAN)
*val = tmp.raw.bits[1];
else
*val = tmp.raw.bits[0];
return 0;
}
if (IA64_IS_REG_LOC (loc))
return (*c->acc.access_reg)(IA64_GET_LOC (loc), val, 0, c->acc.arg);
else
return (*c->acc.access_mem)(loc, val, 0, c->acc.arg);
}
static inline int
ia64_put (struct ia64_cursor *c, unw_word_t loc, unw_word_t val)
{
if (IA64_IS_FP_LOC (loc))
{
unw_fpreg_t tmp;
memset (&tmp, 0, sizeof (tmp));
if (c->pi.flags & IA64_FLAG_BIG_ENDIAN)
tmp.raw.bits[1] = val;
else
tmp.raw.bits[0] = val;
return ia64_putfp (c, loc, tmp);
}
if (loc & 1)
return (*c->acc.access_reg)(loc >> 1, &val, 1, c->acc.arg);
else
return (*c->acc.access_mem)(loc, &val, 1, c->acc.arg);
}
#else
extern int ia64_acquire_unwind_info (unw_word_t, void *);
extern int ia64_release_unwind_info (void *);
# define ia64_acquire_unwind_info(c,ip,i) \
ia64_acquire_unwind_info((ip), (i))
# define ia64_release_unwind_info(c,ip,i) \
ia64_release_unwind_info((i))
# define ia64_get(c,l,v) (*(v) = *(unw_word_t *) (l), 0)
#endif
struct ia64_unwind_block
{
unw_word_t header;
unw_word_t desc[0]; /* unwind descriptors */
/* Personality routine and language-specific data follow behind
descriptors. */
};
struct ia64_unwind_table_entry
{
unw_word_t start_offset;
unw_word_t end_offset;
unw_word_t info_offset;
};
struct ia64_unwind_table
{
struct ia64_unwind_table *next; /* must be first member! */
unw_word_t start; /* start offset covered by table */
unw_word_t end; /* end offset covered table */
unw_ia64_table_t info;
};
enum ia64_where
{
IA64_WHERE_NONE, /* register isn't saved at all */
IA64_WHERE_GR, /* register is saved in a general register */
IA64_WHERE_FR, /* register is saved in a floating-point register */
IA64_WHERE_BR, /* register is saved in a branch register */
IA64_WHERE_SPREL, /* register is saved on memstack (sp-relative) */
IA64_WHERE_PSPREL, /* register is saved on memstack (psp-relative) */
/* At the end of each prologue these locations get resolved to
IA64_WHERE_PSPREL and IA64_WHERE_GR, respectively: */
IA64_WHERE_SPILL_HOME, /* register is saved in its spill home */
IA64_WHERE_GR_SAVE /* register is saved in next general register */
};
#define IA64_WHEN_NEVER 0x7fffffff
struct ia64_reg_info
{
unw_word_t val; /* save location: register number or offset */
enum ia64_where where; /* where the register gets saved */
int when; /* when the register gets saved */
};
struct ia64_state_record
{
unsigned int first_region : 1; /* is this the first region? */
unsigned int done : 1; /* are we done scanning descriptors? */
unsigned int any_spills : 1; /* got any register spills? */
unsigned int in_body : 1; /* are we inside prologue or body? */
unsigned int flags; /* see IA64_FLAG_* */
uint8_t *imask; /* imask of of spill_mask record or NULL */
unw_word_t pr_val; /* predicate values */
unw_word_t pr_mask; /* predicate mask */
long spill_offset; /* psp-relative offset for spill base */
int region_start;
int region_len;
int epilogue_start;
int epilogue_count;
int when_target;
uint8_t gr_save_loc; /* next save register */
uint8_t return_link_reg; /* branch register used as return pointer */
struct ia64_reg_state
{
struct ia64_reg_state *next;
unsigned long label; /* label of this state record */
struct ia64_reg_info reg[IA64_NUM_PREGS];
}
curr, *stack, *reg_state_list;
};
struct ia64_global_unwind_state
{
int first_time;
/* List of unwind tables (one per load-module). */
struct ia64_unwind_table *tables;
/* Table of registers that prologues can save (and order in which
they're saved). */
const unsigned char save_order[8];
/* Maps a preserved register index (preg_index) to corresponding
ucontext_t offset. */
unsigned short uc_off[sizeof(unw_cursor_t) / 8];
/* Index into unw_cursor_t for preserved register i */
unsigned short preg_index[IA64_NUM_PREGS];
unw_fpreg_t f0, f1_le, f1_be, nat_val_le;
unw_fpreg_t nat_val_be, int_val_le, int_val_be;
#ifdef IA64_UNW_SCRIPT_CACHE
unsigned short lru_head; /* index of lead-recently used script */
unsigned short lru_tail; /* index of most-recently used script */
/* hash table that maps instruction pointer to script index: */
unsigned short hash[IA64_UNW_HASH_SIZE];
/* script cache: */
struct ia64_script cache[IA64_UNW_CACHE_SIZE];
#endif
# if IA64_UNW_DEBUG
long debug_level;
const char *preg_name[IA64_NUM_PREGS];
# endif
# if IA64_UNW_STATS
struct
{
struct
{
int lookups;
int hinted_hits;
int normal_hits;
int collision_chain_traversals;
}
cache;
struct
{
unsigned long build_time;
unsigned long run_time;
unsigned long parse_time;
int builds;
int news;
int collisions;
int runs;
}
script;
struct
{
unsigned long init_time;
unsigned long unwind_time;
int inits;
int unwinds;
}
api;
}
stat;
# endif /* IA64_UNW_STATS */
};
/* Convenience macros: */
#define unw UNW_OBJ(ia64_data)
#define ia64_get_proc_info UNW_OBJ(ia64_get_proc_info)
#define ia64_create_state_record UNW_OBJ(ia64_create_state_record)
#define ia64_free_state_record UNW_OBJ(ia64_free_state_record)
#define ia64_get_frame_state UNW_OBJ(ia64_get_frame_state)
#define ia64_find_save_locs UNW_OBJ(ia64_find_save_locs)
#define ia64_init UNW_OBJ(ia64_init)
#define ia64_init_remote UNW_OBJ(ia64_init_remote)
#define ia64_glibc_acquire_unwind_info UNW_OBJ(ia64_glibc_acquire_unwind_info)
#define ia64_glibc_release_unwind_info UNW_OBJ(ia64_glibc_release_unwind_info)
#define ia64_access_reg UNW_OBJ(ia64_access_reg)
#define ia64_access_fpreg UNW_OBJ(ia64_access_fpreg)
#define ia64_get_sigcontext_addr UNW_OBJ(ia64_get_sigcontext_addr)
extern struct ia64_global_unwind_state unw;
extern int ia64_get_proc_info (struct ia64_cursor *c);
extern int ia64_create_state_record (struct ia64_cursor *c,
struct ia64_state_record *sr);
extern int ia64_free_state_record (struct ia64_state_record *sr);
extern int ia64_get_frame_state (struct ia64_cursor *c);
extern int ia64_find_save_locs (struct ia64_cursor *c);
extern void ia64_init (void);
extern int ia64_init_remote (unw_cursor_t *c, unw_accessors_t *a);
extern int ia64_glibc_acquire_unwind_info (unw_word_t ip, void *info,
void *arg);
extern int ia64_glibc_release_unwind_info (void *info, void *arg);
extern int ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg,
unw_word_t *valp, int write);
extern int ia64_access_fpreg (struct ia64_cursor *c, unw_regnum_t reg,
unw_fpreg_t *valp, int write);
extern unw_word_t ia64_get_sigcontext_addr (struct ia64_cursor *c);
extern void __ia64_install_context (const ucontext_t *ucp, long r15, long r16,
long r17, long r18)
__attribute__ ((noreturn));
/* XXX temporary (from glibc): */
#define weak_alias(name, aliasname) \
extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));
#define alias(name, aliasname) \
extern __typeof (name) aliasname __attribute__ ((alias (#name)));
/* XXX should be in glibc: */
#ifndef IA64_SC_FLAG_ONSTACK
# define IA64_SC_FLAG_ONSTACK_BIT 0 /* running on signal stack? */
# define IA64_SC_FLAG_IN_SYSCALL_BIT 1 /* did signal interrupt a syscall? */
# define IA64_SC_FLAG_FPH_VALID_BIT 2 /* is state in f[32]-f[127] valid? */
# define IA64_SC_FLAG_ONSTACK (1 << IA64_SC_FLAG_ONSTACK_BIT)
# define IA64_SC_FLAG_IN_SYSCALL (1 << IA64_SC_FLAG_IN_SYSCALL_BIT)
# define IA64_SC_FLAG_FPH_VALID (1 << IA64_SC_FLAG_FPH_VALID_BIT)
#endif

View file

@ -0,0 +1,19 @@
CPPFLAGS = -I../../include
CFLAGS = -g -O -Wall
PROGS = bt exc
all: $(PROGS)
clean:
rm -f *.o $(PROGS)
distclean: clean
rm -f *~
.PHONY: clean distclean
verify: verify.o ../libunwind.a
exc: exc.o ../libunwind.a
sig: sig.o ../libunwind.a
bt: bt.o ../libunwind.a

View file

@ -0,0 +1,74 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. */
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <libunwind.h>
#define panic(args...) \
{ fprintf (stderr, args); exit (-1); }
static void
do_backtrace (void)
{
unw_cursor_t cursor;
unw_word_t ip, sp;
unw_context_t uc;
unw_getcontext (&uc);
if (unw_init_local (&cursor, &uc) < 0)
panic ("unw_init_local failed!\n");
do
{
unw_get_reg (&cursor, UNW_REG_IP, &ip);
unw_get_reg (&cursor, UNW_REG_SP, &sp);
printf ("ip=%016lx sp=%016lx\n", ip, sp);
{
unw_word_t proc_start, handler, lsda, bsp;
unw_get_reg (&cursor, UNW_REG_PROC_START, &proc_start);
unw_get_reg (&cursor, UNW_REG_HANDLER, &handler);
unw_get_reg (&cursor, UNW_REG_LSDA, &lsda);
unw_get_reg (&cursor, UNW_IA64_CURRENT_BSP, &bsp);
printf ("\tproc_start=%016lx handler=%lx lsda=%lx bsp=%lx\n",
proc_start, handler, lsda, bsp);
}
}
while (unw_step (&cursor) > 0);
}
static void
foo (void)
{
void *buffer[20];
int i, n;
do_backtrace ();
n = backtrace (buffer, 20);
for (i = 0; i < n; ++i)
printf ("[%d] ip=%p\n", i, buffer[i]);
}
int
main (int argc, char **argv)
{
foo ();
return 0;
}

View file

@ -0,0 +1,89 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. */
/* This illustrates the basics of using the unwind interface for
exception handling. */
#include <stdio.h>
#include <stdlib.h>
#include <libunwind.h>
#define panic(args...) \
{ fprintf (stderr, args); exit (-1); }
int true = 1;
static void
raise_exception (void *addr)
{
unw_cursor_t cursor;
unw_word_t ip;
unw_context_t uc;
unw_getcontext (&uc);
if (unw_init_local (&cursor, &uc) < 0)
panic ("unw_init_local() failed!\n");
/* unwind to frame b(): */
if (unw_step (&cursor) < 0)
panic ("unw_step() failed!\n");
/* unwind to frame a(): */
if (unw_step (&cursor) < 0)
panic ("unw_step() failed!\n");
unw_get_reg (&cursor, UNW_REG_IP, &ip);
printf ("ip = %lx\n", ip);
if (unw_set_reg (&cursor, UNW_REG_IP, (unw_word_t) addr) < 0)
panic ("unw_set_reg() failed!\n");
unw_resume (&cursor); /* transfer control to exception handler */
}
static void
b (void *addr)
{
printf ("b() calling raise_exception()\n");
raise_exception (addr);
}
static int
a (void)
{
register long sp asm ("r12");
printf("a: sp=%lx bsp=%p\n", sp, __builtin_ia64_bsp ());
b (&&handler);
printf ("unexpected return from func()!\n");
if (true)
return -1;
handler:
printf ("exception handler: here we go (sp=%lx, bsp=%p)...\n",
sp, __builtin_ia64_bsp ());
return 0;
}
int
main (int argc, char **argv)
{
if (a () == 0)
printf ("test succeeded!\n");
else
printf ("bummer: test failed; try again?\n");
return 0;
}

View file

@ -0,0 +1,82 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. */
/* This shows how to use the unwind interface to modify any ancestor
frame while still returning to the parent frame. */
#include <signal.h>
#include <stdio.h>
#include <unwind.h>
#define panic(args...) \
{ fprintf (stderr, args); exit (-1); }
static void
sighandler (int signal)
{
unw_cursor_t cursor, cursor2;
unw_word_t rp;
unw_context_t uc;
printf ("caught signal %d\n", signal);
unw_getcontext(&uc);
if (unw_init (&cursor, &uc) < 0)
panic ("unw_init() failed!\n");
/* get cursor for caller of sighandler: */
if (unw_step (&cursor) < 0)
panic ("unw_step() failed!\n");
cursor2 = cursor;
while (!unw_is_signal_frame (&cursor2))
if (unw_step (&cursor2) < 0)
panic ("failed to find signal frame!\n");
if (unw_get_reg (&cursor2, UNW_REG_RP, &rp) < 0)
panic ("failed to get IP!\n");
/* skip faulting instruction (doesn't handle MLX template) */
++rp;
if (rp & 0x3 == 0x3)
rp += 13;
if (unw_set_reg (&cursor2, UNW_REG_RP, rp) < 0)
panic ("failed to set IP!\n");
unw_resume (&cursor); /* update context & return to caller of sighandler() */
panic ("unexpected return from unw_resume()!\n");
}
static void
doit (char *p)
{
int ch;
ch = *p; /* trigger SIGSEGV */
printf ("doit: finishing execution!\n");
}
int
main (int argc, char **argv)
{
signal (SIGSEGV, sighandler);
doit (0);
}

View file

@ -0,0 +1,137 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
This file is part of libunwind.
libunwind is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
libunwind is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. */
#include <stdio.h>
#include <stdlib.h>
#include <unwind.h>
#define panic(args...) \
{ fprintf (stderr, args); exit (-1); }
static void
init_state (unw_context_t *ucp)
{
int i;
ucp->uc_mcontext.sc_flags = 0;
ucp->uc_mcontext.sc_ar_ccv = random ();
ucp->uc_mcontext.sc_ar_lc = random ();
ucp->uc_mcontext.sc_pr = random ();
#if 0
ucp->uc_mcontext.sc_ip = xxx;
ucp->uc_mcontext.sc_cfm = xxx;
ucp->uc_mcontext.sc_um = xxx;
ucp->uc_mcontext.sc_ar_rsc = xxx;
ucp->uc_mcontext.sc_ar_bsp = xxx;
ucp->uc_mcontext.sc_ar_rnat = xxx;
ucp->uc_mcontext.sc_ar_unat = xxx;
ucp->uc_mcontext.sc_ar_fpsr = xxx;
ucp->uc_mcontext.sc_ar_pfs = xxx;
#endif
/* initialize static registers without trashing gp (r1), sp (r12),
or tp (r13). */
for (i = 2; i < 32; ++i)
{
if (i != 12 && i != 13)
{
ucp->uc_mcontext.sc_gr[i] = random ();
ucp->uc_mcontext.sc_nat |= (random () & 1) << i;
}
}
#if 0
/* initialize stacked registers: */
for (i = 32; i < 128; ++i)
{
xxx;
}
#endif
for (i = 0; i < 8; ++i)
ucp->uc_mcontext.sc_br[i] = random ();
for (i = 0; i < 128; ++i)
{
ucp->uc_mcontext.sc_fr[i].u.bits[0] = random ();
ucp->uc_mcontext.sc_fr[i].u.bits[0] = random ();
}
#if 0
ucp->uc_mcontext.sc_rbs_base = xxx;
ucp->uc_mcontext.sc_loadrs = xxx;
ucp->uc_mcontext.sc_ar25 = xxx;
ucp->uc_mcontext.sc_ar26 = xxx;
#endif
}
static void
check_state (ucontext_t *orig_state, unw_cursor_t *c)
{
unw_word_t val;
unw_get_reg (c, UNW_REG_IP, &val);
printf ("IP: orig=%016lx now=%016lx\n", orig_state->uc_mcontext.sc_ip, val);
}
static void
setup_context (ucontext_t *unwind_ucp)
{
asm volatile ("mov ar.fpsr = %0" :: "r"(0x9804c8a70033f));
init_state (unwind_ucp);
setcontext (unwind_ucp);
}
static void
check (ucontext_t *unwind_ucp, ucontext_t *setup_ucp,
void (*doit) (ucontext_t *))
{
swapcontext (unwind_ucp, setup_ucp);
(*doit) (unwind_ucp);
}
static void
test1 (ucontext_t *orig_state)
{
unw_cursor_t cursor;
ucontext_t uc;
getcontext (&uc);
if (unw_init_local (&cursor, &uc) < 0)
panic ("unw_init_local failed\n");
if (unw_step (&cursor) < 0)
panic ("unw_step failed\n");
check_state (orig_state, &cursor);
}
int
main (int argc, char **argv)
{
ucontext_t unwind_uc, setup_uc;
unsigned char stack_mem[256*1024];
setup_uc.uc_stack.ss_sp = stack_mem;
setup_uc.uc_stack.ss_flags = 0;
setup_uc.uc_stack.ss_size = sizeof (stack_mem);
makecontext (&setup_uc, (void (*) (void)) setup_context,
2, &setup_uc, &unwind_uc);
check (&unwind_uc, &setup_uc, test1);
return 0;
}