summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormostang.com!davidm <mostang.com!davidm>2002-02-15 23:22:05 +0000
committermostang.com!davidm <mostang.com!davidm>2002-02-15 23:22:05 +0000
commit7fbfe0a255eb7ff3f27efa5adc6ed69dab471ecf (patch)
tree306beb6154163ef05dd977338c2efba3051aaa65
parent63669f7ad4fc6eb752c88713235e2438a8e327d5 (diff)
downloadlibunwind-7fbfe0a255eb7ff3f27efa5adc6ed69dab471ecf.tar.gz
(Logical change 1.3)
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--COPYING340
-rw-r--r--ChangeLog39
-rw-r--r--NOTES74
-rw-r--r--README46
-rw-r--r--include/config.h1
-rw-r--r--include/libunwind-config.h2
-rw-r--r--include/libunwind-ia64.h99
-rw-r--r--include/libunwind.h189
-rw-r--r--src/Makefile342
-rw-r--r--src/backtrace.c50
-rw-r--r--src/ia64/NOTES62
-rw-r--r--src/ia64/TODO3
-rw-r--r--src/ia64/__ia64_install_context.S146
-rw-r--r--src/ia64/init.c250
-rw-r--r--src/ia64/parser.c875
-rw-r--r--src/ia64/regs.c590
-rw-r--r--src/ia64/rse.h66
-rw-r--r--src/ia64/script.c469
-rw-r--r--src/ia64/script.h73
-rw-r--r--src/ia64/tables-glibc.c197
-rw-r--r--src/ia64/ucontext_i.h59
-rw-r--r--src/ia64/unw_get_reg.c32
-rw-r--r--src/ia64/unw_init_local.c279
-rw-r--r--src/ia64/unw_init_remote.c98
-rw-r--r--src/ia64/unw_is_signal_frame.c32
-rw-r--r--src/ia64/unw_resume.c36
-rw-r--r--src/ia64/unw_set_reg.c32
-rw-r--r--src/ia64/unw_step.c134
-rw-r--r--src/ia64/unwind_decoder.c482
-rw-r--r--src/ia64/unwind_i.h485
-rw-r--r--src/tests/Makefile19
-rw-r--r--src/tests/bt.c74
-rw-r--r--src/tests/exc.c89
-rw-r--r--src/tests/sig.c82
-rw-r--r--src/tests/verify.c137
36 files changed, 5984 insertions, 0 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index e69de29b..be9e31a3 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -0,0 +1 @@
+davidm@panda.mostang.com
diff --git a/COPYING b/COPYING
index e69de29b..5b6e7c66 100644
--- a/COPYING
+++ b/COPYING
@@ -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.
diff --git a/ChangeLog b/ChangeLog
index e69de29b..7e03bdb2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/NOTES b/NOTES
index e69de29b..a2a2f63d 100644
--- a/NOTES
+++ b/NOTES
@@ -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.
diff --git a/README b/README
index e69de29b..fc1a5984 100644
--- a/README
+++ b/README
@@ -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
diff --git a/include/config.h b/include/config.h
index e69de29b..726a584f 100644
--- a/include/config.h
+++ b/include/config.h
@@ -0,0 +1 @@
+#undef SIGCONTEXT_HAS_AR25_AND_AR26
diff --git a/include/libunwind-config.h b/include/libunwind-config.h
index e69de29b..703ff6d3 100644
--- a/include/libunwind-config.h
+++ b/include/libunwind-config.h
@@ -0,0 +1,2 @@
+#define UNW_TARGET_IA64
+#undef UNW_LOCAL_ONLY
diff --git a/include/libunwind-ia64.h b/include/libunwind-ia64.h
index e69de29b..ba357c99 100644
--- a/include/libunwind-ia64.h
+++ b/include/libunwind-ia64.h
@@ -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)
diff --git a/include/libunwind.h b/include/libunwind.h
index e69de29b..27c5d2b4 100644
--- a/include/libunwind.h
+++ b/include/libunwind.h
@@ -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 */
diff --git a/src/Makefile b/src/Makefile
index e69de29b..58167282 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -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
diff --git a/src/backtrace.c b/src/backtrace.c
index e69de29b..e3d0a9a3 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -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;
+}
diff --git a/src/ia64/NOTES b/src/ia64/NOTES
index e69de29b..fa2e2a80 100644
--- a/src/ia64/NOTES
+++ b/src/ia64/NOTES
@@ -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
diff --git a/src/ia64/TODO b/src/ia64/TODO
index e69de29b..c74a09b6 100644
--- a/src/ia64/TODO
+++ b/src/ia64/TODO
@@ -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)
diff --git a/src/ia64/__ia64_install_context.S b/src/ia64/__ia64_install_context.S
index e69de29b..3fff0d4f 100644
--- a/src/ia64/__ia64_install_context.S
+++ b/src/ia64/__ia64_install_context.S
@@ -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
diff --git a/src/ia64/init.c b/src/ia64/init.c
index e69de29b..e4c6298e 100644
--- a/src/ia64/init.c
+++ b/src/ia64/init.c
@@ -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;
+}
diff --git a/src/ia64/parser.c b/src/ia64/parser.c
index e69de29b..a943ca7f 100644
--- a/src/ia64/parser.c
+++ b/src/ia64/parser.c
@@ -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);
+}
diff --git a/src/ia64/regs.c b/src/ia64/regs.c
index e69de29b..da049736 100644
--- a/src/ia64/regs.c
+++ b/src/ia64/regs.c
@@ -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);
+}
diff --git a/src/ia64/rse.h b/src/ia64/rse.h
index e69de29b..b65b2842 100644
--- a/src/ia64/rse.h
+++ b/src/ia64/rse.h
@@ -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 */
diff --git a/src/ia64/script.c b/src/ia64/script.c
index e69de29b..b3b861ca 100644
--- a/src/ia64/script.c
+++ b/src/ia64/script.c
@@ -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;
+}
diff --git a/src/ia64/script.h b/src/ia64/script.h
index e69de29b..6659df1e 100644
--- a/src/ia64/script.h
+++ b/src/ia64/script.h
@@ -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);
diff --git a/src/ia64/tables-glibc.c b/src/ia64/tables-glibc.c
index e69de29b..ebb54294 100644
--- a/src/ia64/tables-glibc.c
+++ b/src/ia64/tables-glibc.c
@@ -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;
+}
diff --git a/src/ia64/ucontext_i.h b/src/ia64/ucontext_i.h
index e69de29b..8efaf913 100644
--- a/src/ia64/ucontext_i.h
+++ b/src/ia64/ucontext_i.h
@@ -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
diff --git a/src/ia64/unw_get_reg.c b/src/ia64/unw_get_reg.c
index e69de29b..4f6f9742 100644
--- a/src/ia64/unw_get_reg.c
+++ b/src/ia64/unw_get_reg.c
@@ -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);
+}
diff --git a/src/ia64/unw_init_local.c b/src/ia64/unw_init_local.c
index e69de29b..5dcc285e 100644
--- a/src/ia64/unw_init_local.c
+++ b/src/ia64/unw_init_local.c
@@ -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;
+}
diff --git a/src/ia64/unw_init_remote.c b/src/ia64/unw_init_remote.c
index e69de29b..caa96c7c 100644
--- a/src/ia64/unw_init_remote.c
+++ b/src/ia64/unw_init_remote.c
@@ -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))
diff --git a/src/ia64/unw_is_signal_frame.c b/src/ia64/unw_is_signal_frame.c
index e69de29b..d11cab49 100644
--- a/src/ia64/unw_is_signal_frame.c
+++ b/src/ia64/unw_is_signal_frame.c
@@ -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;
+}
diff --git a/src/ia64/unw_resume.c b/src/ia64/unw_resume.c
index e69de29b..dcb20522 100644
--- a/src/ia64/unw_resume.c
+++ b/src/ia64/unw_resume.c
@@ -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
+}
diff --git a/src/ia64/unw_set_reg.c b/src/ia64/unw_set_reg.c
index e69de29b..272a30aa 100644
--- a/src/ia64/unw_set_reg.c
+++ b/src/ia64/unw_set_reg.c
@@ -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);
+}
diff --git a/src/ia64/unw_step.c b/src/ia64/unw_step.c
index e69de29b..039a8477 100644
--- a/src/ia64/unw_step.c
+++ b/src/ia64/unw_step.c
@@ -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;
+}
diff --git a/src/ia64/unwind_decoder.c b/src/ia64/unwind_decoder.c
index e69de29b..f704eed2 100644
--- a/src/ia64/unwind_decoder.c
+++ b/src/ia64/unwind_decoder.c
@@ -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;
+}
diff --git a/src/ia64/unwind_i.h b/src/ia64/unwind_i.h
index e69de29b..b681bf64 100644
--- a/src/ia64/unwind_i.h
+++ b/src/ia64/unwind_i.h
@@ -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
diff --git a/src/tests/Makefile b/src/tests/Makefile
index e69de29b..282248ac 100644
--- a/src/tests/Makefile
+++ b/src/tests/Makefile
@@ -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
diff --git a/src/tests/bt.c b/src/tests/bt.c
index e69de29b..decb1e95 100644
--- a/src/tests/bt.c
+++ b/src/tests/bt.c
@@ -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;
+}
diff --git a/src/tests/exc.c b/src/tests/exc.c
index e69de29b..49100027 100644
--- a/src/tests/exc.c
+++ b/src/tests/exc.c
@@ -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;
+}
diff --git a/src/tests/sig.c b/src/tests/sig.c
index e69de29b..94308afa 100644
--- a/src/tests/sig.c
+++ b/src/tests/sig.c
@@ -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);
+}
diff --git a/src/tests/verify.c b/src/tests/verify.c
index e69de29b..db143f5d 100644
--- a/src/tests/verify.c
+++ b/src/tests/verify.c
@@ -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;
+}