mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-25 16:47:38 +01:00
(Logical change 1.3)
This commit is contained in:
parent
63669f7ad4
commit
7fbfe0a255
36 changed files with 5984 additions and 0 deletions
|
@ -0,0 +1 @@
|
||||||
|
davidm@panda.mostang.com
|
340
COPYING
340
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.
|
39
ChangeLog
39
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.
|
74
NOTES
74
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.
|
46
README
46
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
|
|
@ -0,0 +1 @@
|
||||||
|
#undef SIGCONTEXT_HAS_AR25_AND_AR26
|
|
@ -0,0 +1,2 @@
|
||||||
|
#define UNW_TARGET_IA64
|
||||||
|
#undef UNW_LOCAL_ONLY
|
|
@ -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)
|
|
@ -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 */
|
342
src/Makefile
342
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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
250
src/ia64/init.c
250
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;
|
||||||
|
}
|
|
@ -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 (®s[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);
|
||||||
|
}
|
590
src/ia64/regs.c
590
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);
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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))
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in a new issue