forked from Imagelibrary/binutils-gdb
Compare commits
1 Commits
gdb-12-bra
...
binutils-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea22f9f817 |
143
gdb/CONTRIBUTE
143
gdb/CONTRIBUTE
@@ -1,143 +0,0 @@
|
||||
|
||||
Contributing to GDB
|
||||
|
||||
GDB is a collaborative project and one which wants to encourage new
|
||||
development. You may wish to fix GDB bugs, improve testing, port GDB
|
||||
to a new platform, update documentation, add new GDB features, and the
|
||||
like. To help with this, there is a lot of documentation
|
||||
available.. In addition to the user guide and internals manual
|
||||
included in the GDB distribution, the GDB web pages also contain much
|
||||
information.
|
||||
|
||||
You may also want to submit your change so that can be considered for
|
||||
conclusion in a future version of GDB (see below). Regardless, we
|
||||
encourage you to distribute the change yourself.
|
||||
|
||||
If you don't feel up to hacking GDB, there are still plenty of ways to
|
||||
help! You can answer questions on the mailing lists, write
|
||||
documentation, find bugs, create a GDB related website (contribute to
|
||||
the official GDB web site), or create a GDB related software
|
||||
package. We welcome all of the above and feel free to ask on the GDB
|
||||
mailing lists if you are looking for feedback or for people to review
|
||||
a work in progress.
|
||||
|
||||
Ref: http://www.gnu.org/software/gdb/
|
||||
|
||||
Finally, there are certain legal requirements and style issues which
|
||||
all contributors need to be aware of.
|
||||
|
||||
o Coding Standards
|
||||
|
||||
All contributions must conform to the GNU Coding Standard.
|
||||
Submissions which do not conform to the standards will be
|
||||
returned with a request to reformat the changes.
|
||||
|
||||
GDB has certain additional coding requirements. Those
|
||||
requirements are explained in the GDB internals documentation
|
||||
in the gdb/doc directory.
|
||||
|
||||
Ref: http://www.gnu.org/prep/standards_toc.html
|
||||
|
||||
|
||||
o Copyright Assignment
|
||||
|
||||
Before we can accept code contributions from you, we need a
|
||||
copyright assignment form filled out and filed with the FSF.
|
||||
|
||||
See some documentation by the FSF for details and contact us
|
||||
(either via the GDB mailing list or the GDB maintainer that is
|
||||
taking care of your contributions) to obtain the relevant
|
||||
forms.
|
||||
|
||||
Small changes can be accepted without a copyright assignment form on file.
|
||||
|
||||
Ref: http://www.gnu.org/prep/maintain.html#SEC6
|
||||
|
||||
|
||||
o Submitting Patches
|
||||
|
||||
Every patch must have several pieces of information before we
|
||||
can properly evaluate it.
|
||||
|
||||
A description of the bug and how your patch fixes this
|
||||
bug. A reference to a testsuite failure is very helpful. For
|
||||
new features a description of the feature and your
|
||||
implementation.
|
||||
|
||||
A ChangeLog entry as plaintext (separate from the patch); see
|
||||
the various ChangeLog files for format and content. Note that,
|
||||
unlike some other projects, we do require ChangeLogs also for
|
||||
documentation (i.e., .texi files).
|
||||
|
||||
The patch itself. If you are accessing the CVS repository use
|
||||
"cvs update; cvs diff -cp"; else, use "diff -cp OLD NEW" or
|
||||
"diff -up OLD NEW". If your version of diff does not support
|
||||
these options, then get the latest version of GNU diff.
|
||||
|
||||
We accept patches as plain text (preferred for the compilers
|
||||
themselves), MIME attachments (preferred for the web pages),
|
||||
or as uuencoded gzipped text.
|
||||
|
||||
When you have all these pieces, bundle them up in a mail
|
||||
message and send it to gdb-patches@sources.redhat.com. All
|
||||
patches and related discussion should be sent to the
|
||||
gdb-patches mailinglist. For further information on the GDB
|
||||
CVS repository, see the Anonymous read-only CVS access and
|
||||
Read-write CVS access page.
|
||||
|
||||
--
|
||||
|
||||
Supplemental information for GDB:
|
||||
|
||||
o Please try to run the relevant testsuite before and after
|
||||
committing a patch
|
||||
|
||||
If the contributor doesn't do it then the maintainer will. A
|
||||
contributor might include before/after test results in their
|
||||
contribution.
|
||||
|
||||
|
||||
o For bug fixes, please try to include a way of
|
||||
demonstrating that the patch actually fixes something.
|
||||
|
||||
The best way of doing this is to ensure that the
|
||||
testsuite contains one or more test cases that
|
||||
fail without the fix but pass with the fix.
|
||||
|
||||
People are encouraged to submit patches that extend
|
||||
the testsuite.
|
||||
|
||||
|
||||
o Please read your patch before submitting it.
|
||||
|
||||
A patch containing several unrelated changes or
|
||||
arbitrary reformats will be returned with a request
|
||||
to re-formatting / split it.
|
||||
|
||||
|
||||
o If ``gdb/configure.in'' is modified then you don't
|
||||
need to include patches to the regenerated file
|
||||
``configure''.
|
||||
|
||||
The maintainer will re-generate those files
|
||||
using autoconf (2.13 as of 2000-02-29).
|
||||
|
||||
|
||||
o If ``gdb/gdbarch.sh'' is modified, you don't
|
||||
need to include patches to the generated files
|
||||
``gdbarch.h'' and ``gdbarch.c''.
|
||||
|
||||
See ``gdb/configure.in'' above.
|
||||
|
||||
|
||||
o When submitting a patch that fixes a bug
|
||||
in GDB's bug database a brief reference
|
||||
to the bug can be included in the ChangeLog
|
||||
vis
|
||||
|
||||
* CONTRIBUTE: Mention PR convention.
|
||||
Fix PR gdb/4705.
|
||||
|
||||
The text ``PR gdb/4705'' should also be included
|
||||
in the CVS commit message. That causes the
|
||||
patch to automatically be archived with the PR.
|
||||
342
gdb/COPYING
342
gdb/COPYING
@@ -1,342 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, 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) 19yy <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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, 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) 19yy 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.
|
||||
1567
gdb/ChangeLog
1567
gdb/ChangeLog
File diff suppressed because it is too large
Load Diff
3155
gdb/ChangeLog-1990
3155
gdb/ChangeLog-1990
File diff suppressed because it is too large
Load Diff
5175
gdb/ChangeLog-1991
5175
gdb/ChangeLog-1991
File diff suppressed because it is too large
Load Diff
6285
gdb/ChangeLog-1992
6285
gdb/ChangeLog-1992
File diff suppressed because it is too large
Load Diff
7597
gdb/ChangeLog-1993
7597
gdb/ChangeLog-1993
File diff suppressed because it is too large
Load Diff
5705
gdb/ChangeLog-1994
5705
gdb/ChangeLog-1994
File diff suppressed because it is too large
Load Diff
4915
gdb/ChangeLog-1995
4915
gdb/ChangeLog-1995
File diff suppressed because it is too large
Load Diff
5116
gdb/ChangeLog-1996
5116
gdb/ChangeLog-1996
File diff suppressed because it is too large
Load Diff
2909
gdb/ChangeLog-1997
2909
gdb/ChangeLog-1997
File diff suppressed because it is too large
Load Diff
7220
gdb/ChangeLog-1998
7220
gdb/ChangeLog-1998
File diff suppressed because it is too large
Load Diff
9296
gdb/ChangeLog-1999
9296
gdb/ChangeLog-1999
File diff suppressed because it is too large
Load Diff
8204
gdb/ChangeLog-2000
8204
gdb/ChangeLog-2000
File diff suppressed because it is too large
Load Diff
9895
gdb/ChangeLog-2001
9895
gdb/ChangeLog-2001
File diff suppressed because it is too large
Load Diff
15039
gdb/ChangeLog-2002
15039
gdb/ChangeLog-2002
File diff suppressed because it is too large
Load Diff
15447
gdb/ChangeLog-2003
15447
gdb/ChangeLog-2003
File diff suppressed because it is too large
Load Diff
15227
gdb/ChangeLog-2004
15227
gdb/ChangeLog-2004
File diff suppressed because it is too large
Load Diff
6743
gdb/ChangeLog-2005
6743
gdb/ChangeLog-2005
File diff suppressed because it is too large
Load Diff
4838
gdb/ChangeLog-3.x
4838
gdb/ChangeLog-3.x
File diff suppressed because it is too large
Load Diff
582
gdb/MAINTAINERS
582
gdb/MAINTAINERS
@@ -1,582 +0,0 @@
|
||||
GDB Maintainers
|
||||
===============
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
This file describes different groups of people who are, together, the
|
||||
maintainers and developers of the GDB project. Don't worry - it sounds
|
||||
more complicated than it really is.
|
||||
|
||||
There are four groups of GDB developers, covering the patch development and
|
||||
review process:
|
||||
|
||||
- The Global Maintainers.
|
||||
|
||||
These are the developers in charge of most daily development. They
|
||||
have wide authority to apply and reject patches, but defer to the
|
||||
Responsible Maintainers (see below) within their spheres of
|
||||
responsibility.
|
||||
|
||||
- The Responsible Maintainers.
|
||||
|
||||
These are developers who have expertise and interest in a particular
|
||||
area of GDB, who are generally available to review patches, and who
|
||||
prefer to enforce a single vision within their areas.
|
||||
|
||||
- The Authorized Committers.
|
||||
|
||||
These are developers who are trusted to make changes within a specific
|
||||
area of GDB without additional oversight.
|
||||
|
||||
- The Write After Approval Maintainers.
|
||||
|
||||
These are developers who have write access to the GDB source tree. They
|
||||
can check in their own changes once a developer with the appropriate
|
||||
authority has approved the changes; they can also apply the Obvious
|
||||
Fix Rule (below).
|
||||
|
||||
All maintainers are encouraged to post major patches to the gdb-patches
|
||||
mailing list for comments, even if they have the authority to commit the
|
||||
patch without review from another maintainer. This especially includes
|
||||
patches which change internal interfaces (e.g. global functions, data
|
||||
structures) or external interfaces (e.g. user, remote, MI, et cetera).
|
||||
|
||||
The term "review" is used in this file to describe several kinds of feedback
|
||||
from a maintainer: approval, rejection, and requests for changes or
|
||||
clarification with the intention of approving a revised version. Review is
|
||||
a privilege and/or responsibility of various positions among the GDB
|
||||
Maintainers. Of course, anyone - whether they hold a position but not the
|
||||
relevant one for a particular patch, or are just following along on the
|
||||
mailing lists for fun, or anything in between - may suggest changes or
|
||||
ask questions about a patch!
|
||||
|
||||
There's also a couple of other people who play special roles in the GDB
|
||||
community, separately from the patch process:
|
||||
|
||||
- The GDB Steering Committee.
|
||||
|
||||
These are the official (FSF-appointed) maintainers of GDB. They have
|
||||
final and overriding authority for all GDB-related decisions, including
|
||||
anything described in this file. The committee is not generally
|
||||
involved in day-to-day development (although its members may be, as
|
||||
individuals).
|
||||
|
||||
- The Release Manager.
|
||||
|
||||
This developer is in charge of making new releases of GDB.
|
||||
|
||||
- The Patch Champions.
|
||||
|
||||
These volunteers make sure that no contribution is overlooked or
|
||||
forgotten.
|
||||
|
||||
Most changes to the list of maintainers in this file are handled by
|
||||
consensus among the global maintainers and any other involved parties.
|
||||
In cases where consensus can not be reached, the global maintainers may
|
||||
ask the Steering Committee for a final decision.
|
||||
|
||||
|
||||
The Obvious Fix Rule
|
||||
--------------------
|
||||
|
||||
All maintainers listed in this file, including the Write After Approval
|
||||
developers, are allowed to check in obvious fixes.
|
||||
|
||||
An "obvious fix" means that there is no possibility that anyone will
|
||||
disagree with the change.
|
||||
|
||||
A good mental test is "will the person who hates my work the most be
|
||||
able to find fault with the change" - if so, then it's not obvious and
|
||||
needs to be posted first. :-)
|
||||
|
||||
Something like changing or bypassing an interface is _not_ an obvious
|
||||
fix, since such a change without discussion will result in
|
||||
instantaneous and loud complaints.
|
||||
|
||||
|
||||
GDB Steering Committee
|
||||
----------------------
|
||||
|
||||
The members of the GDB Steering Committee are the FSF-appointed
|
||||
maintainers of the GDB project.
|
||||
|
||||
The Steering Committee has final authority for all GDB-related topics;
|
||||
they may make whatever changes that they deem necessary, or that the FSF
|
||||
requests. However, they are generally not involved in day-to-day
|
||||
development.
|
||||
|
||||
The current members of the steering committee are listed below, in
|
||||
alphabetical order. Their affiliations are provided for reference only -
|
||||
their membership on the Steering Committee is individual and not through
|
||||
their affiliation, and they act on behalf of the GNU project.
|
||||
|
||||
Jim Blandy (CodeSourcery)
|
||||
Andrew Cagney (Red Hat)
|
||||
Robert Dewar (AdaCore, NYU)
|
||||
Klee Dienes (Apple)
|
||||
Paul Hilfinger (UC Berkeley)
|
||||
Dan Jacobowitz (CodeSourcery)
|
||||
Stan Shebs (Apple)
|
||||
Richard Stallman (FSF)
|
||||
Ian Lance Taylor (C2)
|
||||
Todd Whitesel
|
||||
|
||||
|
||||
Global Maintainers
|
||||
------------------
|
||||
|
||||
The global maintainers may review and commit any change to GDB, except in
|
||||
areas with a Responsible Maintainer available. For major changes, or
|
||||
changes to areas with other active developers, global maintainers are
|
||||
strongly encouraged to post their own patches for feedback before
|
||||
committing.
|
||||
|
||||
The global maintainers are responsible for reviewing patches to any area
|
||||
for which no Responsible Maintainer is listed.
|
||||
|
||||
Global maintainers also have the authority to revert patches which should
|
||||
not have been applied, e.g. patches which were not approved, controversial
|
||||
patches committed under the Obvious Fix Rule, patches with important bugs
|
||||
that can't be immediately fixed, or patches which go against an accepted and
|
||||
documented roadmap for GDB development. Any global maintainer may request
|
||||
the reversion of a patch. If no global maintainer, or responsible
|
||||
maintainer in the affected areas, supports the patch (except for the
|
||||
maintainer who originally committed it), then after 48 hours the maintainer
|
||||
who called for the reversion may revert the patch.
|
||||
|
||||
No one may reapply a reverted patch without the agreement of the maintainer
|
||||
who reverted it, or bringing the issue to the GDB Steering Committee for
|
||||
discussion.
|
||||
|
||||
At the moment there are no documented roadmaps for GDB development; in the
|
||||
future, if there are, a reference to the list will be included here.
|
||||
|
||||
The current global maintainers are (in alphabetical order):
|
||||
|
||||
Jim Blandy jimb@codesourcery.com
|
||||
Kevin Buettner kevinb@redhat.com
|
||||
Andrew Cagney cagney@gnu.org
|
||||
Fred Fish fnf@ninemoons.com
|
||||
Daniel Jacobowitz dan@debian.org
|
||||
Mark Kettenis kettenis@gnu.org
|
||||
Stan Shebs shebs@apple.com
|
||||
Michael Snyder msnyder@redhat.com
|
||||
Elena Zannoni ezannoni@redhat.com
|
||||
Eli Zaretskii eliz@gnu.org
|
||||
|
||||
|
||||
Release Manager
|
||||
---------------
|
||||
|
||||
The current release manager is: Joel Brobecker <brobecker@adacore.com>
|
||||
|
||||
His responsibilities are:
|
||||
|
||||
* organizing, scheduling, and managing releases of GDB.
|
||||
|
||||
* deciding the approval and commit policies for release branches,
|
||||
and can change them as needed.
|
||||
|
||||
|
||||
|
||||
Patch Champions
|
||||
---------------
|
||||
|
||||
These volunteers track all patches submitted to the gdb-patches list. They
|
||||
endeavor to prevent any posted patch from being overlooked; work with
|
||||
contributors to meet GDB's coding style and general requirements, along with
|
||||
FSF copyright assignments; remind (ping) responsible maintainers to review
|
||||
patches; and ensure that contributors are given credit.
|
||||
|
||||
Current patch champions (in alphabetical order):
|
||||
|
||||
Daniel Jacobowitz <dan@debian.org>
|
||||
|
||||
|
||||
|
||||
Responsible Maintainers
|
||||
-----------------------
|
||||
|
||||
These developers have agreed to review patches in specific areas of GDB, in
|
||||
which they have knowledge and experience. These areas are generally broad;
|
||||
the role of a responsible maintainer is to provide coherent and cohesive
|
||||
structure within their area of GDB, to assure that patches from many
|
||||
different contributors all work together for the best results.
|
||||
|
||||
Global maintainers will defer to responsible maintainers within their areas,
|
||||
as long as the responsible maintainer is active. Active means that
|
||||
responsible maintainers agree to review submitted patches in their area
|
||||
promptly; patches and followups should generally be answered within a week.
|
||||
If a responsible maintainer is interested in reviewing a patch but will not
|
||||
have time within a week of posting, the maintainer should send an
|
||||
acknowledgement of the patch to the gdb-patches mailing list, and
|
||||
plan to follow up with a review within a month. These deadlines are for
|
||||
initial responses to a patch - if the maintainer has suggestions
|
||||
or questions, it may take an extended discussion before the patch
|
||||
is ready to commit. There are no written requirements for discussion,
|
||||
but maintainers are asked to be responsive.
|
||||
|
||||
If a responsible maintainer misses these deadlines occasionally (e.g.
|
||||
vacation or unexpected workload), it's not a disaster - any global
|
||||
maintainer may step in to review the patch. But sometimes life intervenes
|
||||
more permanently, and a maintainer may no longer have time for these duties.
|
||||
When this happens, he or she should step down (either into the Authorized
|
||||
Committers section if still interested in the area, or simply removed from
|
||||
the list of Responsible Maintainers if not).
|
||||
|
||||
If a responsible maintainer is unresponsive for an extended period of time
|
||||
without stepping down, please contact the Global Maintainers; they will try
|
||||
to contact the maintainer directly and fix the problem - potentially by
|
||||
removing that maintainer from their listed position.
|
||||
|
||||
If there are several maintainers for a given domain then any one of them
|
||||
may review a submitted patch.
|
||||
|
||||
Target Instruction Set Architectures:
|
||||
|
||||
The *-tdep.c files. ISA (Instruction Set Architecture) and OS-ABI
|
||||
(Operating System / Application Binary Interface) issues including CPU
|
||||
variants.
|
||||
|
||||
The Target/Architecture maintainer works with the host maintainer when
|
||||
resolving build issues. The Target/Architecture maintainer works with
|
||||
the native maintainer when resolving ABI issues.
|
||||
|
||||
alpha --target=alpha-elf ,-Werror
|
||||
|
||||
arm --target=arm-elf ,-Werror
|
||||
Richard Earnshaw rearnsha@arm.com
|
||||
|
||||
avr --target=avr ,-Werror
|
||||
|
||||
cris --target=cris-elf ,-Werror
|
||||
|
||||
d10v OBSOLETE
|
||||
|
||||
frv --target=frv-elf ,-Werror
|
||||
|
||||
h8300 --target=h8300-elf ,-Werror
|
||||
|
||||
i386 --target=i386-elf ,-Werror
|
||||
Mark Kettenis kettenis@gnu.org
|
||||
|
||||
ia64 --target=ia64-linux-gnu ,-Werror
|
||||
(--target=ia64-elf broken)
|
||||
|
||||
m32r --target=m32r-elf ,-Werror
|
||||
|
||||
m68hc11 --target=m68hc11-elf ,-Werror ,
|
||||
Stephane Carrez stcarrez@nerim.fr
|
||||
|
||||
m68k --target=m68k-elf ,-Werror
|
||||
|
||||
m88k --target=m88k-openbsd ,-Werror
|
||||
Mark Kettenis kettenis@gnu.org
|
||||
|
||||
mcore Deleted
|
||||
|
||||
mips --target=mips-elf ,-Werror
|
||||
|
||||
mn10300 --target=mn10300-elf broken
|
||||
(sim/ dies with make -j)
|
||||
Michael Snyder msnyder@redhat.com
|
||||
|
||||
ms1 --target=ms1-elf ,-Werror
|
||||
Kevin Buettner kevinb@redhat.com
|
||||
|
||||
ns32k Deleted
|
||||
|
||||
pa --target=hppa-elf ,-Werror
|
||||
|
||||
powerpc --target=powerpc-eabi ,-Werror
|
||||
|
||||
s390 --target=s390-linux-gnu ,-Werror
|
||||
|
||||
sh --target=sh-elf ,-Werror
|
||||
--target=sh64-elf ,-Werror
|
||||
|
||||
sparc --target=sparc-elf ,-Werror
|
||||
|
||||
v850 --target=v850-elf ,-Werror
|
||||
|
||||
vax --target=vax-netbsd ,-Werror
|
||||
|
||||
x86-64 --target=x86_64-linux-gnu ,-Werror
|
||||
|
||||
xstormy16 --target=xstormy16-elf
|
||||
Corinna Vinschen vinschen@redhat.com
|
||||
|
||||
All developers recognized by this file can make arbitrary changes to
|
||||
OBSOLETE targets.
|
||||
|
||||
The Bourne shell script gdb_mbuild.sh can be used to rebuild all the
|
||||
above targets.
|
||||
|
||||
|
||||
Host/Native:
|
||||
|
||||
The Native maintainer is responsible for target specific native
|
||||
support - typically shared libraries and quirks to procfs/ptrace/...
|
||||
The Native maintainer works with the Arch and Core maintainers when
|
||||
resolving more generic problems.
|
||||
|
||||
The host maintainer ensures that gdb can be built as a cross debugger on
|
||||
their platform.
|
||||
|
||||
AIX Joel Brobecker brobecker@adacore.com
|
||||
|
||||
djgpp native Eli Zaretskii eliz@gnu.org
|
||||
MS Windows (NT, '00, 9x, Me, XP) host & native
|
||||
Chris Faylor cgf@alum.bu.edu
|
||||
GNU/Linux/x86 native & host
|
||||
Mark Kettenis kettenis@gnu.org
|
||||
GNU/Linux MIPS native & host
|
||||
Daniel Jacobowitz dan@debian.org
|
||||
GNU/Linux m68k Andreas Schwab schwab@suse.de
|
||||
FreeBSD native & host Mark Kettenis kettenis@gnu.org
|
||||
|
||||
|
||||
|
||||
Core: Generic components used by all of GDB
|
||||
|
||||
tracing Michael Snyder msnyder@redhat.com
|
||||
threads Michael Snyder msnyder@redhat.com
|
||||
Mark Kettenis kettenis@gnu.org
|
||||
language support
|
||||
C++ Daniel Jacobowitz dan@debian.org
|
||||
Objective C support Adam Fedor fedor@gnu.org
|
||||
shared libs Kevin Buettner kevinb@redhat.com
|
||||
|
||||
documentation Eli Zaretskii eliz@gnu.org
|
||||
testsuite
|
||||
gdbtk (gdb.gdbtk) Keith Seitz keiths@redhat.com
|
||||
threads (gdb.threads) Michael Snyder msnyder@redhat.com
|
||||
trace (gdb.trace) Michael Snyder msnyder@redhat.com
|
||||
|
||||
|
||||
UI: External (user) interfaces.
|
||||
|
||||
gdbtk (c & tcl) Fernando Nasser fnasser@redhat.com
|
||||
Keith Seitz keiths@redhat.com
|
||||
libgui (w/foundry, sn) Keith Seitz keiths@redhat.com
|
||||
|
||||
|
||||
Misc:
|
||||
|
||||
gdb/gdbserver Daniel Jacobowitz dan@debian.org
|
||||
|
||||
Makefile.in, configure* ALL
|
||||
|
||||
mmalloc/ ALL Host maintainers
|
||||
|
||||
NEWS ALL
|
||||
|
||||
sim/ See sim/MAINTAINERS
|
||||
|
||||
readline/ Master version: ftp://ftp.cwru.edu/pub/bash/
|
||||
ALL
|
||||
Host maintainers (host dependant parts)
|
||||
(but get your changes into the master version)
|
||||
|
||||
tcl/ tk/ itcl/ ALL
|
||||
|
||||
|
||||
Authorized Committers
|
||||
---------------------
|
||||
|
||||
These are developers working on particular areas of GDB, who are trusted to
|
||||
commit their own (or other developers') patches in those areas without
|
||||
further review from a Global Maintainer or Responsible Maintainer. They are
|
||||
under no obligation to review posted patches - but, of course, are invited
|
||||
to do so!
|
||||
|
||||
PowerPC Andrew Cagney cagney@gnu.org
|
||||
CRIS Hans-Peter Nilsson hp@bitrange.com
|
||||
IA64 Jeff Johnston jjohnstn@redhat.com
|
||||
MIPS Joel Brobecker brobecker@adacore.com
|
||||
m32r Kei Sakamoto sakamoto.kei@renesas.com
|
||||
PowerPC Kevin Buettner kevinb@redhat.com
|
||||
CRIS Orjan Friberg orjanf@axis.com
|
||||
HPPA Randolph Chung tausq@debian.org
|
||||
S390 Ulrich Weigand uweigand@de.ibm.com
|
||||
djgpp DJ Delorie dj@delorie.com
|
||||
[Please use this address to contact DJ about DJGPP]
|
||||
tui Stephane Carrez stcarrez@nerim.fr
|
||||
ia64 Kevin Buettner kevinb@redhat.com
|
||||
AIX Kevin Buettner kevinb@redhat.com
|
||||
GNU/Linux PPC native Kevin Buettner kevinb@redhat.com
|
||||
gdb.java tests Anthony Green green@redhat.com
|
||||
FreeBSD native & host David O'Brien obrien@freebsd.org
|
||||
event loop Elena Zannoni ezannoni@redhat.com
|
||||
generic symtabs Elena Zannoni ezannoni@redhat.com
|
||||
dwarf readers Elena Zannoni ezannoni@redhat.com
|
||||
elf reader Elena Zannoni ezannoni@redhat.com
|
||||
stabs reader Elena Zannoni ezannoni@redhat.com
|
||||
readline/ Elena Zannoni ezannoni@redhat.com
|
||||
Kernel Object Display Fernando Nasser fnasser@redhat.com
|
||||
NetBSD native & host Jason Thorpe thorpej@netbsd.org
|
||||
Pascal support Pierre Muller muller@sources.redhat.com
|
||||
avr Theodore A. Roth troth@openavr.org
|
||||
|
||||
|
||||
Write After Approval
|
||||
(alphabetic)
|
||||
|
||||
To get recommended for the Write After Approval list you need a valid
|
||||
FSF assignment and have submitted one good patch.
|
||||
|
||||
David Anderson davea@sgi.com
|
||||
John David Anglin dave.anglin@nrc-cnrc.gc.ca
|
||||
Shrinivas Atre shrinivasa@kpitcummins.com
|
||||
Scott Bambrough scottb@netwinder.org
|
||||
Jan Beulich jbeulich@novell.com
|
||||
Jim Blandy jimb@codesourcery.com
|
||||
Philip Blundell philb@gnu.org
|
||||
Per Bothner per@bothner.com
|
||||
Joel Brobecker brobecker@adacore.com
|
||||
Dave Brolley brolley@redhat.com
|
||||
Paul Brook paul@codesourcery.com
|
||||
Kevin Buettner kevinb@redhat.com
|
||||
Andrew Cagney cagney@gnu.org
|
||||
David Carlton carlton@bactrian.org
|
||||
Stephane Carrez stcarrez@nerim.fr
|
||||
Michael Chastain mec.gnu@mindspring.com
|
||||
Eric Christopher echristo@apple.com
|
||||
Randolph Chung tausq@debian.org
|
||||
Nick Clifton nickc@redhat.com
|
||||
J.T. Conklin jtc@acorntoolworks.com
|
||||
Brendan Conoboy blc@redhat.com
|
||||
DJ Delorie dj@redhat.com
|
||||
Philippe De Muyter phdm@macqel.be
|
||||
Dhananjay Deshpande dhananjayd@kpitcummins.com
|
||||
Klee Dienes kdienes@apple.com
|
||||
Richard Earnshaw rearnsha@arm.com
|
||||
Steve Ellcey sje@cup.hp.com
|
||||
Frank Ch. Eigler fche@redhat.com
|
||||
Ben Elliston bje@gnu.org
|
||||
Adam Fedor fedor@gnu.org
|
||||
Fred Fish fnf@ninemoons.com
|
||||
Brian Ford ford@vss.fsi.com
|
||||
Orjan Friberg orjanf@axis.com
|
||||
Paul Gilliam pgilliam@us.ibm.com
|
||||
Raoul Gough RaoulGough@yahoo.co.uk
|
||||
Anthony Green green@redhat.com
|
||||
Matthew Green mrg@eterna.com.au
|
||||
Jerome Guitton guitton@act-europe.fr
|
||||
Ben Harris bjh21@netbsd.org
|
||||
Richard Henderson rth@redhat.com
|
||||
Aldy Hernandez aldyh@redhat.com
|
||||
Paul Hilfinger hilfinger@gnat.com
|
||||
Matt Hiller hiller@redhat.com
|
||||
Kazu Hirata kazu@cs.umass.edu
|
||||
Jeff Holcomb jeffh@redhat.com
|
||||
Don Howard dhoward@redhat.com
|
||||
Martin Hunt hunt@redhat.com
|
||||
Jim Ingham jingham@apple.com
|
||||
Baurzhan Ismagulov ibr@radix50.net
|
||||
Manoj Iyer manjo@austin.ibm.com
|
||||
Daniel Jacobowitz dan@debian.org
|
||||
Andreas Jaeger aj@suse.de
|
||||
Jeff Johnston jjohnstn@redhat.com
|
||||
Geoff Keating geoffk@redhat.com
|
||||
Mark Kettenis kettenis@gnu.org
|
||||
Jim Kingdon kingdon@panix.com
|
||||
Jonathan Larmour jlarmour@redhat.co.uk
|
||||
Jeff Law law@redhat.com
|
||||
David Lecomber david@streamline-computing.com
|
||||
Robert Lipe rjl@sco.com
|
||||
H.J. Lu hjl@lucon.org
|
||||
Michal Ludvig mludvig@suse.cz
|
||||
Glen McCready gkm@redhat.com
|
||||
Greg McGary greg@mcgary.org
|
||||
Roland McGrath roland@redhat.com
|
||||
Bryce McKinlay mckinlay@redhat.com
|
||||
Jason Merrill jason@redhat.com
|
||||
David S. Miller davem@redhat.com
|
||||
Mark Mitchell mark@codesourcery.com
|
||||
Marko Mlinar markom@opencores.org
|
||||
Alan Modra amodra@bigpond.net.au
|
||||
Jason Molenda jmolenda@apple.com
|
||||
Pierre Muller muller@sources.redhat.com
|
||||
Joseph Myers joseph@codesourcery.com
|
||||
Fernando Nasser fnasser@redhat.com
|
||||
Nathanael Nerode neroden@gcc.gnu.org
|
||||
Hans-Peter Nilsson hp@bitrange.com
|
||||
David O'Brien obrien@freebsd.org
|
||||
Alexandre Oliva aoliva@redhat.com
|
||||
Ramana Radhakrishnan ramana.radhakrishnan@codito.com
|
||||
Frederic Riss frederic.riss@st.com
|
||||
Tom Rix trix@redhat.com
|
||||
Nick Roberts nickrob@snap.net.nz
|
||||
Bob Rossi bob_rossi@cox.net
|
||||
Theodore A. Roth troth@openavr.org
|
||||
Ian Roxborough irox@redhat.com
|
||||
Grace Sainsbury graces@redhat.com
|
||||
Kei Sakamoto sakamoto.kei@renesas.com
|
||||
Mark Salter msalter@redhat.com
|
||||
Richard Sandiford richard@codesourcery.com
|
||||
Peter Schauer Peter.Schauer@mytum.de
|
||||
Andreas Schwab schwab@suse.de
|
||||
Keith Seitz keiths@redhat.com
|
||||
Stan Shebs shebs@apple.com
|
||||
Aidan Skinner aidan@velvet.net
|
||||
Jiri Smid smid@suse.cz
|
||||
David Smith dsmith@redhat.com
|
||||
Stephen P. Smith ischis2@cox.net
|
||||
Jackie Smith Cashion jsmith@redhat.com
|
||||
Michael Snyder msnyder@redhat.com
|
||||
Petr Sorfa petrs@caldera.com
|
||||
Andrew Stubbs andrew.stubbs@st.com
|
||||
Ian Lance Taylor ian@airs.com
|
||||
Gary Thomas gthomas@redhat.com
|
||||
Jason Thorpe thorpej@netbsd.org
|
||||
Tom Tromey tromey@redhat.com
|
||||
David Ung davidu@mips.com
|
||||
D Venkatasubramanian dvenkat@noida.hcltech.com
|
||||
Corinna Vinschen vinschen@redhat.com
|
||||
Keith Walker keith.walker@arm.com
|
||||
Kris Warkentin kewarken@qnx.com
|
||||
Ulrich Weigand uweigand@de.ibm.com
|
||||
Nathan Williams nathanw@wasabisystems.com
|
||||
Jim Wilson wilson@specifixinc.com
|
||||
Elena Zannoni ezannoni@redhat.com
|
||||
Eli Zaretskii eliz@gnu.org
|
||||
Wu Zhou woodzltc@cn.ibm.com
|
||||
Yoshinori Sato ysato@users.sourceforge.jp
|
||||
|
||||
|
||||
Past Maintainers
|
||||
|
||||
Whenever removing yourself, or someone else, from this file, consider
|
||||
listing their areas of development here for posterity.
|
||||
|
||||
Jimmy Guo (gdb.hp, tui) guo at cup dot hp dot com
|
||||
Jeff Law (hppa) law at cygnus dot com
|
||||
Daniel Berlin (C++ support) dan at cgsoftware dot com
|
||||
Nick Duffek (powerpc, SCO, Sol/x86) nick at duffek dot com
|
||||
David Taylor (d10v, sparc, utils, defs,
|
||||
expression evaluator, language support) taylor at candd dot org
|
||||
J.T. Conklin (dcache, NetBSD, remote, global) jtc at acorntoolworks dot com
|
||||
Frank Ch. Eigler (sim) fche at redhat dot com
|
||||
Per Bothner (Java) per at bothner dot com
|
||||
Anthony Green (Java) green at redhat dot com
|
||||
Fernando Nasser (testsuite/, mi, cli) fnasser at redhat dot com
|
||||
Mark Salter (testsuite/lib+config) msalter at redhat dot com
|
||||
Jim Kingdon (web pages) kingdon at panix dot com
|
||||
Jim Ingham (gdbtk, libgui) jingham at apple dot com
|
||||
Mark Kettenis (hurd native) kettenis at gnu dot org
|
||||
Ian Roxborough (in-tree tcl, tk, itcl) irox at redhat dot com
|
||||
Robert Lipe (SCO/Unixware) rjl at sco dot com
|
||||
Peter Schauer (global, AIX, xcoffsolib,
|
||||
Solaris/x86) Peter.Schauer at mytum dot de
|
||||
Scott Bambrough (ARM) scottb at netwinder dot org
|
||||
Philippe De Muyter (coff) phdm at macqel dot be
|
||||
Michael Chastain (testsuite) mec.gnu at mindspring dot com
|
||||
|
||||
|
||||
|
||||
Folks that have been caught up in a paper trail:
|
||||
|
||||
David Carlton carlton@bactrian.org
|
||||
3152
gdb/Makefile.in
3152
gdb/Makefile.in
File diff suppressed because it is too large
Load Diff
100
gdb/PROBLEMS
100
gdb/PROBLEMS
@@ -1,100 +0,0 @@
|
||||
|
||||
Known problems in GDB 6.3
|
||||
|
||||
See also: http://www.gnu.org/software/gdb/bugs/
|
||||
|
||||
|
||||
*** Build problems
|
||||
|
||||
build/1411: build fails on hpux 10.20 and hpux 11.00 with CMA threads
|
||||
|
||||
GDB does not build on HP/UX 10.20 or HP/UX 11.00 if the CMA
|
||||
thread package is installed. The compile error is:
|
||||
|
||||
../../gdb/hpux-thread.c:222: variable-size type declared outside of any function
|
||||
|
||||
This happens only if the CMA thread package is installed.
|
||||
|
||||
As a workaround, you can disable support for CMA threads
|
||||
by editing the file gdb/configure. Find the line:
|
||||
|
||||
if test -f /usr/include/dce/cma_config.h ; then
|
||||
|
||||
And replace it with:
|
||||
|
||||
if false ; then
|
||||
|
||||
*** Misc
|
||||
|
||||
gdb/1560: Control-C does not always interrupt GDB.
|
||||
|
||||
When GDB is busy processing a command which takes a long time to
|
||||
complete, hitting Control-C does not have the expected effect.
|
||||
The command execution is not aborted, and the "QUIT" message confirming
|
||||
the abortion is displayed only after the command has been completed.
|
||||
|
||||
*** C++ support
|
||||
|
||||
gdb/931: GDB could be more generous when reading types C++ templates on input
|
||||
|
||||
When the user types a template, GDB frequently requires the type to be
|
||||
typed in a certain way (e.g. "const char*" as opposed to "const char *"
|
||||
or "char const *" or "char const*").
|
||||
|
||||
gdb/1512: no canonical way to output names of C++ types
|
||||
|
||||
We currently don't have any canonical way to output names of C++ types.
|
||||
E.g. "const char *" versus "char const *"; more subtleties arise when
|
||||
dealing with templates.
|
||||
|
||||
gdb/1516: [regression] local classes, gcc 2.95.3, dwarf-2
|
||||
|
||||
With gcc 2.95.3 and the dwarf-2 debugging format, classes which are
|
||||
defined locally to a function include the demangled name of the function
|
||||
as part of their name. For example, if a function "foobar" contains a
|
||||
local class definition "Local", gdb will say that the name of the class
|
||||
type is "foobar__Fi.0:Local".
|
||||
|
||||
This applies only to classes where the class type is defined inside a
|
||||
function, not to variables defined with types that are defined somewhere
|
||||
outside any function (which most types are).
|
||||
|
||||
gdb/1588: names of c++ nested types in casts must be enclosed in quotes
|
||||
|
||||
You must type
|
||||
(gdb) print ('Foo::Bar') x
|
||||
or
|
||||
(gdb) print ('Foo::Bar' *) y
|
||||
instead of
|
||||
(gdb) print (Foo::Bar) x
|
||||
or
|
||||
(gdb) print (Foo::Bar *) y
|
||||
respectively.
|
||||
|
||||
gdb/1091: Constructor breakpoints ignored
|
||||
gdb/1193: g++ 3.3 creates multiple constructors: gdb 5.3 can't set breakpoints
|
||||
|
||||
When gcc 3.x compiles a C++ constructor or C++ destructor, it generates
|
||||
2 or 3 different versions of the object code. These versions have
|
||||
unique mangled names (they have to, in order for linking to work), but
|
||||
they have identical source code names, which leads to a great deal of
|
||||
confusion. Specifically, if you set a breakpoint in a constructor or a
|
||||
destructor, gdb will put a breakpoint in one of the versions, but your
|
||||
program may execute the other version. This makes it impossible to set
|
||||
breakpoints reliably in constructors or destructors.
|
||||
|
||||
gcc 3.x generates these multiple object code functions in order to
|
||||
implement virtual base classes. gcc 2.x generated just one object code
|
||||
function with a hidden parameter, but gcc 3.x conforms to a multi-vendor
|
||||
ABI for C++ which requires multiple object code functions.
|
||||
|
||||
*** Threads
|
||||
|
||||
threads/1650: manythreads.exp
|
||||
|
||||
On GNU/Linux systems that use the old LinuxThreads thread library, a
|
||||
program rapidly creating and deleting threads can confuse GDB leading
|
||||
to an internal error.
|
||||
|
||||
This problem does not occur on newer systems that use the NPTL
|
||||
library, and did not occur with GDB 6.1.
|
||||
560
gdb/README
560
gdb/README
@@ -1,560 +0,0 @@
|
||||
README for gdb-6.3 release
|
||||
Updated 8, November, 2004 by Andrew Cagney
|
||||
|
||||
This is GDB, the GNU source-level debugger.
|
||||
|
||||
A summary of new features is in the file `gdb/NEWS'.
|
||||
|
||||
Check the GDB home page at http://www.gnu.org/software/gdb/ for up to
|
||||
date release information, mailing list links and archives, etc.
|
||||
|
||||
The file `gdb/PROBLEMS' contains information on problems identified
|
||||
late in the release cycle. GDB's bug tracking data base at
|
||||
http://www.gnu.org/software/gdb/bugs/ contains a more complete list of
|
||||
bugs.
|
||||
|
||||
|
||||
Unpacking and Installation -- quick overview
|
||||
==========================
|
||||
|
||||
In this release, the GDB debugger sources, the generic GNU include
|
||||
files, the BFD ("binary file description") library, the readline
|
||||
library, and other libraries all have directories of their own
|
||||
underneath the gdb-6.3 directory. The idea is that a variety of GNU
|
||||
tools can share a common copy of these things. Be aware of variation
|
||||
over time--for example don't try to build gdb with a copy of bfd from
|
||||
a release other than the gdb release (such as a binutils release),
|
||||
especially if the releases are more than a few weeks apart.
|
||||
Configuration scripts and makefiles exist to cruise up and down this
|
||||
directory tree and automatically build all the pieces in the right
|
||||
order.
|
||||
|
||||
When you unpack the gdb-6.3.tar.gz file, you'll find a directory
|
||||
called `gdb-6.3', which contains:
|
||||
|
||||
COPYING config-ml.in gettext.m4 ltconfig sim
|
||||
COPYING.LIB config.guess include ltmain.sh src-release
|
||||
Makefile.def config.sub install-sh md5.sum symlink-tree
|
||||
Makefile.in configure libiberty missing texinfo
|
||||
Makefile.tpl configure.in libtool.m4 mkinstalldirs ylwrap
|
||||
README djunpack.bat ltcf-c.sh move-if-change
|
||||
bfd etc ltcf-cxx.sh opcodes
|
||||
config gdb ltcf-gcj.sh readline
|
||||
|
||||
You can build GDB right in the source directory:
|
||||
|
||||
cd gdb-6.3
|
||||
./configure
|
||||
make
|
||||
cp gdb/gdb /usr/local/bin/gdb (or wherever you want)
|
||||
|
||||
However, we recommend that an empty directory be used instead.
|
||||
This way you do not clutter your source tree with binary files
|
||||
and will be able to create different builds with different
|
||||
configuration options.
|
||||
|
||||
You can build GDB in any empty build directory:
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
<full path to your sources>/gdb-6.3/configure
|
||||
make
|
||||
cp gdb/gdb /usr/local/bin/gdb (or wherever you want)
|
||||
|
||||
(Building GDB with DJGPP tools for MS-DOS/MS-Windows is slightly
|
||||
different; see the file gdb-6.3/gdb/config/djgpp/README for details.)
|
||||
|
||||
This will configure and build all the libraries as well as GDB. If
|
||||
`configure' can't determine your system type, specify one as its
|
||||
argument, e.g., `./configure sun4' or `./configure decstation'.
|
||||
|
||||
Make sure that your 'configure' line ends in 'gdb-6.3/configure':
|
||||
|
||||
/berman/migchain/source/gdb-6.3/configure # RIGHT
|
||||
/berman/migchain/source/gdb-6.3/gdb/configure # WRONG
|
||||
|
||||
The gdb package contains several subdirectories, such as 'gdb',
|
||||
'bfd', and 'readline'. If your 'configure' line ends in
|
||||
'gdb-6.3/gdb/configure', then you are configuring only the gdb
|
||||
subdirectory, not the whole gdb package. This leads to build errors
|
||||
such as:
|
||||
|
||||
make: *** No rule to make target `../bfd/bfd.h', needed by `gdb.o'. Stop.
|
||||
|
||||
If you get other compiler errors during this stage, see the `Reporting
|
||||
Bugs' section below; there are a few known problems.
|
||||
|
||||
GDB requires an ISO C (ANSI C) compiler. If you do not have an ISO
|
||||
C compiler for your system, you may be able to download and install
|
||||
the GNU CC compiler. It is available via anonymous FTP from the
|
||||
directory `ftp://ftp.gnu.org/pub/gnu/gcc'.
|
||||
|
||||
GDB can be used as a cross-debugger, running on a machine of one
|
||||
type while debugging a program running on a machine of another type.
|
||||
See below.
|
||||
|
||||
|
||||
More Documentation
|
||||
******************
|
||||
|
||||
All the documentation for GDB comes as part of the machine-readable
|
||||
distribution. The documentation is written in Texinfo format, which
|
||||
is a documentation system that uses a single source file to produce
|
||||
both on-line information and a printed manual. You can use one of the
|
||||
Info formatting commands to create the on-line version of the
|
||||
documentation and TeX (or `texi2roff') to typeset the printed version.
|
||||
|
||||
GDB includes an already formatted copy of the on-line Info version
|
||||
of this manual in the `gdb/doc' subdirectory. The main Info file is
|
||||
`gdb-6.3/gdb/doc/gdb.info', and it refers to subordinate files
|
||||
matching `gdb.info*' in the same directory. If necessary, you can
|
||||
print out these files, or read them with any editor; but they are
|
||||
easier to read using the `info' subsystem in GNU Emacs or the
|
||||
standalone `info' program, available as part of the GNU Texinfo
|
||||
distribution.
|
||||
|
||||
If you want to format these Info files yourself, you need one of the
|
||||
Info formatting programs, such as `texinfo-format-buffer' or
|
||||
`makeinfo'.
|
||||
|
||||
If you have `makeinfo' installed, and are in the top level GDB
|
||||
source directory (`gdb-6.3', in the case of version 6.3), you can make
|
||||
the Info file by typing:
|
||||
|
||||
cd gdb/doc
|
||||
make info
|
||||
|
||||
If you want to typeset and print copies of this manual, you need
|
||||
TeX, a program to print its DVI output files, and `texinfo.tex', the
|
||||
Texinfo definitions file. This file is included in the GDB
|
||||
distribution, in the directory `gdb-6.3/texinfo'.
|
||||
|
||||
TeX is a typesetting program; it does not print files directly, but
|
||||
produces output files called DVI files. To print a typeset document,
|
||||
you need a program to print DVI files. If your system has TeX
|
||||
installed, chances are it has such a program. The precise command to
|
||||
use depends on your system; `lpr -d' is common; another (for PostScript
|
||||
devices) is `dvips'. The DVI print command may require a file name
|
||||
without any extension or a `.dvi' extension.
|
||||
|
||||
TeX also requires a macro definitions file called `texinfo.tex'.
|
||||
This file tells TeX how to typeset a document written in Texinfo
|
||||
format. On its own, TeX cannot read, much less typeset a Texinfo file.
|
||||
`texinfo.tex' is distributed with GDB and is located in the
|
||||
`gdb-6.3/texinfo' directory.
|
||||
|
||||
If you have TeX and a DVI printer program installed, you can typeset
|
||||
and print this manual. First switch to the the `gdb' subdirectory of
|
||||
the main source directory (for example, to `gdb-6.3/gdb') and then type:
|
||||
|
||||
make doc/gdb.dvi
|
||||
|
||||
If you prefer to have the manual in PDF format, type this from the
|
||||
`gdb/doc' subdirectory of the main source directory:
|
||||
|
||||
make gdb.pdf
|
||||
|
||||
For this to work, you will need the PDFTeX package to be installed.
|
||||
|
||||
|
||||
Installing GDB
|
||||
**************
|
||||
|
||||
GDB comes with a `configure' script that automates the process of
|
||||
preparing GDB for installation; you can then use `make' to build the
|
||||
`gdb' program.
|
||||
|
||||
The GDB distribution includes all the source code you need for GDB in
|
||||
a single directory, whose name is usually composed by appending the
|
||||
version number to `gdb'.
|
||||
|
||||
For example, the GDB version 6.3 distribution is in the `gdb-6.3'
|
||||
directory. That directory contains:
|
||||
|
||||
`gdb-6.3/{COPYING,COPYING.LIB}'
|
||||
Standard GNU license files. Please read them.
|
||||
|
||||
`gdb-6.3/bfd'
|
||||
source for the Binary File Descriptor library
|
||||
|
||||
`gdb-6.3/config*'
|
||||
script for configuring GDB, along with other support files
|
||||
|
||||
`gdb-6.3/gdb'
|
||||
the source specific to GDB itself
|
||||
|
||||
`gdb-6.3/include'
|
||||
GNU include files
|
||||
|
||||
`gdb-6.3/libiberty'
|
||||
source for the `-liberty' free software library
|
||||
|
||||
`gdb-6.3/opcodes'
|
||||
source for the library of opcode tables and disassemblers
|
||||
|
||||
`gdb-6.3/readline'
|
||||
source for the GNU command-line interface
|
||||
NOTE: The readline library is compiled for use by GDB, but will
|
||||
not be installed on your system when "make install" is issued.
|
||||
|
||||
`gdb-6.3/sim'
|
||||
source for some simulators (ARM, D10V, SPARC, M32R, MIPS, PPC, V850, etc)
|
||||
|
||||
`gdb-6.3/texinfo'
|
||||
The `texinfo.tex' file, which you need in order to make a printed
|
||||
manual using TeX.
|
||||
|
||||
`gdb-6.3/etc'
|
||||
Coding standards, useful files for editing GDB, and other
|
||||
miscellanea.
|
||||
|
||||
Note: the following instructions are for building GDB on Unix or
|
||||
Unix-like systems. Instructions for building with DJGPP for
|
||||
MS-DOS/MS-Windows are in the file gdb/config/djgpp/README.
|
||||
|
||||
The simplest way to configure and build GDB is to run `configure'
|
||||
from the `gdb-VERSION-NUMBER' source directory, which in this example
|
||||
is the `gdb-6.3' directory.
|
||||
|
||||
First switch to the `gdb-VERSION-NUMBER' source directory if you are
|
||||
not already in it; then run `configure'.
|
||||
|
||||
For example:
|
||||
|
||||
cd gdb-6.3
|
||||
./configure
|
||||
make
|
||||
|
||||
Running `configure' followed by `make' builds the `bfd',
|
||||
`readline', `mmalloc', and `libiberty' libraries, then `gdb' itself.
|
||||
The configured source files, and the binaries, are left in the
|
||||
corresponding source directories.
|
||||
|
||||
`configure' is a Bourne-shell (`/bin/sh') script; if your system
|
||||
does not recognize this automatically when you run a different shell,
|
||||
you may need to run `sh' on it explicitly:
|
||||
|
||||
sh configure
|
||||
|
||||
If you run `configure' from a directory that contains source
|
||||
directories for multiple libraries or programs, such as the `gdb-6.3'
|
||||
source directory for version 6.3, `configure' creates configuration
|
||||
files for every directory level underneath (unless you tell it not to,
|
||||
with the `--norecursion' option).
|
||||
|
||||
You can run the `configure' script from any of the subordinate
|
||||
directories in the GDB distribution, if you only want to configure that
|
||||
subdirectory; but be sure to specify a path to it.
|
||||
|
||||
For example, with version 6.3, type the following to configure only
|
||||
the `bfd' subdirectory:
|
||||
|
||||
cd gdb-6.3/bfd
|
||||
../configure
|
||||
|
||||
You can install `gdb' anywhere; it has no hardwired paths. However,
|
||||
you should make sure that the shell on your path (named by the `SHELL'
|
||||
environment variable) is publicly readable. Remember that GDB uses the
|
||||
shell to start your program--some systems refuse to let GDB debug child
|
||||
processes whose programs are not readable.
|
||||
|
||||
|
||||
Compiling GDB in another directory
|
||||
==================================
|
||||
|
||||
If you want to run GDB versions for several host or target machines,
|
||||
you need a different `gdb' compiled for each combination of host and
|
||||
target. `configure' is designed to make this easy by allowing you to
|
||||
generate each configuration in a separate subdirectory, rather than in
|
||||
the source directory. If your `make' program handles the `VPATH'
|
||||
feature correctly (GNU `make' and SunOS 'make' are two that should),
|
||||
running `make' in each of these directories builds the `gdb' program
|
||||
specified there.
|
||||
|
||||
To build `gdb' in a separate directory, run `configure' with the
|
||||
`--srcdir' option to specify where to find the source. (You also need
|
||||
to specify a path to find `configure' itself from your working
|
||||
directory. If the path to `configure' would be the same as the
|
||||
argument to `--srcdir', you can leave out the `--srcdir' option; it
|
||||
will be assumed.)
|
||||
|
||||
For example, with version 6.3, you can build GDB in a separate
|
||||
directory for a Sun 4 like this:
|
||||
|
||||
cd gdb-6.3
|
||||
mkdir ../gdb-sun4
|
||||
cd ../gdb-sun4
|
||||
../gdb-6.3/configure
|
||||
make
|
||||
|
||||
When `configure' builds a configuration using a remote source
|
||||
directory, it creates a tree for the binaries with the same structure
|
||||
(and using the same names) as the tree under the source directory. In
|
||||
the example, you'd find the Sun 4 library `libiberty.a' in the
|
||||
directory `gdb-sun4/libiberty', and GDB itself in `gdb-sun4/gdb'.
|
||||
|
||||
One popular reason to build several GDB configurations in separate
|
||||
directories is to configure GDB for cross-compiling (where GDB runs on
|
||||
one machine--the host--while debugging programs that run on another
|
||||
machine--the target). You specify a cross-debugging target by giving
|
||||
the `--target=TARGET' option to `configure'.
|
||||
|
||||
When you run `make' to build a program or library, you must run it
|
||||
in a configured directory--whatever directory you were in when you
|
||||
called `configure' (or one of its subdirectories).
|
||||
|
||||
The `Makefile' that `configure' generates in each source directory
|
||||
also runs recursively. If you type `make' in a source directory such
|
||||
as `gdb-6.3' (or in a separate configured directory configured with
|
||||
`--srcdir=PATH/gdb-6.3'), you will build all the required libraries,
|
||||
and then build GDB.
|
||||
|
||||
When you have multiple hosts or targets configured in separate
|
||||
directories, you can run `make' on them in parallel (for example, if
|
||||
they are NFS-mounted on each of the hosts); they will not interfere
|
||||
with each other.
|
||||
|
||||
|
||||
Specifying names for hosts and targets
|
||||
======================================
|
||||
|
||||
The specifications used for hosts and targets in the `configure'
|
||||
script are based on a three-part naming scheme, but some short
|
||||
predefined aliases are also supported. The full naming scheme encodes
|
||||
three pieces of information in the following pattern:
|
||||
|
||||
ARCHITECTURE-VENDOR-OS
|
||||
|
||||
For example, you can use the alias `sun4' as a HOST argument or in a
|
||||
`--target=TARGET' option. The equivalent full name is
|
||||
`sparc-sun-sunos4'.
|
||||
|
||||
The `configure' script accompanying GDB does not provide any query
|
||||
facility to list all supported host and target names or aliases.
|
||||
`configure' calls the Bourne shell script `config.sub' to map
|
||||
abbreviations to full names; you can read the script, if you wish, or
|
||||
you can use it to test your guesses on abbreviations--for example:
|
||||
|
||||
% sh config.sub sun4
|
||||
sparc-sun-sunos4.1.1
|
||||
% sh config.sub sun3
|
||||
m68k-sun-sunos4.1.1
|
||||
% sh config.sub decstation
|
||||
mips-dec-ultrix4.2
|
||||
% sh config.sub hp300bsd
|
||||
m68k-hp-bsd
|
||||
% sh config.sub i386v
|
||||
i386-pc-sysv
|
||||
% sh config.sub i786v
|
||||
Invalid configuration `i786v': machine `i786v' not recognized
|
||||
|
||||
`config.sub' is also distributed in the GDB source directory
|
||||
(`gdb-6.3', for version 6.3).
|
||||
|
||||
|
||||
`configure' options
|
||||
===================
|
||||
|
||||
Here is a summary of the `configure' options and arguments that are
|
||||
most often useful for building GDB. `configure' also has several other
|
||||
options not listed here. *note : (configure.info)What Configure Does,
|
||||
for a full explanation of `configure'.
|
||||
|
||||
configure [--help]
|
||||
[--prefix=DIR]
|
||||
[--srcdir=PATH]
|
||||
[--norecursion] [--rm]
|
||||
[--enable-build-warnings]
|
||||
[--target=TARGET]
|
||||
[--host=HOST]
|
||||
[HOST]
|
||||
|
||||
You may introduce options with a single `-' rather than `--' if you
|
||||
prefer; but you may abbreviate option names if you use `--'.
|
||||
|
||||
`--help'
|
||||
Display a quick summary of how to invoke `configure'.
|
||||
|
||||
`-prefix=DIR'
|
||||
Configure the source to install programs and files under directory
|
||||
`DIR'.
|
||||
|
||||
`--srcdir=PATH'
|
||||
*Warning: using this option requires GNU `make', or another `make'
|
||||
that compatibly implements the `VPATH' feature.*
|
||||
Use this option to make configurations in directories separate
|
||||
from the GDB source directories. Among other things, you can use
|
||||
this to build (or maintain) several configurations simultaneously,
|
||||
in separate directories. `configure' writes configuration
|
||||
specific files in the current directory, but arranges for them to
|
||||
use the source in the directory PATH. `configure' will create
|
||||
directories under the working directory in parallel to the source
|
||||
directories below PATH.
|
||||
|
||||
`--norecursion'
|
||||
Configure only the directory level where `configure' is executed;
|
||||
do not propagate configuration to subdirectories.
|
||||
|
||||
`--rm'
|
||||
Remove the configuration that the other arguments specify.
|
||||
|
||||
`--enable-build-warnings'
|
||||
When building the GDB sources, ask the compiler to warn about any
|
||||
code which looks even vaguely suspicious. You should only using
|
||||
this feature if you're compiling with GNU CC. It passes the
|
||||
following flags:
|
||||
-Wimplicit
|
||||
-Wreturn-type
|
||||
-Wcomment
|
||||
-Wtrigraphs
|
||||
-Wformat
|
||||
-Wparentheses
|
||||
-Wpointer-arith
|
||||
|
||||
`--target=TARGET'
|
||||
Configure GDB for cross-debugging programs running on the specified
|
||||
TARGET. Without this option, GDB is configured to debug programs
|
||||
that run on the same machine (HOST) as GDB itself.
|
||||
|
||||
There is no convenient way to generate a list of all available
|
||||
targets.
|
||||
|
||||
`--host=HOST'
|
||||
Configure GDB to run on the specified HOST.
|
||||
|
||||
There is no convenient way to generate a list of all available
|
||||
hosts.
|
||||
|
||||
`HOST ...'
|
||||
Same as `--host=HOST'. If you omit this, GDB will guess; it's
|
||||
quite accurate.
|
||||
|
||||
`configure' accepts other options, for compatibility with configuring
|
||||
other GNU tools recursively; but these are the only options that affect
|
||||
GDB or its supporting libraries.
|
||||
|
||||
|
||||
Remote debugging
|
||||
=================
|
||||
|
||||
The files m68k-stub.c, i386-stub.c, and sparc-stub.c are examples
|
||||
of remote stubs to be used with remote.c. They are designed to run
|
||||
standalone on an m68k, i386, or SPARC cpu and communicate properly
|
||||
with the remote.c stub over a serial line.
|
||||
|
||||
The directory gdb/gdbserver/ contains `gdbserver', a program that
|
||||
allows remote debugging for Unix applications. gdbserver is only
|
||||
supported for some native configurations, including Sun 3, Sun 4, and
|
||||
Linux.
|
||||
|
||||
There are a number of remote interfaces for talking to existing ROM
|
||||
monitors and other hardware:
|
||||
|
||||
remote-e7000.c Renesas E7000 ICE
|
||||
remote-est.c EST emulator
|
||||
remote-hms.c Renesas Micro Systems H8/300 monitor
|
||||
remote-mips.c MIPS remote debugging protocol
|
||||
remote-rdp.c ARM with Demon monitor
|
||||
remote-sds.c PowerPC SDS monitor
|
||||
remote-sim.c Generalized simulator protocol
|
||||
remote-st.c Tandem ST-2000 monitor
|
||||
remote-vx.c VxWorks realtime kernel
|
||||
|
||||
Remote-vx.c and the vx-share subdirectory contain a remote
|
||||
interface for the VxWorks realtime kernel, which communicates over TCP
|
||||
using the Sun RPC library. This would be a useful starting point for
|
||||
other remote- via-ethernet back ends.
|
||||
|
||||
|
||||
Reporting Bugs in GDB
|
||||
=====================
|
||||
|
||||
There are several ways of reporting bugs in GDB. The prefered
|
||||
method is to use the World Wide Web:
|
||||
|
||||
http://www.gnu.org/software/gdb/bugs/
|
||||
|
||||
As an alternative, the bug report can be submitted, via e-mail, to the
|
||||
address "bug-gdb@gnu.org".
|
||||
|
||||
When submitting a bug, please include the GDB version number (e.g.,
|
||||
gdb-6.3), and how you configured it (e.g., "sun4" or "mach386 host,
|
||||
i586-intel-synopsys target"). Since GDB now supports so many
|
||||
different configurations, it is important that you be precise about
|
||||
this. If at all possible, you should include the actual banner that
|
||||
GDB prints when it starts up, or failing that, the actual configure
|
||||
command that you used when configuring GDB.
|
||||
|
||||
For more information on how/whether to report bugs, see the
|
||||
Reporting Bugs chapter of the GDB manual (gdb/doc/gdb.texinfo).
|
||||
|
||||
|
||||
Graphical interface to GDB -- X Windows, MS Windows
|
||||
==========================
|
||||
|
||||
Several graphical interfaces to GDB are available. You should
|
||||
check:
|
||||
|
||||
http://www.gnu.org/software/gdb/links/
|
||||
|
||||
for an up-to-date list.
|
||||
|
||||
Emacs users will very likely enjoy the Grand Unified Debugger mode;
|
||||
try typing `M-x gdb RET'.
|
||||
|
||||
|
||||
Writing Code for GDB
|
||||
=====================
|
||||
|
||||
There is a lot of information about writing code for GDB in the
|
||||
internals manual, distributed with GDB in gdb/doc/gdbint.texinfo. You
|
||||
can read it by hand, print it by using TeX and texinfo, or process it
|
||||
into an `info' file for use with Emacs' info mode or the standalone
|
||||
`info' program.
|
||||
|
||||
If you are pondering writing anything but a short patch, especially
|
||||
take note of the information about copyrights in the node Submitting
|
||||
Patches. It can take quite a while to get all the paperwork done, so
|
||||
we encourage you to start that process as soon as you decide you are
|
||||
planning to work on something, or at least well ahead of when you
|
||||
think you will be ready to submit the patches.
|
||||
|
||||
|
||||
GDB Testsuite
|
||||
=============
|
||||
|
||||
Included with the GDB distribution is a DejaGNU based testsuite
|
||||
that can either be used to test your newly built GDB, or for
|
||||
regression testing a GDB with local modifications.
|
||||
|
||||
Running the testsuite requires the prior installation of DejaGNU,
|
||||
which is generally available via ftp. The directory
|
||||
ftp://sources.redhat.com/pub/dejagnu/ will contain a recent snapshot.
|
||||
Once DejaGNU is installed, you can run the tests in one of the
|
||||
following ways:
|
||||
|
||||
(1) cd gdb-6.3
|
||||
make check-gdb
|
||||
|
||||
or
|
||||
|
||||
(2) cd gdb-6.3/gdb
|
||||
make check
|
||||
|
||||
or
|
||||
|
||||
(3) cd gdb-6.3/gdb/testsuite
|
||||
make site.exp (builds the site specific file)
|
||||
runtest -tool gdb GDB=../gdb (or GDB=<somepath> as appropriate)
|
||||
|
||||
The last method gives you slightly more control in case of problems
|
||||
with building one or more test executables or if you are using the
|
||||
testsuite `standalone', without it being part of the GDB source tree.
|
||||
|
||||
See the DejaGNU documentation for further details.
|
||||
|
||||
|
||||
(this is for editing this file with GNU emacs)
|
||||
Local Variables:
|
||||
mode: text
|
||||
End:
|
||||
182
gdb/abug-rom.c
182
gdb/abug-rom.c
@@ -1,182 +0,0 @@
|
||||
/* Remote debugging interface for ABug Rom monitor for GDB, the GNU debugger.
|
||||
Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
Written by Rob Savoye of Cygnus Support
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "monitor.h"
|
||||
#include "serial.h"
|
||||
#include "regcache.h"
|
||||
|
||||
#include "m68k-tdep.h"
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
|
||||
static void abug_open (char *args, int from_tty);
|
||||
|
||||
static void
|
||||
abug_supply_register (char *regname, int regnamelen, char *val, int vallen)
|
||||
{
|
||||
int regno;
|
||||
|
||||
if (regnamelen != 2)
|
||||
return;
|
||||
|
||||
switch (regname[0])
|
||||
{
|
||||
case 'S':
|
||||
if (regname[1] != 'R')
|
||||
return;
|
||||
regno = PS_REGNUM;
|
||||
break;
|
||||
case 'P':
|
||||
if (regname[1] != 'C')
|
||||
return;
|
||||
regno = PC_REGNUM;
|
||||
break;
|
||||
case 'D':
|
||||
if (regname[1] < '0' || regname[1] > '7')
|
||||
return;
|
||||
regno = regname[1] - '0' + M68K_D0_REGNUM;
|
||||
break;
|
||||
case 'A':
|
||||
if (regname[1] < '0' || regname[1] > '7')
|
||||
return;
|
||||
regno = regname[1] - '0' + M68K_A0_REGNUM;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_supply_register (regno, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* This array of registers needs to match the indexes used by GDB. The
|
||||
* whole reason this exists is because the various ROM monitors use
|
||||
* different names than GDB does, and don't support all the
|
||||
* registers either. So, typing "info reg sp" becomes an "A7".
|
||||
*/
|
||||
|
||||
static const char *
|
||||
abug_regname (int index)
|
||||
{
|
||||
static char *regnames[] =
|
||||
{
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
|
||||
"PC",
|
||||
};
|
||||
|
||||
if ((index >= (sizeof (regnames) / sizeof (regnames[0])))
|
||||
|| (index < 0) || (index >= NUM_REGS))
|
||||
return NULL;
|
||||
else
|
||||
return regnames[index];
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the monitor command strings. Since these are passed directly
|
||||
* through to a printf style function, we need can include formatting
|
||||
* strings. We also need a CR or LF on the end.
|
||||
*/
|
||||
|
||||
static struct target_ops abug_ops;
|
||||
|
||||
static char *abug_inits[] =
|
||||
{"\r", NULL};
|
||||
|
||||
static struct monitor_ops abug_cmds;
|
||||
|
||||
static void
|
||||
init_abug_cmds (void)
|
||||
{
|
||||
abug_cmds.flags = MO_CLR_BREAK_USES_ADDR;
|
||||
abug_cmds.init = abug_inits; /* Init strings */
|
||||
abug_cmds.cont = "g\r"; /* continue command */
|
||||
abug_cmds.step = "t\r"; /* single step */
|
||||
abug_cmds.stop = NULL; /* interrupt command */
|
||||
abug_cmds.set_break = "br %x\r"; /* set a breakpoint */
|
||||
abug_cmds.clr_break = "nobr %x\r"; /* clear a breakpoint */
|
||||
abug_cmds.clr_all_break = "nobr\r"; /* clear all breakpoints */
|
||||
abug_cmds.fill = "bf %x:%x %x;b\r"; /* fill (start count val) */
|
||||
abug_cmds.setmem.cmdb = "ms %x %02x\r"; /* setmem.cmdb (addr, value) */
|
||||
abug_cmds.setmem.cmdw = "ms %x %04x\r"; /* setmem.cmdw (addr, value) */
|
||||
abug_cmds.setmem.cmdl = "ms %x %08x\r"; /* setmem.cmdl (addr, value) */
|
||||
abug_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */
|
||||
abug_cmds.setmem.resp_delim = NULL; /* setreg.resp_delim */
|
||||
abug_cmds.setmem.term = NULL; /* setreg.term */
|
||||
abug_cmds.setmem.term_cmd = NULL; /* setreg.term_cmd */
|
||||
abug_cmds.getmem.cmdb = "md %x:%x;b\r"; /* getmem.cmdb (addr, len) */
|
||||
abug_cmds.getmem.cmdw = "md %x:%x;b\r"; /* getmem.cmdw (addr, len) */
|
||||
abug_cmds.getmem.cmdl = "md %x:%x;b\r"; /* getmem.cmdl (addr, len) */
|
||||
abug_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */
|
||||
abug_cmds.getmem.resp_delim = " "; /* getmem.resp_delim */
|
||||
abug_cmds.getmem.term = NULL; /* getmem.term */
|
||||
abug_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */
|
||||
abug_cmds.setreg.cmd = "rm %s %x\r"; /* setreg.cmd (name, value) */
|
||||
abug_cmds.setreg.resp_delim = "="; /* setreg.resp_delim */
|
||||
abug_cmds.setreg.term = "? "; /* setreg.term */
|
||||
abug_cmds.setreg.term_cmd = ".\r"; /* setreg.term_cmd */
|
||||
abug_cmds.getreg.cmd = "rm %s\r"; /* getreg.cmd (name) */
|
||||
abug_cmds.getreg.resp_delim = "="; /* getreg.resp_delim */
|
||||
abug_cmds.getreg.term = "? "; /* getreg.term */
|
||||
abug_cmds.getreg.term_cmd = ".\r"; /* getreg.term_cmd */
|
||||
abug_cmds.dump_registers = "rd\r"; /* dump_registers */
|
||||
abug_cmds.register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)"; /* register_pattern */
|
||||
abug_cmds.supply_register = abug_supply_register;
|
||||
abug_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */
|
||||
abug_cmds.load = "lo 0\r"; /* download command */
|
||||
abug_cmds.loadresp = "\n"; /* load response */
|
||||
abug_cmds.prompt = "135Bug>"; /* monitor command prompt */
|
||||
abug_cmds.line_term = "\r"; /* end-of-line terminator */
|
||||
abug_cmds.cmd_end = NULL; /* optional command terminator */
|
||||
abug_cmds.target = &abug_ops; /* target operations */
|
||||
abug_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */
|
||||
abug_cmds.regnames = NULL; /* registers names */
|
||||
abug_cmds.regname = abug_regname;
|
||||
abug_cmds.magic = MONITOR_OPS_MAGIC; /* magic */
|
||||
};
|
||||
|
||||
static void
|
||||
abug_open (char *args, int from_tty)
|
||||
{
|
||||
monitor_open (args, &abug_cmds, from_tty);
|
||||
}
|
||||
|
||||
extern initialize_file_ftype _initialize_abug_rom; /* -Wmissing-prototypes */
|
||||
|
||||
void
|
||||
_initialize_abug_rom (void)
|
||||
{
|
||||
init_abug_cmds ();
|
||||
init_monitor_ops (&abug_ops);
|
||||
|
||||
abug_ops.to_shortname = "abug";
|
||||
abug_ops.to_longname = _("ABug monitor");
|
||||
abug_ops.to_doc = _("Debug via the ABug monitor.\n\
|
||||
Specify the serial device it is connected to (e.g. /dev/ttya).");
|
||||
abug_ops.to_open = abug_open;
|
||||
|
||||
add_target (&abug_ops);
|
||||
}
|
||||
989
gdb/acinclude.m4
989
gdb/acinclude.m4
@@ -1,989 +0,0 @@
|
||||
dnl written by Rob Savoye <rob@cygnus.com> for Cygnus Support
|
||||
dnl major rewriting for Tcl 7.5 by Don Libes <libes@nist.gov>
|
||||
|
||||
dnl gdb/configure.in uses BFD_NEED_DECLARATION, so get its definition.
|
||||
sinclude(../bfd/bfd.m4)
|
||||
|
||||
dnl This gets the standard macros, like the TCL, TK, etc ones.
|
||||
sinclude(../config/acinclude.m4)
|
||||
|
||||
sinclude(../gettext.m4)
|
||||
dnl The lines below arrange for aclocal not to bring gettext.m4's
|
||||
dnl CY_GNU_GETTEXT into aclocal.m4.
|
||||
ifelse(yes,no,[
|
||||
AC_DEFUN([CY_GNU_GETTEXT],)
|
||||
])
|
||||
|
||||
dnl CYGNUS LOCAL: This gets the right posix flag for gcc
|
||||
AC_DEFUN([CY_AC_TCL_LYNX_POSIX],
|
||||
[AC_REQUIRE([AC_PROG_CC])AC_REQUIRE([AC_PROG_CPP])
|
||||
AC_MSG_CHECKING([if running LynxOS])
|
||||
AC_CACHE_VAL(ac_cv_os_lynx,
|
||||
[AC_EGREP_CPP(yes,
|
||||
[/*
|
||||
* The old Lynx "cc" only defines "Lynx", but the newer one uses "__Lynx__"
|
||||
*/
|
||||
#if defined(__Lynx__) || defined(Lynx)
|
||||
yes
|
||||
#endif
|
||||
], ac_cv_os_lynx=yes, ac_cv_os_lynx=no)])
|
||||
#
|
||||
if test "$ac_cv_os_lynx" = "yes" ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(LYNX)
|
||||
AC_MSG_CHECKING([whether -mposix or -X is available])
|
||||
AC_CACHE_VAL(ac_cv_c_posix_flag,
|
||||
[AC_TRY_COMPILE(,[
|
||||
/*
|
||||
* This flag varies depending on how old the compiler is.
|
||||
* -X is for the old "cc" and "gcc" (based on 1.42).
|
||||
* -mposix is for the new gcc (at least 2.5.8).
|
||||
*/
|
||||
#if defined(__GNUC__) && __GNUC__ >= 2
|
||||
choke me
|
||||
#endif
|
||||
], ac_cv_c_posix_flag=" -mposix", ac_cv_c_posix_flag=" -X")])
|
||||
CC="$CC $ac_cv_c_posix_flag"
|
||||
AC_MSG_RESULT($ac_cv_c_posix_flag)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
])
|
||||
|
||||
#
|
||||
# Sometimes the native compiler is a bogus stub for gcc or /usr/ucb/cc. This
|
||||
# makes configure think it's cross compiling. If --target wasn't used, then
|
||||
# we can't configure, so something is wrong. We don't use the cache
|
||||
# here cause if somebody fixes their compiler install, we want this to work.
|
||||
AC_DEFUN([CY_AC_C_WORKS],
|
||||
[# If we cannot compile and link a trivial program, we can't expect anything to work
|
||||
AC_MSG_CHECKING(whether the compiler ($CC) actually works)
|
||||
AC_TRY_COMPILE(, [/* don't need anything here */],
|
||||
c_compiles=yes, c_compiles=no)
|
||||
|
||||
AC_TRY_LINK(, [/* don't need anything here */],
|
||||
c_links=yes, c_links=no)
|
||||
|
||||
if test x"${c_compiles}" = x"no" ; then
|
||||
AC_MSG_ERROR(the native compiler is broken and won't compile.)
|
||||
fi
|
||||
|
||||
if test x"${c_links}" = x"no" ; then
|
||||
AC_MSG_ERROR(the native compiler is broken and won't link.)
|
||||
fi
|
||||
AC_MSG_RESULT(yes)
|
||||
])
|
||||
|
||||
AC_DEFUN([CY_AC_PATH_TCLH], [
|
||||
#
|
||||
# Ok, lets find the tcl source trees so we can use the headers
|
||||
# Warning: transition of version 9 to 10 will break this algorithm
|
||||
# because 10 sorts before 9. We also look for just tcl. We have to
|
||||
# be careful that we don't match stuff like tclX by accident.
|
||||
# the alternative search directory is involked by --with-tclinclude
|
||||
#
|
||||
|
||||
no_tcl=true
|
||||
AC_MSG_CHECKING(for Tcl private headers. dir=${configdir})
|
||||
AC_ARG_WITH(tclinclude, [ --with-tclinclude=DIR Directory where tcl private headers are], with_tclinclude=${withval})
|
||||
AC_CACHE_VAL(ac_cv_c_tclh,[
|
||||
# first check to see if --with-tclinclude was specified
|
||||
if test x"${with_tclinclude}" != x ; then
|
||||
if test -f ${with_tclinclude}/tclInt.h ; then
|
||||
ac_cv_c_tclh=`(cd ${with_tclinclude}; pwd)`
|
||||
elif test -f ${with_tclinclude}/generic/tclInt.h ; then
|
||||
ac_cv_c_tclh=`(cd ${with_tclinclude}/generic; pwd)`
|
||||
else
|
||||
AC_MSG_ERROR([${with_tclinclude} directory doesn't contain private headers])
|
||||
fi
|
||||
fi
|
||||
|
||||
# next check if it came with Tcl configuration file
|
||||
if test x"${ac_cv_c_tclconfig}" = x ; then
|
||||
if test -f $ac_cv_c_tclconfig/../generic/tclInt.h ; then
|
||||
ac_cv_c_tclh=`(cd $ac_cv_c_tclconfig/..; pwd)`
|
||||
fi
|
||||
fi
|
||||
|
||||
# next check in private source directory
|
||||
#
|
||||
# since ls returns lowest version numbers first, reverse its output
|
||||
if test x"${ac_cv_c_tclh}" = x ; then
|
||||
for i in \
|
||||
${srcdir}/../tcl \
|
||||
`ls -dr ${srcdir}/../tcl[[7-9]]* 2>/dev/null` \
|
||||
${srcdir}/../../tcl \
|
||||
`ls -dr ${srcdir}/../../tcl[[7-9]]* 2>/dev/null` \
|
||||
${srcdir}/../../../tcl \
|
||||
`ls -dr ${srcdir}/../../../tcl[[7-9]]* 2>/dev/null ` ; do
|
||||
if test -f $i/generic/tclInt.h ; then
|
||||
ac_cv_c_tclh=`(cd $i/generic; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# finally check in a few common install locations
|
||||
#
|
||||
# since ls returns lowest version numbers first, reverse its output
|
||||
if test x"${ac_cv_c_tclh}" = x ; then
|
||||
for i in \
|
||||
`ls -dr /usr/local/src/tcl[[7-9]]* 2>/dev/null` \
|
||||
`ls -dr /usr/local/lib/tcl[[7-9]]* 2>/dev/null` \
|
||||
/usr/local/src/tcl \
|
||||
/usr/local/lib/tcl \
|
||||
${prefix}/include ; do
|
||||
if test -f $i/generic/tclInt.h ; then
|
||||
ac_cv_c_tclh=`(cd $i/generic; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# see if one is installed
|
||||
if test x"${ac_cv_c_tclh}" = x ; then
|
||||
AC_HEADER_CHECK(tclInt.h, ac_cv_c_tclh=installed, ac_cv_c_tclh="")
|
||||
fi
|
||||
])
|
||||
if test x"${ac_cv_c_tclh}" = x ; then
|
||||
TCLHDIR="# no Tcl private headers found"
|
||||
AC_MSG_ERROR([Can't find Tcl private headers])
|
||||
fi
|
||||
if test x"${ac_cv_c_tclh}" != x ; then
|
||||
no_tcl=""
|
||||
if test x"${ac_cv_c_tclh}" = x"installed" ; then
|
||||
AC_MSG_RESULT([is installed])
|
||||
TCLHDIR=""
|
||||
else
|
||||
AC_MSG_RESULT([found in ${ac_cv_c_tclh}])
|
||||
# this hack is cause the TCLHDIR won't print if there is a "-I" in it.
|
||||
TCLHDIR="-I${ac_cv_c_tclh}"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(TCLHDIR)
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([CY_AC_PATH_TCLCONFIG], [
|
||||
#
|
||||
# Ok, lets find the tcl configuration
|
||||
# First, look for one uninstalled.
|
||||
# the alternative search directory is invoked by --with-tclconfig
|
||||
#
|
||||
|
||||
if test x"${no_tcl}" = x ; then
|
||||
# we reset no_tcl in case something fails here
|
||||
no_tcl=true
|
||||
AC_ARG_WITH(tclconfig, [ --with-tclconfig=DIR Directory containing tcl configuration (tclConfig.sh)],
|
||||
with_tclconfig=${withval})
|
||||
AC_MSG_CHECKING([for Tcl configuration])
|
||||
AC_CACHE_VAL(ac_cv_c_tclconfig,[
|
||||
|
||||
# First check to see if --with-tclconfig was specified.
|
||||
if test x"${with_tclconfig}" != x ; then
|
||||
if test -f "${with_tclconfig}/tclConfig.sh" ; then
|
||||
ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
|
||||
else
|
||||
AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh])
|
||||
fi
|
||||
fi
|
||||
|
||||
# then check for a private Tcl installation
|
||||
if test x"${ac_cv_c_tclconfig}" = x ; then
|
||||
for i in \
|
||||
../tcl \
|
||||
`ls -dr ../tcl[[7-9]]* 2>/dev/null` \
|
||||
../../tcl \
|
||||
`ls -dr ../../tcl[[7-9]]* 2>/dev/null` \
|
||||
../../../tcl \
|
||||
`ls -dr ../../../tcl[[7-9]]* 2>/dev/null` ; do
|
||||
if test -f "$i/${configdir}/tclConfig.sh" ; then
|
||||
ac_cv_c_tclconfig=`(cd $i/${configdir}; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# check in a few common install locations
|
||||
if test x"${ac_cv_c_tclconfig}" = x ; then
|
||||
for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
|
||||
if test -f "$i/tclConfig.sh" ; then
|
||||
ac_cv_c_tclconfig=`(cd $i; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# check in a few other private locations
|
||||
if test x"${ac_cv_c_tclconfig}" = x ; then
|
||||
for i in \
|
||||
${srcdir}/../tcl \
|
||||
`ls -dr ${srcdir}/../tcl[[7-9]]* 2>/dev/null` ; do
|
||||
if test -f "$i/${configdir}/tclConfig.sh" ; then
|
||||
ac_cv_c_tclconfig=`(cd $i/${configdir}; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
])
|
||||
if test x"${ac_cv_c_tclconfig}" = x ; then
|
||||
TCLCONFIG="# no Tcl configs found"
|
||||
AC_MSG_WARN(Can't find Tcl configuration definitions)
|
||||
else
|
||||
no_tcl=
|
||||
TCLCONFIG=${ac_cv_c_tclconfig}/tclConfig.sh
|
||||
AC_MSG_RESULT(found $TCLCONFIG)
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
# Defined as a separate macro so we don't have to cache the values
|
||||
# from PATH_TCLCONFIG (because this can also be cached).
|
||||
AC_DEFUN([CY_AC_LOAD_TCLCONFIG], [
|
||||
. $TCLCONFIG
|
||||
|
||||
AC_SUBST(TCL_VERSION)
|
||||
AC_SUBST(TCL_MAJOR_VERSION)
|
||||
AC_SUBST(TCL_MINOR_VERSION)
|
||||
AC_SUBST(TCL_CC)
|
||||
AC_SUBST(TCL_DEFS)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(TCL_LIB_FILE)
|
||||
|
||||
dnl don't export, not used outside of configure
|
||||
dnl AC_SUBST(TCL_LIBS)
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(TCL_PREFIX)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(TCL_EXEC_PREFIX)
|
||||
|
||||
AC_SUBST(TCL_SHLIB_CFLAGS)
|
||||
AC_SUBST(TCL_SHLIB_LD)
|
||||
dnl don't export, not used outside of configure
|
||||
AC_SUBST(TCL_SHLIB_LD_LIBS)
|
||||
AC_SUBST(TCL_SHLIB_SUFFIX)
|
||||
dnl not used, don't export to save symbols
|
||||
AC_SUBST(TCL_DL_LIBS)
|
||||
AC_SUBST(TCL_LD_FLAGS)
|
||||
dnl don't export, not used outside of configure
|
||||
AC_SUBST(TCL_LD_SEARCH_FLAGS)
|
||||
AC_SUBST(TCL_CC_SEARCH_FLAGS)
|
||||
AC_SUBST(TCL_COMPAT_OBJS)
|
||||
AC_SUBST(TCL_RANLIB)
|
||||
AC_SUBST(TCL_BUILD_LIB_SPEC)
|
||||
AC_SUBST(TCL_LIB_SPEC)
|
||||
AC_SUBST(TCL_LIB_VERSIONS_OK)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(TCL_SHARED_LIB_SUFFIX)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(TCL_UNSHARED_LIB_SUFFIX)
|
||||
])
|
||||
|
||||
# Warning: Tk definitions are very similar to Tcl definitions but
|
||||
# are not precisely the same. There are a couple of differences,
|
||||
# so don't do changes to Tcl thinking you can cut and paste it do
|
||||
# the Tk differences and later simply substitute "Tk" for "Tcl".
|
||||
# Known differences:
|
||||
# - Acceptable Tcl major version #s is 7-9 while Tk is 4-9
|
||||
# - Searching for Tcl includes looking for tclInt.h, Tk looks for tk.h
|
||||
# - Computing major/minor versions is different because Tk depends on
|
||||
# headers to Tcl, Tk, and X.
|
||||
# - Symbols in tkConfig.sh are different than tclConfig.sh
|
||||
# - Acceptable for Tk to be missing but not Tcl.
|
||||
|
||||
AC_DEFUN([CY_AC_PATH_TKH], [
|
||||
#
|
||||
# Ok, lets find the tk source trees so we can use the headers
|
||||
# If the directory (presumably symlink) named "tk" exists, use that one
|
||||
# in preference to any others. Same logic is used when choosing library
|
||||
# and again with Tcl. The search order is the best place to look first, then in
|
||||
# decreasing significance. The loop breaks if the trigger file is found.
|
||||
# Note the gross little conversion here of srcdir by cd'ing to the found
|
||||
# directory. This converts the path from a relative to an absolute, so
|
||||
# recursive cache variables for the path will work right. We check all
|
||||
# the possible paths in one loop rather than many seperate loops to speed
|
||||
# things up.
|
||||
# the alternative search directory is involked by --with-tkinclude
|
||||
#
|
||||
no_tk=true
|
||||
AC_MSG_CHECKING(for Tk private headers)
|
||||
AC_ARG_WITH(tkinclude, [ --with-tkinclude=DIR Directory where tk private headers are], with_tkinclude=${withval})
|
||||
AC_CACHE_VAL(ac_cv_c_tkh,[
|
||||
# first check to see if --with-tkinclude was specified
|
||||
if test x"${with_tkinclude}" != x ; then
|
||||
if test -f ${with_tkinclude}/tk.h ; then
|
||||
ac_cv_c_tkh=`(cd ${with_tkinclude}; pwd)`
|
||||
elif test -f ${with_tkinclude}/generic/tk.h ; then
|
||||
ac_cv_c_tkh=`(cd ${with_tkinclude}/generic; pwd)`
|
||||
else
|
||||
AC_MSG_ERROR([${with_tkinclude} directory doesn't contain private headers])
|
||||
fi
|
||||
fi
|
||||
|
||||
# next check if it came with Tk configuration file
|
||||
if test x"${ac_cv_c_tkconfig}" = x ; then
|
||||
if test -f $ac_cv_c_tkconfig/../generic/tk.h ; then
|
||||
ac_cv_c_tkh=`(cd $ac_cv_c_tkconfig/..; pwd)`
|
||||
fi
|
||||
fi
|
||||
|
||||
# next check in private source directory
|
||||
#
|
||||
# since ls returns lowest version numbers first, reverse its output
|
||||
if test x"${ac_cv_c_tkh}" = x ; then
|
||||
for i in \
|
||||
${srcdir}/../tk \
|
||||
`ls -dr ${srcdir}/../tk[[4-9]]* 2>/dev/null` \
|
||||
${srcdir}/../../tk \
|
||||
`ls -dr ${srcdir}/../../tk[[4-9]]* 2>/dev/null` \
|
||||
${srcdir}/../../../tk \
|
||||
`ls -dr ${srcdir}/../../../tk[[4-9]]* 2>/dev/null ` ; do
|
||||
if test -f $i/generic/tk.h ; then
|
||||
ac_cv_c_tkh=`(cd $i/generic; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# finally check in a few common install locations
|
||||
#
|
||||
# since ls returns lowest version numbers first, reverse its output
|
||||
if test x"${ac_cv_c_tkh}" = x ; then
|
||||
for i in \
|
||||
`ls -dr /usr/local/src/tk[[4-9]]* 2>/dev/null` \
|
||||
`ls -dr /usr/local/lib/tk[[4-9]]* 2>/dev/null` \
|
||||
/usr/local/src/tk \
|
||||
/usr/local/lib/tk \
|
||||
${prefix}/include ; do
|
||||
if test -f $i/generic/tk.h ; then
|
||||
ac_cv_c_tkh=`(cd $i/generic; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# see if one is installed
|
||||
if test x"${ac_cv_c_tkh}" = x ; then
|
||||
AC_HEADER_CHECK(tk.h, ac_cv_c_tkh=installed, ac_cv_c_tkh="")
|
||||
fi
|
||||
])
|
||||
if test x"${ac_cv_c_tkh}" != x ; then
|
||||
no_tk=""
|
||||
if test x"${ac_cv_c_tkh}" = x"installed" ; then
|
||||
AC_MSG_RESULT([is installed])
|
||||
TKHDIR=""
|
||||
else
|
||||
AC_MSG_RESULT([found in ${ac_cv_c_tkh}])
|
||||
# this hack is cause the TKHDIR won't print if there is a "-I" in it.
|
||||
TKHDIR="-I${ac_cv_c_tkh}"
|
||||
fi
|
||||
else
|
||||
TKHDIR="# no Tk directory found"
|
||||
AC_MSG_WARN([Can't find Tk private headers])
|
||||
no_tk=true
|
||||
fi
|
||||
|
||||
AC_SUBST(TKHDIR)
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([CY_AC_PATH_TKCONFIG], [
|
||||
#
|
||||
# Ok, lets find the tk configuration
|
||||
# First, look for one uninstalled.
|
||||
# the alternative search directory is invoked by --with-tkconfig
|
||||
#
|
||||
|
||||
if test x"${no_tk}" = x ; then
|
||||
# we reset no_tk in case something fails here
|
||||
no_tk=true
|
||||
AC_ARG_WITH(tkconfig, [ --with-tkconfig=DIR Directory containing tk configuration (tkConfig.sh)],
|
||||
with_tkconfig=${withval})
|
||||
AC_MSG_CHECKING([for Tk configuration])
|
||||
AC_CACHE_VAL(ac_cv_c_tkconfig,[
|
||||
|
||||
# First check to see if --with-tkconfig was specified.
|
||||
if test x"${with_tkconfig}" != x ; then
|
||||
if test -f "${with_tkconfig}/tkConfig.sh" ; then
|
||||
ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)`
|
||||
else
|
||||
AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh])
|
||||
fi
|
||||
fi
|
||||
|
||||
# then check for a private Tk library
|
||||
if test x"${ac_cv_c_tkconfig}" = x ; then
|
||||
for i in \
|
||||
../tk \
|
||||
`ls -dr ../tk[[4-9]]* 2>/dev/null` \
|
||||
../../tk \
|
||||
`ls -dr ../../tk[[4-9]]* 2>/dev/null` \
|
||||
../../../tk \
|
||||
`ls -dr ../../../tk[[4-9]]* 2>/dev/null` ; do
|
||||
if test -f "$i/${configdir}/tkConfig.sh" ; then
|
||||
ac_cv_c_tkconfig=`(cd $i/${configdir}; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# check in a few common install locations
|
||||
if test x"${ac_cv_c_tkconfig}" = x ; then
|
||||
for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
|
||||
if test -f "$i/tkConfig.sh" ; then
|
||||
ac_cv_c_tkconfig=`(cd $i; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# check in a few other private locations
|
||||
if test x"${ac_cv_c_tkconfig}" = x ; then
|
||||
for i in \
|
||||
${srcdir}/../tk \
|
||||
`ls -dr ${srcdir}/../tk[[4-9]]* 2>/dev/null` ; do
|
||||
if test -f "$i/${configdir}/tkConfig.sh" ; then
|
||||
ac_cv_c_tkconfig=`(cd $i/${configdir}; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
])
|
||||
if test x"${ac_cv_c_tkconfig}" = x ; then
|
||||
TKCONFIG="# no Tk configs found"
|
||||
AC_MSG_WARN(Can't find Tk configuration definitions)
|
||||
else
|
||||
no_tk=
|
||||
TKCONFIG=${ac_cv_c_tkconfig}/tkConfig.sh
|
||||
AC_MSG_RESULT(found $TKCONFIG)
|
||||
fi
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
# Defined as a separate macro so we don't have to cache the values
|
||||
# from PATH_TKCONFIG (because this can also be cached).
|
||||
AC_DEFUN([CY_AC_LOAD_TKCONFIG], [
|
||||
if test -f "$TKCONFIG" ; then
|
||||
. $TKCONFIG
|
||||
fi
|
||||
|
||||
AC_SUBST(TK_VERSION)
|
||||
dnl not actually used, don't export to save symbols
|
||||
dnl AC_SUBST(TK_MAJOR_VERSION)
|
||||
dnl AC_SUBST(TK_MINOR_VERSION)
|
||||
AC_SUBST(TK_DEFS)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(TK_LIB_FILE)
|
||||
|
||||
dnl not used outside of configure
|
||||
dnl AC_SUBST(TK_LIBS)
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(TK_PREFIX)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(TK_EXEC_PREFIX)
|
||||
|
||||
AC_SUBST(TK_BUILD_INCLUDES)
|
||||
AC_SUBST(TK_XINCLUDES)
|
||||
AC_SUBST(TK_XLIBSW)
|
||||
AC_SUBST(TK_BUILD_LIB_SPEC)
|
||||
AC_SUBST(TK_LIB_SPEC)
|
||||
])
|
||||
|
||||
# check for Itcl headers.
|
||||
|
||||
AC_DEFUN([CY_AC_PATH_ITCLCONFIG], [
|
||||
#
|
||||
# Ok, lets find the itcl configuration
|
||||
# First, look for one uninstalled.
|
||||
# the alternative search directory is invoked by --with-itclconfig
|
||||
#
|
||||
|
||||
if test x"${no_itcl}" = x ; then
|
||||
# we reset no_itcl in case something fails here
|
||||
no_itcl=true
|
||||
AC_ARG_WITH(itclconfig, [ --with-itclconfig Directory containing itcl configuration (itclConfig.sh)],
|
||||
with_itclconfig=${withval})
|
||||
AC_MSG_CHECKING([for Itcl configuration])
|
||||
AC_CACHE_VAL(ac_cv_c_itclconfig,[
|
||||
|
||||
# First check to see if --with-itclconfig was specified.
|
||||
if test x"${with_itclconfig}" != x ; then
|
||||
if test -f "${with_itclconfig}/itclConfig.sh" ; then
|
||||
ac_cv_c_itclconfig=`(cd ${with_itclconfig}; pwd)`
|
||||
else
|
||||
AC_MSG_ERROR([${with_itclconfig} directory doesn't contain itclConfig.sh])
|
||||
fi
|
||||
fi
|
||||
|
||||
# then check for a private Itcl library
|
||||
if test x"${ac_cv_c_itclconfig}" = x ; then
|
||||
for i in \
|
||||
../itcl/itcl \
|
||||
`ls -dr ../itcl[[4-9]]*/itcl 2>/dev/null` \
|
||||
../../itcl \
|
||||
`ls -dr ../../itcl[[4-9]]*/itcl 2>/dev/null` \
|
||||
../../../itcl \
|
||||
`ls -dr ../../../itcl[[4-9]]*/itcl 2>/dev/null` ; do
|
||||
if test -f "$i/itclConfig.sh" ; then
|
||||
ac_cv_c_itclconfig=`(cd $i; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# check in a few common install locations
|
||||
if test x"${ac_cv_c_itclconfig}" = x ; then
|
||||
for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
|
||||
if test -f "$i/itclConfig.sh" ; then
|
||||
ac_cv_c_itclconfig=`(cd $i; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# check in a few other private locations
|
||||
if test x"${ac_cv_c_itclconfig}" = x ; then
|
||||
for i in \
|
||||
${srcdir}/../itcl/itcl \
|
||||
`ls -dr ${srcdir}/../itcl[[4-9]]*/itcl 2>/dev/null` ; do
|
||||
if test -f "$i/itclConfig.sh" ; then
|
||||
ac_cv_c_itclconfig=`(cd $i; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
])
|
||||
if test x"${ac_cv_c_itclconfig}" = x ; then
|
||||
ITCLCONFIG="# no Itcl configs found"
|
||||
AC_MSG_WARN(Can't find Itcl configuration definitions)
|
||||
else
|
||||
no_itcl=
|
||||
ITCLCONFIG=${ac_cv_c_itclconfig}/itclConfig.sh
|
||||
AC_MSG_RESULT(found $ITCLCONFIG)
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
# Defined as a separate macro so we don't have to cache the values
|
||||
# from PATH_ITCLCONFIG (because this can also be cached).
|
||||
AC_DEFUN([CY_AC_LOAD_ITCLCONFIG], [
|
||||
if test -f "$ITCLCONFIG" ; then
|
||||
. $ITCLCONFIG
|
||||
fi
|
||||
|
||||
AC_SUBST(ITCL_VERSION)
|
||||
dnl not actually used, don't export to save symbols
|
||||
dnl AC_SUBST(ITCL_MAJOR_VERSION)
|
||||
dnl AC_SUBST(ITCL_MINOR_VERSION)
|
||||
AC_SUBST(ITCL_DEFS)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(ITCL_LIB_FILE)
|
||||
|
||||
dnl not used outside of configure
|
||||
dnl AC_SUBST(ITCL_LIBS)
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(ITCL_PREFIX)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(ITCL_EXEC_PREFIX)
|
||||
|
||||
AC_SUBST(ITCL_BUILD_INCLUDES)
|
||||
AC_SUBST(ITCL_BUILD_LIB_SPEC)
|
||||
AC_SUBST(ITCL_LIB_SPEC)
|
||||
])
|
||||
|
||||
# check for Itcl headers.
|
||||
|
||||
AC_DEFUN([CY_AC_PATH_ITCLH], [
|
||||
AC_MSG_CHECKING(for Itcl private headers. srcdir=${srcdir})
|
||||
if test x"${ac_cv_c_itclh}" = x ; then
|
||||
for i in ${srcdir}/../itcl ${srcdir}/../../itcl ${srcdir}/../../../itcl ${srcdir}/../itcl/itcl; do
|
||||
if test -f $i/generic/itcl.h ; then
|
||||
ac_cv_c_itclh=`(cd $i/generic; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test x"${ac_cv_c_itclh}" = x ; then
|
||||
ITCLHDIR="# no Itcl private headers found"
|
||||
AC_MSG_ERROR([Can't find Itcl private headers])
|
||||
fi
|
||||
if test x"${ac_cv_c_itclh}" != x ; then
|
||||
ITCLHDIR="-I${ac_cv_c_itclh}"
|
||||
fi
|
||||
# should always be here
|
||||
# ITCLLIB="../itcl/itcl/unix/libitcl.a"
|
||||
AC_SUBST(ITCLHDIR)
|
||||
#AC_SUBST(ITCLLIB)
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([CY_AC_PATH_ITKCONFIG], [
|
||||
#
|
||||
# Ok, lets find the itk configuration
|
||||
# First, look for one uninstalled.
|
||||
# the alternative search directory is invoked by --with-itkconfig
|
||||
#
|
||||
|
||||
if test x"${no_itk}" = x ; then
|
||||
# we reset no_itk in case something fails here
|
||||
no_itk=true
|
||||
AC_ARG_WITH(itkconfig, [ --with-itkconfig Directory containing itk configuration (itkConfig.sh)],
|
||||
with_itkconfig=${withval})
|
||||
AC_MSG_CHECKING([for Itk configuration])
|
||||
AC_CACHE_VAL(ac_cv_c_itkconfig,[
|
||||
|
||||
# First check to see if --with-itkconfig was specified.
|
||||
if test x"${with_itkconfig}" != x ; then
|
||||
if test -f "${with_itkconfig}/itkConfig.sh" ; then
|
||||
ac_cv_c_itkconfig=`(cd ${with_itkconfig}; pwd)`
|
||||
else
|
||||
AC_MSG_ERROR([${with_itkconfig} directory doesn't contain itkConfig.sh])
|
||||
fi
|
||||
fi
|
||||
|
||||
# then check for a private Itk library
|
||||
if test x"${ac_cv_c_itkconfig}" = x ; then
|
||||
for i in \
|
||||
../itcl/itk \
|
||||
`ls -dr ../itcl[[4-9]]*/itk 2>/dev/null` \
|
||||
../../itk \
|
||||
`ls -dr ../../itcl[[4-9]]*/itk 2>/dev/null` \
|
||||
../../../itk \
|
||||
`ls -dr ../../../itcl[[4-9]]*/itk 2>/dev/null` ; do
|
||||
if test -f "$i/itkConfig.sh" ; then
|
||||
ac_cv_c_itkconfig=`(cd $i; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# check in a few common install locations
|
||||
if test x"${ac_cv_c_itkconfig}" = x ; then
|
||||
for i in `ls -d ${prefix}/lib /usr/local/lib 2>/dev/null` ; do
|
||||
if test -f "$i/itkConfig.sh" ; then
|
||||
ac_cv_c_itkconfig=`(cd $i; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
# check in a few other private locations
|
||||
if test x"${ac_cv_c_itkconfig}" = x ; then
|
||||
for i in \
|
||||
${srcdir}/../itcl/itk \
|
||||
`ls -dr ${srcdir}/../itcl[[4-9]]*/itk 2>/dev/null` ; do
|
||||
if test -f "$i/itkConfig.sh" ; then
|
||||
ac_cv_c_itkconfig=`(cd $i; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
])
|
||||
if test x"${ac_cv_c_itkconfig}" = x ; then
|
||||
ITKCONFIG="# no Itk configs found"
|
||||
AC_MSG_WARN(Can't find Itk configuration definitions)
|
||||
else
|
||||
no_itk=
|
||||
ITKCONFIG=${ac_cv_c_itkconfig}/itkConfig.sh
|
||||
AC_MSG_RESULT(found $ITKCONFIG)
|
||||
fi
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
# Defined as a separate macro so we don't have to cache the values
|
||||
# from PATH_ITKCONFIG (because this can also be cached).
|
||||
AC_DEFUN([CY_AC_LOAD_ITKCONFIG], [
|
||||
if test -f "$ITKCONFIG" ; then
|
||||
. $ITKCONFIG
|
||||
fi
|
||||
|
||||
AC_SUBST(ITK_VERSION)
|
||||
dnl not actually used, don't export to save symbols
|
||||
dnl AC_SUBST(ITK_MAJOR_VERSION)
|
||||
dnl AC_SUBST(ITK_MINOR_VERSION)
|
||||
AC_SUBST(ITK_DEFS)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(ITK_LIB_FILE)
|
||||
|
||||
dnl not used outside of configure
|
||||
dnl AC_SUBST(ITK_LIBS)
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(ITK_PREFIX)
|
||||
|
||||
dnl not used, don't export to save symbols
|
||||
dnl AC_SUBST(ITK_EXEC_PREFIX)
|
||||
|
||||
AC_SUBST(ITK_BUILD_INCLUDES)
|
||||
AC_SUBST(ITK_BUILD_LIB_SPEC)
|
||||
AC_SUBST(ITK_LIB_SPEC)
|
||||
])
|
||||
|
||||
AC_DEFUN([CY_AC_PATH_ITKH], [
|
||||
AC_MSG_CHECKING(for Itk private headers. srcdir=${srcdir})
|
||||
if test x"${ac_cv_c_itkh}" = x ; then
|
||||
for i in ${srcdir}/../itcl ${srcdir}/../../itcl ${srcdir}/../../../itcl ${srcdir}/../itcl/itk; do
|
||||
if test -f $i/generic/itk.h ; then
|
||||
ac_cv_c_itkh=`(cd $i/generic; pwd)`
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test x"${ac_cv_c_itkh}" = x ; then
|
||||
ITKHDIR="# no Itk private headers found"
|
||||
AC_MSG_ERROR([Can't find Itk private headers])
|
||||
fi
|
||||
if test x"${ac_cv_c_itkh}" != x ; then
|
||||
ITKHDIR="-I${ac_cv_c_itkh}"
|
||||
fi
|
||||
# should always be here
|
||||
# ITKLIB="../itcl/itk/unix/libitk.a"
|
||||
AC_SUBST(ITKHDIR)
|
||||
#AC_SUBST(ITKLIB)
|
||||
])
|
||||
|
||||
|
||||
## ----------------------------------------- ##
|
||||
## ANSIfy the C compiler whenever possible. ##
|
||||
## From Franc,ois Pinard ##
|
||||
## ----------------------------------------- ##
|
||||
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
# 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, 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., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
# serial 1
|
||||
|
||||
# @defmac AC_PROG_CC_STDC
|
||||
# @maindex PROG_CC_STDC
|
||||
# @ovindex CC
|
||||
# If the C compiler in not in ANSI C mode by default, try to add an option
|
||||
# to output variable @code{CC} to make it so. This macro tries various
|
||||
# options that select ANSI C on some system or another. It considers the
|
||||
# compiler to be in ANSI C mode if it handles function prototypes correctly.
|
||||
#
|
||||
# If you use this macro, you should check after calling it whether the C
|
||||
# compiler has been set to accept ANSI C; if not, the shell variable
|
||||
# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source
|
||||
# code in ANSI C, you can make an un-ANSIfied copy of it by using the
|
||||
# program @code{ansi2knr}, which comes with Ghostscript.
|
||||
# @end defmac
|
||||
|
||||
AC_DEFUN([AM_PROG_CC_STDC],
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_BEFORE([$0], [AC_C_INLINE])
|
||||
AC_BEFORE([$0], [AC_C_CONST])
|
||||
dnl Force this before AC_PROG_CPP. Some cpp's, eg on HPUX, require
|
||||
dnl a magic option to avoid problems with ANSI preprocessor commands
|
||||
dnl like #elif.
|
||||
dnl FIXME: can't do this because then AC_AIX won't work due to a
|
||||
dnl circular dependency.
|
||||
dnl AC_BEFORE([$0], [AC_PROG_CPP])
|
||||
AC_MSG_CHECKING([for ${CC-cc} option to accept ANSI C])
|
||||
AC_CACHE_VAL(am_cv_prog_cc_stdc,
|
||||
[am_cv_prog_cc_stdc=no
|
||||
ac_save_CC="$CC"
|
||||
# Don't try gcc -ansi; that turns off useful extensions and
|
||||
# breaks some systems' header files.
|
||||
# AIX -qlanglvl=ansi
|
||||
# Ultrix and OSF/1 -std1
|
||||
# HP-UX 10.20 and later -Ae
|
||||
# HP-UX older versions -Aa -D_HPUX_SOURCE
|
||||
# SVR4 -Xc -D__EXTENSIONS__
|
||||
for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
|
||||
do
|
||||
CC="$ac_save_CC $ac_arg"
|
||||
AC_TRY_COMPILE(
|
||||
[#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
|
||||
struct buf { int x; };
|
||||
FILE * (*rcsopen) (struct buf *, struct stat *, int);
|
||||
static char *e (p, i)
|
||||
char **p;
|
||||
int i;
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
static char *f (char * (*g) (char **, int), char **p, ...)
|
||||
{
|
||||
char *s;
|
||||
va_list v;
|
||||
va_start (v,p);
|
||||
s = g (p, va_arg (v,int));
|
||||
va_end (v);
|
||||
return s;
|
||||
}
|
||||
int test (int i, double x);
|
||||
struct s1 {int (*f) (int a);};
|
||||
struct s2 {int (*f) (double a);};
|
||||
int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
|
||||
int argc;
|
||||
char **argv;
|
||||
], [
|
||||
return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
|
||||
],
|
||||
[am_cv_prog_cc_stdc="$ac_arg"; break])
|
||||
done
|
||||
CC="$ac_save_CC"
|
||||
])
|
||||
if test -z "$am_cv_prog_cc_stdc"; then
|
||||
AC_MSG_RESULT([none needed])
|
||||
else
|
||||
AC_MSG_RESULT([$am_cv_prog_cc_stdc])
|
||||
fi
|
||||
case "x$am_cv_prog_cc_stdc" in
|
||||
x|xno) ;;
|
||||
*) CC="$CC $am_cv_prog_cc_stdc" ;;
|
||||
esac
|
||||
])
|
||||
|
||||
dnl From Bruno Haible.
|
||||
|
||||
AC_DEFUN([AM_ICONV],
|
||||
[
|
||||
dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
|
||||
dnl those with the standalone portable GNU libiconv installed).
|
||||
|
||||
AC_ARG_WITH([libiconv-prefix],
|
||||
[ --with-libiconv-prefix=DIR search for libiconv in DIR/include and DIR/lib], [
|
||||
for dir in `echo "$withval" | tr : ' '`; do
|
||||
if test -d $dir/include; then CPPFLAGS="$CPPFLAGS -I$dir/include"; fi
|
||||
if test -d $dir/lib; then LDFLAGS="$LDFLAGS -L$dir/lib"; fi
|
||||
done
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [
|
||||
am_cv_func_iconv="no, consider installing GNU libiconv"
|
||||
am_cv_lib_iconv=no
|
||||
AC_TRY_LINK([#include <stdlib.h>
|
||||
#include <iconv.h>],
|
||||
[iconv_t cd = iconv_open("","");
|
||||
iconv(cd,NULL,NULL,NULL,NULL);
|
||||
iconv_close(cd);],
|
||||
am_cv_func_iconv=yes)
|
||||
if test "$am_cv_func_iconv" != yes; then
|
||||
am_save_LIBS="$LIBS"
|
||||
LIBS="$LIBS -liconv"
|
||||
AC_TRY_LINK([#include <stdlib.h>
|
||||
#include <iconv.h>],
|
||||
[iconv_t cd = iconv_open("","");
|
||||
iconv(cd,NULL,NULL,NULL,NULL);
|
||||
iconv_close(cd);],
|
||||
am_cv_lib_iconv=yes
|
||||
am_cv_func_iconv=yes)
|
||||
LIBS="$am_save_LIBS"
|
||||
fi
|
||||
])
|
||||
if test "$am_cv_func_iconv" = yes; then
|
||||
AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.])
|
||||
AC_MSG_CHECKING([for iconv declaration])
|
||||
AC_CACHE_VAL(am_cv_proto_iconv, [
|
||||
AC_TRY_COMPILE([
|
||||
#include <stdlib.h>
|
||||
#include <iconv.h>
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
#endif
|
||||
#if defined(__STDC__) || defined(__cplusplus)
|
||||
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
|
||||
#else
|
||||
size_t iconv();
|
||||
#endif
|
||||
], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
|
||||
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
|
||||
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
|
||||
AC_MSG_RESULT([$]{ac_t:-
|
||||
}[$]am_cv_proto_iconv)
|
||||
AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
|
||||
[Define as const if the declaration of iconv() needs const.])
|
||||
fi
|
||||
LIBICONV=
|
||||
if test "$am_cv_lib_iconv" = yes; then
|
||||
LIBICONV="-liconv"
|
||||
fi
|
||||
AC_SUBST(LIBICONV)
|
||||
])
|
||||
|
||||
dnl written by Guido Draheim <guidod@gmx.de>, original by Alexandre Oliva
|
||||
dnl Version 1.3 (2001/03/02)
|
||||
dnl source http://www.gnu.org/software/ac-archive/Miscellaneous/ac_define_dir.html
|
||||
|
||||
AC_DEFUN([AC_DEFINE_DIR], [
|
||||
test "x$prefix" = xNONE && prefix="$ac_default_prefix"
|
||||
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
ac_define_dir=`eval echo [$]$2`
|
||||
ac_define_dir=`eval echo [$]ac_define_dir`
|
||||
ifelse($3, ,
|
||||
AC_DEFINE_UNQUOTED($1, "$ac_define_dir"),
|
||||
AC_DEFINE_UNQUOTED($1, "$ac_define_dir", $3))
|
||||
])
|
||||
|
||||
dnl See whether we need a declaration for a function.
|
||||
dnl The result is highly dependent on the INCLUDES passed in, so make sure
|
||||
dnl to use a different cache variable name in this macro if it is invoked
|
||||
dnl in a different context somewhere else.
|
||||
dnl gcc_AC_CHECK_DECL(SYMBOL,
|
||||
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, INCLUDES]]])
|
||||
AC_DEFUN([gcc_AC_CHECK_DECL],
|
||||
[AC_MSG_CHECKING([whether $1 is declared])
|
||||
AC_CACHE_VAL(gcc_cv_have_decl_$1,
|
||||
[AC_TRY_COMPILE([$4],
|
||||
[#ifndef $1
|
||||
char *(*pfn) = (char *(*)) $1 ;
|
||||
#endif], eval "gcc_cv_have_decl_$1=yes", eval "gcc_cv_have_decl_$1=no")])
|
||||
if eval "test \"`echo '$gcc_cv_have_decl_'$1`\" = yes"; then
|
||||
AC_MSG_RESULT(yes) ; ifelse([$2], , :, [$2])
|
||||
else
|
||||
AC_MSG_RESULT(no) ; ifelse([$3], , :, [$3])
|
||||
fi
|
||||
])dnl
|
||||
|
||||
dnl Check multiple functions to see whether each needs a declaration.
|
||||
dnl Arrange to define HAVE_DECL_<FUNCTION> to 0 or 1 as appropriate.
|
||||
dnl gcc_AC_CHECK_DECLS(SYMBOLS,
|
||||
dnl [ACTION-IF-NEEDED [, ACTION-IF-NOT-NEEDED [, INCLUDES]]])
|
||||
AC_DEFUN([gcc_AC_CHECK_DECLS],
|
||||
[for ac_func in $1
|
||||
do
|
||||
changequote(, )dnl
|
||||
ac_tr_decl=HAVE_DECL_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
|
||||
changequote([, ])dnl
|
||||
gcc_AC_CHECK_DECL($ac_func,
|
||||
[AC_DEFINE_UNQUOTED($ac_tr_decl, 1) $2],
|
||||
[AC_DEFINE_UNQUOTED($ac_tr_decl, 0) $3],
|
||||
dnl It is possible that the include files passed in here are local headers
|
||||
dnl which supply a backup declaration for the relevant prototype based on
|
||||
dnl the definition of (or lack of) the HAVE_DECL_ macro. If so, this test
|
||||
dnl will always return success. E.g. see libiberty.h's handling of
|
||||
dnl `basename'. To avoid this, we define the relevant HAVE_DECL_ macro to
|
||||
dnl 1 so that any local headers used do not provide their own prototype
|
||||
dnl during this test.
|
||||
#undef $ac_tr_decl
|
||||
#define $ac_tr_decl 1
|
||||
$4
|
||||
)
|
||||
done
|
||||
dnl Automatically generate config.h entries via autoheader.
|
||||
if test x = y ; then
|
||||
patsubst(translit([$1], [a-z], [A-Z]), [\w+],
|
||||
[AC_DEFINE([HAVE_DECL_\&], 1,
|
||||
[Define to 1 if we found this declaration otherwise define to 0.])])dnl
|
||||
fi
|
||||
])
|
||||
|
||||
97
gdb/aclocal.m4
vendored
97
gdb/aclocal.m4
vendored
@@ -1,97 +0,0 @@
|
||||
# generated automatically by aclocal 1.9.2 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
|
||||
# Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
# AM_CONDITIONAL -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
# 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, 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.
|
||||
|
||||
# serial 6
|
||||
|
||||
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
|
||||
# -------------------------------------
|
||||
# Define a conditional.
|
||||
AC_DEFUN([AM_CONDITIONAL],
|
||||
[AC_PREREQ(2.52)dnl
|
||||
ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
|
||||
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
|
||||
AC_SUBST([$1_TRUE])
|
||||
AC_SUBST([$1_FALSE])
|
||||
if $2; then
|
||||
$1_TRUE=
|
||||
$1_FALSE='#'
|
||||
else
|
||||
$1_TRUE='#'
|
||||
$1_FALSE=
|
||||
fi
|
||||
AC_CONFIG_COMMANDS_PRE(
|
||||
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
|
||||
AC_MSG_ERROR([[conditional "$1" was never defined.
|
||||
Usually this means the macro was only invoked conditionally.]])
|
||||
fi])])
|
||||
|
||||
# Add --enable-maintainer-mode option to configure.
|
||||
# From Jim Meyering
|
||||
|
||||
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004
|
||||
# Free Software Foundation, Inc.
|
||||
|
||||
# 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, 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.
|
||||
|
||||
# serial 3
|
||||
|
||||
AC_DEFUN([AM_MAINTAINER_MODE],
|
||||
[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
|
||||
dnl maintainer-mode is disabled by default
|
||||
AC_ARG_ENABLE(maintainer-mode,
|
||||
[ --enable-maintainer-mode enable make rules and dependencies not useful
|
||||
(and sometimes confusing) to the casual installer],
|
||||
USE_MAINTAINER_MODE=$enableval,
|
||||
USE_MAINTAINER_MODE=no)
|
||||
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
|
||||
AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
|
||||
MAINT=$MAINTAINER_MODE_TRUE
|
||||
AC_SUBST(MAINT)dnl
|
||||
]
|
||||
)
|
||||
|
||||
AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
|
||||
|
||||
m4_include([acinclude.m4])
|
||||
1420
gdb/ada-exp.y
1420
gdb/ada-exp.y
File diff suppressed because it is too large
Load Diff
9611
gdb/ada-lang.c
9611
gdb/ada-lang.c
File diff suppressed because it is too large
Load Diff
489
gdb/ada-lang.h
489
gdb/ada-lang.h
@@ -1,489 +0,0 @@
|
||||
/* Ada language support definitions for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#if !defined (ADA_LANG_H)
|
||||
#define ADA_LANG_H 1
|
||||
|
||||
struct partial_symbol;
|
||||
struct frame_info;
|
||||
|
||||
#include "value.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "breakpoint.h"
|
||||
|
||||
/* Names of specific files known to be part of the runtime
|
||||
system and that might consider (confusing) debugging information.
|
||||
Each name (a basic regular expression string) is followed by a
|
||||
comma. FIXME: Should be part of a configuration file. */
|
||||
#if defined(__alpha__) && defined(__osf__)
|
||||
#define ADA_KNOWN_RUNTIME_FILE_NAME_PATTERNS \
|
||||
"^[agis]-.*\\.ad[bs]$", \
|
||||
"/usr/shlib/libpthread\\.so",
|
||||
#elif defined (__linux__)
|
||||
#define ADA_KNOWN_RUNTIME_FILE_NAME_PATTERNS \
|
||||
"^[agis]-.*\\.ad[bs]$", \
|
||||
"/lib.*/libpthread\\.so[.0-9]*$", "/lib.*/libpthread\\.a$", \
|
||||
"/lib.*/libc\\.so[.0-9]*$", "/lib.*/libc\\.a$",
|
||||
#endif
|
||||
|
||||
#if !defined (ADA_KNOWN_RUNTIME_FILE_NAME_PATTERNS)
|
||||
#define ADA_KNOWN_RUNTIME_FILE_NAME_PATTERNS \
|
||||
"^[agis]-.*\\.ad[bs]$",
|
||||
#endif
|
||||
|
||||
/* Names of compiler-generated auxiliary functions probably of no
|
||||
interest to users. Each name (a basic regular expression string)
|
||||
is followed by a comma. */
|
||||
#define ADA_KNOWN_AUXILIARY_FUNCTION_NAME_PATTERNS \
|
||||
"___clean[.$a-zA-Z0-9_]*$",
|
||||
|
||||
/* The maximum number of frame levels searched for non-local,
|
||||
* non-global symbols. This limit exists as a precaution to prevent
|
||||
* infinite search loops when the stack is screwed up. */
|
||||
#define MAX_ENCLOSING_FRAME_LEVELS 7
|
||||
|
||||
/* Maximum number of steps followed in looking for the ultimate
|
||||
referent of a renaming. This prevents certain infinite loops that
|
||||
can otherwise result. */
|
||||
#define MAX_RENAMING_CHAIN_LENGTH 10
|
||||
|
||||
struct block;
|
||||
|
||||
/* Corresponding encoded/decoded names and opcodes for Ada user-definable
|
||||
operators. */
|
||||
struct ada_opname_map
|
||||
{
|
||||
const char *encoded;
|
||||
const char *decoded;
|
||||
enum exp_opcode op;
|
||||
};
|
||||
|
||||
/* Table of Ada operators in encoded and decoded forms. */
|
||||
/* Defined in ada-lang.c */
|
||||
extern const struct ada_opname_map ada_opname_table[];
|
||||
|
||||
enum ada_operator
|
||||
{
|
||||
/* X IN A'RANGE(N). N is an immediate operand, surrounded by
|
||||
BINOP_IN_BOUNDS before and after. A is an array, X an index
|
||||
value. Evaluates to true iff X is within range of the Nth
|
||||
dimension (1-based) of A. (A multi-dimensional array
|
||||
type is represented as array of array of ...) */
|
||||
BINOP_IN_BOUNDS = OP_EXTENDED0,
|
||||
|
||||
/* X IN L .. U. True iff L <= X <= U. */
|
||||
TERNOP_IN_RANGE,
|
||||
|
||||
/* Ada attributes ('Foo). */
|
||||
OP_ATR_FIRST,
|
||||
OP_ATR_LAST,
|
||||
OP_ATR_LENGTH,
|
||||
OP_ATR_IMAGE,
|
||||
OP_ATR_MAX,
|
||||
OP_ATR_MIN,
|
||||
OP_ATR_MODULUS,
|
||||
OP_ATR_POS,
|
||||
OP_ATR_SIZE,
|
||||
OP_ATR_TAG,
|
||||
OP_ATR_VAL,
|
||||
|
||||
/* Ada type qualification. It is encoded as for UNOP_CAST, above,
|
||||
and denotes the TYPE'(EXPR) construct. */
|
||||
UNOP_QUAL,
|
||||
|
||||
/* X IN TYPE. The `TYPE' argument is immediate, with
|
||||
UNOP_IN_RANGE before and after it. True iff X is a member of
|
||||
type TYPE (typically a subrange). */
|
||||
UNOP_IN_RANGE,
|
||||
|
||||
/* An aggregate. A single immediate operand, N>0, gives
|
||||
the number of component specifications that follow. The
|
||||
immediate operand is followed by a second OP_AGGREGATE.
|
||||
Next come N component specifications. A component
|
||||
specification is either an OP_OTHERS (others=>...), an
|
||||
OP_CHOICES (for named associations), or other expression (for
|
||||
positional aggregates only). Aggregates currently
|
||||
occur only as the right sides of assignments. */
|
||||
OP_AGGREGATE,
|
||||
|
||||
/* An others clause. Followed by a single expression. */
|
||||
OP_OTHERS,
|
||||
|
||||
/* An aggregate component association. A single immediate operand, N,
|
||||
gives the number of choices that follow. This is followed by a second
|
||||
OP_CHOICES operator. Next come N operands, each of which is an
|
||||
expression, an OP_DISCRETE_RANGE, or an OP_NAME---the latter
|
||||
for a simple name that must be a record component name and does
|
||||
not correspond to a single existing symbol. After the N choice
|
||||
indicators comes an expression giving the value.
|
||||
|
||||
In an aggregate such as (X => E1, ...), where X is a simple
|
||||
name, X could syntactically be either a component_selector_name
|
||||
or an expression used as a discrete_choice, depending on the
|
||||
aggregate's type context. Since this is not known at parsing
|
||||
time, we don't attempt to disambiguate X if it has multiple
|
||||
definitions, but instead supply an OP_NAME. If X has a single
|
||||
definition, we represent it with an OP_VAR_VALUE, even though
|
||||
it may turn out to be within a record aggregate. Aggregate
|
||||
evaluation can use either OP_NAMEs or OP_VAR_VALUEs to get a
|
||||
record field name, and can evaluate OP_VAR_VALUE normally to
|
||||
get its value as an expression. Unfortunately, we lose out in
|
||||
cases where X has multiple meanings and is part of an array
|
||||
aggregate. I hope these are not common enough to annoy users,
|
||||
who can work around the problem in any case by putting
|
||||
parentheses around X. */
|
||||
OP_CHOICES,
|
||||
|
||||
/* A positional aggregate component association. The operator is
|
||||
followed by a single integer indicating the position in the
|
||||
aggregate (0-based), followed by a second OP_POSITIONAL. Next
|
||||
follows a single expression giving the component value. */
|
||||
OP_POSITIONAL,
|
||||
|
||||
/* A range of values. Followed by two expressions giving the
|
||||
upper and lower bounds of the range. */
|
||||
OP_DISCRETE_RANGE,
|
||||
|
||||
/* End marker */
|
||||
OP_ADA_LAST
|
||||
};
|
||||
|
||||
/* A triple, (symbol, block, symtab), representing one instance of a
|
||||
* symbol-lookup operation. */
|
||||
struct ada_symbol_info {
|
||||
struct symbol* sym;
|
||||
struct block* block;
|
||||
struct symtab* symtab;
|
||||
};
|
||||
|
||||
/* Ada task structures. */
|
||||
|
||||
/* Ada task control block, as defined in the GNAT runt-time library. */
|
||||
|
||||
struct task_control_block
|
||||
{
|
||||
char state;
|
||||
CORE_ADDR parent;
|
||||
int priority;
|
||||
char image [32];
|
||||
int image_len; /* This field is not always present in the ATCB. */
|
||||
CORE_ADDR call;
|
||||
CORE_ADDR thread;
|
||||
CORE_ADDR lwp; /* This field is not always present in the ATCB. */
|
||||
|
||||
/* If the task is waiting on a task entry, this field contains the
|
||||
task_id of the other task. */
|
||||
CORE_ADDR called_task;
|
||||
};
|
||||
|
||||
struct task_ptid
|
||||
{
|
||||
int pid; /* The Process id */
|
||||
long lwp; /* The Light Weight Process id */
|
||||
long tid; /* The Thread id */
|
||||
};
|
||||
typedef struct task_ptid task_ptid_t;
|
||||
|
||||
struct task_entry
|
||||
{
|
||||
CORE_ADDR task_id;
|
||||
struct task_control_block atcb;
|
||||
int task_num;
|
||||
int known_tasks_index;
|
||||
struct task_entry *next_task;
|
||||
task_ptid_t task_ptid;
|
||||
int stack_per;
|
||||
};
|
||||
|
||||
/* task entry list. */
|
||||
extern struct task_entry *task_list;
|
||||
|
||||
|
||||
/* Assuming V points to an array of S objects, make sure that it contains at
|
||||
least M objects, updating V and S as necessary. */
|
||||
|
||||
#define GROW_VECT(v, s, m) \
|
||||
if ((s) < (m)) (v) = grow_vect (v, &(s), m, sizeof *(v));
|
||||
|
||||
extern void *grow_vect (void *, size_t *, size_t, int);
|
||||
|
||||
extern int ada_get_field_index (const struct type *type,
|
||||
const char *field_name,
|
||||
int maybe_missing);
|
||||
|
||||
extern int ada_parse (void); /* Defined in ada-exp.y */
|
||||
|
||||
extern void ada_error (char *); /* Defined in ada-exp.y */
|
||||
|
||||
/* Defined in ada-typeprint.c */
|
||||
extern void ada_print_type (struct type *, char *, struct ui_file *, int,
|
||||
int);
|
||||
|
||||
extern int ada_val_print (struct type *, const gdb_byte *, int, CORE_ADDR,
|
||||
struct ui_file *, int, int, int,
|
||||
enum val_prettyprint);
|
||||
|
||||
extern int ada_value_print (struct value *, struct ui_file *, int,
|
||||
enum val_prettyprint);
|
||||
|
||||
/* Defined in ada-lang.c */
|
||||
|
||||
extern struct value *value_from_contents_and_address (struct type *,
|
||||
const gdb_byte *,
|
||||
CORE_ADDR);
|
||||
|
||||
extern void ada_emit_char (int, struct ui_file *, int, int);
|
||||
|
||||
extern void ada_printchar (int, struct ui_file *);
|
||||
|
||||
extern void ada_printstr (struct ui_file *, const gdb_byte *,
|
||||
unsigned int, int, int);
|
||||
|
||||
extern void ada_convert_actuals (struct value *, int, struct value **,
|
||||
CORE_ADDR *);
|
||||
|
||||
extern struct value *ada_value_subscript (struct value *, int,
|
||||
struct value **);
|
||||
|
||||
extern struct type *ada_array_element_type (struct type *, int);
|
||||
|
||||
extern int ada_array_arity (struct type *);
|
||||
|
||||
struct type *ada_type_of_array (struct value *, int);
|
||||
|
||||
extern struct value *ada_coerce_to_simple_array_ptr (struct value *);
|
||||
|
||||
extern int ada_is_simple_array_type (struct type *);
|
||||
|
||||
extern int ada_is_array_descriptor_type (struct type *);
|
||||
|
||||
extern int ada_is_bogus_array_descriptor (struct type *);
|
||||
|
||||
extern struct type *ada_index_type (struct type *, int);
|
||||
|
||||
extern struct value *ada_array_bound (struct value *, int, int);
|
||||
|
||||
extern char *ada_decode_symbol (const struct general_symbol_info*);
|
||||
|
||||
extern const char *ada_decode (const char*);
|
||||
|
||||
extern enum language ada_update_initial_language (enum language,
|
||||
struct partial_symtab*);
|
||||
|
||||
extern void clear_ada_sym_cache (void);
|
||||
|
||||
extern char **ada_make_symbol_completion_list (const char *text0,
|
||||
const char *word);
|
||||
|
||||
extern int ada_lookup_symbol_list (const char *, const struct block *,
|
||||
domain_enum, struct ada_symbol_info**);
|
||||
|
||||
extern char *ada_fold_name (const char *);
|
||||
|
||||
extern struct symbol *ada_lookup_symbol (const char *, const struct block *,
|
||||
domain_enum, int *,
|
||||
struct symtab **);
|
||||
|
||||
extern struct minimal_symbol *ada_lookup_simple_minsym (const char *);
|
||||
|
||||
extern void ada_fill_in_ada_prototype (struct symbol *);
|
||||
|
||||
extern int user_select_syms (struct ada_symbol_info *, int, int);
|
||||
|
||||
extern int get_selections (int *, int, int, int, char *);
|
||||
|
||||
extern char *ada_start_decode_line_1 (char *);
|
||||
|
||||
extern struct symtabs_and_lines ada_finish_decode_line_1 (char **,
|
||||
struct symtab *,
|
||||
int, char ***);
|
||||
|
||||
extern struct symtabs_and_lines ada_sals_for_line (const char*, int,
|
||||
int, char***, int);
|
||||
|
||||
extern int ada_scan_number (const char *, int, LONGEST *, int *);
|
||||
|
||||
extern struct type *ada_parent_type (struct type *);
|
||||
|
||||
extern int ada_is_ignored_field (struct type *, int);
|
||||
|
||||
extern int ada_is_packed_array_type (struct type *);
|
||||
|
||||
extern struct value *ada_value_primitive_packed_val (struct value *,
|
||||
const gdb_byte *,
|
||||
long, int, int,
|
||||
struct type *);
|
||||
|
||||
extern struct type *ada_coerce_to_simple_array_type (struct type *);
|
||||
|
||||
extern int ada_is_character_type (struct type *);
|
||||
|
||||
extern int ada_is_string_type (struct type *);
|
||||
|
||||
extern int ada_is_tagged_type (struct type *, int);
|
||||
|
||||
extern int ada_is_tag_type (struct type *);
|
||||
|
||||
extern struct type *ada_tag_type (struct value *);
|
||||
|
||||
extern struct value *ada_value_tag (struct value *);
|
||||
|
||||
extern const char *ada_tag_name (struct value *);
|
||||
|
||||
extern int ada_is_parent_field (struct type *, int);
|
||||
|
||||
extern int ada_is_wrapper_field (struct type *, int);
|
||||
|
||||
extern int ada_is_variant_part (struct type *, int);
|
||||
|
||||
extern struct type *ada_variant_discrim_type (struct type *, struct type *);
|
||||
|
||||
extern int ada_is_others_clause (struct type *, int);
|
||||
|
||||
extern int ada_in_variant (LONGEST, struct type *, int);
|
||||
|
||||
extern char *ada_variant_discrim_name (struct type *);
|
||||
|
||||
extern struct value *ada_value_struct_elt (struct value *, char *, int);
|
||||
|
||||
extern int ada_is_aligner_type (struct type *);
|
||||
|
||||
extern struct type *ada_aligned_type (struct type *);
|
||||
|
||||
extern const gdb_byte *ada_aligned_value_addr (struct type *,
|
||||
const gdb_byte *);
|
||||
|
||||
extern const char *ada_attribute_name (enum exp_opcode);
|
||||
|
||||
extern int ada_is_fixed_point_type (struct type *);
|
||||
|
||||
extern int ada_is_system_address_type (struct type *);
|
||||
|
||||
extern DOUBLEST ada_delta (struct type *);
|
||||
|
||||
extern DOUBLEST ada_fixed_to_float (struct type *, LONGEST);
|
||||
|
||||
extern LONGEST ada_float_to_fixed (struct type *, DOUBLEST);
|
||||
|
||||
extern int ada_is_vax_floating_type (struct type *);
|
||||
|
||||
extern int ada_vax_float_type_suffix (struct type *);
|
||||
|
||||
extern struct value *ada_vax_float_print_function (struct type *);
|
||||
|
||||
extern struct type *ada_system_address_type (void);
|
||||
|
||||
extern int ada_which_variant_applies (struct type *, struct type *,
|
||||
const gdb_byte *);
|
||||
|
||||
extern struct type *ada_to_fixed_type (struct type *, const gdb_byte *,
|
||||
CORE_ADDR, struct value *);
|
||||
|
||||
extern struct type *ada_template_to_fixed_record_type_1 (struct type *type,
|
||||
const gdb_byte *valaddr,
|
||||
CORE_ADDR address,
|
||||
struct value *dval0,
|
||||
int keep_dynamic_fields);
|
||||
|
||||
extern int ada_name_prefix_len (const char *);
|
||||
|
||||
extern char *ada_type_name (struct type *);
|
||||
|
||||
extern struct type *ada_find_parallel_type (struct type *,
|
||||
const char *suffix);
|
||||
|
||||
extern LONGEST get_int_var_value (char *, int *);
|
||||
|
||||
extern struct symbol *ada_find_any_symbol (const char *name);
|
||||
|
||||
extern struct type *ada_find_any_type (const char *name);
|
||||
|
||||
extern struct symbol *ada_find_renaming_symbol (const char *name,
|
||||
struct block *block);
|
||||
|
||||
extern int ada_prefer_type (struct type *, struct type *);
|
||||
|
||||
extern struct type *ada_get_base_type (struct type *);
|
||||
|
||||
extern struct type *ada_check_typedef (struct type *);
|
||||
|
||||
extern char *ada_encode (const char *);
|
||||
|
||||
extern const char *ada_enum_name (const char *);
|
||||
|
||||
extern int ada_is_modular_type (struct type *);
|
||||
|
||||
extern ULONGEST ada_modulus (struct type *);
|
||||
|
||||
extern struct value *ada_value_ind (struct value *);
|
||||
|
||||
extern void ada_print_scalar (struct type *, LONGEST, struct ui_file *);
|
||||
|
||||
extern int ada_is_range_type_name (const char *);
|
||||
|
||||
extern const char *ada_renaming_type (struct type *);
|
||||
|
||||
extern int ada_is_object_renaming (struct symbol *);
|
||||
|
||||
extern char *ada_simple_renamed_entity (struct symbol *);
|
||||
|
||||
extern char *ada_breakpoint_rewrite (char *, int *);
|
||||
|
||||
extern char *ada_main_name (void);
|
||||
|
||||
/* Tasking-related: ada-tasks.c */
|
||||
|
||||
extern int valid_task_id (int);
|
||||
|
||||
extern void init_task_list (void);
|
||||
|
||||
extern int ada_is_exception_breakpoint (bpstat bs);
|
||||
|
||||
extern void ada_adjust_exception_stop (bpstat bs);
|
||||
|
||||
extern void ada_print_exception_stop (bpstat bs);
|
||||
|
||||
extern int ada_get_current_task (ptid_t);
|
||||
|
||||
extern int breakpoint_ada_task_match (CORE_ADDR, ptid_t);
|
||||
|
||||
extern int ada_print_exception_breakpoint_nontask (struct breakpoint *);
|
||||
|
||||
extern void ada_print_exception_breakpoint_task (struct breakpoint *);
|
||||
|
||||
extern void ada_find_printable_frame (struct frame_info *fi);
|
||||
|
||||
extern void ada_reset_thread_registers (void);
|
||||
|
||||
extern int ada_build_task_list (void);
|
||||
|
||||
/* Look up a symbol by name using the search conventions of
|
||||
a specific language (optional block, optional symtab).
|
||||
FIXME: Should be symtab.h. */
|
||||
|
||||
extern struct symbol *lookup_symbol_in_language (const char *,
|
||||
const struct block *,
|
||||
domain_enum,
|
||||
enum language,
|
||||
int *,
|
||||
struct symtab **);
|
||||
#endif
|
||||
658
gdb/ada-lex.l
658
gdb/ada-lex.l
@@ -1,658 +0,0 @@
|
||||
/* FLEX lexer for Ada expressions, for GDB.
|
||||
Copyright (C) 1994, 1997, 1998, 2000, 2001, 2002, 2003
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/* The converted version of this file is to be included in ada-exp.y, */
|
||||
/* the Ada parser for gdb. The function yylex obtains characters from */
|
||||
/* the global pointer lexptr. It returns a syntactic category for */
|
||||
/* each successive token and places a semantic value into yylval */
|
||||
/* (ada-lval), defined by the parser. */
|
||||
|
||||
DIG [0-9]
|
||||
NUM10 ({DIG}({DIG}|_)*)
|
||||
HEXDIG [0-9a-f]
|
||||
NUM16 ({HEXDIG}({HEXDIG}|_)*)
|
||||
OCTDIG [0-7]
|
||||
LETTER [a-z_]
|
||||
ID ({LETTER}({LETTER}|{DIG})*|"<"{LETTER}({LETTER}|{DIG})*">")
|
||||
WHITE [ \t\n]
|
||||
TICK ("'"{WHITE}*)
|
||||
GRAPHIC [a-z0-9 #&'()*+,-./:;<>=_|!$%?@\[\]\\^`{}~]
|
||||
OPER ([-+*/=<>&]|"<="|">="|"**"|"/="|"and"|"or"|"xor"|"not"|"mod"|"rem"|"abs")
|
||||
|
||||
EXP (e[+-]{NUM10})
|
||||
POSEXP (e"+"?{NUM10})
|
||||
|
||||
%{
|
||||
|
||||
#define NUMERAL_WIDTH 256
|
||||
#define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1))
|
||||
|
||||
/* Temporary staging for numeric literals. */
|
||||
static char numbuf[NUMERAL_WIDTH];
|
||||
static void canonicalizeNumeral (char *s1, const char *);
|
||||
static struct stoken processString (const char*, int);
|
||||
static int processInt (const char *, const char *, const char *);
|
||||
static int processReal (const char *);
|
||||
static struct stoken processId (const char *, int);
|
||||
static int processAttribute (const char *);
|
||||
static int find_dot_all (const char *);
|
||||
|
||||
#undef YY_DECL
|
||||
#define YY_DECL static int yylex ( void )
|
||||
|
||||
#undef YY_INPUT
|
||||
#define YY_INPUT(BUF, RESULT, MAX_SIZE) \
|
||||
if ( *lexptr == '\000' ) \
|
||||
(RESULT) = YY_NULL; \
|
||||
else \
|
||||
{ \
|
||||
*(BUF) = *lexptr; \
|
||||
(RESULT) = 1; \
|
||||
lexptr += 1; \
|
||||
}
|
||||
|
||||
static int find_dot_all (const char *);
|
||||
|
||||
%}
|
||||
|
||||
%option case-insensitive interactive nodefault
|
||||
|
||||
%s BEFORE_QUAL_QUOTE
|
||||
|
||||
%%
|
||||
|
||||
{WHITE} { }
|
||||
|
||||
"--".* { yyterminate(); }
|
||||
|
||||
{NUM10}{POSEXP} {
|
||||
canonicalizeNumeral (numbuf, yytext);
|
||||
return processInt (NULL, numbuf, strrchr(numbuf, 'e')+1);
|
||||
}
|
||||
|
||||
{NUM10} {
|
||||
canonicalizeNumeral (numbuf, yytext);
|
||||
return processInt (NULL, numbuf, NULL);
|
||||
}
|
||||
|
||||
{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#"{POSEXP} {
|
||||
canonicalizeNumeral (numbuf, yytext);
|
||||
return processInt (numbuf,
|
||||
strchr (numbuf, '#') + 1,
|
||||
strrchr(numbuf, '#') + 1);
|
||||
}
|
||||
|
||||
{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#" {
|
||||
canonicalizeNumeral (numbuf, yytext);
|
||||
return processInt (numbuf, strchr (numbuf, '#') + 1, NULL);
|
||||
}
|
||||
|
||||
"0x"{HEXDIG}+ {
|
||||
canonicalizeNumeral (numbuf, yytext+2);
|
||||
return processInt ("16#", numbuf, NULL);
|
||||
}
|
||||
|
||||
|
||||
{NUM10}"."{NUM10}{EXP} {
|
||||
canonicalizeNumeral (numbuf, yytext);
|
||||
return processReal (numbuf);
|
||||
}
|
||||
|
||||
{NUM10}"."{NUM10} {
|
||||
canonicalizeNumeral (numbuf, yytext);
|
||||
return processReal (numbuf);
|
||||
}
|
||||
|
||||
{NUM10}"#"{NUM16}"."{NUM16}"#"{EXP} {
|
||||
error (_("Based real literals not implemented yet."));
|
||||
}
|
||||
|
||||
{NUM10}"#"{NUM16}"."{NUM16}"#" {
|
||||
error (_("Based real literals not implemented yet."));
|
||||
}
|
||||
|
||||
<INITIAL>"'"({GRAPHIC}|\")"'" {
|
||||
yylval.typed_val.type = type_char ();
|
||||
yylval.typed_val.val = yytext[1];
|
||||
return CHARLIT;
|
||||
}
|
||||
|
||||
<INITIAL>"'[\""{HEXDIG}{2}"\"]'" {
|
||||
int v;
|
||||
yylval.typed_val.type = type_char ();
|
||||
sscanf (yytext+3, "%2x", &v);
|
||||
yylval.typed_val.val = v;
|
||||
return CHARLIT;
|
||||
}
|
||||
|
||||
\"({GRAPHIC}|"[\""({HEXDIG}{2}|\")"\"]")*\" {
|
||||
yylval.sval = processString (yytext+1, yyleng-2);
|
||||
return STRING;
|
||||
}
|
||||
|
||||
\" {
|
||||
error (_("ill-formed or non-terminated string literal"));
|
||||
}
|
||||
|
||||
|
||||
if {
|
||||
while (*lexptr != 'i' && *lexptr != 'I')
|
||||
lexptr -= 1;
|
||||
yyrestart(NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ADA KEYWORDS */
|
||||
|
||||
abs { return ABS; }
|
||||
and { return _AND_; }
|
||||
else { return ELSE; }
|
||||
in { return IN; }
|
||||
mod { return MOD; }
|
||||
new { return NEW; }
|
||||
not { return NOT; }
|
||||
null { return NULL_PTR; }
|
||||
or { return OR; }
|
||||
others { return OTHERS; }
|
||||
rem { return REM; }
|
||||
then { return THEN; }
|
||||
xor { return XOR; }
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
{TICK}[a-zA-Z][a-zA-Z]+ { return processAttribute (yytext+1); }
|
||||
|
||||
/* PUNCTUATION */
|
||||
|
||||
"=>" { return ARROW; }
|
||||
".." { return DOTDOT; }
|
||||
"**" { return STARSTAR; }
|
||||
":=" { return ASSIGN; }
|
||||
"/=" { return NOTEQUAL; }
|
||||
"<=" { return LEQ; }
|
||||
">=" { return GEQ; }
|
||||
|
||||
<BEFORE_QUAL_QUOTE>"'" { BEGIN INITIAL; return '\''; }
|
||||
|
||||
[-&*+./:<>=|;\[\]] { return yytext[0]; }
|
||||
|
||||
"," { if (paren_depth == 0 && comma_terminates)
|
||||
{
|
||||
lexptr -= 1;
|
||||
yyrestart(NULL);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return ',';
|
||||
}
|
||||
|
||||
"(" { paren_depth += 1; return '('; }
|
||||
")" { if (paren_depth == 0)
|
||||
{
|
||||
lexptr -= 1;
|
||||
yyrestart(NULL);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
paren_depth -= 1;
|
||||
return ')';
|
||||
}
|
||||
}
|
||||
|
||||
"."{WHITE}*all { return DOT_ALL; }
|
||||
|
||||
"."{WHITE}*{ID} {
|
||||
yylval.sval = processId (yytext+1, yyleng-1);
|
||||
return DOT_ID;
|
||||
}
|
||||
|
||||
{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*(" "*"'")? {
|
||||
int all_posn = find_dot_all (yytext);
|
||||
|
||||
if (all_posn == -1 && yytext[yyleng-1] == '\'')
|
||||
{
|
||||
BEGIN BEFORE_QUAL_QUOTE;
|
||||
yyless (yyleng-1);
|
||||
}
|
||||
else if (all_posn >= 0)
|
||||
yyless (all_posn);
|
||||
yylval.sval = processId (yytext, yyleng);
|
||||
return NAME;
|
||||
}
|
||||
|
||||
|
||||
/* GDB EXPRESSION CONSTRUCTS */
|
||||
|
||||
"'"[^']+"'"{WHITE}*:: {
|
||||
yyless (yyleng - 2);
|
||||
yylval.sval = processId (yytext, yyleng);
|
||||
return NAME;
|
||||
}
|
||||
|
||||
"::" { return COLONCOLON; }
|
||||
|
||||
[{}@] { return yytext[0]; }
|
||||
|
||||
/* REGISTERS AND GDB CONVENIENCE VARIABLES */
|
||||
|
||||
"$"({LETTER}|{DIG}|"$")* {
|
||||
yylval.sval.ptr = yytext;
|
||||
yylval.sval.length = yyleng;
|
||||
return SPECIAL_VARIABLE;
|
||||
}
|
||||
|
||||
/* CATCH-ALL ERROR CASE */
|
||||
|
||||
. { error (_("Invalid character '%s' in expression."), yytext); }
|
||||
%%
|
||||
|
||||
#include <ctype.h>
|
||||
#include "gdb_string.h"
|
||||
|
||||
/* Initialize the lexer for processing new expression. */
|
||||
|
||||
void
|
||||
lexer_init (FILE *inp)
|
||||
{
|
||||
BEGIN INITIAL;
|
||||
yyrestart (inp);
|
||||
}
|
||||
|
||||
|
||||
/* Copy S2 to S1, removing all underscores, and downcasing all letters. */
|
||||
|
||||
static void
|
||||
canonicalizeNumeral (char *s1, const char *s2)
|
||||
{
|
||||
for (; *s2 != '\000'; s2 += 1)
|
||||
{
|
||||
if (*s2 != '_')
|
||||
{
|
||||
*s1 = tolower(*s2);
|
||||
s1 += 1;
|
||||
}
|
||||
}
|
||||
s1[0] = '\000';
|
||||
}
|
||||
|
||||
#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
|
||||
|
||||
/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
|
||||
where 2 <= BASE <= 16. */
|
||||
|
||||
static int
|
||||
is_digit_in_base (unsigned char digit, int base)
|
||||
{
|
||||
if (!isxdigit (digit))
|
||||
return 0;
|
||||
if (base <= 10)
|
||||
return (isdigit (digit) && digit < base + '0');
|
||||
else
|
||||
return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
|
||||
}
|
||||
|
||||
static int
|
||||
digit_to_int (unsigned char c)
|
||||
{
|
||||
if (isdigit (c))
|
||||
return c - '0';
|
||||
else
|
||||
return tolower (c) - 'a' + 10;
|
||||
}
|
||||
|
||||
/* As for strtoul, but for ULONGEST results. */
|
||||
|
||||
ULONGEST
|
||||
strtoulst (const char *num, const char **trailer, int base)
|
||||
{
|
||||
unsigned int high_part;
|
||||
ULONGEST result;
|
||||
int i;
|
||||
unsigned char lim;
|
||||
|
||||
if (base < 2 || base > 16)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
lim = base - 1 + '0';
|
||||
|
||||
result = high_part = 0;
|
||||
for (i = 0; is_digit_in_base (num[i], base); i += 1)
|
||||
{
|
||||
result = result*base + digit_to_int (num[i]);
|
||||
high_part = high_part*base + (unsigned int) (result >> HIGH_BYTE_POSN);
|
||||
result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
|
||||
if (high_part > 0xff)
|
||||
{
|
||||
errno = ERANGE;
|
||||
result = high_part = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (trailer != NULL)
|
||||
*trailer = &num[i];
|
||||
|
||||
return result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
|
||||
}
|
||||
|
||||
/* Interprets the prefix of NUM that consists of digits of the given BASE
|
||||
as an integer of that BASE, with the string EXP as an exponent.
|
||||
Puts value in yylval, and returns INT, if the string is valid. Causes
|
||||
an error if the number is improperly formated. BASE, if NULL, defaults
|
||||
to "10", and EXP to "1". The EXP does not contain a leading 'e' or 'E'.
|
||||
*/
|
||||
|
||||
static int
|
||||
processInt (const char *base0, const char *num0, const char *exp0)
|
||||
{
|
||||
ULONGEST result;
|
||||
long exp;
|
||||
int base;
|
||||
|
||||
char *trailer;
|
||||
|
||||
if (base0 == NULL)
|
||||
base = 10;
|
||||
else
|
||||
{
|
||||
base = strtol (base0, (char **) NULL, 10);
|
||||
if (base < 2 || base > 16)
|
||||
error (_("Invalid base: %d."), base);
|
||||
}
|
||||
|
||||
if (exp0 == NULL)
|
||||
exp = 0;
|
||||
else
|
||||
exp = strtol(exp0, (char **) NULL, 10);
|
||||
|
||||
errno = 0;
|
||||
result = strtoulst (num0, (const char **) &trailer, base);
|
||||
if (errno == ERANGE)
|
||||
error (_("Integer literal out of range"));
|
||||
if (isxdigit(*trailer))
|
||||
error (_("Invalid digit `%c' in based literal"), *trailer);
|
||||
|
||||
while (exp > 0)
|
||||
{
|
||||
if (result > (ULONG_MAX / base))
|
||||
error (_("Integer literal out of range"));
|
||||
result *= base;
|
||||
exp -= 1;
|
||||
}
|
||||
|
||||
if ((result >> (TARGET_INT_BIT-1)) == 0)
|
||||
yylval.typed_val.type = type_int ();
|
||||
else if ((result >> (TARGET_LONG_BIT-1)) == 0)
|
||||
yylval.typed_val.type = type_long ();
|
||||
else if (((result >> (TARGET_LONG_BIT-1)) >> 1) == 0)
|
||||
{
|
||||
/* We have a number representable as an unsigned integer quantity.
|
||||
For consistency with the C treatment, we will treat it as an
|
||||
anonymous modular (unsigned) quantity. Alas, the types are such
|
||||
that we need to store .val as a signed quantity. Sorry
|
||||
for the mess, but C doesn't officially guarantee that a simple
|
||||
assignment does the trick (no, it doesn't; read the reference manual).
|
||||
*/
|
||||
yylval.typed_val.type = builtin_type_unsigned_long;
|
||||
if (result & LONGEST_SIGN)
|
||||
yylval.typed_val.val =
|
||||
(LONGEST) (result & ~LONGEST_SIGN)
|
||||
- (LONGEST_SIGN>>1) - (LONGEST_SIGN>>1);
|
||||
else
|
||||
yylval.typed_val.val = (LONGEST) result;
|
||||
return INT;
|
||||
}
|
||||
else
|
||||
yylval.typed_val.type = type_long_long ();
|
||||
|
||||
yylval.typed_val.val = (LONGEST) result;
|
||||
return INT;
|
||||
}
|
||||
|
||||
static int
|
||||
processReal (const char *num0)
|
||||
{
|
||||
sscanf (num0, DOUBLEST_SCAN_FORMAT, &yylval.typed_val_float.dval);
|
||||
|
||||
yylval.typed_val_float.type = type_float ();
|
||||
if (sizeof(DOUBLEST) >= TARGET_DOUBLE_BIT / TARGET_CHAR_BIT)
|
||||
yylval.typed_val_float.type = type_double ();
|
||||
if (sizeof(DOUBLEST) >= TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT)
|
||||
yylval.typed_val_float.type = type_long_double ();
|
||||
|
||||
return FLOAT;
|
||||
}
|
||||
|
||||
|
||||
/* Store a canonicalized version of NAME0[0..LEN-1] in yylval.ssym. The
|
||||
resulting string is valid until the next call to ada_parse. It differs
|
||||
from NAME0 in that:
|
||||
+ Characters between '...' or <...> are transfered verbatim to
|
||||
yylval.ssym.
|
||||
+ <, >, and trailing "'" characters in quoted sequences are removed
|
||||
(a leading quote is preserved to indicate that the name is not to be
|
||||
GNAT-encoded).
|
||||
+ Unquoted whitespace is removed.
|
||||
+ Unquoted alphabetic characters are mapped to lower case.
|
||||
Result is returned as a struct stoken, but for convenience, the string
|
||||
is also null-terminated. Result string valid until the next call of
|
||||
ada_parse.
|
||||
*/
|
||||
static struct stoken
|
||||
processId (const char *name0, int len)
|
||||
{
|
||||
char *name = obstack_alloc (&temp_parse_space, len + 11);
|
||||
int i0, i;
|
||||
struct stoken result;
|
||||
|
||||
while (len > 0 && isspace (name0[len-1]))
|
||||
len -= 1;
|
||||
i = i0 = 0;
|
||||
while (i0 < len)
|
||||
{
|
||||
if (isalnum (name0[i0]))
|
||||
{
|
||||
name[i] = tolower (name0[i0]);
|
||||
i += 1; i0 += 1;
|
||||
}
|
||||
else switch (name0[i0])
|
||||
{
|
||||
default:
|
||||
name[i] = name0[i0];
|
||||
i += 1; i0 += 1;
|
||||
break;
|
||||
case ' ': case '\t':
|
||||
i0 += 1;
|
||||
break;
|
||||
case '\'':
|
||||
do
|
||||
{
|
||||
name[i] = name0[i0];
|
||||
i += 1; i0 += 1;
|
||||
}
|
||||
while (i0 < len && name0[i0] != '\'');
|
||||
i0 += 1;
|
||||
break;
|
||||
case '<':
|
||||
i0 += 1;
|
||||
while (i0 < len && name0[i0] != '>')
|
||||
{
|
||||
name[i] = name0[i0];
|
||||
i += 1; i0 += 1;
|
||||
}
|
||||
i0 += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
name[i] = '\000';
|
||||
|
||||
result.ptr = name;
|
||||
result.length = i;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return TEXT[0..LEN-1], a string literal without surrounding quotes,
|
||||
with special hex character notations replaced with characters.
|
||||
Result valid until the next call to ada_parse. */
|
||||
|
||||
static struct stoken
|
||||
processString (const char *text, int len)
|
||||
{
|
||||
const char *p;
|
||||
char *q;
|
||||
const char *lim = text + len;
|
||||
struct stoken result;
|
||||
|
||||
q = result.ptr = obstack_alloc (&temp_parse_space, len);
|
||||
p = text;
|
||||
while (p < lim)
|
||||
{
|
||||
if (p[0] == '[' && p[1] == '"' && p+2 < lim)
|
||||
{
|
||||
if (p[2] == '"') /* "...["""]... */
|
||||
{
|
||||
*q = '"';
|
||||
p += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
int chr;
|
||||
sscanf (p+2, "%2x", &chr);
|
||||
*q = (char) chr;
|
||||
p += 5;
|
||||
}
|
||||
}
|
||||
else
|
||||
*q = *p;
|
||||
q += 1;
|
||||
p += 1;
|
||||
}
|
||||
result.length = q - result.ptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Returns the position within STR of the '.' in a
|
||||
'.{WHITE}*all' component of a dotted name, or -1 if there is none.
|
||||
Note: we actually don't need this routine, since 'all' can never be an
|
||||
Ada identifier. Thus, looking up foo.all or foo.all.x as a name
|
||||
must fail, and will eventually be interpreted as (foo).all or
|
||||
(foo).all.x. However, this does avoid an extraneous lookup. */
|
||||
|
||||
static int
|
||||
find_dot_all (const char *str)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; str[i] != '\000'; i += 1)
|
||||
{
|
||||
if (str[i] == '.')
|
||||
{
|
||||
int i0 = i;
|
||||
do
|
||||
i += 1;
|
||||
while (isspace (str[i]));
|
||||
if (strncmp (str+i, "all", 3) == 0
|
||||
&& ! isalnum (str[i+3]) && str[i+3] != '_')
|
||||
return i0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns non-zero iff string SUBSEQ matches a subsequence of STR, ignoring
|
||||
case. */
|
||||
|
||||
static int
|
||||
subseqMatch (const char *subseq, const char *str)
|
||||
{
|
||||
if (subseq[0] == '\0')
|
||||
return 1;
|
||||
else if (str[0] == '\0')
|
||||
return 0;
|
||||
else if (tolower (subseq[0]) == tolower (str[0]))
|
||||
return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
|
||||
else
|
||||
return subseqMatch (subseq, str+1);
|
||||
}
|
||||
|
||||
|
||||
static struct { const char *name; int code; }
|
||||
attributes[] = {
|
||||
{ "address", TICK_ADDRESS },
|
||||
{ "unchecked_access", TICK_ACCESS },
|
||||
{ "unrestricted_access", TICK_ACCESS },
|
||||
{ "access", TICK_ACCESS },
|
||||
{ "first", TICK_FIRST },
|
||||
{ "last", TICK_LAST },
|
||||
{ "length", TICK_LENGTH },
|
||||
{ "max", TICK_MAX },
|
||||
{ "min", TICK_MIN },
|
||||
{ "modulus", TICK_MODULUS },
|
||||
{ "pos", TICK_POS },
|
||||
{ "range", TICK_RANGE },
|
||||
{ "size", TICK_SIZE },
|
||||
{ "tag", TICK_TAG },
|
||||
{ "val", TICK_VAL },
|
||||
{ NULL, -1 }
|
||||
};
|
||||
|
||||
/* Return the syntactic code corresponding to the attribute name or
|
||||
abbreviation STR. */
|
||||
|
||||
static int
|
||||
processAttribute (const char *str)
|
||||
{
|
||||
int i, k;
|
||||
|
||||
for (i = 0; attributes[i].code != -1; i += 1)
|
||||
if (strcasecmp (str, attributes[i].name) == 0)
|
||||
return attributes[i].code;
|
||||
|
||||
for (i = 0, k = -1; attributes[i].code != -1; i += 1)
|
||||
if (subseqMatch (str, attributes[i].name))
|
||||
{
|
||||
if (k == -1)
|
||||
k = i;
|
||||
else
|
||||
error (_("ambiguous attribute name: `%s'"), str);
|
||||
}
|
||||
if (k == -1)
|
||||
error (_("unrecognized attribute: `%s'"), str);
|
||||
|
||||
return attributes[k].code;
|
||||
}
|
||||
|
||||
int
|
||||
yywrap(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Dummy definition to suppress warnings about unused static definitions. */
|
||||
typedef void (*dummy_function) ();
|
||||
dummy_function ada_flex_use[] =
|
||||
{
|
||||
(dummy_function) yyunput
|
||||
};
|
||||
@@ -1,864 +0,0 @@
|
||||
/* Support for printing Ada types for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1988, 1989, 1991, 1997, 1998, 1999, 2000,
|
||||
2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdb_obstack.h"
|
||||
#include "bfd.h" /* Binary File Description */
|
||||
#include "symtab.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "expression.h"
|
||||
#include "value.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "command.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "language.h"
|
||||
#include "demangle.h"
|
||||
#include "c-lang.h"
|
||||
#include "typeprint.h"
|
||||
#include "ada-lang.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include "gdb_string.h"
|
||||
#include <errno.h>
|
||||
|
||||
static int print_record_field_types (struct type *, struct type *,
|
||||
struct ui_file *, int, int);
|
||||
|
||||
static void print_array_type (struct type *, struct ui_file *, int, int);
|
||||
|
||||
static void print_choices (struct type *, int, struct ui_file *,
|
||||
struct type *);
|
||||
|
||||
static void print_range (struct type *, struct ui_file *);
|
||||
|
||||
static void print_range_bound (struct type *, char *, int *,
|
||||
struct ui_file *);
|
||||
|
||||
static void
|
||||
print_dynamic_range_bound (struct type *, const char *, int,
|
||||
const char *, struct ui_file *);
|
||||
|
||||
static void print_range_type_named (char *, struct ui_file *);
|
||||
|
||||
|
||||
|
||||
static char *name_buffer;
|
||||
static int name_buffer_len;
|
||||
|
||||
/* The (decoded) Ada name of TYPE. This value persists until the
|
||||
next call. */
|
||||
|
||||
static char *
|
||||
decoded_type_name (struct type *type)
|
||||
{
|
||||
if (ada_type_name (type) == NULL)
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
char *raw_name = ada_type_name (type);
|
||||
char *s, *q;
|
||||
|
||||
if (name_buffer == NULL || name_buffer_len <= strlen (raw_name))
|
||||
{
|
||||
name_buffer_len = 16 + 2 * strlen (raw_name);
|
||||
name_buffer = xrealloc (name_buffer, name_buffer_len);
|
||||
}
|
||||
strcpy (name_buffer, raw_name);
|
||||
|
||||
s = (char *) strstr (name_buffer, "___");
|
||||
if (s != NULL)
|
||||
*s = '\0';
|
||||
|
||||
s = name_buffer + strlen (name_buffer) - 1;
|
||||
while (s > name_buffer && (s[0] != '_' || s[-1] != '_'))
|
||||
s -= 1;
|
||||
|
||||
if (s == name_buffer)
|
||||
return name_buffer;
|
||||
|
||||
if (!islower (s[1]))
|
||||
return NULL;
|
||||
|
||||
for (s = q = name_buffer; *s != '\0'; q += 1)
|
||||
{
|
||||
if (s[0] == '_' && s[1] == '_')
|
||||
{
|
||||
*q = '.';
|
||||
s += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*q = *s;
|
||||
s += 1;
|
||||
}
|
||||
}
|
||||
*q = '\0';
|
||||
return name_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Print a description of a type in the format of a
|
||||
typedef for the current language.
|
||||
NEW is the new name for a type TYPE. */
|
||||
|
||||
void
|
||||
ada_typedef_print (struct type *type, struct symbol *new,
|
||||
struct ui_file *stream)
|
||||
{
|
||||
/* XXX: type_sprint */
|
||||
fprintf_filtered (stream, "type %.*s is ",
|
||||
ada_name_prefix_len (SYMBOL_PRINT_NAME (new)),
|
||||
SYMBOL_PRINT_NAME (new));
|
||||
type_print (type, "", stream, 1);
|
||||
}
|
||||
|
||||
/* Print range type TYPE on STREAM. */
|
||||
|
||||
static void
|
||||
print_range (struct type *type, struct ui_file *stream)
|
||||
{
|
||||
struct type *target_type;
|
||||
target_type = TYPE_TARGET_TYPE (type);
|
||||
if (target_type == NULL)
|
||||
target_type = type;
|
||||
|
||||
switch (TYPE_CODE (target_type))
|
||||
{
|
||||
case TYPE_CODE_RANGE:
|
||||
case TYPE_CODE_INT:
|
||||
case TYPE_CODE_BOOL:
|
||||
case TYPE_CODE_CHAR:
|
||||
case TYPE_CODE_ENUM:
|
||||
break;
|
||||
default:
|
||||
target_type = builtin_type_int;
|
||||
break;
|
||||
}
|
||||
|
||||
if (TYPE_NFIELDS (type) < 2)
|
||||
{
|
||||
/* A range needs at least 2 bounds to be printed. If there are less
|
||||
than 2, just print the type name instead of the range itself.
|
||||
This check handles cases such as characters, for example.
|
||||
|
||||
If the name is not defined, then we don't print anything.
|
||||
*/
|
||||
fprintf_filtered (stream, "%.*s",
|
||||
ada_name_prefix_len (TYPE_NAME (type)),
|
||||
TYPE_NAME (type));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We extract the range type bounds respectively from the first element
|
||||
and the last element of the type->fields array */
|
||||
const LONGEST lower_bound = (LONGEST) TYPE_LOW_BOUND (type);
|
||||
const LONGEST upper_bound =
|
||||
(LONGEST) TYPE_FIELD_BITPOS (type, TYPE_NFIELDS (type) - 1);
|
||||
|
||||
ada_print_scalar (target_type, lower_bound, stream);
|
||||
fprintf_filtered (stream, " .. ");
|
||||
ada_print_scalar (target_type, upper_bound, stream);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the number or discriminant bound at BOUNDS+*N on STREAM, and
|
||||
set *N past the bound and its delimiter, if any. */
|
||||
|
||||
static void
|
||||
print_range_bound (struct type *type, char *bounds, int *n,
|
||||
struct ui_file *stream)
|
||||
{
|
||||
LONGEST B;
|
||||
if (ada_scan_number (bounds, *n, &B, n))
|
||||
{
|
||||
/* STABS decodes all range types which bounds are 0 .. -1 as
|
||||
unsigned integers (ie. the type code is TYPE_CODE_INT, not
|
||||
TYPE_CODE_RANGE). Unfortunately, ada_print_scalar() relies
|
||||
on the unsigned flag to determine whether the bound should
|
||||
be printed as a signed or an unsigned value. This causes
|
||||
the upper bound of the 0 .. -1 range types to be printed as
|
||||
a very large unsigned number instead of -1.
|
||||
To workaround this stabs deficiency, we replace the TYPE by
|
||||
builtin_type_long when we detect that the bound is negative,
|
||||
and the type is a TYPE_CODE_INT. The bound is negative when
|
||||
'm' is the last character of the number scanned in BOUNDS. */
|
||||
if (bounds[*n - 1] == 'm' && TYPE_CODE (type) == TYPE_CODE_INT)
|
||||
type = builtin_type_long;
|
||||
ada_print_scalar (type, B, stream);
|
||||
if (bounds[*n] == '_')
|
||||
*n += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int bound_len;
|
||||
char *bound = bounds + *n;
|
||||
char *pend;
|
||||
|
||||
pend = strstr (bound, "__");
|
||||
if (pend == NULL)
|
||||
*n += bound_len = strlen (bound);
|
||||
else
|
||||
{
|
||||
bound_len = pend - bound;
|
||||
*n += bound_len + 2;
|
||||
}
|
||||
fprintf_filtered (stream, "%.*s", bound_len, bound);
|
||||
}
|
||||
}
|
||||
|
||||
/* Assuming NAME[0 .. NAME_LEN-1] is the name of a range type, print
|
||||
the value (if found) of the bound indicated by SUFFIX ("___L" or
|
||||
"___U") according to the ___XD conventions. */
|
||||
|
||||
static void
|
||||
print_dynamic_range_bound (struct type *type, const char *name, int name_len,
|
||||
const char *suffix, struct ui_file *stream)
|
||||
{
|
||||
static char *name_buf = NULL;
|
||||
static size_t name_buf_len = 0;
|
||||
LONGEST B;
|
||||
int OK;
|
||||
|
||||
GROW_VECT (name_buf, name_buf_len, name_len + strlen (suffix) + 1);
|
||||
strncpy (name_buf, name, name_len);
|
||||
strcpy (name_buf + name_len, suffix);
|
||||
|
||||
B = get_int_var_value (name_buf, &OK);
|
||||
if (OK)
|
||||
ada_print_scalar (type, B, stream);
|
||||
else
|
||||
fprintf_filtered (stream, "?");
|
||||
}
|
||||
|
||||
/* Print the range type named NAME. */
|
||||
|
||||
static void
|
||||
print_range_type_named (char *name, struct ui_file *stream)
|
||||
{
|
||||
struct type *raw_type = ada_find_any_type (name);
|
||||
struct type *base_type;
|
||||
char *subtype_info;
|
||||
|
||||
if (raw_type == NULL)
|
||||
base_type = builtin_type_int;
|
||||
else if (TYPE_CODE (raw_type) == TYPE_CODE_RANGE)
|
||||
base_type = TYPE_TARGET_TYPE (raw_type);
|
||||
else
|
||||
base_type = raw_type;
|
||||
|
||||
subtype_info = strstr (name, "___XD");
|
||||
if (subtype_info == NULL && raw_type == NULL)
|
||||
fprintf_filtered (stream, "? .. ?");
|
||||
else if (subtype_info == NULL)
|
||||
print_range (raw_type, stream);
|
||||
else
|
||||
{
|
||||
int prefix_len = subtype_info - name;
|
||||
char *bounds_str;
|
||||
int n;
|
||||
|
||||
subtype_info += 5;
|
||||
bounds_str = strchr (subtype_info, '_');
|
||||
n = 1;
|
||||
|
||||
if (*subtype_info == 'L')
|
||||
{
|
||||
print_range_bound (base_type, bounds_str, &n, stream);
|
||||
subtype_info += 1;
|
||||
}
|
||||
else
|
||||
print_dynamic_range_bound (base_type, name, prefix_len, "___L",
|
||||
stream);
|
||||
|
||||
fprintf_filtered (stream, " .. ");
|
||||
|
||||
if (*subtype_info == 'U')
|
||||
print_range_bound (base_type, bounds_str, &n, stream);
|
||||
else
|
||||
print_dynamic_range_bound (base_type, name, prefix_len, "___U",
|
||||
stream);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print enumerated type TYPE on STREAM. */
|
||||
|
||||
static void
|
||||
print_enum_type (struct type *type, struct ui_file *stream)
|
||||
{
|
||||
int len = TYPE_NFIELDS (type);
|
||||
int i, lastval;
|
||||
|
||||
fprintf_filtered (stream, "(");
|
||||
wrap_here (" ");
|
||||
|
||||
lastval = 0;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
QUIT;
|
||||
if (i)
|
||||
fprintf_filtered (stream, ", ");
|
||||
wrap_here (" ");
|
||||
fputs_filtered (ada_enum_name (TYPE_FIELD_NAME (type, i)), stream);
|
||||
if (lastval != TYPE_FIELD_BITPOS (type, i))
|
||||
{
|
||||
fprintf_filtered (stream, " => %d", TYPE_FIELD_BITPOS (type, i));
|
||||
lastval = TYPE_FIELD_BITPOS (type, i);
|
||||
}
|
||||
lastval += 1;
|
||||
}
|
||||
fprintf_filtered (stream, ")");
|
||||
}
|
||||
|
||||
/* Print representation of Ada fixed-point type TYPE on STREAM. */
|
||||
|
||||
static void
|
||||
print_fixed_point_type (struct type *type, struct ui_file *stream)
|
||||
{
|
||||
DOUBLEST delta = ada_delta (type);
|
||||
DOUBLEST small = ada_fixed_to_float (type, 1.0);
|
||||
|
||||
if (delta < 0.0)
|
||||
fprintf_filtered (stream, "delta ??");
|
||||
else
|
||||
{
|
||||
fprintf_filtered (stream, "delta %g", (double) delta);
|
||||
if (delta != small)
|
||||
fprintf_filtered (stream, " <'small = %g>", (double) small);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print representation of special VAX floating-point type TYPE on STREAM. */
|
||||
|
||||
static void
|
||||
print_vax_floating_point_type (struct type *type, struct ui_file *stream)
|
||||
{
|
||||
fprintf_filtered (stream, "<float format %c>",
|
||||
ada_vax_float_type_suffix (type));
|
||||
}
|
||||
|
||||
/* Print simple (constrained) array type TYPE on STREAM. LEVEL is the
|
||||
recursion (indentation) level, in case the element type itself has
|
||||
nested structure, and SHOW is the number of levels of internal
|
||||
structure to show (see ada_print_type). */
|
||||
|
||||
static void
|
||||
print_array_type (struct type *type, struct ui_file *stream, int show,
|
||||
int level)
|
||||
{
|
||||
int bitsize;
|
||||
int n_indices;
|
||||
|
||||
bitsize = 0;
|
||||
fprintf_filtered (stream, "array (");
|
||||
|
||||
n_indices = -1;
|
||||
if (show < 0)
|
||||
fprintf_filtered (stream, "...");
|
||||
else
|
||||
{
|
||||
if (ada_is_packed_array_type (type))
|
||||
type = ada_coerce_to_simple_array_type (type);
|
||||
if (type == NULL)
|
||||
{
|
||||
fprintf_filtered (stream, _("<undecipherable array type>"));
|
||||
return;
|
||||
}
|
||||
if (ada_is_simple_array_type (type))
|
||||
{
|
||||
struct type *range_desc_type =
|
||||
ada_find_parallel_type (type, "___XA");
|
||||
struct type *arr_type;
|
||||
|
||||
bitsize = 0;
|
||||
if (range_desc_type == NULL)
|
||||
{
|
||||
for (arr_type = type; TYPE_CODE (arr_type) == TYPE_CODE_ARRAY;
|
||||
arr_type = TYPE_TARGET_TYPE (arr_type))
|
||||
{
|
||||
if (arr_type != type)
|
||||
fprintf_filtered (stream, ", ");
|
||||
print_range (TYPE_INDEX_TYPE (arr_type), stream);
|
||||
if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0)
|
||||
bitsize = TYPE_FIELD_BITSIZE (arr_type, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int k;
|
||||
n_indices = TYPE_NFIELDS (range_desc_type);
|
||||
for (k = 0, arr_type = type;
|
||||
k < n_indices;
|
||||
k += 1, arr_type = TYPE_TARGET_TYPE (arr_type))
|
||||
{
|
||||
if (k > 0)
|
||||
fprintf_filtered (stream, ", ");
|
||||
print_range_type_named (TYPE_FIELD_NAME
|
||||
(range_desc_type, k), stream);
|
||||
if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0)
|
||||
bitsize = TYPE_FIELD_BITSIZE (arr_type, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, i0;
|
||||
for (i = i0 = ada_array_arity (type); i > 0; i -= 1)
|
||||
fprintf_filtered (stream, "%s<>", i == i0 ? "" : ", ");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf_filtered (stream, ") of ");
|
||||
wrap_here ("");
|
||||
ada_print_type (ada_array_element_type (type, n_indices), "", stream,
|
||||
show == 0 ? 0 : show - 1, level + 1);
|
||||
if (bitsize > 0)
|
||||
fprintf_filtered (stream, " <packed: %d-bit elements>", bitsize);
|
||||
}
|
||||
|
||||
/* Print the choices encoded by field FIELD_NUM of variant-part TYPE on
|
||||
STREAM, assuming the VAL_TYPE is the type of the values. */
|
||||
|
||||
static void
|
||||
print_choices (struct type *type, int field_num, struct ui_file *stream,
|
||||
struct type *val_type)
|
||||
{
|
||||
int have_output;
|
||||
int p;
|
||||
const char *name = TYPE_FIELD_NAME (type, field_num);
|
||||
|
||||
have_output = 0;
|
||||
|
||||
/* Skip over leading 'V': NOTE soon to be obsolete. */
|
||||
if (name[0] == 'V')
|
||||
{
|
||||
if (!ada_scan_number (name, 1, NULL, &p))
|
||||
goto Huh;
|
||||
}
|
||||
else
|
||||
p = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (name[p])
|
||||
{
|
||||
default:
|
||||
return;
|
||||
case 'S':
|
||||
case 'R':
|
||||
case 'O':
|
||||
if (have_output)
|
||||
fprintf_filtered (stream, " | ");
|
||||
have_output = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (name[p])
|
||||
{
|
||||
case 'S':
|
||||
{
|
||||
LONGEST W;
|
||||
if (!ada_scan_number (name, p + 1, &W, &p))
|
||||
goto Huh;
|
||||
ada_print_scalar (val_type, W, stream);
|
||||
break;
|
||||
}
|
||||
case 'R':
|
||||
{
|
||||
LONGEST L, U;
|
||||
if (!ada_scan_number (name, p + 1, &L, &p)
|
||||
|| name[p] != 'T' || !ada_scan_number (name, p + 1, &U, &p))
|
||||
goto Huh;
|
||||
ada_print_scalar (val_type, L, stream);
|
||||
fprintf_filtered (stream, " .. ");
|
||||
ada_print_scalar (val_type, U, stream);
|
||||
break;
|
||||
}
|
||||
case 'O':
|
||||
fprintf_filtered (stream, "others");
|
||||
p += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Huh:
|
||||
fprintf_filtered (stream, "??");
|
||||
|
||||
}
|
||||
|
||||
/* Assuming that field FIELD_NUM of TYPE is a VARIANTS field whose
|
||||
discriminant is contained in OUTER_TYPE, print its variants on STREAM.
|
||||
LEVEL is the recursion
|
||||
(indentation) level, in case any of the fields themselves have
|
||||
nested structure, and SHOW is the number of levels of internal structure
|
||||
to show (see ada_print_type). For this purpose, fields nested in a
|
||||
variant part are taken to be at the same level as the fields
|
||||
immediately outside the variant part. */
|
||||
|
||||
static void
|
||||
print_variant_clauses (struct type *type, int field_num,
|
||||
struct type *outer_type, struct ui_file *stream,
|
||||
int show, int level)
|
||||
{
|
||||
int i;
|
||||
struct type *var_type, *par_type;
|
||||
struct type *discr_type;
|
||||
|
||||
var_type = TYPE_FIELD_TYPE (type, field_num);
|
||||
discr_type = ada_variant_discrim_type (var_type, outer_type);
|
||||
|
||||
if (TYPE_CODE (var_type) == TYPE_CODE_PTR)
|
||||
{
|
||||
var_type = TYPE_TARGET_TYPE (var_type);
|
||||
if (var_type == NULL || TYPE_CODE (var_type) != TYPE_CODE_UNION)
|
||||
return;
|
||||
}
|
||||
|
||||
par_type = ada_find_parallel_type (var_type, "___XVU");
|
||||
if (par_type != NULL)
|
||||
var_type = par_type;
|
||||
|
||||
for (i = 0; i < TYPE_NFIELDS (var_type); i += 1)
|
||||
{
|
||||
fprintf_filtered (stream, "\n%*swhen ", level + 4, "");
|
||||
print_choices (var_type, i, stream, discr_type);
|
||||
fprintf_filtered (stream, " =>");
|
||||
if (print_record_field_types (TYPE_FIELD_TYPE (var_type, i),
|
||||
outer_type, stream, show, level + 4) <= 0)
|
||||
fprintf_filtered (stream, " null;");
|
||||
}
|
||||
}
|
||||
|
||||
/* Assuming that field FIELD_NUM of TYPE is a variant part whose
|
||||
discriminants are contained in OUTER_TYPE, print a description of it
|
||||
on STREAM. LEVEL is the recursion (indentation) level, in case any of
|
||||
the fields themselves have nested structure, and SHOW is the number of
|
||||
levels of internal structure to show (see ada_print_type). For this
|
||||
purpose, fields nested in a variant part are taken to be at the same
|
||||
level as the fields immediately outside the variant part. */
|
||||
|
||||
static void
|
||||
print_variant_part (struct type *type, int field_num, struct type *outer_type,
|
||||
struct ui_file *stream, int show, int level)
|
||||
{
|
||||
fprintf_filtered (stream, "\n%*scase %s is", level + 4, "",
|
||||
ada_variant_discrim_name
|
||||
(TYPE_FIELD_TYPE (type, field_num)));
|
||||
print_variant_clauses (type, field_num, outer_type, stream, show,
|
||||
level + 4);
|
||||
fprintf_filtered (stream, "\n%*send case;", level + 4, "");
|
||||
}
|
||||
|
||||
/* Print a description on STREAM of the fields in record type TYPE, whose
|
||||
discriminants are in OUTER_TYPE. LEVEL is the recursion (indentation)
|
||||
level, in case any of the fields themselves have nested structure,
|
||||
and SHOW is the number of levels of internal structure to show
|
||||
(see ada_print_type). Does not print parent type information of TYPE.
|
||||
Returns 0 if no fields printed, -1 for an incomplete type, else > 0.
|
||||
Prints each field beginning on a new line, but does not put a new line at
|
||||
end. */
|
||||
|
||||
static int
|
||||
print_record_field_types (struct type *type, struct type *outer_type,
|
||||
struct ui_file *stream, int show, int level)
|
||||
{
|
||||
int len, i, flds;
|
||||
|
||||
flds = 0;
|
||||
len = TYPE_NFIELDS (type);
|
||||
|
||||
if (len == 0 && (TYPE_FLAGS (type) & TYPE_FLAG_STUB) != 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < len; i += 1)
|
||||
{
|
||||
QUIT;
|
||||
|
||||
if (ada_is_parent_field (type, i) || ada_is_ignored_field (type, i))
|
||||
;
|
||||
else if (ada_is_wrapper_field (type, i))
|
||||
flds += print_record_field_types (TYPE_FIELD_TYPE (type, i), type,
|
||||
stream, show, level);
|
||||
else if (ada_is_variant_part (type, i))
|
||||
{
|
||||
print_variant_part (type, i, outer_type, stream, show, level);
|
||||
flds = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
flds += 1;
|
||||
fprintf_filtered (stream, "\n%*s", level + 4, "");
|
||||
ada_print_type (TYPE_FIELD_TYPE (type, i),
|
||||
TYPE_FIELD_NAME (type, i),
|
||||
stream, show - 1, level + 4);
|
||||
fprintf_filtered (stream, ";");
|
||||
}
|
||||
}
|
||||
|
||||
return flds;
|
||||
}
|
||||
|
||||
/* Print record type TYPE on STREAM. LEVEL is the recursion (indentation)
|
||||
level, in case the element type itself has nested structure, and SHOW is
|
||||
the number of levels of internal structure to show (see ada_print_type). */
|
||||
|
||||
static void
|
||||
print_record_type (struct type *type0, struct ui_file *stream, int show,
|
||||
int level)
|
||||
{
|
||||
struct type *parent_type;
|
||||
struct type *type;
|
||||
|
||||
type = ada_find_parallel_type (type0, "___XVE");
|
||||
if (type == NULL)
|
||||
type = type0;
|
||||
|
||||
parent_type = ada_parent_type (type);
|
||||
if (ada_type_name (parent_type) != NULL)
|
||||
fprintf_filtered (stream, "new %s with record",
|
||||
decoded_type_name (parent_type));
|
||||
else if (parent_type == NULL && ada_is_tagged_type (type, 0))
|
||||
fprintf_filtered (stream, "tagged record");
|
||||
else
|
||||
fprintf_filtered (stream, "record");
|
||||
|
||||
if (show < 0)
|
||||
fprintf_filtered (stream, " ... end record");
|
||||
else
|
||||
{
|
||||
int flds;
|
||||
|
||||
flds = 0;
|
||||
if (parent_type != NULL && ada_type_name (parent_type) == NULL)
|
||||
flds += print_record_field_types (parent_type, parent_type,
|
||||
stream, show, level);
|
||||
flds += print_record_field_types (type, type, stream, show, level);
|
||||
|
||||
if (flds > 0)
|
||||
fprintf_filtered (stream, "\n%*send record", level, "");
|
||||
else if (flds < 0)
|
||||
fprintf_filtered (stream, _(" <incomplete type> end record"));
|
||||
else
|
||||
fprintf_filtered (stream, " null; end record");
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the unchecked union type TYPE in something resembling Ada
|
||||
format on STREAM. LEVEL is the recursion (indentation) level
|
||||
in case the element type itself has nested structure, and SHOW is the
|
||||
number of levels of internal structure to show (see ada_print_type). */
|
||||
static void
|
||||
print_unchecked_union_type (struct type *type, struct ui_file *stream,
|
||||
int show, int level)
|
||||
{
|
||||
if (show < 0)
|
||||
fprintf_filtered (stream, "record (?) is ... end record");
|
||||
else if (TYPE_NFIELDS (type) == 0)
|
||||
fprintf_filtered (stream, "record (?) is null; end record");
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf_filtered (stream, "record (?) is\n%*scase ? is", level + 4, "");
|
||||
|
||||
for (i = 0; i < TYPE_NFIELDS (type); i += 1)
|
||||
{
|
||||
fprintf_filtered (stream, "\n%*swhen ? =>\n%*s", level + 8, "",
|
||||
level + 12, "");
|
||||
ada_print_type (TYPE_FIELD_TYPE (type, i),
|
||||
TYPE_FIELD_NAME (type, i),
|
||||
stream, show - 1, level + 12);
|
||||
fprintf_filtered (stream, ";");
|
||||
}
|
||||
|
||||
fprintf_filtered (stream, "\n%*send case;\n%*send record",
|
||||
level + 4, "", level, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Print function or procedure type TYPE on STREAM. Make it a header
|
||||
for function or procedure NAME if NAME is not null. */
|
||||
|
||||
static void
|
||||
print_func_type (struct type *type, struct ui_file *stream, char *name)
|
||||
{
|
||||
int i, len = TYPE_NFIELDS (type);
|
||||
|
||||
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID)
|
||||
fprintf_filtered (stream, "procedure");
|
||||
else
|
||||
fprintf_filtered (stream, "function");
|
||||
|
||||
if (name != NULL && name[0] != '\0')
|
||||
fprintf_filtered (stream, " %s", name);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
fprintf_filtered (stream, " (");
|
||||
for (i = 0; i < len; i += 1)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
fputs_filtered ("; ", stream);
|
||||
wrap_here (" ");
|
||||
}
|
||||
fprintf_filtered (stream, "a%d: ", i + 1);
|
||||
ada_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0);
|
||||
}
|
||||
fprintf_filtered (stream, ")");
|
||||
}
|
||||
|
||||
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
|
||||
{
|
||||
fprintf_filtered (stream, " return ");
|
||||
ada_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Print a description of a type TYPE0.
|
||||
Output goes to STREAM (via stdio).
|
||||
If VARSTRING is a non-empty string, print as an Ada variable/field
|
||||
declaration.
|
||||
SHOW+1 is the maximum number of levels of internal type structure
|
||||
to show (this applies to record types, enumerated types, and
|
||||
array types).
|
||||
SHOW is the number of levels of internal type structure to show
|
||||
when there is a type name for the SHOWth deepest level (0th is
|
||||
outer level).
|
||||
When SHOW<0, no inner structure is shown.
|
||||
LEVEL indicates level of recursion (for nested definitions). */
|
||||
|
||||
void
|
||||
ada_print_type (struct type *type0, char *varstring, struct ui_file *stream,
|
||||
int show, int level)
|
||||
{
|
||||
struct type *type = ada_check_typedef (ada_get_base_type (type0));
|
||||
char *type_name = decoded_type_name (type);
|
||||
int is_var_decl = (varstring != NULL && varstring[0] != '\0');
|
||||
|
||||
if (type == NULL)
|
||||
{
|
||||
if (is_var_decl)
|
||||
fprintf_filtered (stream, "%.*s: ",
|
||||
ada_name_prefix_len (varstring), varstring);
|
||||
fprintf_filtered (stream, "<null type?>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (show > 0)
|
||||
type = ada_check_typedef (type);
|
||||
|
||||
if (is_var_decl && TYPE_CODE (type) != TYPE_CODE_FUNC)
|
||||
fprintf_filtered (stream, "%.*s: ",
|
||||
ada_name_prefix_len (varstring), varstring);
|
||||
|
||||
if (type_name != NULL && show <= 0)
|
||||
{
|
||||
fprintf_filtered (stream, "%.*s",
|
||||
ada_name_prefix_len (type_name), type_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ada_is_aligner_type (type))
|
||||
ada_print_type (ada_aligned_type (type), "", stream, show, level);
|
||||
else if (ada_is_packed_array_type (type))
|
||||
print_array_type (type, stream, show, level);
|
||||
else
|
||||
switch (TYPE_CODE (type))
|
||||
{
|
||||
default:
|
||||
fprintf_filtered (stream, "<");
|
||||
c_print_type (type, "", stream, show, level);
|
||||
fprintf_filtered (stream, ">");
|
||||
break;
|
||||
case TYPE_CODE_PTR:
|
||||
fprintf_filtered (stream, "access ");
|
||||
ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level);
|
||||
break;
|
||||
case TYPE_CODE_REF:
|
||||
fprintf_filtered (stream, "<ref> ");
|
||||
ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show, level);
|
||||
break;
|
||||
case TYPE_CODE_ARRAY:
|
||||
print_array_type (type, stream, show, level);
|
||||
break;
|
||||
case TYPE_CODE_INT:
|
||||
if (ada_is_fixed_point_type (type))
|
||||
print_fixed_point_type (type, stream);
|
||||
else if (ada_is_vax_floating_type (type))
|
||||
print_vax_floating_point_type (type, stream);
|
||||
else
|
||||
{
|
||||
char *name = ada_type_name (type);
|
||||
if (!ada_is_range_type_name (name))
|
||||
fprintf_filtered (stream, _("<%d-byte integer>"),
|
||||
TYPE_LENGTH (type));
|
||||
else
|
||||
{
|
||||
fprintf_filtered (stream, "range ");
|
||||
print_range_type_named (name, stream);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TYPE_CODE_RANGE:
|
||||
if (ada_is_fixed_point_type (type))
|
||||
print_fixed_point_type (type, stream);
|
||||
else if (ada_is_vax_floating_type (type))
|
||||
print_vax_floating_point_type (type, stream);
|
||||
else if (ada_is_modular_type (type))
|
||||
fprintf_filtered (stream, "mod %s",
|
||||
int_string (ada_modulus (type), 10, 0, 0, 1));
|
||||
else
|
||||
{
|
||||
fprintf_filtered (stream, "range ");
|
||||
print_range (type, stream);
|
||||
}
|
||||
break;
|
||||
case TYPE_CODE_FLT:
|
||||
fprintf_filtered (stream, _("<%d-byte float>"), TYPE_LENGTH (type));
|
||||
break;
|
||||
case TYPE_CODE_ENUM:
|
||||
if (show < 0)
|
||||
fprintf_filtered (stream, "(...)");
|
||||
else
|
||||
print_enum_type (type, stream);
|
||||
break;
|
||||
case TYPE_CODE_STRUCT:
|
||||
if (ada_is_array_descriptor_type (type))
|
||||
print_array_type (type, stream, show, level);
|
||||
else if (ada_is_bogus_array_descriptor (type))
|
||||
fprintf_filtered (stream,
|
||||
_("array (?) of ? (<mal-formed descriptor>)"));
|
||||
else
|
||||
print_record_type (type, stream, show, level);
|
||||
break;
|
||||
case TYPE_CODE_UNION:
|
||||
print_unchecked_union_type (type, stream, show, level);
|
||||
break;
|
||||
case TYPE_CODE_FUNC:
|
||||
print_func_type (type, stream, varstring);
|
||||
break;
|
||||
}
|
||||
}
|
||||
1108
gdb/ada-valprint.c
1108
gdb/ada-valprint.c
File diff suppressed because it is too large
Load Diff
1786
gdb/aix-thread.c
1786
gdb/aix-thread.c
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
||||
/* Low level Alpha GNU/Linux interface, for GDB when running native.
|
||||
Copyright (C) 2005
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "target.h"
|
||||
#include "linux-nat.h"
|
||||
|
||||
void _initialialize_alpha_linux_nat (void);
|
||||
|
||||
void
|
||||
_initialize_alpha_linux_nat (void)
|
||||
{
|
||||
add_target (linux_target ());
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/* Target-dependent code for GNU/Linux on Alpha.
|
||||
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "gdb_assert.h"
|
||||
#include "osabi.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
|
||||
/* Under GNU/Linux, signal handler invocations can be identified by
|
||||
the designated code sequence that is used to return from a signal
|
||||
handler. In particular, the return address of a signal handler
|
||||
points to a sequence that copies $sp to $16, loads $0 with the
|
||||
appropriate syscall number, and finally enters the kernel.
|
||||
|
||||
This is somewhat complicated in that:
|
||||
(1) the expansion of the "mov" assembler macro has changed over
|
||||
time, from "bis src,src,dst" to "bis zero,src,dst",
|
||||
(2) the kernel has changed from using "addq" to "lda" to load the
|
||||
syscall number,
|
||||
(3) there is a "normal" sigreturn and an "rt" sigreturn which
|
||||
has a different stack layout.
|
||||
*/
|
||||
|
||||
static long
|
||||
alpha_linux_sigtramp_offset_1 (CORE_ADDR pc)
|
||||
{
|
||||
switch (alpha_read_insn (pc))
|
||||
{
|
||||
case 0x47de0410: /* bis $30,$30,$16 */
|
||||
case 0x47fe0410: /* bis $31,$30,$16 */
|
||||
return 0;
|
||||
|
||||
case 0x43ecf400: /* addq $31,103,$0 */
|
||||
case 0x201f0067: /* lda $0,103($31) */
|
||||
case 0x201f015f: /* lda $0,351($31) */
|
||||
return 4;
|
||||
|
||||
case 0x00000083: /* call_pal callsys */
|
||||
return 8;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static LONGEST
|
||||
alpha_linux_sigtramp_offset (CORE_ADDR pc)
|
||||
{
|
||||
long i, off;
|
||||
|
||||
if (pc & 3)
|
||||
return -1;
|
||||
|
||||
/* Guess where we might be in the sequence. */
|
||||
off = alpha_linux_sigtramp_offset_1 (pc);
|
||||
if (off < 0)
|
||||
return -1;
|
||||
|
||||
/* Verify that the other two insns of the sequence are as we expect. */
|
||||
pc -= off;
|
||||
for (i = 0; i < 12; i += 4)
|
||||
{
|
||||
if (i == off)
|
||||
continue;
|
||||
if (alpha_linux_sigtramp_offset_1 (pc + i) != i)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
static int
|
||||
alpha_linux_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
|
||||
{
|
||||
return alpha_linux_sigtramp_offset (pc) >= 0;
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_linux_sigcontext_addr (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR pc;
|
||||
ULONGEST sp;
|
||||
long off;
|
||||
|
||||
pc = frame_pc_unwind (next_frame);
|
||||
frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &sp);
|
||||
|
||||
off = alpha_linux_sigtramp_offset (pc);
|
||||
gdb_assert (off >= 0);
|
||||
|
||||
/* __NR_rt_sigreturn has a couple of structures on the stack. This is:
|
||||
|
||||
struct rt_sigframe {
|
||||
struct siginfo info;
|
||||
struct ucontext uc;
|
||||
};
|
||||
|
||||
offsetof (struct rt_sigframe, uc.uc_mcontext);
|
||||
*/
|
||||
if (alpha_read_insn (pc - off + 4) == 0x201f015f)
|
||||
return sp + 176;
|
||||
|
||||
/* __NR_sigreturn has the sigcontext structure at the top of the stack. */
|
||||
return sp;
|
||||
}
|
||||
|
||||
static void
|
||||
alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep;
|
||||
|
||||
/* Hook into the DWARF CFI frame unwinder. */
|
||||
alpha_dwarf2_init_abi (info, gdbarch);
|
||||
|
||||
/* Hook into the MDEBUG frame unwinder. */
|
||||
alpha_mdebug_init_abi (info, gdbarch);
|
||||
|
||||
tdep = gdbarch_tdep (gdbarch);
|
||||
tdep->dynamic_sigtramp_offset = alpha_linux_sigtramp_offset;
|
||||
tdep->sigcontext_addr = alpha_linux_sigcontext_addr;
|
||||
tdep->pc_in_sigtramp = alpha_linux_pc_in_sigtramp;
|
||||
tdep->jb_pc = 2;
|
||||
tdep->jb_elt_size = 8;
|
||||
|
||||
/* Enable TLS support. */
|
||||
set_gdbarch_fetch_tls_load_module_address (gdbarch,
|
||||
svr4_fetch_objfile_link_map);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_alpha_linux_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_LINUX,
|
||||
alpha_linux_init_abi);
|
||||
}
|
||||
@@ -1,387 +0,0 @@
|
||||
/* Target-dependent mdebug code for the ALPHA architecture.
|
||||
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "frame-unwind.h"
|
||||
#include "frame-base.h"
|
||||
#include "symtab.h"
|
||||
#include "gdbcore.h"
|
||||
#include "block.h"
|
||||
#include "gdb_assert.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
#include "mdebugread.h"
|
||||
|
||||
/* FIXME: Some of this code should perhaps be merged with mips. */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
/* Layout of a stack frame on the alpha:
|
||||
|
||||
| |
|
||||
pdr members: | 7th ... nth arg, |
|
||||
| `pushed' by caller. |
|
||||
| |
|
||||
----------------|-------------------------------|<-- old_sp == vfp
|
||||
^ ^ ^ ^ | |
|
||||
| | | | | |
|
||||
| |localoff | Copies of 1st .. 6th |
|
||||
| | | | | argument if necessary. |
|
||||
| | | v | |
|
||||
| | | --- |-------------------------------|<-- LOCALS_ADDRESS
|
||||
| | | | |
|
||||
| | | | Locals and temporaries. |
|
||||
| | | | |
|
||||
| | | |-------------------------------|
|
||||
| | | | |
|
||||
|-fregoffset | Saved float registers. |
|
||||
| | | | F9 |
|
||||
| | | | . |
|
||||
| | | | . |
|
||||
| | | | F2 |
|
||||
| | v | |
|
||||
| | -------|-------------------------------|
|
||||
| | | |
|
||||
| | | Saved registers. |
|
||||
| | | S6 |
|
||||
|-regoffset | . |
|
||||
| | | . |
|
||||
| | | S0 |
|
||||
| | | pdr.pcreg |
|
||||
| v | |
|
||||
| ----------|-------------------------------|
|
||||
| | |
|
||||
frameoffset | Argument build area, gets |
|
||||
| | 7th ... nth arg for any |
|
||||
| | called procedure. |
|
||||
v | |
|
||||
-------------|-------------------------------|<-- sp
|
||||
| |
|
||||
*/
|
||||
/* *INDENT-ON* */
|
||||
|
||||
#define PROC_LOW_ADDR(proc) ((proc)->pdr.adr)
|
||||
#define PROC_FRAME_OFFSET(proc) ((proc)->pdr.frameoffset)
|
||||
#define PROC_FRAME_REG(proc) ((proc)->pdr.framereg)
|
||||
#define PROC_REG_MASK(proc) ((proc)->pdr.regmask)
|
||||
#define PROC_FREG_MASK(proc) ((proc)->pdr.fregmask)
|
||||
#define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)
|
||||
#define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)
|
||||
#define PROC_PC_REG(proc) ((proc)->pdr.pcreg)
|
||||
#define PROC_LOCALOFF(proc) ((proc)->pdr.localoff)
|
||||
|
||||
/* Locate the mdebug PDR for the given PC. Return null if one can't
|
||||
be found; you'll have to fall back to other methods in that case. */
|
||||
|
||||
static struct mdebug_extra_func_info *
|
||||
find_proc_desc (CORE_ADDR pc)
|
||||
{
|
||||
struct block *b = block_for_pc (pc);
|
||||
struct mdebug_extra_func_info *proc_desc = NULL;
|
||||
struct symbol *sym = NULL;
|
||||
|
||||
if (b)
|
||||
{
|
||||
CORE_ADDR startaddr;
|
||||
find_pc_partial_function (pc, NULL, &startaddr, NULL);
|
||||
|
||||
if (startaddr > BLOCK_START (b))
|
||||
/* This is the "pathological" case referred to in a comment in
|
||||
print_frame_info. It might be better to move this check into
|
||||
symbol reading. */
|
||||
sym = NULL;
|
||||
else
|
||||
sym = lookup_symbol (MDEBUG_EFI_SYMBOL_NAME, b, LABEL_DOMAIN, 0, NULL);
|
||||
}
|
||||
|
||||
if (sym)
|
||||
{
|
||||
proc_desc = (struct mdebug_extra_func_info *) SYMBOL_VALUE (sym);
|
||||
|
||||
/* If we never found a PDR for this function in symbol reading,
|
||||
then examine prologues to find the information. */
|
||||
if (proc_desc->pdr.framereg == -1)
|
||||
proc_desc = NULL;
|
||||
}
|
||||
|
||||
return proc_desc;
|
||||
}
|
||||
|
||||
/* This returns the PC of the first inst after the prologue. If we can't
|
||||
find the prologue, then return 0. */
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_mdebug_after_prologue (CORE_ADDR pc, struct mdebug_extra_func_info *proc_desc)
|
||||
{
|
||||
if (proc_desc)
|
||||
{
|
||||
/* If function is frameless, then we need to do it the hard way. I
|
||||
strongly suspect that frameless always means prologueless... */
|
||||
if (PROC_FRAME_REG (proc_desc) == ALPHA_SP_REGNUM
|
||||
&& PROC_FRAME_OFFSET (proc_desc) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return alpha_after_prologue (pc);
|
||||
}
|
||||
|
||||
/* Return non-zero if we *might* be in a function prologue. Return zero
|
||||
if we are definitively *not* in a function prologue. */
|
||||
|
||||
static int
|
||||
alpha_mdebug_in_prologue (CORE_ADDR pc, struct mdebug_extra_func_info *proc_desc)
|
||||
{
|
||||
CORE_ADDR after_prologue_pc = alpha_mdebug_after_prologue (pc, proc_desc);
|
||||
return (after_prologue_pc == 0 || pc < after_prologue_pc);
|
||||
}
|
||||
|
||||
|
||||
/* Frame unwinder that reads mdebug PDRs. */
|
||||
|
||||
struct alpha_mdebug_unwind_cache
|
||||
{
|
||||
struct mdebug_extra_func_info *proc_desc;
|
||||
CORE_ADDR vfp;
|
||||
CORE_ADDR *saved_regs;
|
||||
};
|
||||
|
||||
/* Extract all of the information about the frame from PROC_DESC
|
||||
and store the resulting register save locations in the structure. */
|
||||
|
||||
static struct alpha_mdebug_unwind_cache *
|
||||
alpha_mdebug_frame_unwind_cache (struct frame_info *next_frame,
|
||||
void **this_prologue_cache)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info;
|
||||
struct mdebug_extra_func_info *proc_desc;
|
||||
ULONGEST vfp;
|
||||
CORE_ADDR pc, reg_position;
|
||||
unsigned long mask;
|
||||
int ireg, returnreg;
|
||||
|
||||
if (*this_prologue_cache)
|
||||
return *this_prologue_cache;
|
||||
|
||||
info = FRAME_OBSTACK_ZALLOC (struct alpha_mdebug_unwind_cache);
|
||||
*this_prologue_cache = info;
|
||||
pc = frame_pc_unwind (next_frame);
|
||||
|
||||
/* ??? We don't seem to be able to cache the lookup of the PDR
|
||||
from alpha_mdebug_frame_p. It'd be nice if we could change
|
||||
the arguments to that function. Oh well. */
|
||||
proc_desc = find_proc_desc (pc);
|
||||
info->proc_desc = proc_desc;
|
||||
gdb_assert (proc_desc != NULL);
|
||||
|
||||
info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
|
||||
|
||||
/* The VFP of the frame is at FRAME_REG+FRAME_OFFSET. */
|
||||
frame_unwind_unsigned_register (next_frame, PROC_FRAME_REG (proc_desc), &vfp);
|
||||
vfp += PROC_FRAME_OFFSET (info->proc_desc);
|
||||
info->vfp = vfp;
|
||||
|
||||
/* Fill in the offsets for the registers which gen_mask says were saved. */
|
||||
|
||||
reg_position = vfp + PROC_REG_OFFSET (proc_desc);
|
||||
mask = PROC_REG_MASK (proc_desc);
|
||||
returnreg = PROC_PC_REG (proc_desc);
|
||||
|
||||
/* Note that RA is always saved first, regardless of its actual
|
||||
register number. */
|
||||
if (mask & (1 << returnreg))
|
||||
{
|
||||
/* Clear bit for RA so we don't save it again later. */
|
||||
mask &= ~(1 << returnreg);
|
||||
|
||||
info->saved_regs[returnreg] = reg_position;
|
||||
reg_position += 8;
|
||||
}
|
||||
|
||||
for (ireg = 0; ireg <= 31; ++ireg)
|
||||
if (mask & (1 << ireg))
|
||||
{
|
||||
info->saved_regs[ireg] = reg_position;
|
||||
reg_position += 8;
|
||||
}
|
||||
|
||||
reg_position = vfp + PROC_FREG_OFFSET (proc_desc);
|
||||
mask = PROC_FREG_MASK (proc_desc);
|
||||
|
||||
for (ireg = 0; ireg <= 31; ++ireg)
|
||||
if (mask & (1 << ireg))
|
||||
{
|
||||
info->saved_regs[ALPHA_FP0_REGNUM + ireg] = reg_position;
|
||||
reg_position += 8;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/* Given a GDB frame, determine the address of the calling function's
|
||||
frame. This will be used to create a new GDB frame struct. */
|
||||
|
||||
static void
|
||||
alpha_mdebug_frame_this_id (struct frame_info *next_frame,
|
||||
void **this_prologue_cache,
|
||||
struct frame_id *this_id)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
|
||||
|
||||
*this_id = frame_id_build (info->vfp, frame_func_unwind (next_frame));
|
||||
}
|
||||
|
||||
/* Retrieve the value of REGNUM in FRAME. Don't give up! */
|
||||
|
||||
static void
|
||||
alpha_mdebug_frame_prev_register (struct frame_info *next_frame,
|
||||
void **this_prologue_cache,
|
||||
int regnum, int *optimizedp,
|
||||
enum lval_type *lvalp, CORE_ADDR *addrp,
|
||||
int *realnump, gdb_byte *bufferp)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
|
||||
|
||||
/* The PC of the previous frame is stored in the link register of
|
||||
the current frame. Frob regnum so that we pull the value from
|
||||
the correct place. */
|
||||
if (regnum == ALPHA_PC_REGNUM)
|
||||
regnum = PROC_PC_REG (info->proc_desc);
|
||||
|
||||
/* For all registers known to be saved in the current frame,
|
||||
do the obvious and pull the value out. */
|
||||
if (info->saved_regs[regnum])
|
||||
{
|
||||
*optimizedp = 0;
|
||||
*lvalp = lval_memory;
|
||||
*addrp = info->saved_regs[regnum];
|
||||
*realnump = -1;
|
||||
if (bufferp != NULL)
|
||||
get_frame_memory (next_frame, *addrp, bufferp, ALPHA_REGISTER_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The stack pointer of the previous frame is computed by popping
|
||||
the current stack frame. */
|
||||
if (regnum == ALPHA_SP_REGNUM)
|
||||
{
|
||||
*optimizedp = 0;
|
||||
*lvalp = not_lval;
|
||||
*addrp = 0;
|
||||
*realnump = -1;
|
||||
if (bufferp != NULL)
|
||||
store_unsigned_integer (bufferp, ALPHA_REGISTER_SIZE, info->vfp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise assume the next frame has the same register value. */
|
||||
frame_register (next_frame, regnum, optimizedp, lvalp, addrp,
|
||||
realnump, bufferp);
|
||||
}
|
||||
|
||||
static const struct frame_unwind alpha_mdebug_frame_unwind = {
|
||||
NORMAL_FRAME,
|
||||
alpha_mdebug_frame_this_id,
|
||||
alpha_mdebug_frame_prev_register
|
||||
};
|
||||
|
||||
const struct frame_unwind *
|
||||
alpha_mdebug_frame_sniffer (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR pc = frame_pc_unwind (next_frame);
|
||||
struct mdebug_extra_func_info *proc_desc;
|
||||
|
||||
/* If this PC does not map to a PDR, then clearly this isn't an
|
||||
mdebug frame. */
|
||||
proc_desc = find_proc_desc (pc);
|
||||
if (proc_desc == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If we're in the prologue, the PDR for this frame is not yet valid.
|
||||
Say no here and we'll fall back on the heuristic unwinder. */
|
||||
if (alpha_mdebug_in_prologue (pc, proc_desc))
|
||||
return NULL;
|
||||
|
||||
return &alpha_mdebug_frame_unwind;
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_mdebug_frame_base_address (struct frame_info *next_frame,
|
||||
void **this_prologue_cache)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
|
||||
|
||||
return info->vfp;
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_mdebug_frame_locals_address (struct frame_info *next_frame,
|
||||
void **this_prologue_cache)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
|
||||
|
||||
return info->vfp - PROC_LOCALOFF (info->proc_desc);
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_mdebug_frame_args_address (struct frame_info *next_frame,
|
||||
void **this_prologue_cache)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (next_frame, this_prologue_cache);
|
||||
|
||||
return info->vfp - ALPHA_NUM_ARG_REGS * 8;
|
||||
}
|
||||
|
||||
static const struct frame_base alpha_mdebug_frame_base = {
|
||||
&alpha_mdebug_frame_unwind,
|
||||
alpha_mdebug_frame_base_address,
|
||||
alpha_mdebug_frame_locals_address,
|
||||
alpha_mdebug_frame_args_address
|
||||
};
|
||||
|
||||
static const struct frame_base *
|
||||
alpha_mdebug_frame_base_sniffer (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR pc = frame_pc_unwind (next_frame);
|
||||
struct mdebug_extra_func_info *proc_desc;
|
||||
|
||||
/* If this PC does not map to a PDR, then clearly this isn't an
|
||||
mdebug frame. */
|
||||
proc_desc = find_proc_desc (pc);
|
||||
if (proc_desc == NULL)
|
||||
return NULL;
|
||||
|
||||
return &alpha_mdebug_frame_base;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
alpha_mdebug_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
frame_unwind_append_sniffer (gdbarch, alpha_mdebug_frame_sniffer);
|
||||
frame_base_append_sniffer (gdbarch, alpha_mdebug_frame_base_sniffer);
|
||||
}
|
||||
272
gdb/alpha-nat.c
272
gdb/alpha-nat.c
@@ -1,272 +0,0 @@
|
||||
/* Low level Alpha interface, for GDB when running native.
|
||||
Copyright (C) 1993, 1995, 1996, 1998, 1999, 2000, 2001, 2003
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdb_string.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "regcache.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#ifdef __linux__
|
||||
#include <asm/reg.h>
|
||||
#include <alpha/ptrace.h>
|
||||
#else
|
||||
#include <alpha/coreregs.h>
|
||||
#endif
|
||||
#include <sys/user.h>
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
|
||||
static void fetch_osf_core_registers (char *, unsigned, int, CORE_ADDR);
|
||||
static void fetch_elf_core_registers (char *, unsigned, int, CORE_ADDR);
|
||||
|
||||
/* Extract the register values out of the core file and store
|
||||
them where `read_register' will find them.
|
||||
|
||||
CORE_REG_SECT points to the register values themselves, read into memory.
|
||||
CORE_REG_SIZE is the size of that area.
|
||||
WHICH says which set of registers we are handling (0 = int, 2 = float
|
||||
on machines where they are discontiguous).
|
||||
REG_ADDR is the offset from u.u_ar0 to the register values relative to
|
||||
core_reg_sect. This is used with old-fashioned core files to
|
||||
locate the registers in a large upage-plus-stack ".reg" section.
|
||||
Original upage address X is at location core_reg_sect+x+reg_addr.
|
||||
*/
|
||||
|
||||
static void
|
||||
fetch_osf_core_registers (char *core_reg_sect, unsigned core_reg_size,
|
||||
int which, CORE_ADDR reg_addr)
|
||||
{
|
||||
int regno;
|
||||
int addr;
|
||||
int bad_reg = -1;
|
||||
|
||||
/* Table to map a gdb regnum to an index in the core register
|
||||
section. The floating point register values are garbage in
|
||||
OSF/1.2 core files. OSF5 uses different names for the register
|
||||
enum list, need to handle two cases. The actual values are the
|
||||
same. */
|
||||
static int const core_reg_mapping[ALPHA_NUM_REGS] =
|
||||
{
|
||||
#ifdef NCF_REGS
|
||||
#define EFL NCF_REGS
|
||||
CF_V0, CF_T0, CF_T1, CF_T2, CF_T3, CF_T4, CF_T5, CF_T6,
|
||||
CF_T7, CF_S0, CF_S1, CF_S2, CF_S3, CF_S4, CF_S5, CF_S6,
|
||||
CF_A0, CF_A1, CF_A2, CF_A3, CF_A4, CF_A5, CF_T8, CF_T9,
|
||||
CF_T10, CF_T11, CF_RA, CF_T12, CF_AT, CF_GP, CF_SP, -1,
|
||||
EFL + 0, EFL + 1, EFL + 2, EFL + 3, EFL + 4, EFL + 5, EFL + 6, EFL + 7,
|
||||
EFL + 8, EFL + 9, EFL + 10, EFL + 11, EFL + 12, EFL + 13, EFL + 14, EFL + 15,
|
||||
EFL + 16, EFL + 17, EFL + 18, EFL + 19, EFL + 20, EFL + 21, EFL + 22, EFL + 23,
|
||||
EFL + 24, EFL + 25, EFL + 26, EFL + 27, EFL + 28, EFL + 29, EFL + 30, EFL + 31,
|
||||
CF_PC, -1, -1
|
||||
#else
|
||||
#define EFL (EF_SIZE / 8)
|
||||
EF_V0, EF_T0, EF_T1, EF_T2, EF_T3, EF_T4, EF_T5, EF_T6,
|
||||
EF_T7, EF_S0, EF_S1, EF_S2, EF_S3, EF_S4, EF_S5, EF_S6,
|
||||
EF_A0, EF_A1, EF_A2, EF_A3, EF_A4, EF_A5, EF_T8, EF_T9,
|
||||
EF_T10, EF_T11, EF_RA, EF_T12, EF_AT, EF_GP, EF_SP, -1,
|
||||
EFL + 0, EFL + 1, EFL + 2, EFL + 3, EFL + 4, EFL + 5, EFL + 6, EFL + 7,
|
||||
EFL + 8, EFL + 9, EFL + 10, EFL + 11, EFL + 12, EFL + 13, EFL + 14, EFL + 15,
|
||||
EFL + 16, EFL + 17, EFL + 18, EFL + 19, EFL + 20, EFL + 21, EFL + 22, EFL + 23,
|
||||
EFL + 24, EFL + 25, EFL + 26, EFL + 27, EFL + 28, EFL + 29, EFL + 30, EFL + 31,
|
||||
EF_PC, -1, -1
|
||||
#endif
|
||||
};
|
||||
|
||||
for (regno = 0; regno < ALPHA_NUM_REGS; regno++)
|
||||
{
|
||||
if (CANNOT_FETCH_REGISTER (regno))
|
||||
{
|
||||
regcache_raw_supply (current_regcache, regno, NULL);
|
||||
continue;
|
||||
}
|
||||
addr = 8 * core_reg_mapping[regno];
|
||||
if (addr < 0 || addr >= core_reg_size)
|
||||
{
|
||||
/* ??? UNIQUE is a new addition. Don't generate an error. */
|
||||
if (regno == ALPHA_UNIQUE_REGNUM)
|
||||
{
|
||||
regcache_raw_supply (current_regcache, regno, NULL);
|
||||
continue;
|
||||
}
|
||||
if (bad_reg < 0)
|
||||
bad_reg = regno;
|
||||
}
|
||||
else
|
||||
{
|
||||
regcache_raw_supply (current_regcache, regno, core_reg_sect + addr);
|
||||
}
|
||||
}
|
||||
if (bad_reg >= 0)
|
||||
{
|
||||
error (_("Register %s not found in core file."), REGISTER_NAME (bad_reg));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_elf_core_registers (char *core_reg_sect, unsigned core_reg_size,
|
||||
int which, CORE_ADDR reg_addr)
|
||||
{
|
||||
if (core_reg_size < 32 * 8)
|
||||
{
|
||||
error (_("Core file register section too small (%u bytes)."), core_reg_size);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (which)
|
||||
{
|
||||
case 0: /* integer registers */
|
||||
/* PC is in slot 32; UNIQUE is in slot 33, if present. */
|
||||
alpha_supply_int_regs (-1, core_reg_sect, core_reg_sect + 31*8,
|
||||
(core_reg_size >= 33 * 8
|
||||
? core_reg_sect + 32*8 : NULL));
|
||||
break;
|
||||
|
||||
case 2: /* floating-point registers */
|
||||
/* FPCR is in slot 32. */
|
||||
alpha_supply_fp_regs (-1, core_reg_sect, core_reg_sect + 31*8);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Map gdb internal register number to a ptrace ``address''.
|
||||
These ``addresses'' are defined in <sys/ptrace.h>, with
|
||||
the exception of ALPHA_UNIQUE_PTRACE_ADDR. */
|
||||
|
||||
#ifndef ALPHA_UNIQUE_PTRACE_ADDR
|
||||
#define ALPHA_UNIQUE_PTRACE_ADDR 0
|
||||
#endif
|
||||
|
||||
CORE_ADDR
|
||||
register_addr (int regno, CORE_ADDR blockend)
|
||||
{
|
||||
if (regno == PC_REGNUM)
|
||||
return PC;
|
||||
if (regno == ALPHA_UNIQUE_REGNUM)
|
||||
return ALPHA_UNIQUE_PTRACE_ADDR;
|
||||
if (regno < FP0_REGNUM)
|
||||
return GPR_BASE + regno;
|
||||
else
|
||||
return FPR_BASE + regno - FP0_REGNUM;
|
||||
}
|
||||
|
||||
int
|
||||
kernel_u_size (void)
|
||||
{
|
||||
return (sizeof (struct user));
|
||||
}
|
||||
|
||||
#if defined(USE_PROC_FS) || defined(HAVE_GREGSET_T)
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/* Prototypes for supply_gregset etc. */
|
||||
#include "gregset.h"
|
||||
|
||||
/* Locate the UNIQUE value within the gregset_t. */
|
||||
#ifndef ALPHA_REGSET_UNIQUE
|
||||
#define ALPHA_REGSET_UNIQUE(ptr) NULL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* See the comment in m68k-tdep.c regarding the utility of these functions.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_gregset (gdb_gregset_t *gregsetp)
|
||||
{
|
||||
long *regp = ALPHA_REGSET_BASE (gregsetp);
|
||||
void *unique = ALPHA_REGSET_UNIQUE (gregsetp);
|
||||
|
||||
/* PC is in slot 32. */
|
||||
alpha_supply_int_regs (-1, regp, regp + 31, unique);
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (gdb_gregset_t *gregsetp, int regno)
|
||||
{
|
||||
long *regp = ALPHA_REGSET_BASE (gregsetp);
|
||||
void *unique = ALPHA_REGSET_UNIQUE (gregsetp);
|
||||
|
||||
/* PC is in slot 32. */
|
||||
alpha_fill_int_regs (regno, regp, regp + 31, unique);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we do the same thing for floating-point registers.
|
||||
* Again, see the comments in m68k-tdep.c.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_fpregset (gdb_fpregset_t *fpregsetp)
|
||||
{
|
||||
long *regp = ALPHA_REGSET_BASE (fpregsetp);
|
||||
|
||||
/* FPCR is in slot 32. */
|
||||
alpha_supply_fp_regs (-1, regp, regp + 31);
|
||||
}
|
||||
|
||||
void
|
||||
fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
|
||||
{
|
||||
long *regp = ALPHA_REGSET_BASE (fpregsetp);
|
||||
|
||||
/* FPCR is in slot 32. */
|
||||
alpha_fill_fp_regs (regno, regp, regp + 31);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Register that we are able to handle alpha core file formats. */
|
||||
|
||||
static struct core_fns alpha_osf_core_fns =
|
||||
{
|
||||
/* This really is bfd_target_unknown_flavour. */
|
||||
|
||||
bfd_target_unknown_flavour, /* core_flavour */
|
||||
default_check_format, /* check_format */
|
||||
default_core_sniffer, /* core_sniffer */
|
||||
fetch_osf_core_registers, /* core_read_registers */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
static struct core_fns alpha_elf_core_fns =
|
||||
{
|
||||
bfd_target_elf_flavour, /* core_flavour */
|
||||
default_check_format, /* check_format */
|
||||
default_core_sniffer, /* core_sniffer */
|
||||
fetch_elf_core_registers, /* core_read_registers */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_alpha (void)
|
||||
{
|
||||
deprecated_add_core_fns (&alpha_osf_core_fns);
|
||||
deprecated_add_core_fns (&alpha_elf_core_fns);
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/* Target-dependent code for OSF/1 on Alpha.
|
||||
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "value.h"
|
||||
#include "osabi.h"
|
||||
#include "gdb_string.h"
|
||||
#include "objfiles.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
|
||||
static int
|
||||
alpha_osf1_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
|
||||
{
|
||||
return (func_name != NULL && strcmp ("__sigtramp", func_name) == 0);
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_osf1_sigcontext_addr (struct frame_info *next_frame)
|
||||
{
|
||||
const struct frame_id next_id = get_frame_id (next_frame);
|
||||
|
||||
return (read_memory_integer (next_id.stack_addr, 8));
|
||||
}
|
||||
|
||||
static void
|
||||
alpha_osf1_init_abi (struct gdbarch_info info,
|
||||
struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
/* Hook into the MDEBUG frame unwinder. */
|
||||
alpha_mdebug_init_abi (info, gdbarch);
|
||||
|
||||
/* The next/step support via procfs on OSF1 is broken when running
|
||||
on multi-processor machines. We need to use software single stepping
|
||||
instead. */
|
||||
set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
|
||||
|
||||
tdep->sigcontext_addr = alpha_osf1_sigcontext_addr;
|
||||
tdep->pc_in_sigtramp = alpha_osf1_pc_in_sigtramp;
|
||||
|
||||
tdep->jb_pc = 2;
|
||||
tdep->jb_elt_size = 8;
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_alpha_osf1_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OSF1,
|
||||
alpha_osf1_init_abi);
|
||||
}
|
||||
1664
gdb/alpha-tdep.c
1664
gdb/alpha-tdep.c
File diff suppressed because it is too large
Load Diff
115
gdb/alpha-tdep.h
115
gdb/alpha-tdep.h
@@ -1,115 +0,0 @@
|
||||
/* Common target dependent code for GDB on Alpha systems.
|
||||
Copyright (C) 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002, 2003 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef ALPHA_TDEP_H
|
||||
#define ALPHA_TDEP_H
|
||||
|
||||
/* Say how long (ordinary) registers are. This is a piece of bogosity
|
||||
used in push_word and a few other places; register_size() is the
|
||||
real way to know how big a register is. */
|
||||
#define ALPHA_REGISTER_SIZE 8
|
||||
|
||||
/* Number of machine registers. */
|
||||
#define ALPHA_NUM_REGS 67
|
||||
|
||||
/* Total amount of space needed to store our copies of the machine's
|
||||
register state. */
|
||||
#define ALPHA_REGISTER_BYTES (ALPHA_NUM_REGS * 8)
|
||||
|
||||
/* Register numbers of various important registers. Note that most of
|
||||
these values are "real" register numbers, and correspond to the
|
||||
general registers of the machine. */
|
||||
|
||||
#define ALPHA_V0_REGNUM 0 /* Function integer return value */
|
||||
#define ALPHA_T7_REGNUM 8 /* Return address register for OSF/1 __add* */
|
||||
#define ALPHA_GCC_FP_REGNUM 15 /* Used by gcc as frame register */
|
||||
#define ALPHA_A0_REGNUM 16 /* Loc of first arg during a subr call */
|
||||
#define ALPHA_T9_REGNUM 23 /* Return address register for OSF/1 __div* */
|
||||
#define ALPHA_RA_REGNUM 26 /* Contains return address value */
|
||||
#define ALPHA_T12_REGNUM 27 /* Contains start addr of current proc */
|
||||
#define ALPHA_GP_REGNUM 29 /* Contains the global pointer */
|
||||
#define ALPHA_SP_REGNUM 30 /* Contains address of top of stack */
|
||||
#define ALPHA_ZERO_REGNUM 31 /* Read-only register, always 0 */
|
||||
#define ALPHA_FP0_REGNUM 32 /* Floating point register 0 */
|
||||
#define ALPHA_FPA0_REGNUM 48 /* First float arg during a subr call */
|
||||
#define ALPHA_FPCR_REGNUM 63 /* Floating point control register */
|
||||
#define ALPHA_PC_REGNUM 64 /* Contains program counter */
|
||||
#define ALPHA_UNIQUE_REGNUM 66 /* PAL_rduniq value */
|
||||
|
||||
/* The alpha has two different virtual pointers for arguments and locals.
|
||||
|
||||
The virtual argument pointer is pointing to the bottom of the argument
|
||||
transfer area, which is located immediately below the virtual frame
|
||||
pointer. Its size is fixed for the native compiler, it is either zero
|
||||
(for the no arguments case) or large enough to hold all argument registers.
|
||||
gcc uses a variable sized argument transfer area. As it has
|
||||
to stay compatible with the native debugging tools it has to use the same
|
||||
virtual argument pointer and adjust the argument offsets accordingly.
|
||||
|
||||
The virtual local pointer is localoff bytes below the virtual frame
|
||||
pointer, the value of localoff is obtained from the PDR. */
|
||||
#define ALPHA_NUM_ARG_REGS 6
|
||||
|
||||
/* Target-dependent structure in gdbarch. */
|
||||
struct gdbarch_tdep
|
||||
{
|
||||
CORE_ADDR vm_min_address; /* Used by alpha_heuristic_proc_start. */
|
||||
|
||||
/* If PC is inside a dynamically-generated signal trampoline function
|
||||
(i.e. one copied onto the user stack at run-time), return how many
|
||||
bytes PC is beyond the start of that function. Otherwise, return -1. */
|
||||
LONGEST (*dynamic_sigtramp_offset) (CORE_ADDR);
|
||||
|
||||
/* Translate a signal handler stack base address into the address of
|
||||
the sigcontext structure for that signal handler. */
|
||||
CORE_ADDR (*sigcontext_addr) (struct frame_info *);
|
||||
|
||||
/* Does the PC fall in a signal trampoline. */
|
||||
/* NOTE: cagney/2004-04-30: Do not copy/clone this code. Instead
|
||||
look at tramp-frame.h and other simplier per-architecture
|
||||
sigtramp unwinders. */
|
||||
int (*pc_in_sigtramp) (CORE_ADDR pc, char *name);
|
||||
|
||||
/* Offset of registers in `struct sigcontext'. */
|
||||
int sc_pc_offset;
|
||||
int sc_regs_offset;
|
||||
int sc_fpregs_offset;
|
||||
|
||||
int jb_pc; /* Offset to PC value in jump buffer.
|
||||
If htis is negative, longjmp support
|
||||
will be disabled. */
|
||||
size_t jb_elt_size; /* And the size of each entry in the buf. */
|
||||
};
|
||||
|
||||
extern unsigned int alpha_read_insn (CORE_ADDR pc);
|
||||
extern void alpha_software_single_step (enum target_signal, int);
|
||||
extern CORE_ADDR alpha_after_prologue (CORE_ADDR pc);
|
||||
|
||||
extern void alpha_mdebug_init_abi (struct gdbarch_info, struct gdbarch *);
|
||||
extern void alpha_dwarf2_init_abi (struct gdbarch_info, struct gdbarch *);
|
||||
|
||||
extern void alpha_supply_int_regs (int, const void *, const void *,
|
||||
const void *);
|
||||
extern void alpha_fill_int_regs (int, void *, void *, void *);
|
||||
extern void alpha_supply_fp_regs (int, const void *, const void *);
|
||||
extern void alpha_fill_fp_regs (int, void *, void *);
|
||||
|
||||
#endif /* ALPHA_TDEP_H */
|
||||
@@ -1,166 +0,0 @@
|
||||
/* Native-dependent code for Alpha BSD's.
|
||||
|
||||
Copyright (C) 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "regcache.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
#include "alphabsd-tdep.h"
|
||||
#include "inf-ptrace.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
#ifdef HAVE_SYS_PROCFS_H
|
||||
#include <sys/procfs.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GREGSET_T
|
||||
typedef struct reg gregset_t;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FPREGSET_T
|
||||
typedef struct fpreg fpregset_t;
|
||||
#endif
|
||||
|
||||
#include "gregset.h"
|
||||
|
||||
/* Provide *regset() wrappers around the generic Alpha BSD register
|
||||
supply/fill routines. */
|
||||
|
||||
void
|
||||
supply_gregset (gregset_t *gregsetp)
|
||||
{
|
||||
alphabsd_supply_reg ((char *) gregsetp, -1);
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (gregset_t *gregsetp, int regno)
|
||||
{
|
||||
alphabsd_fill_reg ((char *) gregsetp, regno);
|
||||
}
|
||||
|
||||
void
|
||||
supply_fpregset (fpregset_t *fpregsetp)
|
||||
{
|
||||
alphabsd_supply_fpreg ((char *) fpregsetp, -1);
|
||||
}
|
||||
|
||||
void
|
||||
fill_fpregset (fpregset_t *fpregsetp, int regno)
|
||||
{
|
||||
alphabsd_fill_fpreg ((char *) fpregsetp, regno);
|
||||
}
|
||||
|
||||
/* Determine if PT_GETREGS fetches this register. */
|
||||
|
||||
static int
|
||||
getregs_supplies (int regno)
|
||||
{
|
||||
return ((regno >= ALPHA_V0_REGNUM && regno <= ALPHA_ZERO_REGNUM)
|
||||
|| regno >= ALPHA_PC_REGNUM);
|
||||
}
|
||||
|
||||
/* Fetch register REGNO from the inferior. If REGNO is -1, do this
|
||||
for all registers (including the floating point registers). */
|
||||
|
||||
static void
|
||||
alphabsd_fetch_inferior_registers (int regno)
|
||||
{
|
||||
if (regno == -1 || getregs_supplies (regno))
|
||||
{
|
||||
struct reg gregs;
|
||||
|
||||
if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &gregs, 0) == -1)
|
||||
perror_with_name (_("Couldn't get registers"));
|
||||
|
||||
alphabsd_supply_reg ((char *) &gregs, regno);
|
||||
if (regno != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (regno == -1 || regno >= FP0_REGNUM)
|
||||
{
|
||||
struct fpreg fpregs;
|
||||
|
||||
if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||||
perror_with_name (_("Couldn't get floating point status"));
|
||||
|
||||
alphabsd_supply_fpreg ((char *) &fpregs, regno);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store register REGNO back into the inferior. If REGNO is -1, do
|
||||
this for all registers (including the floating point registers). */
|
||||
|
||||
static void
|
||||
alphabsd_store_inferior_registers (int regno)
|
||||
{
|
||||
if (regno == -1 || getregs_supplies (regno))
|
||||
{
|
||||
struct reg gregs;
|
||||
if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &gregs, 0) == -1)
|
||||
perror_with_name (_("Couldn't get registers"));
|
||||
|
||||
alphabsd_fill_reg ((char *) &gregs, regno);
|
||||
|
||||
if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &gregs, 0) == -1)
|
||||
perror_with_name (_("Couldn't write registers"));
|
||||
|
||||
if (regno != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (regno == -1 || regno >= FP0_REGNUM)
|
||||
{
|
||||
struct fpreg fpregs;
|
||||
|
||||
if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||||
perror_with_name (_("Couldn't get floating point status"));
|
||||
|
||||
alphabsd_fill_fpreg ((char *) &fpregs, regno);
|
||||
|
||||
if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||||
perror_with_name (_("Couldn't write floating point status"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_alphabsd_nat (void);
|
||||
|
||||
void
|
||||
_initialize_alphabsd_nat (void)
|
||||
{
|
||||
struct target_ops *t;
|
||||
|
||||
t = inf_ptrace_target ();
|
||||
t->to_fetch_registers = alphabsd_fetch_inferior_registers;
|
||||
t->to_store_registers = alphabsd_store_inferior_registers;
|
||||
add_target (t);
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/* Common target dependent code for GDB on Alpha systems running BSD.
|
||||
Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
#include "alphabsd-tdep.h"
|
||||
|
||||
/* Conviently, GDB uses the same register numbering as the
|
||||
ptrace register structure used by BSD on Alpha. */
|
||||
|
||||
void
|
||||
alphabsd_supply_reg (char *regs, int regno)
|
||||
{
|
||||
/* PC is at slot 32; UNIQUE not present. */
|
||||
alpha_supply_int_regs (regno, regs, regs + 31*8, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
alphabsd_fill_reg (char *regs, int regno)
|
||||
{
|
||||
/* PC is at slot 32; UNIQUE not present. */
|
||||
alpha_fill_int_regs (regno, regs, regs + 31*8, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
alphabsd_supply_fpreg (char *fpregs, int regno)
|
||||
{
|
||||
/* FPCR is at slot 33; slot 32 unused. */
|
||||
alpha_supply_fp_regs (regno, fpregs, fpregs + 32*8);
|
||||
}
|
||||
|
||||
void
|
||||
alphabsd_fill_fpreg (char *fpregs, int regno)
|
||||
{
|
||||
/* FPCR is at slot 33; slot 32 unused. */
|
||||
alpha_fill_fp_regs (regno, fpregs, fpregs + 32*8);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/* Common target dependent code for GDB on Alpha systems running BSD.
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef ALPHABSD_TDEP_H
|
||||
#define ALPHABSD_TDEP_H
|
||||
|
||||
void alphabsd_supply_reg (char *, int);
|
||||
void alphabsd_fill_reg (char *, int);
|
||||
|
||||
void alphabsd_supply_fpreg (char *, int);
|
||||
void alphabsd_fill_fpreg (char *, int);
|
||||
|
||||
#define SIZEOF_STRUCT_REG (32 * 8)
|
||||
#define SIZEOF_STRUCT_FPREG (33 * 8)
|
||||
|
||||
#endif /* ALPHABSD_TDEP_H */
|
||||
@@ -1,130 +0,0 @@
|
||||
/* Target-dependent code for FreeBSD/alpha.
|
||||
|
||||
Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "value.h"
|
||||
#include "osabi.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
static int
|
||||
alphafbsd_use_struct_convention (int gcc_p, struct type *type)
|
||||
{
|
||||
enum type_code code;
|
||||
int i;
|
||||
|
||||
/* All aggregate types that won't fit in a register must be returned
|
||||
in memory. */
|
||||
if (TYPE_LENGTH (type) > ALPHA_REGISTER_SIZE)
|
||||
return 1;
|
||||
|
||||
/* The only aggregate types that can be returned in a register are
|
||||
structs and unions. Arrays must be returned in memory. */
|
||||
code = TYPE_CODE (type);
|
||||
if (code != TYPE_CODE_STRUCT && code != TYPE_CODE_UNION)
|
||||
return 1;
|
||||
|
||||
/* We need to check if this struct/union is "integer" like. For
|
||||
this to be true, the offset of each adressable subfield must be
|
||||
zero. Note that bit fields are not addressable. */
|
||||
for (i = 0; i < TYPE_NFIELDS (type); i++)
|
||||
{
|
||||
/* If the field bitsize is non-zero, it isn't adressable. */
|
||||
if (TYPE_FIELD_BITPOS (type, i) != 0
|
||||
&& TYPE_FIELD_BITSIZE (type, i) == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Support for signal handlers. */
|
||||
|
||||
/* Return whether PC is in a BSD sigtramp routine. */
|
||||
|
||||
CORE_ADDR alphafbsd_sigtramp_start = 0x11ffff68;
|
||||
CORE_ADDR alphafbsd_sigtramp_end = 0x11ffffe0;
|
||||
|
||||
static int
|
||||
alphafbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
|
||||
{
|
||||
return (pc >= alphafbsd_sigtramp_start && pc < alphafbsd_sigtramp_end);
|
||||
}
|
||||
|
||||
static LONGEST
|
||||
alphafbsd_sigtramp_offset (CORE_ADDR pc)
|
||||
{
|
||||
return pc - alphafbsd_sigtramp_start;
|
||||
}
|
||||
|
||||
/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
|
||||
routine, return the address of the associated sigcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
alphafbsd_sigcontext_addr (struct frame_info *next_frame)
|
||||
{
|
||||
return frame_unwind_register_unsigned (next_frame, ALPHA_SP_REGNUM) + 24;
|
||||
}
|
||||
|
||||
/* FreeBSD 5.0-RELEASE or later. */
|
||||
|
||||
static void
|
||||
alphafbsd_init_abi (struct gdbarch_info info,
|
||||
struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
/* Hook into the DWARF CFI frame unwinder. */
|
||||
alpha_dwarf2_init_abi (info, gdbarch);
|
||||
|
||||
/* Hook into the MDEBUG frame unwinder. */
|
||||
alpha_mdebug_init_abi (info, gdbarch);
|
||||
|
||||
/* FreeBSD/alpha has SVR4-style shared libraries. */
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_lp64_fetch_link_map_offsets);
|
||||
|
||||
set_gdbarch_deprecated_use_struct_convention
|
||||
(gdbarch, alphafbsd_use_struct_convention);
|
||||
|
||||
tdep->dynamic_sigtramp_offset = alphafbsd_sigtramp_offset;
|
||||
tdep->sigcontext_addr = alphafbsd_sigcontext_addr;
|
||||
tdep->pc_in_sigtramp = alphafbsd_pc_in_sigtramp;
|
||||
tdep->sc_pc_offset = 288;
|
||||
tdep->sc_regs_offset = 24;
|
||||
tdep->sc_fpregs_offset = 320;
|
||||
|
||||
tdep->jb_pc = 2;
|
||||
tdep->jb_elt_size = 8;
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_alphafbsd_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_alphafbsd_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_FREEBSD_ELF,
|
||||
alphafbsd_init_abi);
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
/* Target-dependent code for NetBSD/Alpha.
|
||||
|
||||
Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
Contributed by Wasabi Systems, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "frame.h"
|
||||
#include "regcache.h"
|
||||
#include "value.h"
|
||||
#include "osabi.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
#include "alphabsd-tdep.h"
|
||||
#include "nbsd-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
static void
|
||||
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
|
||||
CORE_ADDR ignore)
|
||||
{
|
||||
char *regs, *fpregs;
|
||||
int regno;
|
||||
|
||||
/* Table to map a gdb register number to a trapframe register index. */
|
||||
static const int regmap[] =
|
||||
{
|
||||
0, 1, 2, 3,
|
||||
4, 5, 6, 7,
|
||||
8, 9, 10, 11,
|
||||
12, 13, 14, 15,
|
||||
30, 31, 32, 16,
|
||||
17, 18, 19, 20,
|
||||
21, 22, 23, 24,
|
||||
25, 29, 26
|
||||
};
|
||||
#define SIZEOF_TRAPFRAME (33 * 8)
|
||||
|
||||
/* We get everything from one section. */
|
||||
if (which != 0)
|
||||
return;
|
||||
|
||||
regs = core_reg_sect;
|
||||
fpregs = core_reg_sect + SIZEOF_TRAPFRAME;
|
||||
|
||||
if (core_reg_size < (SIZEOF_TRAPFRAME + SIZEOF_STRUCT_FPREG))
|
||||
{
|
||||
warning (_("Wrong size register set in core file."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Integer registers. */
|
||||
for (regno = 0; regno < ALPHA_ZERO_REGNUM; regno++)
|
||||
regcache_raw_supply (current_regcache, regno, regs + (regmap[regno] * 8));
|
||||
regcache_raw_supply (current_regcache, ALPHA_ZERO_REGNUM, NULL);
|
||||
regcache_raw_supply (current_regcache, PC_REGNUM, regs + (28 * 8));
|
||||
|
||||
/* Floating point registers. */
|
||||
alphabsd_supply_fpreg (fpregs, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
|
||||
CORE_ADDR ignore)
|
||||
{
|
||||
switch (which)
|
||||
{
|
||||
case 0: /* Integer registers. */
|
||||
if (core_reg_size != SIZEOF_STRUCT_REG)
|
||||
warning (_("Wrong size register set in core file."));
|
||||
else
|
||||
alphabsd_supply_reg (core_reg_sect, -1);
|
||||
break;
|
||||
|
||||
case 2: /* Floating point registers. */
|
||||
if (core_reg_size != SIZEOF_STRUCT_FPREG)
|
||||
warning (_("Wrong size FP register set in core file."));
|
||||
else
|
||||
alphabsd_supply_fpreg (core_reg_sect, -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Don't know what kind of register request this is; just ignore it. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct core_fns alphanbsd_core_fns =
|
||||
{
|
||||
bfd_target_unknown_flavour, /* core_flavour */
|
||||
default_check_format, /* check_format */
|
||||
default_core_sniffer, /* core_sniffer */
|
||||
fetch_core_registers, /* core_read_registers */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
static struct core_fns alphanbsd_elfcore_fns =
|
||||
{
|
||||
bfd_target_elf_flavour, /* core_flavour */
|
||||
default_check_format, /* check_format */
|
||||
default_core_sniffer, /* core_sniffer */
|
||||
fetch_elfcore_registers, /* core_read_registers */
|
||||
NULL /* next */
|
||||
};
|
||||
|
||||
/* Under NetBSD/alpha, signal handler invocations can be identified by the
|
||||
designated code sequence that is used to return from a signal handler.
|
||||
In particular, the return address of a signal handler points to the
|
||||
following code sequence:
|
||||
|
||||
ldq a0, 0(sp)
|
||||
lda sp, 16(sp)
|
||||
lda v0, 295(zero) # __sigreturn14
|
||||
call_pal callsys
|
||||
|
||||
Each instruction has a unique encoding, so we simply attempt to match
|
||||
the instruction the PC is pointing to with any of the above instructions.
|
||||
If there is a hit, we know the offset to the start of the designated
|
||||
sequence and can then check whether we really are executing in the
|
||||
signal trampoline. If not, -1 is returned, otherwise the offset from the
|
||||
start of the return sequence is returned. */
|
||||
static const unsigned char sigtramp_retcode[] =
|
||||
{
|
||||
0x00, 0x00, 0x1e, 0xa6, /* ldq a0, 0(sp) */
|
||||
0x10, 0x00, 0xde, 0x23, /* lda sp, 16(sp) */
|
||||
0x27, 0x01, 0x1f, 0x20, /* lda v0, 295(zero) */
|
||||
0x83, 0x00, 0x00, 0x00, /* call_pal callsys */
|
||||
};
|
||||
#define RETCODE_NWORDS 4
|
||||
#define RETCODE_SIZE (RETCODE_NWORDS * 4)
|
||||
|
||||
LONGEST
|
||||
alphanbsd_sigtramp_offset (CORE_ADDR pc)
|
||||
{
|
||||
unsigned char ret[RETCODE_SIZE], w[4];
|
||||
LONGEST off;
|
||||
int i;
|
||||
|
||||
if (deprecated_read_memory_nobpt (pc, (char *) w, 4) != 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < RETCODE_NWORDS; i++)
|
||||
{
|
||||
if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
|
||||
break;
|
||||
}
|
||||
if (i == RETCODE_NWORDS)
|
||||
return (-1);
|
||||
|
||||
off = i * 4;
|
||||
pc -= off;
|
||||
|
||||
if (deprecated_read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
|
||||
return -1;
|
||||
|
||||
if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
|
||||
return off;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
alphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
|
||||
{
|
||||
return (nbsd_pc_in_sigtramp (pc, func_name)
|
||||
|| alphanbsd_sigtramp_offset (pc) >= 0);
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
alphanbsd_sigcontext_addr (struct frame_info *frame)
|
||||
{
|
||||
/* FIXME: This is not correct for all versions of NetBSD/alpha.
|
||||
We will probably need to disassemble the trampoline to figure
|
||||
out which trampoline frame type we have. */
|
||||
return get_frame_base (frame);
|
||||
}
|
||||
|
||||
static void
|
||||
alphanbsd_init_abi (struct gdbarch_info info,
|
||||
struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
/* Hook into the DWARF CFI frame unwinder. */
|
||||
alpha_dwarf2_init_abi (info, gdbarch);
|
||||
|
||||
/* Hook into the MDEBUG frame unwinder. */
|
||||
alpha_mdebug_init_abi (info, gdbarch);
|
||||
|
||||
/* NetBSD/alpha does not provide single step support via ptrace(2); we
|
||||
must use software single-stepping. */
|
||||
set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
|
||||
|
||||
set_solib_svr4_fetch_link_map_offsets (gdbarch,
|
||||
nbsd_lp64_solib_svr4_fetch_link_map_offsets);
|
||||
|
||||
tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
|
||||
tdep->pc_in_sigtramp = alphanbsd_pc_in_sigtramp;
|
||||
tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
|
||||
|
||||
tdep->jb_pc = 2;
|
||||
tdep->jb_elt_size = 8;
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_alphanbsd_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF,
|
||||
alphanbsd_init_abi);
|
||||
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OPENBSD_ELF,
|
||||
alphanbsd_init_abi);
|
||||
|
||||
deprecated_add_core_fns (&alphanbsd_core_fns);
|
||||
deprecated_add_core_fns (&alphanbsd_elfcore_fns);
|
||||
}
|
||||
@@ -1,403 +0,0 @@
|
||||
/* Native-dependent code for GNU/Linux x86-64.
|
||||
|
||||
Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
Contributed by Jiri Smid, SuSE Labs.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
#include "regcache.h"
|
||||
#include "linux-nat.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/debugreg.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/procfs.h>
|
||||
#include <asm/prctl.h>
|
||||
/* FIXME ezannoni-2003-07-09: we need <sys/reg.h> to be included after
|
||||
<asm/ptrace.h> because the latter redefines FS and GS for no apparent
|
||||
reason, and those definitions don't match the ones that libpthread_db
|
||||
uses, which come from <sys/reg.h>. */
|
||||
/* ezannoni-2003-07-09: I think this is fixed. The extraneous defs have
|
||||
been removed from ptrace.h in the kernel. However, better safe than
|
||||
sorry. */
|
||||
#include <asm/ptrace.h>
|
||||
#include <sys/reg.h>
|
||||
#include "gdb_proc_service.h"
|
||||
|
||||
/* Prototypes for supply_gregset etc. */
|
||||
#include "gregset.h"
|
||||
|
||||
#include "amd64-tdep.h"
|
||||
#include "i386-linux-tdep.h"
|
||||
#include "amd64-nat.h"
|
||||
|
||||
/* Mapping between the general-purpose registers in GNU/Linux x86-64
|
||||
`struct user' format and GDB's register cache layout. */
|
||||
|
||||
static int amd64_linux_gregset64_reg_offset[] =
|
||||
{
|
||||
RAX * 8, RBX * 8, /* %rax, %rbx */
|
||||
RCX * 8, RDX * 8, /* %rcx, %rdx */
|
||||
RSI * 8, RDI * 8, /* %rsi, %rdi */
|
||||
RBP * 8, RSP * 8, /* %rbp, %rsp */
|
||||
R8 * 8, R9 * 8, /* %r8 ... */
|
||||
R10 * 8, R11 * 8,
|
||||
R12 * 8, R13 * 8,
|
||||
R14 * 8, R15 * 8, /* ... %r15 */
|
||||
RIP * 8, EFLAGS * 8, /* %rip, %eflags */
|
||||
CS * 8, SS * 8, /* %cs, %ss */
|
||||
DS * 8, ES * 8, /* %ds, %es */
|
||||
FS * 8, GS * 8 /* %fs, %gs */
|
||||
};
|
||||
|
||||
|
||||
/* Mapping between the general-purpose registers in GNU/Linux x86-64
|
||||
`struct user' format and GDB's register cache layout for GNU/Linux
|
||||
i386.
|
||||
|
||||
Note that most GNU/Linux x86-64 registers are 64-bit, while the
|
||||
GNU/Linux i386 registers are all 32-bit, but since we're
|
||||
little-endian we get away with that. */
|
||||
|
||||
/* From <sys/reg.h> on GNU/Linux i386. */
|
||||
static int amd64_linux_gregset32_reg_offset[] =
|
||||
{
|
||||
RAX * 8, RCX * 8, /* %eax, %ecx */
|
||||
RDX * 8, RBX * 8, /* %edx, %ebx */
|
||||
RSP * 8, RBP * 8, /* %esp, %ebp */
|
||||
RSI * 8, RDI * 8, /* %esi, %edi */
|
||||
RIP * 8, EFLAGS * 8, /* %eip, %eflags */
|
||||
CS * 8, SS * 8, /* %cs, %ss */
|
||||
DS * 8, ES * 8, /* %ds, %es */
|
||||
FS * 8, GS * 8, /* %fs, %gs */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
ORIG_RAX * 8 /* "orig_eax" */
|
||||
};
|
||||
|
||||
|
||||
/* Transfering the general-purpose registers between GDB, inferiors
|
||||
and core files. */
|
||||
|
||||
/* Fill GDB's register cache with the general-purpose register values
|
||||
in *GREGSETP. */
|
||||
|
||||
void
|
||||
supply_gregset (elf_gregset_t *gregsetp)
|
||||
{
|
||||
amd64_supply_native_gregset (current_regcache, gregsetp, -1);
|
||||
}
|
||||
|
||||
/* Fill register REGNUM (if it is a general-purpose register) in
|
||||
*GREGSETP with the value in GDB's register cache. If REGNUM is -1,
|
||||
do this for all registers. */
|
||||
|
||||
void
|
||||
fill_gregset (elf_gregset_t *gregsetp, int regnum)
|
||||
{
|
||||
amd64_collect_native_gregset (current_regcache, gregsetp, regnum);
|
||||
}
|
||||
|
||||
/* Transfering floating-point registers between GDB, inferiors and cores. */
|
||||
|
||||
/* Fill GDB's register cache with the floating-point and SSE register
|
||||
values in *FPREGSETP. */
|
||||
|
||||
void
|
||||
supply_fpregset (elf_fpregset_t *fpregsetp)
|
||||
{
|
||||
amd64_supply_fxsave (current_regcache, -1, fpregsetp);
|
||||
}
|
||||
|
||||
/* Fill register REGNUM (if it is a floating-point or SSE register) in
|
||||
*FPREGSETP with the value in GDB's register cache. If REGNUM is
|
||||
-1, do this for all registers. */
|
||||
|
||||
void
|
||||
fill_fpregset (elf_fpregset_t *fpregsetp, int regnum)
|
||||
{
|
||||
amd64_collect_fxsave (current_regcache, regnum, fpregsetp);
|
||||
}
|
||||
|
||||
|
||||
/* Transferring arbitrary registers between GDB and inferior. */
|
||||
|
||||
/* Fetch register REGNUM from the child process. If REGNUM is -1, do
|
||||
this for all registers (including the floating point and SSE
|
||||
registers). */
|
||||
|
||||
static void
|
||||
amd64_linux_fetch_inferior_registers (int regnum)
|
||||
{
|
||||
int tid;
|
||||
|
||||
/* GNU/Linux LWP ID's are process ID's. */
|
||||
tid = TIDGET (inferior_ptid);
|
||||
if (tid == 0)
|
||||
tid = PIDGET (inferior_ptid); /* Not a threaded program. */
|
||||
|
||||
if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
|
||||
{
|
||||
elf_gregset_t regs;
|
||||
|
||||
if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0)
|
||||
perror_with_name (_("Couldn't get registers"));
|
||||
|
||||
amd64_supply_native_gregset (current_regcache, ®s, -1);
|
||||
if (regnum != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
|
||||
{
|
||||
elf_fpregset_t fpregs;
|
||||
|
||||
if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
|
||||
perror_with_name (_("Couldn't get floating point status"));
|
||||
|
||||
amd64_supply_fxsave (current_regcache, -1, &fpregs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store register REGNUM back into the child process. If REGNUM is
|
||||
-1, do this for all registers (including the floating-point and SSE
|
||||
registers). */
|
||||
|
||||
static void
|
||||
amd64_linux_store_inferior_registers (int regnum)
|
||||
{
|
||||
int tid;
|
||||
|
||||
/* GNU/Linux LWP ID's are process ID's. */
|
||||
tid = TIDGET (inferior_ptid);
|
||||
if (tid == 0)
|
||||
tid = PIDGET (inferior_ptid); /* Not a threaded program. */
|
||||
|
||||
if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
|
||||
{
|
||||
elf_gregset_t regs;
|
||||
|
||||
if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0)
|
||||
perror_with_name (_("Couldn't get registers"));
|
||||
|
||||
amd64_collect_native_gregset (current_regcache, ®s, regnum);
|
||||
|
||||
if (ptrace (PTRACE_SETREGS, tid, 0, (long) ®s) < 0)
|
||||
perror_with_name (_("Couldn't write registers"));
|
||||
|
||||
if (regnum != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
|
||||
{
|
||||
elf_fpregset_t fpregs;
|
||||
|
||||
if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
|
||||
perror_with_name (_("Couldn't get floating point status"));
|
||||
|
||||
amd64_collect_fxsave (current_regcache, regnum, &fpregs);
|
||||
|
||||
if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
|
||||
perror_with_name (_("Couldn't write floating point status"));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static unsigned long
|
||||
amd64_linux_dr_get (int regnum)
|
||||
{
|
||||
int tid;
|
||||
unsigned long value;
|
||||
|
||||
/* FIXME: kettenis/2001-01-29: It's not clear what we should do with
|
||||
multi-threaded processes here. For now, pretend there is just
|
||||
one thread. */
|
||||
tid = PIDGET (inferior_ptid);
|
||||
|
||||
/* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
|
||||
ptrace call fails breaks debugging remote targets. The correct
|
||||
way to fix this is to add the hardware breakpoint and watchpoint
|
||||
stuff to the target vectore. For now, just return zero if the
|
||||
ptrace call fails. */
|
||||
errno = 0;
|
||||
value = ptrace (PT_READ_U, tid,
|
||||
offsetof (struct user, u_debugreg[regnum]), 0);
|
||||
if (errno != 0)
|
||||
#if 0
|
||||
perror_with_name (_("Couldn't read debug register"));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void
|
||||
amd64_linux_dr_set (int regnum, unsigned long value)
|
||||
{
|
||||
int tid;
|
||||
|
||||
/* FIXME: kettenis/2001-01-29: It's not clear what we should do with
|
||||
multi-threaded processes here. For now, pretend there is just
|
||||
one thread. */
|
||||
tid = PIDGET (inferior_ptid);
|
||||
|
||||
errno = 0;
|
||||
ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value);
|
||||
if (errno != 0)
|
||||
perror_with_name (_("Couldn't write debug register"));
|
||||
}
|
||||
|
||||
void
|
||||
amd64_linux_dr_set_control (unsigned long control)
|
||||
{
|
||||
amd64_linux_dr_set (DR_CONTROL, control);
|
||||
}
|
||||
|
||||
void
|
||||
amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
|
||||
{
|
||||
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
|
||||
|
||||
amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr);
|
||||
}
|
||||
|
||||
void
|
||||
amd64_linux_dr_reset_addr (int regnum)
|
||||
{
|
||||
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
|
||||
|
||||
amd64_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
|
||||
}
|
||||
|
||||
unsigned long
|
||||
amd64_linux_dr_get_status (void)
|
||||
{
|
||||
return amd64_linux_dr_get (DR_STATUS);
|
||||
}
|
||||
|
||||
|
||||
/* This function is called by libthread_db as part of its handling of
|
||||
a request for a thread's local storage address. */
|
||||
|
||||
ps_err_e
|
||||
ps_get_thread_area (const struct ps_prochandle *ph,
|
||||
lwpid_t lwpid, int idx, void **base)
|
||||
{
|
||||
if (gdbarch_ptr_bit (current_gdbarch) == 32)
|
||||
{
|
||||
/* The full structure is found in <asm-i386/ldt.h>. The second
|
||||
integer is the LDT's base_address and that is used to locate
|
||||
the thread's local storage. See i386-linux-nat.c more
|
||||
info. */
|
||||
unsigned int desc[4];
|
||||
|
||||
/* This code assumes that "int" is 32 bits and that
|
||||
GET_THREAD_AREA returns no more than 4 int values. */
|
||||
gdb_assert (sizeof (int) == 4);
|
||||
#ifndef PTRACE_GET_THREAD_AREA
|
||||
#define PTRACE_GET_THREAD_AREA 25
|
||||
#endif
|
||||
if (ptrace (PTRACE_GET_THREAD_AREA,
|
||||
lwpid, (void *) (long) idx, (unsigned long) &desc) < 0)
|
||||
return PS_ERR;
|
||||
|
||||
/* Extend the value to 64 bits. Here it's assumed that a "long"
|
||||
and a "void *" are the same. */
|
||||
(*base) = (void *) (long) desc[1];
|
||||
return PS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This definition comes from prctl.h, but some kernels may not
|
||||
have it. */
|
||||
#ifndef PTRACE_ARCH_PRCTL
|
||||
#define PTRACE_ARCH_PRCTL 30
|
||||
#endif
|
||||
/* FIXME: ezannoni-2003-07-09 see comment above about include
|
||||
file order. We could be getting bogus values for these two. */
|
||||
gdb_assert (FS < ELF_NGREG);
|
||||
gdb_assert (GS < ELF_NGREG);
|
||||
switch (idx)
|
||||
{
|
||||
case FS:
|
||||
if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0)
|
||||
return PS_OK;
|
||||
break;
|
||||
case GS:
|
||||
if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0)
|
||||
return PS_OK;
|
||||
break;
|
||||
default: /* Should not happen. */
|
||||
return PS_BADADDR;
|
||||
}
|
||||
}
|
||||
return PS_ERR; /* ptrace failed. */
|
||||
}
|
||||
|
||||
|
||||
static void (*super_post_startup_inferior) (ptid_t ptid);
|
||||
|
||||
static void
|
||||
amd64_linux_child_post_startup_inferior (ptid_t ptid)
|
||||
{
|
||||
i386_cleanup_dregs ();
|
||||
super_post_startup_inferior (ptid);
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_amd64_linux_nat (void);
|
||||
|
||||
void
|
||||
_initialize_amd64_linux_nat (void)
|
||||
{
|
||||
struct target_ops *t;
|
||||
|
||||
amd64_native_gregset32_reg_offset = amd64_linux_gregset32_reg_offset;
|
||||
amd64_native_gregset32_num_regs = I386_LINUX_NUM_REGS;
|
||||
amd64_native_gregset64_reg_offset = amd64_linux_gregset64_reg_offset;
|
||||
|
||||
gdb_assert (ARRAY_SIZE (amd64_linux_gregset32_reg_offset)
|
||||
== amd64_native_gregset32_num_regs);
|
||||
gdb_assert (ARRAY_SIZE (amd64_linux_gregset64_reg_offset)
|
||||
== amd64_native_gregset64_num_regs);
|
||||
|
||||
/* Fill in the generic GNU/Linux methods. */
|
||||
t = linux_target ();
|
||||
|
||||
/* Override the GNU/Linux inferior startup hook. */
|
||||
super_post_startup_inferior = t->to_post_startup_inferior;
|
||||
t->to_post_startup_inferior = amd64_linux_child_post_startup_inferior;
|
||||
|
||||
/* Add our register access methods. */
|
||||
t->to_fetch_registers = amd64_linux_fetch_inferior_registers;
|
||||
t->to_store_registers = amd64_linux_store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
/* Target-dependent code for GNU/Linux x86-64.
|
||||
|
||||
Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
Contributed by Jiri Smid, SuSE Labs.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "regcache.h"
|
||||
#include "osabi.h"
|
||||
#include "symtab.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "amd64-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
/* Mapping between the general-purpose registers in `struct user'
|
||||
format and GDB's register cache layout. */
|
||||
|
||||
/* From <sys/reg.h>. */
|
||||
static int amd64_linux_gregset_reg_offset[] =
|
||||
{
|
||||
10 * 8, /* %rax */
|
||||
5 * 8, /* %rbx */
|
||||
11 * 8, /* %rcx */
|
||||
12 * 8, /* %rdx */
|
||||
13 * 8, /* %rsi */
|
||||
14 * 8, /* %rdi */
|
||||
4 * 8, /* %rbp */
|
||||
19 * 8, /* %rsp */
|
||||
9 * 8, /* %r8 ... */
|
||||
8 * 8,
|
||||
7 * 8,
|
||||
6 * 8,
|
||||
3 * 8,
|
||||
2 * 8,
|
||||
1 * 8,
|
||||
0 * 8, /* ... %r15 */
|
||||
16 * 8, /* %rip */
|
||||
18 * 8, /* %eflags */
|
||||
17 * 8, /* %cs */
|
||||
20 * 8, /* %ss */
|
||||
23 * 8, /* %ds */
|
||||
24 * 8, /* %es */
|
||||
25 * 8, /* %fs */
|
||||
26 * 8 /* %gs */
|
||||
};
|
||||
|
||||
|
||||
/* Support for signal handlers. */
|
||||
|
||||
#define LINUX_SIGTRAMP_INSN0 0x48 /* mov $NNNNNNNN, %rax */
|
||||
#define LINUX_SIGTRAMP_OFFSET0 0
|
||||
#define LINUX_SIGTRAMP_INSN1 0x0f /* syscall */
|
||||
#define LINUX_SIGTRAMP_OFFSET1 7
|
||||
|
||||
static const gdb_byte linux_sigtramp_code[] =
|
||||
{
|
||||
/* mov $__NR_rt_sigreturn, %rax */
|
||||
LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00,
|
||||
/* syscall */
|
||||
LINUX_SIGTRAMP_INSN1, 0x05
|
||||
};
|
||||
|
||||
#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
|
||||
|
||||
/* If PC is in a sigtramp routine, return the address of the start of
|
||||
the routine. Otherwise, return 0. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64_linux_sigtramp_start (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR pc = frame_pc_unwind (next_frame);
|
||||
gdb_byte buf[LINUX_SIGTRAMP_LEN];
|
||||
|
||||
/* We only recognize a signal trampoline if PC is at the start of
|
||||
one of the two instructions. We optimize for finding the PC at
|
||||
the start, as will be the case when the trampoline is not the
|
||||
first frame on the stack. We assume that in the case where the
|
||||
PC is not at the start of the instruction sequence, there will be
|
||||
a few trailing readable bytes on the stack. */
|
||||
|
||||
if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
|
||||
return 0;
|
||||
|
||||
if (buf[0] != LINUX_SIGTRAMP_INSN0)
|
||||
{
|
||||
if (buf[0] != LINUX_SIGTRAMP_INSN1)
|
||||
return 0;
|
||||
|
||||
pc -= LINUX_SIGTRAMP_OFFSET1;
|
||||
if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
|
||||
return 0;
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
/* Return whether the frame preceding NEXT_FRAME corresponds to a
|
||||
GNU/Linux sigtramp routine. */
|
||||
|
||||
static int
|
||||
amd64_linux_sigtramp_p (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR pc = frame_pc_unwind (next_frame);
|
||||
char *name;
|
||||
|
||||
find_pc_partial_function (pc, &name, NULL, NULL);
|
||||
|
||||
/* If we have NAME, we can optimize the search. The trampoline is
|
||||
named __restore_rt. However, it isn't dynamically exported from
|
||||
the shared C library, so the trampoline may appear to be part of
|
||||
the preceding function. This should always be sigaction,
|
||||
__sigaction, or __libc_sigaction (all aliases to the same
|
||||
function). */
|
||||
if (name == NULL || strstr (name, "sigaction") != NULL)
|
||||
return (amd64_linux_sigtramp_start (next_frame) != 0);
|
||||
|
||||
return (strcmp ("__restore_rt", name) == 0);
|
||||
}
|
||||
|
||||
/* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>. */
|
||||
#define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40
|
||||
|
||||
/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
|
||||
routine, return the address of the associated sigcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64_linux_sigcontext_addr (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR sp;
|
||||
gdb_byte buf[8];
|
||||
|
||||
frame_unwind_register (next_frame, SP_REGNUM, buf);
|
||||
sp = extract_unsigned_integer (buf, 8);
|
||||
|
||||
/* The sigcontext structure is part of the user context. A pointer
|
||||
to the user context is passed as the third argument to the signal
|
||||
handler, i.e. in %rdx. Unfortunately %rdx isn't preserved across
|
||||
function calls so we can't use it. Fortunately the user context
|
||||
is part of the signal frame and the unwound %rsp directly points
|
||||
at it. */
|
||||
return sp + AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
/* From <asm/sigcontext.h>. */
|
||||
static int amd64_linux_sc_reg_offset[] =
|
||||
{
|
||||
13 * 8, /* %rax */
|
||||
11 * 8, /* %rbx */
|
||||
14 * 8, /* %rcx */
|
||||
12 * 8, /* %rdx */
|
||||
9 * 8, /* %rsi */
|
||||
8 * 8, /* %rdi */
|
||||
10 * 8, /* %rbp */
|
||||
15 * 8, /* %rsp */
|
||||
0 * 8, /* %r8 */
|
||||
1 * 8, /* %r9 */
|
||||
2 * 8, /* %r10 */
|
||||
3 * 8, /* %r11 */
|
||||
4 * 8, /* %r12 */
|
||||
5 * 8, /* %r13 */
|
||||
6 * 8, /* %r14 */
|
||||
7 * 8, /* %r15 */
|
||||
16 * 8, /* %rip */
|
||||
17 * 8, /* %eflags */
|
||||
|
||||
/* FIXME: kettenis/2002030531: The registers %cs, %fs and %gs are
|
||||
available in `struct sigcontext'. However, they only occupy two
|
||||
bytes instead of four, which makes using them here rather
|
||||
difficult. Leave them out for now. */
|
||||
-1, /* %cs */
|
||||
-1, /* %ss */
|
||||
-1, /* %ds */
|
||||
-1, /* %es */
|
||||
-1, /* %fs */
|
||||
-1 /* %gs */
|
||||
};
|
||||
|
||||
static void
|
||||
amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset;
|
||||
tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
|
||||
tdep->sizeof_gregset = 27 * 8;
|
||||
|
||||
amd64_init_abi (info, gdbarch);
|
||||
|
||||
tdep->sigtramp_p = amd64_linux_sigtramp_p;
|
||||
tdep->sigcontext_addr = amd64_linux_sigcontext_addr;
|
||||
tdep->sc_reg_offset = amd64_linux_sc_reg_offset;
|
||||
tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset);
|
||||
|
||||
/* GNU/Linux uses SVR4-style shared libraries. */
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_lp64_fetch_link_map_offsets);
|
||||
|
||||
/* Enable TLS support. */
|
||||
set_gdbarch_fetch_tls_load_module_address (gdbarch,
|
||||
svr4_fetch_objfile_link_map);
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
extern void _initialize_amd64_linux_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_amd64_linux_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
|
||||
GDB_OSABI_LINUX, amd64_linux_init_abi);
|
||||
}
|
||||
163
gdb/amd64-nat.c
163
gdb/amd64-nat.c
@@ -1,163 +0,0 @@
|
||||
/* Native-dependent code for AMD64.
|
||||
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbarch.h"
|
||||
#include "regcache.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "i386-tdep.h"
|
||||
#include "amd64-tdep.h"
|
||||
|
||||
/* The following bits of code help with implementing debugging 32-bit
|
||||
code natively on AMD64. The idea is to define two mappings between
|
||||
the register number as used by GDB and the register set used by the
|
||||
host to represent the general-purpose registers; one for 32-bit
|
||||
code and one for 64-bit code. The mappings are specified by the
|
||||
follwing variables and consist of an array of offsets within the
|
||||
register set indexed by register number, and the number of
|
||||
registers supported by the mapping. We don't need mappings for the
|
||||
floating-point and SSE registers, since the difference between
|
||||
64-bit and 32-bit variants are negligable. The difference in the
|
||||
number of SSE registers is already handled by the target code. */
|
||||
|
||||
/* General-purpose register mapping for native 32-bit code. */
|
||||
int *amd64_native_gregset32_reg_offset;
|
||||
int amd64_native_gregset32_num_regs = I386_NUM_GREGS;
|
||||
|
||||
/* General-purpose register mapping for native 64-bit code. */
|
||||
int *amd64_native_gregset64_reg_offset;
|
||||
int amd64_native_gregset64_num_regs = AMD64_NUM_GREGS;
|
||||
|
||||
/* Return the offset of REGNUM within the appropriate native
|
||||
general-purpose register set. */
|
||||
|
||||
static int
|
||||
amd64_native_gregset_reg_offset (int regnum)
|
||||
{
|
||||
int *reg_offset = amd64_native_gregset64_reg_offset;
|
||||
int num_regs = amd64_native_gregset64_num_regs;
|
||||
|
||||
gdb_assert (regnum >= 0);
|
||||
|
||||
if (gdbarch_ptr_bit (current_gdbarch) == 32)
|
||||
{
|
||||
reg_offset = amd64_native_gregset32_reg_offset;
|
||||
num_regs = amd64_native_gregset32_num_regs;
|
||||
}
|
||||
|
||||
if (num_regs > NUM_REGS)
|
||||
num_regs = NUM_REGS;
|
||||
|
||||
if (regnum < num_regs && regnum < NUM_REGS)
|
||||
return reg_offset[regnum];
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return whether the native general-purpose register set supplies
|
||||
register REGNUM. */
|
||||
|
||||
int
|
||||
amd64_native_gregset_supplies_p (int regnum)
|
||||
{
|
||||
return (amd64_native_gregset_reg_offset (regnum) != -1);
|
||||
}
|
||||
|
||||
|
||||
/* Supply register REGNUM, whose contents are stored in GREGS, to
|
||||
REGCACHE. If REGNUM is -1, supply all appropriate registers. */
|
||||
|
||||
void
|
||||
amd64_supply_native_gregset (struct regcache *regcache,
|
||||
const void *gregs, int regnum)
|
||||
{
|
||||
const char *regs = gregs;
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
int num_regs = amd64_native_gregset64_num_regs;
|
||||
int i;
|
||||
|
||||
if (gdbarch_ptr_bit (gdbarch) == 32)
|
||||
num_regs = amd64_native_gregset32_num_regs;
|
||||
|
||||
if (num_regs > NUM_REGS)
|
||||
num_regs = NUM_REGS;
|
||||
|
||||
for (i = 0; i < num_regs; i++)
|
||||
{
|
||||
if (regnum == -1 || regnum == i)
|
||||
{
|
||||
int offset = amd64_native_gregset_reg_offset (i);
|
||||
|
||||
if (offset != -1)
|
||||
regcache_raw_supply (regcache, i, regs + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Collect register REGNUM from REGCACHE and store its contents in
|
||||
GREGS. If REGNUM is -1, collect and store all appropriate
|
||||
registers. */
|
||||
|
||||
void
|
||||
amd64_collect_native_gregset (const struct regcache *regcache,
|
||||
void *gregs, int regnum)
|
||||
{
|
||||
char *regs = gregs;
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
int num_regs = amd64_native_gregset64_num_regs;
|
||||
int i;
|
||||
|
||||
if (gdbarch_ptr_bit (gdbarch) == 32)
|
||||
{
|
||||
num_regs = amd64_native_gregset32_num_regs;
|
||||
|
||||
/* Make sure %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and
|
||||
%eip get zero-extended to 64 bits. */
|
||||
for (i = 0; i <= I386_EIP_REGNUM; i++)
|
||||
{
|
||||
if (regnum == -1 || regnum == i)
|
||||
memset (regs + amd64_native_gregset_reg_offset (i), 0, 8);
|
||||
}
|
||||
/* Ditto for %cs, %ss, %ds, %es, %fs, and %gs. */
|
||||
for (i = I386_CS_REGNUM; i <= I386_GS_REGNUM; i++)
|
||||
{
|
||||
if (regnum == -1 || regnum == i)
|
||||
memset (regs + amd64_native_gregset_reg_offset (i), 0, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (num_regs > NUM_REGS)
|
||||
num_regs = NUM_REGS;
|
||||
|
||||
for (i = 0; i < num_regs; i++)
|
||||
{
|
||||
if (regnum == -1 || regnum == i)
|
||||
{
|
||||
int offset = amd64_native_gregset_reg_offset (i);
|
||||
|
||||
if (offset != -1)
|
||||
regcache_raw_collect (regcache, i, regs + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/* Native-dependent code for AMD64.
|
||||
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef AMD64_NAT_H
|
||||
#define AMD64_NAT_H 1
|
||||
|
||||
struct regcache;
|
||||
|
||||
/* General-purpose register set description for native 32-bit code. */
|
||||
extern int *amd64_native_gregset32_reg_offset;
|
||||
extern int amd64_native_gregset32_num_regs;
|
||||
|
||||
/* General-purpose register set description for native 64-bit code. */
|
||||
extern int *amd64_native_gregset64_reg_offset;
|
||||
extern int amd64_native_gregset64_num_regs;
|
||||
|
||||
/* Return whether the native general-purpose register set supplies
|
||||
register REGNUM. */
|
||||
|
||||
extern int amd64_native_gregset_supplies_p (int regnum);
|
||||
|
||||
/* Supply register REGNUM, whose contents are store in BUF, to
|
||||
REGCACHE. If REGNUM is -1, supply all appropriate registers. */
|
||||
|
||||
extern void amd64_supply_native_gregset (struct regcache *regcache,
|
||||
const void *gregs, int regnum);
|
||||
|
||||
/* Collect register REGNUM from REGCACHE and store its contents in
|
||||
GREGS. If REGNUM is -1, collect and store all appropriate
|
||||
registers. */
|
||||
|
||||
extern void amd64_collect_native_gregset (const struct regcache *regcache,
|
||||
void *gregs, int regnum);
|
||||
|
||||
/* Create a prototype *BSD/amd64 target. The client can override it
|
||||
with local methods. */
|
||||
|
||||
extern struct target_ops *amd64bsd_target (void);
|
||||
|
||||
#endif /* amd64-nat.h */
|
||||
@@ -1,128 +0,0 @@
|
||||
/* Target-dependent code for AMD64 Solaris.
|
||||
|
||||
Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
|
||||
|
||||
Contributed by Joseph Myers, CodeSourcery, LLC.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "regcache.h"
|
||||
#include "osabi.h"
|
||||
#include "symtab.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "sol2-tdep.h"
|
||||
#include "amd64-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
/* Mapping between the general-purpose registers in gregset_t format
|
||||
and GDB's register cache layout. */
|
||||
|
||||
/* From <sys/regset.h>. */
|
||||
static int amd64_sol2_gregset_reg_offset[] = {
|
||||
14 * 8, /* %rax */
|
||||
11 * 8, /* %rbx */
|
||||
13 * 8, /* %rcx */
|
||||
12 * 8, /* %rdx */
|
||||
9 * 8, /* %rsi */
|
||||
8 * 8, /* %rdi */
|
||||
10 * 8, /* %rbp */
|
||||
20 * 8, /* %rsp */
|
||||
7 * 8, /* %r8 ... */
|
||||
6 * 8,
|
||||
5 * 8,
|
||||
4 * 8,
|
||||
3 * 8,
|
||||
2 * 8,
|
||||
1 * 8,
|
||||
0 * 8, /* ... %r15 */
|
||||
17 * 8, /* %rip */
|
||||
16 * 8, /* %eflags */
|
||||
18 * 8, /* %cs */
|
||||
21 * 8, /* %ss */
|
||||
25 * 8, /* %ds */
|
||||
24 * 8, /* %es */
|
||||
22 * 8, /* %fs */
|
||||
23 * 8 /* %gs */
|
||||
};
|
||||
|
||||
|
||||
/* Return whether the frame preceding NEXT_FRAME corresponds to a
|
||||
Solaris sigtramp routine. */
|
||||
|
||||
static int
|
||||
amd64_sol2_sigtramp_p (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR pc = frame_pc_unwind (next_frame);
|
||||
char *name;
|
||||
|
||||
find_pc_partial_function (pc, &name, NULL, NULL);
|
||||
return (name && (strcmp ("sigacthandler", name) == 0
|
||||
|| strcmp (name, "ucbsigvechandler") == 0));
|
||||
}
|
||||
|
||||
/* Solaris doesn't have a 'struct sigcontext', but it does have a
|
||||
'mcontext_t' that contains the saved set of machine registers. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64_sol2_mcontext_addr (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR sp, ucontext_addr;
|
||||
|
||||
sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
|
||||
ucontext_addr = get_frame_memory_unsigned (next_frame, sp + 8, 8);
|
||||
|
||||
return ucontext_addr + 72;
|
||||
}
|
||||
|
||||
static void
|
||||
amd64_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
tdep->gregset_reg_offset = amd64_sol2_gregset_reg_offset;
|
||||
tdep->gregset_num_regs = ARRAY_SIZE (amd64_sol2_gregset_reg_offset);
|
||||
tdep->sizeof_gregset = 28 * 8;
|
||||
|
||||
amd64_init_abi (info, gdbarch);
|
||||
|
||||
tdep->sigtramp_p = amd64_sol2_sigtramp_p;
|
||||
tdep->sigcontext_addr = amd64_sol2_mcontext_addr;
|
||||
tdep->sc_reg_offset = tdep->gregset_reg_offset;
|
||||
tdep->sc_num_regs = tdep->gregset_num_regs;
|
||||
|
||||
/* Solaris uses SVR4-style shared libraries. */
|
||||
set_gdbarch_skip_solib_resolver (gdbarch, sol2_skip_solib_resolver);
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_lp64_fetch_link_map_offsets);
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
extern void _initialize_amd64_sol2_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_amd64_sol2_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
|
||||
GDB_OSABI_SOLARIS, amd64_sol2_init_abi);
|
||||
}
|
||||
1263
gdb/amd64-tdep.c
1263
gdb/amd64-tdep.c
File diff suppressed because it is too large
Load Diff
@@ -1,95 +0,0 @@
|
||||
/* Target-dependent definitions for AMD64.
|
||||
|
||||
Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
|
||||
Contributed by Jiri Smid, SuSE Labs.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef AMD64_TDEP_H
|
||||
#define AMD64_TDEP_H
|
||||
|
||||
struct gdbarch;
|
||||
struct frame_info;
|
||||
struct regcache;
|
||||
|
||||
#include "i386-tdep.h"
|
||||
|
||||
/* Register numbers of various important registers. */
|
||||
|
||||
enum amd64_regnum
|
||||
{
|
||||
AMD64_RAX_REGNUM, /* %rax */
|
||||
AMD64_RBX_REGNUM, /* %rbx */
|
||||
AMD64_RCX_REGNUM, /* %rcx */
|
||||
AMD64_RDX_REGNUM, /* %rdx */
|
||||
AMD64_RSI_REGNUM, /* %rsi */
|
||||
AMD64_RDI_REGNUM, /* %rdi */
|
||||
AMD64_RBP_REGNUM, /* %rbp */
|
||||
AMD64_RSP_REGNUM, /* %rsp */
|
||||
AMD64_R8_REGNUM = 8, /* %r8 */
|
||||
AMD64_R15_REGNUM = 15, /* %r15 */
|
||||
AMD64_RIP_REGNUM, /* %rip */
|
||||
AMD64_EFLAGS_REGNUM, /* %eflags */
|
||||
AMD64_CS_REGNUM, /* %cs */
|
||||
AMD64_SS_REGNUM, /* %ss */
|
||||
AMD64_DS_REGNUM, /* %ds */
|
||||
AMD64_ES_REGNUM, /* %es */
|
||||
AMD64_FS_REGNUM, /* %fs */
|
||||
AMD64_GS_REGNUM, /* %gs */
|
||||
AMD64_ST0_REGNUM = 24, /* %st0 */
|
||||
AMD64_FCTRL_REGNUM = AMD64_ST0_REGNUM + 8,
|
||||
AMD64_FSTAT_REGNUM = AMD64_ST0_REGNUM + 9,
|
||||
AMD64_XMM0_REGNUM = 40, /* %xmm0 */
|
||||
AMD64_XMM1_REGNUM, /* %xmm1 */
|
||||
AMD64_MXCSR_REGNUM = AMD64_XMM0_REGNUM + 16
|
||||
};
|
||||
|
||||
/* Number of general purpose registers. */
|
||||
#define AMD64_NUM_GREGS 24
|
||||
|
||||
extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
|
||||
|
||||
/* Fill register REGNUM in REGCACHE with the appropriate
|
||||
floating-point or SSE register value from *FXSAVE. If REGNUM is
|
||||
-1, do this for all registers. This function masks off any of the
|
||||
reserved bits in *FXSAVE. */
|
||||
|
||||
extern void amd64_supply_fxsave (struct regcache *regcache, int regnum,
|
||||
const void *fxsave);
|
||||
|
||||
/* Fill register REGNUM (if it is a floating-point or SSE register) in
|
||||
*FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for
|
||||
all registers. This function doesn't touch any of the reserved
|
||||
bits in *FXSAVE. */
|
||||
|
||||
extern void amd64_collect_fxsave (const struct regcache *regcache, int regnum,
|
||||
void *fxsave);
|
||||
|
||||
|
||||
/* Variables exported from amd64nbsd-tdep.c. */
|
||||
extern int amd64nbsd_r_reg_offset[];
|
||||
|
||||
/* Variables exported from amd64obsd-tdep.c. */
|
||||
extern int amd64obsd_r_reg_offset[];
|
||||
|
||||
/* Variables exported from amd64fbsd-tdep.c. */
|
||||
extern CORE_ADDR amd64fbsd_sigtramp_start_addr;
|
||||
extern CORE_ADDR amd64fbsd_sigtramp_end_addr;
|
||||
extern int amd64fbsd_sc_reg_offset[];
|
||||
|
||||
#endif /* amd64-tdep.h */
|
||||
@@ -1,123 +0,0 @@
|
||||
/* Native-dependent code for AMD64 BSD's.
|
||||
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "regcache.h"
|
||||
#include "target.h"
|
||||
|
||||
/* We include <signal.h> to make sure `struct fxsave64' is defined on
|
||||
NetBSD, since NetBSD's <machine/reg.h> needs it. */
|
||||
#include "gdb_assert.h"
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include "amd64-tdep.h"
|
||||
#include "amd64-nat.h"
|
||||
#include "inf-ptrace.h"
|
||||
|
||||
|
||||
/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
|
||||
for all registers (including the floating-point registers). */
|
||||
|
||||
static void
|
||||
amd64bsd_fetch_inferior_registers (int regnum)
|
||||
{
|
||||
if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
|
||||
{
|
||||
struct reg regs;
|
||||
|
||||
if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) ®s, 0) == -1)
|
||||
perror_with_name (_("Couldn't get registers"));
|
||||
|
||||
amd64_supply_native_gregset (current_regcache, ®s, -1);
|
||||
if (regnum != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
|
||||
{
|
||||
struct fpreg fpregs;
|
||||
|
||||
if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||||
perror_with_name (_("Couldn't get floating point status"));
|
||||
|
||||
amd64_supply_fxsave (current_regcache, -1, &fpregs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store register REGNUM back into the inferior. If REGNUM is -1, do
|
||||
this for all registers (including the floating-point registers). */
|
||||
|
||||
static void
|
||||
amd64bsd_store_inferior_registers (int regnum)
|
||||
{
|
||||
if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
|
||||
{
|
||||
struct reg regs;
|
||||
|
||||
if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) ®s, 0) == -1)
|
||||
perror_with_name (_("Couldn't get registers"));
|
||||
|
||||
amd64_collect_native_gregset (current_regcache, ®s, regnum);
|
||||
|
||||
if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) ®s, 0) == -1)
|
||||
perror_with_name (_("Couldn't write registers"));
|
||||
|
||||
if (regnum != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
|
||||
{
|
||||
struct fpreg fpregs;
|
||||
|
||||
if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||||
perror_with_name (_("Couldn't get floating point status"));
|
||||
|
||||
amd64_collect_fxsave (current_regcache, regnum, &fpregs);
|
||||
|
||||
if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||||
perror_with_name (_("Couldn't write floating point status"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a prototype *BSD/amd64 target. The client can override it
|
||||
with local methods. */
|
||||
|
||||
struct target_ops *
|
||||
amd64bsd_target (void)
|
||||
{
|
||||
struct target_ops *t;
|
||||
|
||||
t = inf_ptrace_target ();
|
||||
t->to_fetch_registers = amd64bsd_fetch_inferior_registers;
|
||||
t->to_store_registers = amd64bsd_store_inferior_registers;
|
||||
return t;
|
||||
}
|
||||
@@ -1,235 +0,0 @@
|
||||
/* Native-dependent code for FreeBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "regcache.h"
|
||||
#include "target.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <machine/reg.h>
|
||||
|
||||
#include "fbsd-nat.h"
|
||||
#include "amd64-tdep.h"
|
||||
#include "amd64-nat.h"
|
||||
|
||||
|
||||
/* Offset in `struct reg' where MEMBER is stored. */
|
||||
#define REG_OFFSET(member) offsetof (struct reg, member)
|
||||
|
||||
/* At amd64fbsd64_r_reg_offset[REGNUM] you'll find the offset in
|
||||
`struct reg' location where the GDB register REGNUM is stored.
|
||||
Unsupported registers are marked with `-1'. */
|
||||
static int amd64fbsd64_r_reg_offset[] =
|
||||
{
|
||||
REG_OFFSET (r_rax),
|
||||
REG_OFFSET (r_rbx),
|
||||
REG_OFFSET (r_rcx),
|
||||
REG_OFFSET (r_rdx),
|
||||
REG_OFFSET (r_rsi),
|
||||
REG_OFFSET (r_rdi),
|
||||
REG_OFFSET (r_rbp),
|
||||
REG_OFFSET (r_rsp),
|
||||
REG_OFFSET (r_r8),
|
||||
REG_OFFSET (r_r9),
|
||||
REG_OFFSET (r_r10),
|
||||
REG_OFFSET (r_r11),
|
||||
REG_OFFSET (r_r12),
|
||||
REG_OFFSET (r_r13),
|
||||
REG_OFFSET (r_r14),
|
||||
REG_OFFSET (r_r15),
|
||||
REG_OFFSET (r_rip),
|
||||
REG_OFFSET (r_rflags),
|
||||
REG_OFFSET (r_cs),
|
||||
REG_OFFSET (r_ss),
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
};
|
||||
|
||||
|
||||
/* Mapping between the general-purpose registers in FreeBSD/amd64
|
||||
`struct reg' format and GDB's register cache layout for
|
||||
FreeBSD/i386.
|
||||
|
||||
Note that most FreeBSD/amd64 registers are 64-bit, while the
|
||||
FreeBSD/i386 registers are all 32-bit, but since we're
|
||||
little-endian we get away with that. */
|
||||
|
||||
/* From <machine/reg.h>. */
|
||||
static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] =
|
||||
{
|
||||
14 * 8, 13 * 8, /* %eax, %ecx */
|
||||
12 * 8, 11 * 8, /* %edx, %ebx */
|
||||
20 * 8, 10 * 8, /* %esp, %ebp */
|
||||
9 * 8, 8 * 8, /* %esi, %edi */
|
||||
17 * 8, 19 * 8, /* %eip, %eflags */
|
||||
18 * 8, 21 * 8, /* %cs, %ss */
|
||||
-1, -1, -1, -1 /* %ds, %es, %fs, %gs */
|
||||
};
|
||||
|
||||
|
||||
/* Support for debugging kernel virtual memory images. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <machine/pcb.h>
|
||||
|
||||
#include "bsd-kvm.h"
|
||||
|
||||
static int
|
||||
amd64fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
|
||||
{
|
||||
/* The following is true for FreeBSD 5.2:
|
||||
|
||||
The pcb contains %rip, %rbx, %rsp, %rbp, %r12, %r13, %r14, %r15,
|
||||
%ds, %es, %fs and %gs. This accounts for all callee-saved
|
||||
registers specified by the psABI and then some. Here %esp
|
||||
contains the stack pointer at the point just after the call to
|
||||
cpu_switch(). From this information we reconstruct the register
|
||||
state as it would like when we just returned from cpu_switch(). */
|
||||
|
||||
/* The stack pointer shouldn't be zero. */
|
||||
if (pcb->pcb_rsp == 0)
|
||||
return 0;
|
||||
|
||||
pcb->pcb_rsp += 8;
|
||||
regcache_raw_supply (regcache, AMD64_RIP_REGNUM, &pcb->pcb_rip);
|
||||
regcache_raw_supply (regcache, AMD64_RBX_REGNUM, &pcb->pcb_rbx);
|
||||
regcache_raw_supply (regcache, AMD64_RSP_REGNUM, &pcb->pcb_rsp);
|
||||
regcache_raw_supply (regcache, AMD64_RBP_REGNUM, &pcb->pcb_rbp);
|
||||
regcache_raw_supply (regcache, 12, &pcb->pcb_r12);
|
||||
regcache_raw_supply (regcache, 13, &pcb->pcb_r13);
|
||||
regcache_raw_supply (regcache, 14, &pcb->pcb_r14);
|
||||
regcache_raw_supply (regcache, 15, &pcb->pcb_r15);
|
||||
regcache_raw_supply (regcache, AMD64_DS_REGNUM, &pcb->pcb_ds);
|
||||
regcache_raw_supply (regcache, AMD64_ES_REGNUM, &pcb->pcb_es);
|
||||
regcache_raw_supply (regcache, AMD64_FS_REGNUM, &pcb->pcb_fs);
|
||||
regcache_raw_supply (regcache, AMD64_GS_REGNUM, &pcb->pcb_gs);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_amd64fbsd_nat (void);
|
||||
|
||||
void
|
||||
_initialize_amd64fbsd_nat (void)
|
||||
{
|
||||
struct target_ops *t;
|
||||
int offset;
|
||||
|
||||
amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset;
|
||||
amd64_native_gregset64_reg_offset = amd64fbsd64_r_reg_offset;
|
||||
|
||||
/* Add some extra features to the common *BSD/i386 target. */
|
||||
t = amd64bsd_target ();
|
||||
t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
|
||||
t->to_find_memory_regions = fbsd_find_memory_regions;
|
||||
t->to_make_corefile_notes = fbsd_make_corefile_notes;
|
||||
add_target (t);
|
||||
|
||||
/* Support debugging kernel virtual memory images. */
|
||||
bsd_kvm_add_target (amd64fbsd_supply_pcb);
|
||||
|
||||
/* To support the recognition of signal handlers, i386bsd-tdep.c
|
||||
hardcodes some constants. Inclusion of this file means that we
|
||||
are compiling a native debugger, which means that we can use the
|
||||
system header files and sysctl(3) to get at the relevant
|
||||
information. */
|
||||
|
||||
#define SC_REG_OFFSET amd64fbsd_sc_reg_offset
|
||||
|
||||
/* We only check the program counter, stack pointer and frame
|
||||
pointer since these members of `struct sigcontext' are essential
|
||||
for providing backtraces. */
|
||||
|
||||
#define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM]
|
||||
#define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM]
|
||||
#define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM]
|
||||
|
||||
/* Override the default value for the offset of the program counter
|
||||
in the sigcontext structure. */
|
||||
offset = offsetof (struct sigcontext, sc_rip);
|
||||
|
||||
if (SC_RIP_OFFSET != offset)
|
||||
{
|
||||
warning (_("\
|
||||
offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\
|
||||
Please report this to <bug-gdb@gnu.org>."),
|
||||
offset, SC_RIP_OFFSET);
|
||||
}
|
||||
|
||||
SC_RIP_OFFSET = offset;
|
||||
|
||||
/* Likewise for the stack pointer. */
|
||||
offset = offsetof (struct sigcontext, sc_rsp);
|
||||
|
||||
if (SC_RSP_OFFSET != offset)
|
||||
{
|
||||
warning (_("\
|
||||
offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\
|
||||
Please report this to <bug-gdb@gnu.org>."),
|
||||
offset, SC_RSP_OFFSET);
|
||||
}
|
||||
|
||||
SC_RSP_OFFSET = offset;
|
||||
|
||||
/* And the frame pointer. */
|
||||
offset = offsetof (struct sigcontext, sc_rbp);
|
||||
|
||||
if (SC_RBP_OFFSET != offset)
|
||||
{
|
||||
warning (_("\
|
||||
offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\
|
||||
Please report this to <bug-gdb@gnu.org>."),
|
||||
offset, SC_RBP_OFFSET);
|
||||
}
|
||||
|
||||
SC_RBP_OFFSET = offset;
|
||||
|
||||
/* FreeBSD provides a kern.ps_strings sysctl that we can use to
|
||||
locate the sigtramp. That way we can still recognize a sigtramp
|
||||
if its location is changed in a new kernel. Of course this is
|
||||
still based on the assumption that the sigtramp is placed
|
||||
directly under the location where the program arguments and
|
||||
environment can be found. */
|
||||
{
|
||||
int mib[2];
|
||||
long ps_strings;
|
||||
size_t len;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PS_STRINGS;
|
||||
len = sizeof (ps_strings);
|
||||
if (sysctl (mib, 2, &ps_strings, &len, NULL, 0) == 0)
|
||||
{
|
||||
amd64fbsd_sigtramp_start_addr = ps_strings - 32;
|
||||
amd64fbsd_sigtramp_end_addr = ps_strings;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
/* Target-dependent code for FreeBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "arch-utils.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "regcache.h"
|
||||
#include "osabi.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "amd64-tdep.h"
|
||||
#include "bsd-uthread.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
/* Support for signal handlers. */
|
||||
|
||||
/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
|
||||
routine, return the address of the associated sigcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64fbsd_sigcontext_addr (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR sp;
|
||||
|
||||
/* The `struct sigcontext' (which really is an `ucontext_t' on
|
||||
FreeBSD/amd64) lives at a fixed offset in the signal frame. See
|
||||
<machine/sigframe.h>. */
|
||||
sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
|
||||
return sp + 16;
|
||||
}
|
||||
|
||||
/* FreeBSD 5.1-RELEASE or later. */
|
||||
|
||||
/* Mapping between the general-purpose registers in `struct reg'
|
||||
format and GDB's register cache layout.
|
||||
|
||||
Note that some registers are 32-bit, but since we're little-endian
|
||||
we get away with that. */
|
||||
|
||||
/* From <machine/reg.h>. */
|
||||
static int amd64fbsd_r_reg_offset[] =
|
||||
{
|
||||
14 * 8, /* %rax */
|
||||
11 * 8, /* %rbx */
|
||||
13 * 8, /* %rcx */
|
||||
12 * 8, /* %rdx */
|
||||
9 * 8, /* %rsi */
|
||||
8 * 8, /* %rdi */
|
||||
10 * 8, /* %rbp */
|
||||
20 * 8, /* %rsp */
|
||||
7 * 8, /* %r8 ... */
|
||||
6 * 8,
|
||||
5 * 8,
|
||||
4 * 8,
|
||||
3 * 8,
|
||||
2 * 8,
|
||||
1 * 8,
|
||||
0 * 8, /* ... %r15 */
|
||||
17 * 8, /* %rip */
|
||||
19 * 8, /* %eflags */
|
||||
18 * 8, /* %cs */
|
||||
21 * 8, /* %ss */
|
||||
-1, /* %ds */
|
||||
-1, /* %es */
|
||||
-1, /* %fs */
|
||||
-1 /* %gs */
|
||||
};
|
||||
|
||||
/* Location of the signal trampoline. */
|
||||
CORE_ADDR amd64fbsd_sigtramp_start_addr = 0x7fffffffffc0;
|
||||
CORE_ADDR amd64fbsd_sigtramp_end_addr = 0x7fffffffffe0;
|
||||
|
||||
/* From <machine/signal.h>. */
|
||||
int amd64fbsd_sc_reg_offset[] =
|
||||
{
|
||||
24 + 6 * 8, /* %rax */
|
||||
24 + 7 * 8, /* %rbx */
|
||||
24 + 3 * 8, /* %rcx */
|
||||
24 + 2 * 8, /* %rdx */
|
||||
24 + 1 * 8, /* %rsi */
|
||||
24 + 0 * 8, /* %rdi */
|
||||
24 + 8 * 8, /* %rbp */
|
||||
24 + 22 * 8, /* %rsp */
|
||||
24 + 4 * 8, /* %r8 ... */
|
||||
24 + 5 * 8,
|
||||
24 + 9 * 8,
|
||||
24 + 10 * 8,
|
||||
24 + 11 * 8,
|
||||
24 + 12 * 8,
|
||||
24 + 13 * 8,
|
||||
24 + 14 * 8, /* ... %r15 */
|
||||
24 + 19 * 8, /* %rip */
|
||||
24 + 21 * 8, /* %eflags */
|
||||
24 + 20 * 8, /* %cs */
|
||||
24 + 23 * 8, /* %ss */
|
||||
-1, /* %ds */
|
||||
-1, /* %es */
|
||||
-1, /* %fs */
|
||||
-1 /* %gs */
|
||||
};
|
||||
|
||||
/* From /usr/src/lib/libc/amd64/gen/_setjmp.S. */
|
||||
static int amd64fbsd_jmp_buf_reg_offset[] =
|
||||
{
|
||||
-1, /* %rax */
|
||||
1 * 8, /* %rbx */
|
||||
-1, /* %rcx */
|
||||
-1, /* %rdx */
|
||||
-1, /* %rsi */
|
||||
-1, /* %rdi */
|
||||
3 * 8, /* %rbp */
|
||||
2 * 8, /* %rsp */
|
||||
-1, /* %r8 ... */
|
||||
-1,
|
||||
-1,
|
||||
-1, /* ... %r11 */
|
||||
4 * 8, /* %r12 ... */
|
||||
5 * 8,
|
||||
6 * 8,
|
||||
7 * 8, /* ... %r15 */
|
||||
0 * 8 /* %rip */
|
||||
};
|
||||
|
||||
static void
|
||||
amd64fbsd_supply_uthread (struct regcache *regcache,
|
||||
int regnum, CORE_ADDR addr)
|
||||
{
|
||||
gdb_byte buf[8];
|
||||
int i;
|
||||
|
||||
gdb_assert (regnum >= -1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (amd64fbsd_jmp_buf_reg_offset); i++)
|
||||
{
|
||||
if (amd64fbsd_jmp_buf_reg_offset[i] != -1
|
||||
&& (regnum == -1 || regnum == i))
|
||||
{
|
||||
read_memory (addr + amd64fbsd_jmp_buf_reg_offset[i], buf, 8);
|
||||
regcache_raw_supply (regcache, i, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
amd64fbsd_collect_uthread (const struct regcache *regcache,
|
||||
int regnum, CORE_ADDR addr)
|
||||
{
|
||||
gdb_byte buf[8];
|
||||
int i;
|
||||
|
||||
gdb_assert (regnum >= -1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (amd64fbsd_jmp_buf_reg_offset); i++)
|
||||
{
|
||||
if (amd64fbsd_jmp_buf_reg_offset[i] != -1
|
||||
&& (regnum == -1 || regnum == i))
|
||||
{
|
||||
regcache_raw_collect (regcache, i, buf);
|
||||
write_memory (addr + amd64fbsd_jmp_buf_reg_offset[i], buf, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
/* Obviously FreeBSD is BSD-based. */
|
||||
i386bsd_init_abi (info, gdbarch);
|
||||
|
||||
tdep->gregset_reg_offset = amd64fbsd_r_reg_offset;
|
||||
tdep->gregset_num_regs = ARRAY_SIZE (amd64fbsd_r_reg_offset);
|
||||
tdep->sizeof_gregset = 22 * 8;
|
||||
|
||||
amd64_init_abi (info, gdbarch);
|
||||
|
||||
tdep->sigtramp_start = amd64fbsd_sigtramp_start_addr;
|
||||
tdep->sigtramp_end = amd64fbsd_sigtramp_end_addr;
|
||||
tdep->sigcontext_addr = amd64fbsd_sigcontext_addr;
|
||||
tdep->sc_reg_offset = amd64fbsd_sc_reg_offset;
|
||||
tdep->sc_num_regs = ARRAY_SIZE (amd64fbsd_sc_reg_offset);
|
||||
|
||||
/* FreeBSD provides a user-level threads implementation. */
|
||||
bsd_uthread_set_supply_uthread (gdbarch, amd64fbsd_supply_uthread);
|
||||
bsd_uthread_set_collect_uthread (gdbarch, amd64fbsd_collect_uthread);
|
||||
|
||||
/* FreeBSD uses SVR4-style shared libraries. */
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_lp64_fetch_link_map_offsets);
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_amd64fbsd_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_amd64fbsd_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
|
||||
GDB_OSABI_FREEBSD_ELF, amd64fbsd_init_abi);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/* Native-dependent code for NetBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "target.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
|
||||
#include "amd64-tdep.h"
|
||||
#include "amd64-nat.h"
|
||||
|
||||
/* Mapping between the general-purpose registers in NetBSD/amd64
|
||||
`struct reg' format and GDB's register cache layout for
|
||||
NetBSD/i386.
|
||||
|
||||
Note that most (if not all) NetBSD/amd64 registers are 64-bit,
|
||||
while the NetBSD/i386 registers are all 32-bit, but since we're
|
||||
little-endian we get away with that. */
|
||||
|
||||
/* From <machine/reg.h>. */
|
||||
static int amd64nbsd32_r_reg_offset[] =
|
||||
{
|
||||
14 * 8, /* %eax */
|
||||
3 * 8, /* %ecx */
|
||||
2 * 8, /* %edx */
|
||||
13 * 8, /* %ebx */
|
||||
24 * 8, /* %esp */
|
||||
12 * 8, /* %ebp */
|
||||
1 * 8, /* %esi */
|
||||
0 * 8, /* %edi */
|
||||
21 * 8, /* %eip */
|
||||
23 * 8, /* %eflags */
|
||||
22 * 8, /* %cs */
|
||||
25 * 8, /* %ss */
|
||||
18 * 8, /* %ds */
|
||||
17 * 8, /* %es */
|
||||
16 * 8, /* %fs */
|
||||
15 * 8 /* %gs */
|
||||
};
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_amd64nbsd_nat (void);
|
||||
|
||||
void
|
||||
_initialize_amd64nbsd_nat (void)
|
||||
{
|
||||
amd64_native_gregset32_reg_offset = amd64nbsd32_r_reg_offset;
|
||||
amd64_native_gregset32_num_regs = ARRAY_SIZE (amd64nbsd32_r_reg_offset);
|
||||
amd64_native_gregset64_reg_offset = amd64nbsd_r_reg_offset;
|
||||
|
||||
/* We've got nothing to add to the common *BSD/amd64 target. */
|
||||
add_target (amd64bsd_target ());
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/* Target-dependent code for NetBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "arch-utils.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "osabi.h"
|
||||
#include "symtab.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
|
||||
#include "amd64-tdep.h"
|
||||
#include "nbsd-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
/* Support for signal handlers. */
|
||||
|
||||
/* Return whether the frame preceding NEXT_FRAME corresponds to a
|
||||
NetBSD sigtramp routine. */
|
||||
|
||||
static int
|
||||
amd64nbsd_sigtramp_p (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR pc = frame_pc_unwind (next_frame);
|
||||
char *name;
|
||||
|
||||
find_pc_partial_function (pc, &name, NULL, NULL);
|
||||
return nbsd_pc_in_sigtramp (pc, name);
|
||||
}
|
||||
|
||||
/* Assuming NEXT_FRAME is preceded by a frame corresponding to a
|
||||
NetBSD sigtramp routine, return the address of the associated
|
||||
mcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64nbsd_mcontext_addr (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
|
||||
/* The register %r15 points at `struct ucontext' upon entry of a
|
||||
signal trampoline. */
|
||||
addr = frame_unwind_register_unsigned (next_frame, AMD64_R15_REGNUM);
|
||||
|
||||
/* The mcontext structure lives as offset 56 in `struct ucontext'. */
|
||||
return addr + 56;
|
||||
}
|
||||
|
||||
/* NetBSD 2.0 or later. */
|
||||
|
||||
/* Mapping between the general-purpose registers in `struct reg'
|
||||
format and GDB's register cache layout. */
|
||||
|
||||
/* From <machine/reg.h>. */
|
||||
int amd64nbsd_r_reg_offset[] =
|
||||
{
|
||||
14 * 8, /* %rax */
|
||||
13 * 8, /* %rbx */
|
||||
3 * 8, /* %rcx */
|
||||
2 * 8, /* %rdx */
|
||||
1 * 8, /* %rsi */
|
||||
0 * 8, /* %rdi */
|
||||
12 * 8, /* %rbp */
|
||||
24 * 8, /* %rsp */
|
||||
4 * 8, /* %r8 .. */
|
||||
5 * 8,
|
||||
6 * 8,
|
||||
7 * 8,
|
||||
8 * 8,
|
||||
9 * 8,
|
||||
10 * 8,
|
||||
11 * 8, /* ... %r15 */
|
||||
21 * 8, /* %rip */
|
||||
23 * 8, /* %eflags */
|
||||
22 * 8, /* %cs */
|
||||
25 * 8, /* %ss */
|
||||
18 * 8, /* %ds */
|
||||
17 * 8, /* %es */
|
||||
16 * 8, /* %fs */
|
||||
15 * 8 /* %gs */
|
||||
};
|
||||
|
||||
static void
|
||||
amd64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
/* Initialize general-purpose register set details first. */
|
||||
tdep->gregset_reg_offset = amd64nbsd_r_reg_offset;
|
||||
tdep->gregset_num_regs = ARRAY_SIZE (amd64nbsd_r_reg_offset);
|
||||
tdep->sizeof_gregset = 26 * 8;
|
||||
|
||||
amd64_init_abi (info, gdbarch);
|
||||
|
||||
tdep->jb_pc_offset = 7 * 8;
|
||||
|
||||
/* NetBSD has its own convention for signal trampolines. */
|
||||
tdep->sigtramp_p = amd64nbsd_sigtramp_p;
|
||||
tdep->sigcontext_addr = amd64nbsd_mcontext_addr;
|
||||
tdep->sc_reg_offset = amd64nbsd_r_reg_offset;
|
||||
tdep->sc_num_regs = ARRAY_SIZE (amd64nbsd_r_reg_offset);
|
||||
|
||||
/* NetBSD uses SVR4-style shared libraries. */
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_lp64_fetch_link_map_offsets);
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_amd64nbsd_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_amd64nbsd_ndep (void)
|
||||
{
|
||||
/* The NetBSD/amd64 native dependent code makes this assumption. */
|
||||
gdb_assert (ARRAY_SIZE (amd64nbsd_r_reg_offset) == AMD64_NUM_GREGS);
|
||||
|
||||
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
|
||||
GDB_OSABI_NETBSD_ELF, amd64nbsd_init_abi);
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/* Native-dependent code for OpenBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "regcache.h"
|
||||
#include "target.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
|
||||
#include "amd64-tdep.h"
|
||||
#include "amd64-nat.h"
|
||||
|
||||
/* Mapping between the general-purpose registers in OpenBSD/amd64
|
||||
`struct reg' format and GDB's register cache layout for
|
||||
OpenBSD/i386.
|
||||
|
||||
Note that most (if not all) OpenBSD/amd64 registers are 64-bit,
|
||||
while the OpenBSD/i386 registers are all 32-bit, but since we're
|
||||
little-endian we get away with that. */
|
||||
|
||||
/* From <machine/reg.h>. */
|
||||
static int amd64obsd32_r_reg_offset[] =
|
||||
{
|
||||
14 * 8, /* %eax */
|
||||
3 * 8, /* %ecx */
|
||||
2 * 8, /* %edx */
|
||||
13 * 8, /* %ebx */
|
||||
15 * 8, /* %esp */
|
||||
12 * 8, /* %ebp */
|
||||
1 * 8, /* %esi */
|
||||
0 * 8, /* %edi */
|
||||
16 * 8, /* %eip */
|
||||
17 * 8, /* %eflags */
|
||||
18 * 8, /* %cs */
|
||||
19 * 8, /* %ss */
|
||||
20 * 8, /* %ds */
|
||||
21 * 8, /* %es */
|
||||
22 * 8, /* %fs */
|
||||
23 * 8 /* %gs */
|
||||
};
|
||||
|
||||
|
||||
/* Support for debugging kernel virtual memory images. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/pcb.h>
|
||||
|
||||
#include "bsd-kvm.h"
|
||||
|
||||
static int
|
||||
amd64obsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
|
||||
{
|
||||
struct switchframe sf;
|
||||
int regnum;
|
||||
|
||||
/* The following is true for OpenBSD 3.5:
|
||||
|
||||
The pcb contains the stack pointer at the point of the context
|
||||
switch in cpu_switch(). At that point we have a stack frame as
|
||||
described by `struct switchframe', which for OpenBSD 3.5 has the
|
||||
following layout:
|
||||
|
||||
interrupt level
|
||||
%r15
|
||||
%r14
|
||||
%r13
|
||||
%r12
|
||||
%rbp
|
||||
%rbx
|
||||
return address
|
||||
|
||||
Together with %rsp in the pcb, this accounts for all callee-saved
|
||||
registers specified by the psABI. From this information we
|
||||
reconstruct the register state as it would look when we just
|
||||
returned from cpu_switch().
|
||||
|
||||
For core dumps the pcb is saved by savectx(). In that case the
|
||||
stack frame only contains the return address, and there is no way
|
||||
to recover the other registers. */
|
||||
|
||||
/* The stack pointer shouldn't be zero. */
|
||||
if (pcb->pcb_rsp == 0)
|
||||
return 0;
|
||||
|
||||
/* Read the stack frame, and check its validity. */
|
||||
read_memory (pcb->pcb_rsp, (gdb_byte *) &sf, sizeof sf);
|
||||
if (sf.sf_rbp == pcb->pcb_rbp)
|
||||
{
|
||||
/* Yes, we have a frame that matches cpu_switch(). */
|
||||
pcb->pcb_rsp += sizeof (struct switchframe);
|
||||
regcache_raw_supply (regcache, 12, &sf.sf_r12);
|
||||
regcache_raw_supply (regcache, 13, &sf.sf_r13);
|
||||
regcache_raw_supply (regcache, 14, &sf.sf_r14);
|
||||
regcache_raw_supply (regcache, 15, &sf.sf_r15);
|
||||
regcache_raw_supply (regcache, AMD64_RBX_REGNUM, &sf.sf_rbx);
|
||||
regcache_raw_supply (regcache, AMD64_RIP_REGNUM, &sf.sf_rip);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No, the pcb must have been last updated by savectx(). */
|
||||
pcb->pcb_rsp += 8;
|
||||
regcache_raw_supply (regcache, AMD64_RIP_REGNUM, &sf);
|
||||
}
|
||||
|
||||
regcache_raw_supply (regcache, AMD64_RSP_REGNUM, &pcb->pcb_rsp);
|
||||
regcache_raw_supply (regcache, AMD64_RBP_REGNUM, &pcb->pcb_rbp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_amd64obsd_nat (void);
|
||||
|
||||
void
|
||||
_initialize_amd64obsd_nat (void)
|
||||
{
|
||||
amd64_native_gregset32_reg_offset = amd64obsd32_r_reg_offset;
|
||||
amd64_native_gregset32_num_regs = ARRAY_SIZE (amd64obsd32_r_reg_offset);
|
||||
amd64_native_gregset64_reg_offset = amd64obsd_r_reg_offset;
|
||||
|
||||
/* We've got nothing to add to the common *BSD/amd64 target. */
|
||||
add_target (amd64bsd_target ());
|
||||
|
||||
/* Support debugging kernel virtual memory images. */
|
||||
bsd_kvm_add_target (amd64obsd_supply_pcb);
|
||||
}
|
||||
@@ -1,496 +0,0 @@
|
||||
/* Target-dependent code for OpenBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "frame-unwind.h"
|
||||
#include "gdbcore.h"
|
||||
#include "symtab.h"
|
||||
#include "objfiles.h"
|
||||
#include "osabi.h"
|
||||
#include "regcache.h"
|
||||
#include "regset.h"
|
||||
#include "target.h"
|
||||
#include "trad-frame.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "amd64-tdep.h"
|
||||
#include "i387-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
#include "bsd-uthread.h"
|
||||
|
||||
/* Support for core dumps. */
|
||||
|
||||
static void
|
||||
amd64obsd_supply_regset (const struct regset *regset,
|
||||
struct regcache *regcache, int regnum,
|
||||
const void *regs, size_t len)
|
||||
{
|
||||
const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
|
||||
|
||||
gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE);
|
||||
|
||||
i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
|
||||
amd64_supply_fxsave (regcache, regnum,
|
||||
((const gdb_byte *)regs) + tdep->sizeof_gregset);
|
||||
}
|
||||
|
||||
static const struct regset *
|
||||
amd64obsd_regset_from_core_section (struct gdbarch *gdbarch,
|
||||
const char *sect_name, size_t sect_size)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
/* OpenBSD core dumps don't use seperate register sets for the
|
||||
general-purpose and floating-point registers. */
|
||||
|
||||
if (strcmp (sect_name, ".reg") == 0
|
||||
&& sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE)
|
||||
{
|
||||
if (tdep->gregset == NULL)
|
||||
tdep->gregset = regset_alloc (gdbarch, amd64obsd_supply_regset, NULL);
|
||||
return tdep->gregset;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Support for signal handlers. */
|
||||
|
||||
/* Default page size. */
|
||||
static const int amd64obsd_page_size = 4096;
|
||||
|
||||
/* Return whether the frame preceding NEXT_FRAME corresponds to an
|
||||
OpenBSD sigtramp routine. */
|
||||
|
||||
static int
|
||||
amd64obsd_sigtramp_p (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR pc = frame_pc_unwind (next_frame);
|
||||
CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1));
|
||||
const gdb_byte sigreturn[] =
|
||||
{
|
||||
0x48, 0xc7, 0xc0,
|
||||
0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */
|
||||
0xcd, 0x80 /* int $0x80 */
|
||||
};
|
||||
size_t buflen = (sizeof sigreturn) + 1;
|
||||
gdb_byte *buf;
|
||||
char *name;
|
||||
|
||||
/* If the function has a valid symbol name, it isn't a
|
||||
trampoline. */
|
||||
find_pc_partial_function (pc, &name, NULL, NULL);
|
||||
if (name != NULL)
|
||||
return 0;
|
||||
|
||||
/* If the function lives in a valid section (even without a starting
|
||||
point) it isn't a trampoline. */
|
||||
if (find_pc_section (pc) != NULL)
|
||||
return 0;
|
||||
|
||||
/* If we can't read the instructions at START_PC, return zero. */
|
||||
buf = alloca ((sizeof sigreturn) + 1);
|
||||
if (!safe_frame_unwind_memory (next_frame, start_pc + 6, buf, buflen))
|
||||
return 0;
|
||||
|
||||
/* Check for sigreturn(2). Depending on how the assembler encoded
|
||||
the `movq %rsp, %rdi' instruction, the code starts at offset 6 or
|
||||
7. */
|
||||
if (memcmp (buf, sigreturn, sizeof sigreturn)
|
||||
&& memcpy (buf + 1, sigreturn, sizeof sigreturn))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
|
||||
routine, return the address of the associated sigcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64obsd_sigcontext_addr (struct frame_info *next_frame)
|
||||
{
|
||||
CORE_ADDR pc = frame_pc_unwind (next_frame);
|
||||
ULONGEST offset = (pc & (amd64obsd_page_size - 1));
|
||||
|
||||
/* The %rsp register points at `struct sigcontext' upon entry of a
|
||||
signal trampoline. The relevant part of the trampoline is
|
||||
|
||||
call *%rax
|
||||
movq %rsp, %rdi
|
||||
pushq %rdi
|
||||
movq $SYS_sigreturn,%rax
|
||||
int $0x80
|
||||
|
||||
(see /usr/src/sys/arch/amd64/amd64/locore.S). The `pushq'
|
||||
instruction clobbers %rsp, but its value is saved in `%rdi'. */
|
||||
|
||||
if (offset > 5)
|
||||
return frame_unwind_register_unsigned (next_frame, AMD64_RDI_REGNUM);
|
||||
else
|
||||
return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
|
||||
}
|
||||
|
||||
/* OpenBSD 3.5 or later. */
|
||||
|
||||
/* Mapping between the general-purpose registers in `struct reg'
|
||||
format and GDB's register cache layout. */
|
||||
|
||||
/* From <machine/reg.h>. */
|
||||
int amd64obsd_r_reg_offset[] =
|
||||
{
|
||||
14 * 8, /* %rax */
|
||||
13 * 8, /* %rbx */
|
||||
3 * 8, /* %rcx */
|
||||
2 * 8, /* %rdx */
|
||||
1 * 8, /* %rsi */
|
||||
0 * 8, /* %rdi */
|
||||
12 * 8, /* %rbp */
|
||||
15 * 8, /* %rsp */
|
||||
4 * 8, /* %r8 .. */
|
||||
5 * 8,
|
||||
6 * 8,
|
||||
7 * 8,
|
||||
8 * 8,
|
||||
9 * 8,
|
||||
10 * 8,
|
||||
11 * 8, /* ... %r15 */
|
||||
16 * 8, /* %rip */
|
||||
17 * 8, /* %eflags */
|
||||
18 * 8, /* %cs */
|
||||
19 * 8, /* %ss */
|
||||
20 * 8, /* %ds */
|
||||
21 * 8, /* %es */
|
||||
22 * 8, /* %fs */
|
||||
23 * 8 /* %gs */
|
||||
};
|
||||
|
||||
/* From <machine/signal.h>. */
|
||||
static int amd64obsd_sc_reg_offset[] =
|
||||
{
|
||||
14 * 8, /* %rax */
|
||||
13 * 8, /* %rbx */
|
||||
3 * 8, /* %rcx */
|
||||
2 * 8, /* %rdx */
|
||||
1 * 8, /* %rsi */
|
||||
0 * 8, /* %rdi */
|
||||
12 * 8, /* %rbp */
|
||||
24 * 8, /* %rsp */
|
||||
4 * 8, /* %r8 ... */
|
||||
5 * 8,
|
||||
6 * 8,
|
||||
7 * 8,
|
||||
8 * 8,
|
||||
9 * 8,
|
||||
10 * 8,
|
||||
11 * 8, /* ... %r15 */
|
||||
21 * 8, /* %rip */
|
||||
23 * 8, /* %eflags */
|
||||
22 * 8, /* %cs */
|
||||
25 * 8, /* %ss */
|
||||
18 * 8, /* %ds */
|
||||
17 * 8, /* %es */
|
||||
16 * 8, /* %fs */
|
||||
15 * 8 /* %gs */
|
||||
};
|
||||
|
||||
/* From /usr/src/lib/libpthread/arch/amd64/uthread_machdep.c. */
|
||||
static int amd64obsd_uthread_reg_offset[] =
|
||||
{
|
||||
19 * 8, /* %rax */
|
||||
16 * 8, /* %rbx */
|
||||
18 * 8, /* %rcx */
|
||||
17 * 8, /* %rdx */
|
||||
14 * 8, /* %rsi */
|
||||
13 * 8, /* %rdi */
|
||||
15 * 8, /* %rbp */
|
||||
-1, /* %rsp */
|
||||
12 * 8, /* %r8 ... */
|
||||
11 * 8,
|
||||
10 * 8,
|
||||
9 * 8,
|
||||
8 * 8,
|
||||
7 * 8,
|
||||
6 * 8,
|
||||
5 * 8, /* ... %r15 */
|
||||
20 * 8, /* %rip */
|
||||
4 * 8, /* %eflags */
|
||||
21 * 8, /* %cs */
|
||||
-1, /* %ss */
|
||||
3 * 8, /* %ds */
|
||||
2 * 8, /* %es */
|
||||
1 * 8, /* %fs */
|
||||
0 * 8 /* %gs */
|
||||
};
|
||||
|
||||
/* Offset within the thread structure where we can find the saved
|
||||
stack pointer (%esp). */
|
||||
#define AMD64OBSD_UTHREAD_RSP_OFFSET 400
|
||||
|
||||
static void
|
||||
amd64obsd_supply_uthread (struct regcache *regcache,
|
||||
int regnum, CORE_ADDR addr)
|
||||
{
|
||||
CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
|
||||
CORE_ADDR sp = 0;
|
||||
gdb_byte buf[8];
|
||||
int i;
|
||||
|
||||
gdb_assert (regnum >= -1);
|
||||
|
||||
if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
|
||||
{
|
||||
int offset;
|
||||
|
||||
/* Fetch stack pointer from thread structure. */
|
||||
sp = read_memory_unsigned_integer (sp_addr, 8);
|
||||
|
||||
/* Adjust the stack pointer such that it looks as if we just
|
||||
returned from _thread_machdep_switch. */
|
||||
offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
|
||||
store_unsigned_integer (buf, 8, sp + offset);
|
||||
regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
|
||||
{
|
||||
if (amd64obsd_uthread_reg_offset[i] != -1
|
||||
&& (regnum == -1 || regnum == i))
|
||||
{
|
||||
/* Fetch stack pointer from thread structure (if we didn't
|
||||
do so already). */
|
||||
if (sp == 0)
|
||||
sp = read_memory_unsigned_integer (sp_addr, 8);
|
||||
|
||||
/* Read the saved register from the stack frame. */
|
||||
read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
|
||||
regcache_raw_supply (regcache, i, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
amd64obsd_collect_uthread (const struct regcache *regcache,
|
||||
int regnum, CORE_ADDR addr)
|
||||
{
|
||||
CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
|
||||
CORE_ADDR sp = 0;
|
||||
gdb_byte buf[8];
|
||||
int i;
|
||||
|
||||
gdb_assert (regnum >= -1);
|
||||
|
||||
if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
|
||||
{
|
||||
int offset;
|
||||
|
||||
/* Calculate the stack pointer (frame pointer) that will be
|
||||
stored into the thread structure. */
|
||||
offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
|
||||
regcache_raw_collect (regcache, AMD64_RSP_REGNUM, buf);
|
||||
sp = extract_unsigned_integer (buf, 8) - offset;
|
||||
|
||||
/* Store the stack pointer. */
|
||||
write_memory_unsigned_integer (sp_addr, 8, sp);
|
||||
|
||||
/* The stack pointer was (potentially) modified. Make sure we
|
||||
build a proper stack frame. */
|
||||
regnum = -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
|
||||
{
|
||||
if (amd64obsd_uthread_reg_offset[i] != -1
|
||||
&& (regnum == -1 || regnum == i))
|
||||
{
|
||||
/* Fetch stack pointer from thread structure (if we didn't
|
||||
calculate it already). */
|
||||
if (sp == 0)
|
||||
sp = read_memory_unsigned_integer (sp_addr, 8);
|
||||
|
||||
/* Write the register into the stack frame. */
|
||||
regcache_raw_collect (regcache, i, buf);
|
||||
write_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Kernel debugging support. */
|
||||
|
||||
/* From <machine/frame.h>. Easy since `struct trapframe' matches
|
||||
`struct sigcontext'. */
|
||||
#define amd64obsd_tf_reg_offset amd64obsd_sc_reg_offset
|
||||
|
||||
static struct trad_frame_cache *
|
||||
amd64obsd_trapframe_cache(struct frame_info *next_frame, void **this_cache)
|
||||
{
|
||||
struct trad_frame_cache *cache;
|
||||
CORE_ADDR func, sp, addr;
|
||||
ULONGEST cs;
|
||||
char *name;
|
||||
int i;
|
||||
|
||||
if (*this_cache)
|
||||
return *this_cache;
|
||||
|
||||
cache = trad_frame_cache_zalloc (next_frame);
|
||||
*this_cache = cache;
|
||||
|
||||
func = frame_func_unwind (next_frame);
|
||||
sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
|
||||
|
||||
find_pc_partial_function (func, &name, NULL, NULL);
|
||||
if (name && strncmp (name, "Xintr", 5) == 0)
|
||||
addr = sp + 8; /* It's an interrupt frame. */
|
||||
else
|
||||
addr = sp;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (amd64obsd_tf_reg_offset); i++)
|
||||
if (amd64obsd_tf_reg_offset[i] != -1)
|
||||
trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]);
|
||||
|
||||
/* Read %cs from trap frame. */
|
||||
addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM];
|
||||
cs = read_memory_unsigned_integer (addr, 8);
|
||||
if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
|
||||
{
|
||||
/* Trap from user space; terminate backtrace. */
|
||||
trad_frame_set_id (cache, null_frame_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Construct the frame ID using the function start. */
|
||||
trad_frame_set_id (cache, frame_id_build (sp + 16, func));
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static void
|
||||
amd64obsd_trapframe_this_id (struct frame_info *next_frame,
|
||||
void **this_cache, struct frame_id *this_id)
|
||||
{
|
||||
struct trad_frame_cache *cache =
|
||||
amd64obsd_trapframe_cache (next_frame, this_cache);
|
||||
|
||||
trad_frame_get_id (cache, this_id);
|
||||
}
|
||||
|
||||
static void
|
||||
amd64obsd_trapframe_prev_register (struct frame_info *next_frame,
|
||||
void **this_cache, int regnum,
|
||||
int *optimizedp, enum lval_type *lvalp,
|
||||
CORE_ADDR *addrp, int *realnump,
|
||||
gdb_byte *valuep)
|
||||
{
|
||||
struct trad_frame_cache *cache =
|
||||
amd64obsd_trapframe_cache (next_frame, this_cache);
|
||||
|
||||
trad_frame_get_register (cache, next_frame, regnum,
|
||||
optimizedp, lvalp, addrp, realnump, valuep);
|
||||
}
|
||||
|
||||
static int
|
||||
amd64obsd_trapframe_sniffer (const struct frame_unwind *self,
|
||||
struct frame_info *next_frame,
|
||||
void **this_prologue_cache)
|
||||
{
|
||||
ULONGEST cs;
|
||||
char *name;
|
||||
|
||||
/* Check Current Privilege Level and bail out if we're not executing
|
||||
in kernel space. */
|
||||
cs = frame_unwind_register_unsigned (next_frame, AMD64_CS_REGNUM);
|
||||
if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
|
||||
return 0;
|
||||
|
||||
find_pc_partial_function (frame_pc_unwind (next_frame), &name, NULL, NULL);
|
||||
return (name && ((strcmp (name, "calltrap") == 0)
|
||||
|| (strcmp (name, "osyscall1") == 0)
|
||||
|| (strcmp (name, "Xsyscall") == 0)
|
||||
|| (strncmp (name, "Xintr", 5) == 0)));
|
||||
}
|
||||
|
||||
static const struct frame_unwind amd64obsd_trapframe_unwind = {
|
||||
/* FIXME: kettenis/20051219: This really is more like an interrupt
|
||||
frame, but SIGTRAMP_FRAME would print <signal handler called>,
|
||||
which really is not what we want here. */
|
||||
NORMAL_FRAME,
|
||||
amd64obsd_trapframe_this_id,
|
||||
amd64obsd_trapframe_prev_register,
|
||||
NULL,
|
||||
amd64obsd_trapframe_sniffer
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
amd64_init_abi (info, gdbarch);
|
||||
|
||||
/* Initialize general-purpose register set details. */
|
||||
tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
|
||||
tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
|
||||
tdep->sizeof_gregset = 24 * 8;
|
||||
|
||||
set_gdbarch_regset_from_core_section (gdbarch,
|
||||
amd64obsd_regset_from_core_section);
|
||||
|
||||
tdep->jb_pc_offset = 7 * 8;
|
||||
|
||||
tdep->sigtramp_p = amd64obsd_sigtramp_p;
|
||||
tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
|
||||
tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
|
||||
tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
|
||||
|
||||
/* OpenBSD provides a user-level threads implementation. */
|
||||
bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread);
|
||||
bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread);
|
||||
|
||||
/* OpenBSD uses SVR4-style shared libraries. */
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_lp64_fetch_link_map_offsets);
|
||||
|
||||
/* Unwind kernel trap frames correctly. */
|
||||
frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind);
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_amd64obsd_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_amd64obsd_tdep (void)
|
||||
{
|
||||
/* The OpenBSD/amd64 native dependent code makes this assumption. */
|
||||
gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
|
||||
|
||||
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
|
||||
GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi);
|
||||
|
||||
/* OpenBSD uses traditional (a.out) NetBSD-style core dumps. */
|
||||
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
|
||||
GDB_OSABI_NETBSD_AOUT, amd64obsd_init_abi);
|
||||
}
|
||||
585
gdb/annotate.c
585
gdb/annotate.c
@@ -1,585 +0,0 @@
|
||||
/* Annotation routines for GDB.
|
||||
Copyright (C) 1986, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1998, 1999,
|
||||
2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "annotate.h"
|
||||
#include "value.h"
|
||||
#include "target.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "breakpoint.h"
|
||||
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
|
||||
extern void _initialize_annotate (void);
|
||||
|
||||
static void print_value_flags (struct type *);
|
||||
|
||||
static void breakpoint_changed (struct breakpoint *);
|
||||
|
||||
void (*deprecated_annotate_starting_hook) (void);
|
||||
void (*deprecated_annotate_stopped_hook) (void);
|
||||
void (*deprecated_annotate_signalled_hook) (void);
|
||||
void (*deprecated_annotate_signal_hook) (void);
|
||||
void (*deprecated_annotate_exited_hook) (void);
|
||||
|
||||
static int ignore_count_changed = 0;
|
||||
|
||||
static void
|
||||
print_value_flags (struct type *t)
|
||||
{
|
||||
if (can_dereference (t))
|
||||
printf_filtered (("*"));
|
||||
else
|
||||
printf_filtered (("-"));
|
||||
}
|
||||
|
||||
void
|
||||
breakpoints_changed (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
target_terminal_ours ();
|
||||
printf_unfiltered (("\n\032\032breakpoints-invalid\n"));
|
||||
if (ignore_count_changed)
|
||||
ignore_count_changed = 0; /* Avoid multiple break annotations. */
|
||||
}
|
||||
}
|
||||
|
||||
/* The GUI needs to be informed of ignore_count changes, but we don't
|
||||
want to provide successive multiple breakpoints-invalid messages
|
||||
that are all caused by the fact that the ignore count is changing
|
||||
(which could keep the GUI very busy). One is enough, after the
|
||||
target actually "stops". */
|
||||
|
||||
void
|
||||
annotate_ignore_count_change (void)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
ignore_count_changed = 1;
|
||||
}
|
||||
|
||||
void
|
||||
annotate_breakpoint (int num)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032breakpoint %d\n"), num);
|
||||
}
|
||||
|
||||
void
|
||||
annotate_catchpoint (int num)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032catchpoint %d\n"), num);
|
||||
}
|
||||
|
||||
void
|
||||
annotate_watchpoint (int num)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032watchpoint %d\n"), num);
|
||||
}
|
||||
|
||||
void
|
||||
annotate_starting (void)
|
||||
{
|
||||
|
||||
if (deprecated_annotate_starting_hook)
|
||||
deprecated_annotate_starting_hook ();
|
||||
else
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
{
|
||||
printf_filtered (("\n\032\032starting\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_stopped (void)
|
||||
{
|
||||
if (deprecated_annotate_stopped_hook)
|
||||
deprecated_annotate_stopped_hook ();
|
||||
else
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032stopped\n"));
|
||||
}
|
||||
if (annotation_level > 1 && ignore_count_changed)
|
||||
{
|
||||
ignore_count_changed = 0;
|
||||
breakpoints_changed ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_exited (int exitstatus)
|
||||
{
|
||||
if (deprecated_annotate_exited_hook)
|
||||
deprecated_annotate_exited_hook ();
|
||||
else
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032exited %d\n"), exitstatus);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_signalled (void)
|
||||
{
|
||||
if (deprecated_annotate_signalled_hook)
|
||||
deprecated_annotate_signalled_hook ();
|
||||
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032signalled\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_signal_name (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032signal-name\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_signal_name_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032signal-name-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_signal_string (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032signal-string\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_signal_string_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032signal-string-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_signal (void)
|
||||
{
|
||||
if (deprecated_annotate_signal_hook)
|
||||
deprecated_annotate_signal_hook ();
|
||||
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032signal\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_breakpoints_headers (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032breakpoints-headers\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_field (int num)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032field %d\n"), num);
|
||||
}
|
||||
|
||||
void
|
||||
annotate_breakpoints_table (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032breakpoints-table\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_record (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032record\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_breakpoints_table_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032breakpoints-table-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frames_invalid (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
target_terminal_ours ();
|
||||
printf_unfiltered (("\n\032\032frames-invalid\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_field_begin (struct type *type)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
printf_filtered (("\n\032\032field-begin "));
|
||||
print_value_flags (type);
|
||||
printf_filtered (("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_field_name_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032field-name-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_field_value (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032field-value\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_field_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032field-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_quit (void)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032quit\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_error (void)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032error\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_error_begin (void)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
fprintf_filtered (gdb_stderr, "\n\032\032error-begin\n");
|
||||
}
|
||||
|
||||
void
|
||||
annotate_value_history_begin (int histindex, struct type *type)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
printf_filtered (("\n\032\032value-history-begin %d "), histindex);
|
||||
print_value_flags (type);
|
||||
printf_filtered (("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_value_begin (struct type *type)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
printf_filtered (("\n\032\032value-begin "));
|
||||
print_value_flags (type);
|
||||
printf_filtered (("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_value_history_value (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032value-history-value\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_value_history_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032value-history-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_value_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032value-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_display_begin (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032display-begin\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_display_number_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032display-number-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_display_format (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032display-format\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_display_expression (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032display-expression\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_display_expression_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032display-expression-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_display_value (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032display-value\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_display_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032display-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_arg_begin (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032arg-begin\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_arg_name_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032arg-name-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_arg_value (struct type *type)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
printf_filtered (("\n\032\032arg-value "));
|
||||
print_value_flags (type);
|
||||
printf_filtered (("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_arg_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032arg-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_source (char *filename, int line, int character, int mid, CORE_ADDR pc)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032source "));
|
||||
else
|
||||
printf_filtered (("\032\032"));
|
||||
|
||||
printf_filtered (("%s:%d:%d:%s:0x"), filename,
|
||||
line, character,
|
||||
mid ? "middle" : "beg");
|
||||
deprecated_print_address_numeric (pc, 0, gdb_stdout);
|
||||
printf_filtered (("\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_begin (int level, CORE_ADDR pc)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
printf_filtered (("\n\032\032frame-begin %d 0x"), level);
|
||||
deprecated_print_address_numeric (pc, 0, gdb_stdout);
|
||||
printf_filtered (("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_function_call (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032function-call\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_signal_handler_caller (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032signal-handler-caller\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_address (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-address\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_address_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-address-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_function_name (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-function-name\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_args (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-args\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_source_begin (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-source-begin\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_source_file (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-source-file\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_source_file_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-source-file-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_source_line (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-source-line\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_source_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-source-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_where (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-where\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032frame-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_array_section_begin (int index, struct type *elttype)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
printf_filtered (("\n\032\032array-section-begin %d "), index);
|
||||
print_value_flags (elttype);
|
||||
printf_filtered (("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_elt_rep (unsigned int repcount)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032elt-rep %u\n"), repcount);
|
||||
}
|
||||
|
||||
void
|
||||
annotate_elt_rep_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032elt-rep-end\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_elt (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032elt\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_array_section_end (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
printf_filtered (("\n\032\032array-section-end\n"));
|
||||
}
|
||||
|
||||
static void
|
||||
breakpoint_changed (struct breakpoint *b)
|
||||
{
|
||||
breakpoints_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_annotate (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
deprecated_delete_breakpoint_hook = breakpoint_changed;
|
||||
deprecated_modify_breakpoint_hook = breakpoint_changed;
|
||||
}
|
||||
}
|
||||
106
gdb/annotate.h
106
gdb/annotate.h
@@ -1,106 +0,0 @@
|
||||
/* Annotation routines for GDB.
|
||||
Copyright (C) 1986, 1989, 1990, 1991, 1992, 1994, 1998, 1999, 2000
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "symtab.h"
|
||||
#include "gdbtypes.h"
|
||||
|
||||
extern void breakpoints_changed (void);
|
||||
|
||||
extern void annotate_ignore_count_change (void);
|
||||
extern void annotate_breakpoint (int);
|
||||
extern void annotate_catchpoint (int);
|
||||
extern void annotate_watchpoint (int);
|
||||
extern void annotate_starting (void);
|
||||
extern void annotate_stopped (void);
|
||||
extern void annotate_exited (int);
|
||||
extern void annotate_signalled (void);
|
||||
extern void annotate_signal_name (void);
|
||||
extern void annotate_signal_name_end (void);
|
||||
extern void annotate_signal_string (void);
|
||||
extern void annotate_signal_string_end (void);
|
||||
extern void annotate_signal (void);
|
||||
|
||||
extern void annotate_breakpoints_headers (void);
|
||||
extern void annotate_field (int);
|
||||
extern void annotate_breakpoints_table (void);
|
||||
extern void annotate_record (void);
|
||||
extern void annotate_breakpoints_table_end (void);
|
||||
|
||||
extern void annotate_frames_invalid (void);
|
||||
|
||||
struct type;
|
||||
|
||||
extern void annotate_field_begin (struct type *);
|
||||
extern void annotate_field_name_end (void);
|
||||
extern void annotate_field_value (void);
|
||||
extern void annotate_field_end (void);
|
||||
|
||||
extern void annotate_quit (void);
|
||||
extern void annotate_error (void);
|
||||
extern void annotate_error_begin (void);
|
||||
|
||||
extern void annotate_value_history_begin (int, struct type *);
|
||||
extern void annotate_value_begin (struct type *);
|
||||
extern void annotate_value_history_value (void);
|
||||
extern void annotate_value_history_end (void);
|
||||
extern void annotate_value_end (void);
|
||||
|
||||
extern void annotate_display_begin (void);
|
||||
extern void annotate_display_number_end (void);
|
||||
extern void annotate_display_format (void);
|
||||
extern void annotate_display_expression (void);
|
||||
extern void annotate_display_expression_end (void);
|
||||
extern void annotate_display_value (void);
|
||||
extern void annotate_display_end (void);
|
||||
|
||||
extern void annotate_arg_begin (void);
|
||||
extern void annotate_arg_name_end (void);
|
||||
extern void annotate_arg_value (struct type *);
|
||||
extern void annotate_arg_end (void);
|
||||
|
||||
extern void annotate_source (char *, int, int, int, CORE_ADDR);
|
||||
|
||||
extern void annotate_frame_begin (int, CORE_ADDR);
|
||||
extern void annotate_function_call (void);
|
||||
extern void annotate_signal_handler_caller (void);
|
||||
extern void annotate_frame_address (void);
|
||||
extern void annotate_frame_address_end (void);
|
||||
extern void annotate_frame_function_name (void);
|
||||
extern void annotate_frame_args (void);
|
||||
extern void annotate_frame_source_begin (void);
|
||||
extern void annotate_frame_source_file (void);
|
||||
extern void annotate_frame_source_file_end (void);
|
||||
extern void annotate_frame_source_line (void);
|
||||
extern void annotate_frame_source_end (void);
|
||||
extern void annotate_frame_where (void);
|
||||
extern void annotate_frame_end (void);
|
||||
|
||||
extern void annotate_array_section_begin (int, struct type *);
|
||||
extern void annotate_elt_rep (unsigned int);
|
||||
extern void annotate_elt_rep_end (void);
|
||||
extern void annotate_elt (void);
|
||||
extern void annotate_array_section_end (void);
|
||||
|
||||
extern void (*deprecated_annotate_starting_hook) (void);
|
||||
extern void (*deprecated_annotate_stopped_hook) (void);
|
||||
extern void (*deprecated_annotate_signalled_hook) (void);
|
||||
extern void (*deprecated_annotate_signal_hook) (void);
|
||||
extern void (*deprecated_annotate_exited_hook) (void);
|
||||
738
gdb/arch-utils.c
738
gdb/arch-utils.c
@@ -1,738 +0,0 @@
|
||||
/* Dynamic architecture support for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include "arch-utils.h"
|
||||
#include "buildsym.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "inferior.h" /* enum CALL_DUMMY_LOCATION et.al. */
|
||||
#include "gdb_string.h"
|
||||
#include "regcache.h"
|
||||
#include "gdb_assert.h"
|
||||
#include "sim-regno.h"
|
||||
#include "gdbcore.h"
|
||||
#include "osabi.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#include "floatformat.h"
|
||||
|
||||
/* Implementation of extract return value that grubs around in the
|
||||
register cache. */
|
||||
void
|
||||
legacy_extract_return_value (struct type *type, struct regcache *regcache,
|
||||
gdb_byte *valbuf)
|
||||
{
|
||||
gdb_byte *registers = deprecated_grub_regcache_for_registers (regcache);
|
||||
gdb_byte *buf = valbuf;
|
||||
DEPRECATED_EXTRACT_RETURN_VALUE (type, registers, buf); /* OK */
|
||||
}
|
||||
|
||||
/* Implementation of store return value that grubs the register cache.
|
||||
Takes a local copy of the buffer to avoid const problems. */
|
||||
void
|
||||
legacy_store_return_value (struct type *type, struct regcache *regcache,
|
||||
const gdb_byte *buf)
|
||||
{
|
||||
gdb_byte *b = alloca (TYPE_LENGTH (type));
|
||||
gdb_assert (regcache == current_regcache);
|
||||
memcpy (b, buf, TYPE_LENGTH (type));
|
||||
DEPRECATED_STORE_RETURN_VALUE (type, b);
|
||||
}
|
||||
|
||||
int
|
||||
always_use_struct_convention (int gcc_p, struct type *value_type)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum return_value_convention
|
||||
legacy_return_value (struct gdbarch *gdbarch, struct type *valtype,
|
||||
struct regcache *regcache, gdb_byte *readbuf,
|
||||
const gdb_byte *writebuf)
|
||||
{
|
||||
/* NOTE: cagney/2004-06-13: The gcc_p parameter to
|
||||
USE_STRUCT_CONVENTION isn't used. */
|
||||
int struct_return = ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
|
||||
|| TYPE_CODE (valtype) == TYPE_CODE_UNION
|
||||
|| TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
|
||||
&& DEPRECATED_USE_STRUCT_CONVENTION (0, valtype));
|
||||
|
||||
if (writebuf != NULL)
|
||||
{
|
||||
gdb_assert (!struct_return);
|
||||
/* NOTE: cagney/2004-06-13: See stack.c:return_command. Old
|
||||
architectures don't expect STORE_RETURN_VALUE to handle small
|
||||
structures. Should not be called with such types. */
|
||||
gdb_assert (TYPE_CODE (valtype) != TYPE_CODE_STRUCT
|
||||
&& TYPE_CODE (valtype) != TYPE_CODE_UNION);
|
||||
STORE_RETURN_VALUE (valtype, regcache, writebuf);
|
||||
}
|
||||
|
||||
if (readbuf != NULL)
|
||||
{
|
||||
gdb_assert (!struct_return);
|
||||
EXTRACT_RETURN_VALUE (valtype, regcache, readbuf);
|
||||
}
|
||||
|
||||
if (struct_return)
|
||||
return RETURN_VALUE_STRUCT_CONVENTION;
|
||||
else
|
||||
return RETURN_VALUE_REGISTER_CONVENTION;
|
||||
}
|
||||
|
||||
int
|
||||
legacy_register_sim_regno (int regnum)
|
||||
{
|
||||
/* Only makes sense to supply raw registers. */
|
||||
gdb_assert (regnum >= 0 && regnum < NUM_REGS);
|
||||
/* NOTE: cagney/2002-05-13: The old code did it this way and it is
|
||||
suspected that some GDB/SIM combinations may rely on this
|
||||
behavour. The default should be one2one_register_sim_regno
|
||||
(below). */
|
||||
if (REGISTER_NAME (regnum) != NULL
|
||||
&& REGISTER_NAME (regnum)[0] != '\0')
|
||||
return regnum;
|
||||
else
|
||||
return LEGACY_SIM_REGNO_IGNORE;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
generic_skip_trampoline_code (CORE_ADDR pc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
generic_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
generic_in_solib_return_trampoline (CORE_ADDR pc, char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
generic_remote_translate_xfer_address (struct gdbarch *gdbarch,
|
||||
struct regcache *regcache,
|
||||
CORE_ADDR gdb_addr, int gdb_len,
|
||||
CORE_ADDR * rem_addr, int *rem_len)
|
||||
{
|
||||
*rem_addr = gdb_addr;
|
||||
*rem_len = gdb_len;
|
||||
}
|
||||
|
||||
/* Helper functions for INNER_THAN */
|
||||
|
||||
int
|
||||
core_addr_lessthan (CORE_ADDR lhs, CORE_ADDR rhs)
|
||||
{
|
||||
return (lhs < rhs);
|
||||
}
|
||||
|
||||
int
|
||||
core_addr_greaterthan (CORE_ADDR lhs, CORE_ADDR rhs)
|
||||
{
|
||||
return (lhs > rhs);
|
||||
}
|
||||
|
||||
|
||||
/* Helper functions for TARGET_{FLOAT,DOUBLE}_FORMAT */
|
||||
|
||||
const struct floatformat *
|
||||
default_float_format (struct gdbarch *gdbarch)
|
||||
{
|
||||
int byte_order = gdbarch_byte_order (gdbarch);
|
||||
switch (byte_order)
|
||||
{
|
||||
case BFD_ENDIAN_BIG:
|
||||
return &floatformat_ieee_single_big;
|
||||
case BFD_ENDIAN_LITTLE:
|
||||
return &floatformat_ieee_single_little;
|
||||
default:
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("default_float_format: bad byte order"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const struct floatformat *
|
||||
default_double_format (struct gdbarch *gdbarch)
|
||||
{
|
||||
int byte_order = gdbarch_byte_order (gdbarch);
|
||||
switch (byte_order)
|
||||
{
|
||||
case BFD_ENDIAN_BIG:
|
||||
return &floatformat_ieee_double_big;
|
||||
case BFD_ENDIAN_LITTLE:
|
||||
return &floatformat_ieee_double_little;
|
||||
default:
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("default_double_format: bad byte order"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Misc helper functions for targets. */
|
||||
|
||||
CORE_ADDR
|
||||
core_addr_identity (CORE_ADDR addr)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
convert_from_func_ptr_addr_identity (struct gdbarch *gdbarch, CORE_ADDR addr,
|
||||
struct target_ops *targ)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
int
|
||||
no_op_reg_to_regnum (int reg)
|
||||
{
|
||||
return reg;
|
||||
}
|
||||
|
||||
void
|
||||
default_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
default_coff_make_msymbol_special (int val, struct minimal_symbol *msym)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
cannot_register_not (int regnum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Legacy version of target_virtual_frame_pointer(). Assumes that
|
||||
there is an DEPRECATED_FP_REGNUM and that it is the same, cooked or
|
||||
raw. */
|
||||
|
||||
void
|
||||
legacy_virtual_frame_pointer (CORE_ADDR pc,
|
||||
int *frame_regnum,
|
||||
LONGEST *frame_offset)
|
||||
{
|
||||
/* FIXME: cagney/2002-09-13: This code is used when identifying the
|
||||
frame pointer of the current PC. It is assuming that a single
|
||||
register and an offset can determine this. I think it should
|
||||
instead generate a byte code expression as that would work better
|
||||
with things like Dwarf2's CFI. */
|
||||
if (DEPRECATED_FP_REGNUM >= 0 && DEPRECATED_FP_REGNUM < NUM_REGS)
|
||||
*frame_regnum = DEPRECATED_FP_REGNUM;
|
||||
else if (SP_REGNUM >= 0 && SP_REGNUM < NUM_REGS)
|
||||
*frame_regnum = SP_REGNUM;
|
||||
else
|
||||
/* Should this be an internal error? I guess so, it is reflecting
|
||||
an architectural limitation in the current design. */
|
||||
internal_error (__FILE__, __LINE__, _("No virtual frame pointer available"));
|
||||
*frame_offset = 0;
|
||||
}
|
||||
|
||||
/* Assume the world is sane, every register's virtual and real size
|
||||
is identical. */
|
||||
|
||||
int
|
||||
generic_register_size (int regnum)
|
||||
{
|
||||
gdb_assert (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS);
|
||||
return TYPE_LENGTH (gdbarch_register_type (current_gdbarch, regnum));
|
||||
}
|
||||
|
||||
/* Assume all registers are adjacent. */
|
||||
|
||||
int
|
||||
generic_register_byte (int regnum)
|
||||
{
|
||||
int byte;
|
||||
int i;
|
||||
gdb_assert (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS);
|
||||
byte = 0;
|
||||
for (i = 0; i < regnum; i++)
|
||||
{
|
||||
byte += generic_register_size (i);
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
legacy_pc_in_sigtramp (CORE_ADDR pc, char *name)
|
||||
{
|
||||
#if defined (DEPRECATED_IN_SIGTRAMP)
|
||||
return DEPRECATED_IN_SIGTRAMP (pc, name);
|
||||
#else
|
||||
return name && strcmp ("_sigtramp", name) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
generic_convert_register_p (int regnum, struct type *type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
default_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
|
||||
{
|
||||
if (DEPRECATED_REG_STRUCT_HAS_ADDR_P ()
|
||||
&& DEPRECATED_REG_STRUCT_HAS_ADDR (processing_gcc_compilation, type))
|
||||
{
|
||||
CHECK_TYPEDEF (type);
|
||||
|
||||
return (TYPE_CODE (type) == TYPE_CODE_STRUCT
|
||||
|| TYPE_CODE (type) == TYPE_CODE_UNION
|
||||
|| TYPE_CODE (type) == TYPE_CODE_SET
|
||||
|| TYPE_CODE (type) == TYPE_CODE_BITSTRING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
generic_instruction_nullified (struct gdbarch *gdbarch,
|
||||
struct regcache *regcache)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Functions to manipulate the endianness of the target. */
|
||||
|
||||
/* ``target_byte_order'' is only used when non- multi-arch.
|
||||
Multi-arch targets obtain the current byte order using the
|
||||
TARGET_BYTE_ORDER gdbarch method.
|
||||
|
||||
The choice of initial value is entirely arbitrary. During startup,
|
||||
the function initialize_current_architecture() updates this value
|
||||
based on default byte-order information extracted from BFD. */
|
||||
static int target_byte_order = BFD_ENDIAN_BIG;
|
||||
static int target_byte_order_auto = 1;
|
||||
|
||||
enum bfd_endian
|
||||
selected_byte_order (void)
|
||||
{
|
||||
if (target_byte_order_auto)
|
||||
return BFD_ENDIAN_UNKNOWN;
|
||||
else
|
||||
return target_byte_order;
|
||||
}
|
||||
|
||||
static const char endian_big[] = "big";
|
||||
static const char endian_little[] = "little";
|
||||
static const char endian_auto[] = "auto";
|
||||
static const char *endian_enum[] =
|
||||
{
|
||||
endian_big,
|
||||
endian_little,
|
||||
endian_auto,
|
||||
NULL,
|
||||
};
|
||||
static const char *set_endian_string;
|
||||
|
||||
/* Called by ``show endian''. */
|
||||
|
||||
static void
|
||||
show_endian (struct ui_file *file, int from_tty, struct cmd_list_element *c,
|
||||
const char *value)
|
||||
{
|
||||
if (target_byte_order_auto)
|
||||
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
|
||||
fprintf_unfiltered (file, _("The target endianness is set automatically "
|
||||
"(currently big endian)\n"));
|
||||
else
|
||||
fprintf_unfiltered (file, _("The target endianness is set automatically "
|
||||
"(currently little endian)\n"));
|
||||
else
|
||||
if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
|
||||
fprintf_unfiltered (file,
|
||||
_("The target is assumed to be big endian\n"));
|
||||
else
|
||||
fprintf_unfiltered (file,
|
||||
_("The target is assumed to be little endian\n"));
|
||||
}
|
||||
|
||||
static void
|
||||
set_endian (char *ignore_args, int from_tty, struct cmd_list_element *c)
|
||||
{
|
||||
if (set_endian_string == endian_auto)
|
||||
{
|
||||
target_byte_order_auto = 1;
|
||||
}
|
||||
else if (set_endian_string == endian_little)
|
||||
{
|
||||
struct gdbarch_info info;
|
||||
target_byte_order_auto = 0;
|
||||
gdbarch_info_init (&info);
|
||||
info.byte_order = BFD_ENDIAN_LITTLE;
|
||||
if (! gdbarch_update_p (info))
|
||||
printf_unfiltered (_("Little endian target not supported by GDB\n"));
|
||||
}
|
||||
else if (set_endian_string == endian_big)
|
||||
{
|
||||
struct gdbarch_info info;
|
||||
target_byte_order_auto = 0;
|
||||
gdbarch_info_init (&info);
|
||||
info.byte_order = BFD_ENDIAN_BIG;
|
||||
if (! gdbarch_update_p (info))
|
||||
printf_unfiltered (_("Big endian target not supported by GDB\n"));
|
||||
}
|
||||
else
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("set_endian: bad value"));
|
||||
show_endian (gdb_stdout, from_tty, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Functions to manipulate the architecture of the target */
|
||||
|
||||
enum set_arch { set_arch_auto, set_arch_manual };
|
||||
|
||||
static int target_architecture_auto = 1;
|
||||
|
||||
static const char *set_architecture_string;
|
||||
|
||||
const char *
|
||||
selected_architecture_name (void)
|
||||
{
|
||||
if (target_architecture_auto)
|
||||
return NULL;
|
||||
else
|
||||
return set_architecture_string;
|
||||
}
|
||||
|
||||
/* Called if the user enters ``show architecture'' without an
|
||||
argument. */
|
||||
|
||||
static void
|
||||
show_architecture (struct ui_file *file, int from_tty,
|
||||
struct cmd_list_element *c, const char *value)
|
||||
{
|
||||
const char *arch;
|
||||
arch = TARGET_ARCHITECTURE->printable_name;
|
||||
if (target_architecture_auto)
|
||||
fprintf_filtered (file, _("\
|
||||
The target architecture is set automatically (currently %s)\n"), arch);
|
||||
else
|
||||
fprintf_filtered (file, _("\
|
||||
The target architecture is assumed to be %s\n"), arch);
|
||||
}
|
||||
|
||||
|
||||
/* Called if the user enters ``set architecture'' with or without an
|
||||
argument. */
|
||||
|
||||
static void
|
||||
set_architecture (char *ignore_args, int from_tty, struct cmd_list_element *c)
|
||||
{
|
||||
if (strcmp (set_architecture_string, "auto") == 0)
|
||||
{
|
||||
target_architecture_auto = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct gdbarch_info info;
|
||||
gdbarch_info_init (&info);
|
||||
info.bfd_arch_info = bfd_scan_arch (set_architecture_string);
|
||||
if (info.bfd_arch_info == NULL)
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("set_architecture: bfd_scan_arch failed"));
|
||||
if (gdbarch_update_p (info))
|
||||
target_architecture_auto = 0;
|
||||
else
|
||||
printf_unfiltered (_("Architecture `%s' not recognized.\n"),
|
||||
set_architecture_string);
|
||||
}
|
||||
show_architecture (gdb_stdout, from_tty, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Try to select a global architecture that matches "info". Return
|
||||
non-zero if the attempt succeds. */
|
||||
int
|
||||
gdbarch_update_p (struct gdbarch_info info)
|
||||
{
|
||||
struct gdbarch *new_gdbarch = gdbarch_find_by_info (info);
|
||||
|
||||
/* If there no architecture by that name, reject the request. */
|
||||
if (new_gdbarch == NULL)
|
||||
{
|
||||
if (gdbarch_debug)
|
||||
fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: "
|
||||
"Architecture not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If it is the same old architecture, accept the request (but don't
|
||||
swap anything). */
|
||||
if (new_gdbarch == current_gdbarch)
|
||||
{
|
||||
if (gdbarch_debug)
|
||||
fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: "
|
||||
"Architecture 0x%08lx (%s) unchanged\n",
|
||||
(long) new_gdbarch,
|
||||
gdbarch_bfd_arch_info (new_gdbarch)->printable_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* It's a new architecture, swap it in. */
|
||||
if (gdbarch_debug)
|
||||
fprintf_unfiltered (gdb_stdlog, "gdbarch_update_p: "
|
||||
"New architecture 0x%08lx (%s) selected\n",
|
||||
(long) new_gdbarch,
|
||||
gdbarch_bfd_arch_info (new_gdbarch)->printable_name);
|
||||
deprecated_current_gdbarch_select_hack (new_gdbarch);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return the architecture for ABFD. If no suitable architecture
|
||||
could be find, return NULL. */
|
||||
|
||||
struct gdbarch *
|
||||
gdbarch_from_bfd (bfd *abfd)
|
||||
{
|
||||
struct gdbarch *old_gdbarch = current_gdbarch;
|
||||
struct gdbarch *new_gdbarch;
|
||||
struct gdbarch_info info;
|
||||
|
||||
gdbarch_info_init (&info);
|
||||
info.abfd = abfd;
|
||||
return gdbarch_find_by_info (info);
|
||||
}
|
||||
|
||||
/* Set the dynamic target-system-dependent parameters (architecture,
|
||||
byte-order) using information found in the BFD */
|
||||
|
||||
void
|
||||
set_gdbarch_from_file (bfd *abfd)
|
||||
{
|
||||
struct gdbarch *gdbarch;
|
||||
|
||||
gdbarch = gdbarch_from_bfd (abfd);
|
||||
if (gdbarch == NULL)
|
||||
error (_("Architecture of file not recognized."));
|
||||
deprecated_current_gdbarch_select_hack (gdbarch);
|
||||
}
|
||||
|
||||
/* Initialize the current architecture. Update the ``set
|
||||
architecture'' command so that it specifies a list of valid
|
||||
architectures. */
|
||||
|
||||
#ifdef DEFAULT_BFD_ARCH
|
||||
extern const bfd_arch_info_type DEFAULT_BFD_ARCH;
|
||||
static const bfd_arch_info_type *default_bfd_arch = &DEFAULT_BFD_ARCH;
|
||||
#else
|
||||
static const bfd_arch_info_type *default_bfd_arch;
|
||||
#endif
|
||||
|
||||
#ifdef DEFAULT_BFD_VEC
|
||||
extern const bfd_target DEFAULT_BFD_VEC;
|
||||
static const bfd_target *default_bfd_vec = &DEFAULT_BFD_VEC;
|
||||
#else
|
||||
static const bfd_target *default_bfd_vec;
|
||||
#endif
|
||||
|
||||
void
|
||||
initialize_current_architecture (void)
|
||||
{
|
||||
const char **arches = gdbarch_printable_names ();
|
||||
|
||||
/* determine a default architecture and byte order. */
|
||||
struct gdbarch_info info;
|
||||
gdbarch_info_init (&info);
|
||||
|
||||
/* Find a default architecture. */
|
||||
if (info.bfd_arch_info == NULL
|
||||
&& default_bfd_arch != NULL)
|
||||
info.bfd_arch_info = default_bfd_arch;
|
||||
if (info.bfd_arch_info == NULL)
|
||||
{
|
||||
/* Choose the architecture by taking the first one
|
||||
alphabetically. */
|
||||
const char *chosen = arches[0];
|
||||
const char **arch;
|
||||
for (arch = arches; *arch != NULL; arch++)
|
||||
{
|
||||
if (strcmp (*arch, chosen) < 0)
|
||||
chosen = *arch;
|
||||
}
|
||||
if (chosen == NULL)
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("initialize_current_architecture: No arch"));
|
||||
info.bfd_arch_info = bfd_scan_arch (chosen);
|
||||
if (info.bfd_arch_info == NULL)
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("initialize_current_architecture: Arch not found"));
|
||||
}
|
||||
|
||||
/* Take several guesses at a byte order. */
|
||||
if (info.byte_order == BFD_ENDIAN_UNKNOWN
|
||||
&& default_bfd_vec != NULL)
|
||||
{
|
||||
/* Extract BFD's default vector's byte order. */
|
||||
switch (default_bfd_vec->byteorder)
|
||||
{
|
||||
case BFD_ENDIAN_BIG:
|
||||
info.byte_order = BFD_ENDIAN_BIG;
|
||||
break;
|
||||
case BFD_ENDIAN_LITTLE:
|
||||
info.byte_order = BFD_ENDIAN_LITTLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (info.byte_order == BFD_ENDIAN_UNKNOWN)
|
||||
{
|
||||
/* look for ``*el-*'' in the target name. */
|
||||
const char *chp;
|
||||
chp = strchr (target_name, '-');
|
||||
if (chp != NULL
|
||||
&& chp - 2 >= target_name
|
||||
&& strncmp (chp - 2, "el", 2) == 0)
|
||||
info.byte_order = BFD_ENDIAN_LITTLE;
|
||||
}
|
||||
if (info.byte_order == BFD_ENDIAN_UNKNOWN)
|
||||
{
|
||||
/* Wire it to big-endian!!! */
|
||||
info.byte_order = BFD_ENDIAN_BIG;
|
||||
}
|
||||
|
||||
if (! gdbarch_update_p (info))
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("initialize_current_architecture: Selection of "
|
||||
"initial architecture failed"));
|
||||
|
||||
/* Create the ``set architecture'' command appending ``auto'' to the
|
||||
list of architectures. */
|
||||
{
|
||||
struct cmd_list_element *c;
|
||||
/* Append ``auto''. */
|
||||
int nr;
|
||||
for (nr = 0; arches[nr] != NULL; nr++);
|
||||
arches = xrealloc (arches, sizeof (char*) * (nr + 2));
|
||||
arches[nr + 0] = "auto";
|
||||
arches[nr + 1] = NULL;
|
||||
add_setshow_enum_cmd ("architecture", class_support,
|
||||
arches, &set_architecture_string, _("\
|
||||
Set architecture of target."), _("\
|
||||
Show architecture of target."), NULL,
|
||||
set_architecture, show_architecture,
|
||||
&setlist, &showlist);
|
||||
add_alias_cmd ("processor", "architecture", class_support, 1, &setlist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Initialize a gdbarch info to values that will be automatically
|
||||
overridden. Note: Originally, this ``struct info'' was initialized
|
||||
using memset(0). Unfortunately, that ran into problems, namely
|
||||
BFD_ENDIAN_BIG is zero. An explicit initialization function that
|
||||
can explicitly set each field to a well defined value is used. */
|
||||
|
||||
void
|
||||
gdbarch_info_init (struct gdbarch_info *info)
|
||||
{
|
||||
memset (info, 0, sizeof (struct gdbarch_info));
|
||||
info->byte_order = BFD_ENDIAN_UNKNOWN;
|
||||
info->osabi = GDB_OSABI_UNINITIALIZED;
|
||||
}
|
||||
|
||||
/* Similar to init, but this time fill in the blanks. Information is
|
||||
obtained from the specified architecture, global "set ..." options,
|
||||
and explicitly initialized INFO fields. */
|
||||
|
||||
void
|
||||
gdbarch_info_fill (struct gdbarch *gdbarch, struct gdbarch_info *info)
|
||||
{
|
||||
/* "(gdb) set architecture ...". */
|
||||
if (info->bfd_arch_info == NULL
|
||||
&& !target_architecture_auto
|
||||
&& gdbarch != NULL)
|
||||
info->bfd_arch_info = gdbarch_bfd_arch_info (gdbarch);
|
||||
if (info->bfd_arch_info == NULL
|
||||
&& info->abfd != NULL
|
||||
&& bfd_get_arch (info->abfd) != bfd_arch_unknown
|
||||
&& bfd_get_arch (info->abfd) != bfd_arch_obscure)
|
||||
info->bfd_arch_info = bfd_get_arch_info (info->abfd);
|
||||
if (info->bfd_arch_info == NULL
|
||||
&& gdbarch != NULL)
|
||||
info->bfd_arch_info = gdbarch_bfd_arch_info (gdbarch);
|
||||
|
||||
/* "(gdb) set byte-order ...". */
|
||||
if (info->byte_order == BFD_ENDIAN_UNKNOWN
|
||||
&& !target_byte_order_auto
|
||||
&& gdbarch != NULL)
|
||||
info->byte_order = gdbarch_byte_order (gdbarch);
|
||||
/* From the INFO struct. */
|
||||
if (info->byte_order == BFD_ENDIAN_UNKNOWN
|
||||
&& info->abfd != NULL)
|
||||
info->byte_order = (bfd_big_endian (info->abfd) ? BFD_ENDIAN_BIG
|
||||
: bfd_little_endian (info->abfd) ? BFD_ENDIAN_LITTLE
|
||||
: BFD_ENDIAN_UNKNOWN);
|
||||
/* From the current target. */
|
||||
if (info->byte_order == BFD_ENDIAN_UNKNOWN
|
||||
&& gdbarch != NULL)
|
||||
info->byte_order = gdbarch_byte_order (gdbarch);
|
||||
|
||||
/* "(gdb) set osabi ...". Handled by gdbarch_lookup_osabi. */
|
||||
if (info->osabi == GDB_OSABI_UNINITIALIZED)
|
||||
info->osabi = gdbarch_lookup_osabi (info->abfd);
|
||||
if (info->osabi == GDB_OSABI_UNINITIALIZED
|
||||
&& gdbarch != NULL)
|
||||
info->osabi = gdbarch_osabi (gdbarch);
|
||||
|
||||
/* Must have at least filled in the architecture. */
|
||||
gdb_assert (info->bfd_arch_info != NULL);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
extern initialize_file_ftype _initialize_gdbarch_utils; /* -Wmissing-prototypes */
|
||||
|
||||
void
|
||||
_initialize_gdbarch_utils (void)
|
||||
{
|
||||
struct cmd_list_element *c;
|
||||
add_setshow_enum_cmd ("endian", class_support,
|
||||
endian_enum, &set_endian_string, _("\
|
||||
Set endianness of target."), _("\
|
||||
Show endianness of target."), NULL,
|
||||
set_endian, show_endian,
|
||||
&setlist, &showlist);
|
||||
}
|
||||
156
gdb/arch-utils.h
156
gdb/arch-utils.h
@@ -1,156 +0,0 @@
|
||||
/* Dynamic architecture support for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef GDBARCH_UTILS_H
|
||||
#define GDBARCH_UTILS_H
|
||||
|
||||
struct gdbarch;
|
||||
struct frame_info;
|
||||
struct minimal_symbol;
|
||||
struct type;
|
||||
struct gdbarch_info;
|
||||
|
||||
/* gdbarch trace variable */
|
||||
extern int gdbarch_debug;
|
||||
|
||||
/* An implementation of return_value that props up architectures still
|
||||
using USE_STRUCT_RETURN, EXTRACT_RETURN_VALUE and
|
||||
STORE_RETURN_VALUE. See also the hacks in "stack.c". */
|
||||
enum return_value_convention legacy_return_value (struct gdbarch *gdbarch,
|
||||
struct type *valtype,
|
||||
struct regcache *regcache,
|
||||
gdb_byte *readbuf,
|
||||
const gdb_byte *writebuf);
|
||||
|
||||
/* Implementation of extract return value that grubs around in the
|
||||
register cache. */
|
||||
extern gdbarch_extract_return_value_ftype legacy_extract_return_value;
|
||||
|
||||
/* Implementation of store return value that grubs the register cache. */
|
||||
extern gdbarch_store_return_value_ftype legacy_store_return_value;
|
||||
|
||||
/* To return any structure or union type by value, store it at the
|
||||
address passed as an invisible first argument to the function. */
|
||||
extern gdbarch_deprecated_use_struct_convention_ftype always_use_struct_convention;
|
||||
|
||||
/* Typical remote_translate_xfer_address */
|
||||
extern gdbarch_remote_translate_xfer_address_ftype generic_remote_translate_xfer_address;
|
||||
|
||||
/* The only possible cases for inner_than. */
|
||||
extern int core_addr_lessthan (CORE_ADDR lhs, CORE_ADDR rhs);
|
||||
extern int core_addr_greaterthan (CORE_ADDR lhs, CORE_ADDR rhs);
|
||||
|
||||
/* Floating point values. */
|
||||
extern const struct floatformat *default_float_format (struct gdbarch *gdbarch);
|
||||
extern const struct floatformat *default_double_format (struct gdbarch *gdbarch);
|
||||
|
||||
/* Identity functions on a CORE_ADDR. Just return the "addr". */
|
||||
|
||||
extern CORE_ADDR core_addr_identity (CORE_ADDR addr);
|
||||
extern gdbarch_convert_from_func_ptr_addr_ftype convert_from_func_ptr_addr_identity;
|
||||
|
||||
/* No-op conversion of reg to regnum. */
|
||||
|
||||
extern int no_op_reg_to_regnum (int reg);
|
||||
|
||||
/* Do nothing version of elf_make_msymbol_special. */
|
||||
|
||||
void default_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym);
|
||||
|
||||
/* Do nothing version of coff_make_msymbol_special. */
|
||||
|
||||
void default_coff_make_msymbol_special (int val, struct minimal_symbol *msym);
|
||||
|
||||
/* Version of cannot_fetch_register() / cannot_store_register() that
|
||||
always fails. */
|
||||
|
||||
int cannot_register_not (int regnum);
|
||||
|
||||
/* Legacy version of target_virtual_frame_pointer(). Assumes that
|
||||
there is an DEPRECATED_FP_REGNUM and that it is the same, cooked or
|
||||
raw. */
|
||||
|
||||
extern gdbarch_virtual_frame_pointer_ftype legacy_virtual_frame_pointer;
|
||||
|
||||
extern CORE_ADDR generic_skip_trampoline_code (CORE_ADDR pc);
|
||||
|
||||
extern CORE_ADDR generic_skip_solib_resolver (struct gdbarch *gdbarch,
|
||||
CORE_ADDR pc);
|
||||
|
||||
extern int generic_in_solib_return_trampoline (CORE_ADDR pc, char *name);
|
||||
|
||||
extern int generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc);
|
||||
|
||||
/* Assume that the world is sane, a registers raw and virtual size
|
||||
both match its type. */
|
||||
|
||||
extern int generic_register_size (int regnum);
|
||||
|
||||
/* Assume that the world is sane, the registers are all adjacent. */
|
||||
extern int generic_register_byte (int regnum);
|
||||
|
||||
/* Prop up old targets that use various sigtramp macros. */
|
||||
extern int legacy_pc_in_sigtramp (CORE_ADDR pc, char *name);
|
||||
|
||||
/* By default, registers are not convertible. */
|
||||
extern int generic_convert_register_p (int regnum, struct type *type);
|
||||
|
||||
extern int default_stabs_argument_has_addr (struct gdbarch *gdbarch,
|
||||
struct type *type);
|
||||
|
||||
extern int generic_instruction_nullified (struct gdbarch *gdbarch,
|
||||
struct regcache *regcache);
|
||||
|
||||
/* For compatibility with older architectures, returns
|
||||
(LEGACY_SIM_REGNO_IGNORE) when the register doesn't have a valid
|
||||
name. */
|
||||
|
||||
extern int legacy_register_sim_regno (int regnum);
|
||||
|
||||
/* Return the selected byte order, or BFD_ENDIAN_UNKNOWN if no byte
|
||||
order was explicitly selected. */
|
||||
extern enum bfd_endian selected_byte_order (void);
|
||||
|
||||
/* Return the selected architecture's name, or NULL if no architecture
|
||||
was explicitly selected. */
|
||||
extern const char *selected_architecture_name (void);
|
||||
|
||||
/* Initialize a ``struct info''. Can't use memset(0) since some
|
||||
default values are not zero. "fill" takes all available
|
||||
information and fills in any unspecified fields. */
|
||||
|
||||
extern void gdbarch_info_init (struct gdbarch_info *info);
|
||||
extern void gdbarch_info_fill (struct gdbarch *gdbarch,
|
||||
struct gdbarch_info *info);
|
||||
|
||||
/* Similar to init, but this time fill in the blanks. Information is
|
||||
obtained from the specified architecture, global "set ..." options,
|
||||
and explicitly initialized INFO fields. */
|
||||
extern void gdbarch_info_fill (struct gdbarch *gdbarch,
|
||||
struct gdbarch_info *info);
|
||||
|
||||
/* Return the architecture for ABFD. If no suitable architecture
|
||||
could be find, return NULL. */
|
||||
|
||||
extern struct gdbarch *gdbarch_from_bfd (bfd *abfd);
|
||||
|
||||
#endif
|
||||
@@ -1,740 +0,0 @@
|
||||
/* GNU/Linux on ARM native support.
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
#include "gdb_string.h"
|
||||
#include "regcache.h"
|
||||
#include "target.h"
|
||||
#include "linux-nat.h"
|
||||
|
||||
#include "arm-tdep.h"
|
||||
|
||||
#include <sys/user.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/* Prototypes for supply_gregset etc. */
|
||||
#include "gregset.h"
|
||||
|
||||
extern int arm_apcs_32;
|
||||
|
||||
#define typeNone 0x00
|
||||
#define typeSingle 0x01
|
||||
#define typeDouble 0x02
|
||||
#define typeExtended 0x03
|
||||
#define FPWORDS 28
|
||||
#define ARM_CPSR_REGNUM 16
|
||||
|
||||
typedef union tagFPREG
|
||||
{
|
||||
unsigned int fSingle;
|
||||
unsigned int fDouble[2];
|
||||
unsigned int fExtended[3];
|
||||
}
|
||||
FPREG;
|
||||
|
||||
typedef struct tagFPA11
|
||||
{
|
||||
FPREG fpreg[8]; /* 8 floating point registers */
|
||||
unsigned int fpsr; /* floating point status register */
|
||||
unsigned int fpcr; /* floating point control register */
|
||||
unsigned char fType[8]; /* type of floating point value held in
|
||||
floating point registers. */
|
||||
int initflag; /* NWFPE initialization flag. */
|
||||
}
|
||||
FPA11;
|
||||
|
||||
/* The following variables are used to determine the version of the
|
||||
underlying GNU/Linux operating system. Examples:
|
||||
|
||||
GNU/Linux 2.0.35 GNU/Linux 2.2.12
|
||||
os_version = 0x00020023 os_version = 0x0002020c
|
||||
os_major = 2 os_major = 2
|
||||
os_minor = 0 os_minor = 2
|
||||
os_release = 35 os_release = 12
|
||||
|
||||
Note: os_version = (os_major << 16) | (os_minor << 8) | os_release
|
||||
|
||||
These are initialized using get_linux_version() from
|
||||
_initialize_arm_linux_nat(). */
|
||||
|
||||
static unsigned int os_version, os_major, os_minor, os_release;
|
||||
|
||||
/* On GNU/Linux, threads are implemented as pseudo-processes, in which
|
||||
case we may be tracing more than one process at a time. In that
|
||||
case, inferior_ptid will contain the main process ID and the
|
||||
individual thread (process) ID. get_thread_id () is used to get
|
||||
the thread id if it's available, and the process id otherwise. */
|
||||
|
||||
int
|
||||
get_thread_id (ptid_t ptid)
|
||||
{
|
||||
int tid = TIDGET (ptid);
|
||||
if (0 == tid)
|
||||
tid = PIDGET (ptid);
|
||||
return tid;
|
||||
}
|
||||
#define GET_THREAD_ID(PTID) get_thread_id ((PTID));
|
||||
|
||||
static void
|
||||
fetch_nwfpe_single (unsigned int fn, FPA11 * fpa11)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
mem[0] = fpa11->fpreg[fn].fSingle;
|
||||
mem[1] = 0;
|
||||
mem[2] = 0;
|
||||
regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_nwfpe_double (unsigned int fn, FPA11 * fpa11)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
mem[0] = fpa11->fpreg[fn].fDouble[1];
|
||||
mem[1] = fpa11->fpreg[fn].fDouble[0];
|
||||
mem[2] = 0;
|
||||
regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_nwfpe_none (unsigned int fn)
|
||||
{
|
||||
unsigned int mem[3] =
|
||||
{0, 0, 0};
|
||||
|
||||
regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_nwfpe_extended (unsigned int fn, FPA11 * fpa11)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
mem[0] = fpa11->fpreg[fn].fExtended[0]; /* sign & exponent */
|
||||
mem[1] = fpa11->fpreg[fn].fExtended[2]; /* ls bits */
|
||||
mem[2] = fpa11->fpreg[fn].fExtended[1]; /* ms bits */
|
||||
regcache_raw_supply (current_regcache, ARM_F0_REGNUM + fn, (char *) &mem[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_nwfpe_register (int regno, FPA11 * fpa11)
|
||||
{
|
||||
int fn = regno - ARM_F0_REGNUM;
|
||||
|
||||
switch (fpa11->fType[fn])
|
||||
{
|
||||
case typeSingle:
|
||||
fetch_nwfpe_single (fn, fpa11);
|
||||
break;
|
||||
|
||||
case typeDouble:
|
||||
fetch_nwfpe_double (fn, fpa11);
|
||||
break;
|
||||
|
||||
case typeExtended:
|
||||
fetch_nwfpe_extended (fn, fpa11);
|
||||
break;
|
||||
|
||||
default:
|
||||
fetch_nwfpe_none (fn);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
store_nwfpe_single (unsigned int fn, FPA11 *fpa11)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn,
|
||||
(char *) &mem[0]);
|
||||
fpa11->fpreg[fn].fSingle = mem[0];
|
||||
fpa11->fType[fn] = typeSingle;
|
||||
}
|
||||
|
||||
static void
|
||||
store_nwfpe_double (unsigned int fn, FPA11 *fpa11)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn,
|
||||
(char *) &mem[0]);
|
||||
fpa11->fpreg[fn].fDouble[1] = mem[0];
|
||||
fpa11->fpreg[fn].fDouble[0] = mem[1];
|
||||
fpa11->fType[fn] = typeDouble;
|
||||
}
|
||||
|
||||
void
|
||||
store_nwfpe_extended (unsigned int fn, FPA11 *fpa11)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
regcache_raw_collect (current_regcache, ARM_F0_REGNUM + fn,
|
||||
(char *) &mem[0]);
|
||||
fpa11->fpreg[fn].fExtended[0] = mem[0]; /* sign & exponent */
|
||||
fpa11->fpreg[fn].fExtended[2] = mem[1]; /* ls bits */
|
||||
fpa11->fpreg[fn].fExtended[1] = mem[2]; /* ms bits */
|
||||
fpa11->fType[fn] = typeDouble;
|
||||
}
|
||||
|
||||
void
|
||||
store_nwfpe_register (int regno, FPA11 * fpa11)
|
||||
{
|
||||
if (register_cached (regno))
|
||||
{
|
||||
unsigned int fn = regno - ARM_F0_REGNUM;
|
||||
switch (fpa11->fType[fn])
|
||||
{
|
||||
case typeSingle:
|
||||
store_nwfpe_single (fn, fpa11);
|
||||
break;
|
||||
|
||||
case typeDouble:
|
||||
store_nwfpe_double (fn, fpa11);
|
||||
break;
|
||||
|
||||
case typeExtended:
|
||||
store_nwfpe_extended (fn, fpa11);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get the value of a particular register from the floating point
|
||||
state of the process and store it into regcache. */
|
||||
|
||||
static void
|
||||
fetch_fpregister (int regno)
|
||||
{
|
||||
int ret, tid;
|
||||
FPA11 fp;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
/* Read the floating point state. */
|
||||
ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch floating point register."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fetch fpsr. */
|
||||
if (ARM_FPS_REGNUM == regno)
|
||||
regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr);
|
||||
|
||||
/* Fetch the floating point register. */
|
||||
if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
|
||||
{
|
||||
int fn = regno - ARM_F0_REGNUM;
|
||||
|
||||
switch (fp.fType[fn])
|
||||
{
|
||||
case typeSingle:
|
||||
fetch_nwfpe_single (fn, &fp);
|
||||
break;
|
||||
|
||||
case typeDouble:
|
||||
fetch_nwfpe_double (fn, &fp);
|
||||
break;
|
||||
|
||||
case typeExtended:
|
||||
fetch_nwfpe_extended (fn, &fp);
|
||||
break;
|
||||
|
||||
default:
|
||||
fetch_nwfpe_none (fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the whole floating point state of the process and store it
|
||||
into regcache. */
|
||||
|
||||
static void
|
||||
fetch_fpregs (void)
|
||||
{
|
||||
int ret, regno, tid;
|
||||
FPA11 fp;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
/* Read the floating point state. */
|
||||
ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch the floating point registers."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fetch fpsr. */
|
||||
regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr);
|
||||
|
||||
/* Fetch the floating point registers. */
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
{
|
||||
int fn = regno - ARM_F0_REGNUM;
|
||||
|
||||
switch (fp.fType[fn])
|
||||
{
|
||||
case typeSingle:
|
||||
fetch_nwfpe_single (fn, &fp);
|
||||
break;
|
||||
|
||||
case typeDouble:
|
||||
fetch_nwfpe_double (fn, &fp);
|
||||
break;
|
||||
|
||||
case typeExtended:
|
||||
fetch_nwfpe_extended (fn, &fp);
|
||||
break;
|
||||
|
||||
default:
|
||||
fetch_nwfpe_none (fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Save a particular register into the floating point state of the
|
||||
process using the contents from regcache. */
|
||||
|
||||
static void
|
||||
store_fpregister (int regno)
|
||||
{
|
||||
int ret, tid;
|
||||
FPA11 fp;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
/* Read the floating point state. */
|
||||
ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch the floating point registers."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store fpsr. */
|
||||
if (ARM_FPS_REGNUM == regno && register_cached (ARM_FPS_REGNUM))
|
||||
regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr);
|
||||
|
||||
/* Store the floating point register. */
|
||||
if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
|
||||
{
|
||||
store_nwfpe_register (regno, &fp);
|
||||
}
|
||||
|
||||
ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to store floating point register."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the whole floating point state of the process using
|
||||
the contents from regcache. */
|
||||
|
||||
static void
|
||||
store_fpregs (void)
|
||||
{
|
||||
int ret, regno, tid;
|
||||
FPA11 fp;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
/* Read the floating point state. */
|
||||
ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch the floating point registers."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store fpsr. */
|
||||
if (register_cached (ARM_FPS_REGNUM))
|
||||
regcache_raw_collect (current_regcache, ARM_FPS_REGNUM, (char *) &fp.fpsr);
|
||||
|
||||
/* Store the floating point registers. */
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
{
|
||||
fetch_nwfpe_register (regno, &fp);
|
||||
}
|
||||
|
||||
ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to store floating point registers."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch a general register of the process and store into
|
||||
regcache. */
|
||||
|
||||
static void
|
||||
fetch_register (int regno)
|
||||
{
|
||||
int ret, tid;
|
||||
elf_gregset_t regs;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch general register."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
|
||||
regcache_raw_supply (current_regcache, regno, (char *) ®s[regno]);
|
||||
|
||||
if (ARM_PS_REGNUM == regno)
|
||||
{
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) ®s[ARM_CPSR_REGNUM]);
|
||||
else
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) ®s[ARM_PC_REGNUM]);
|
||||
}
|
||||
|
||||
if (ARM_PC_REGNUM == regno)
|
||||
{
|
||||
regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]);
|
||||
regcache_raw_supply (current_regcache, ARM_PC_REGNUM,
|
||||
(char *) ®s[ARM_PC_REGNUM]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch all general registers of the process and store into
|
||||
regcache. */
|
||||
|
||||
static void
|
||||
fetch_regs (void)
|
||||
{
|
||||
int ret, regno, tid;
|
||||
elf_gregset_t regs;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch general registers."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
|
||||
regcache_raw_supply (current_regcache, regno, (char *) ®s[regno]);
|
||||
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) ®s[ARM_CPSR_REGNUM]);
|
||||
else
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) ®s[ARM_PC_REGNUM]);
|
||||
|
||||
regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]);
|
||||
regcache_raw_supply (current_regcache, ARM_PC_REGNUM,
|
||||
(char *) ®s[ARM_PC_REGNUM]);
|
||||
}
|
||||
|
||||
/* Store all general registers of the process from the values in
|
||||
regcache. */
|
||||
|
||||
static void
|
||||
store_register (int regno)
|
||||
{
|
||||
int ret, tid;
|
||||
elf_gregset_t regs;
|
||||
|
||||
if (!register_cached (regno))
|
||||
return;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
/* Get the general registers from the process. */
|
||||
ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch general registers."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
|
||||
regcache_raw_collect (current_regcache, regno, (char *) ®s[regno]);
|
||||
else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
|
||||
regcache_raw_collect (current_regcache, regno,
|
||||
(char *) ®s[ARM_CPSR_REGNUM]);
|
||||
else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
|
||||
regcache_raw_collect (current_regcache, ARM_PC_REGNUM,
|
||||
(char *) ®s[ARM_PC_REGNUM]);
|
||||
|
||||
ret = ptrace (PTRACE_SETREGS, tid, 0, ®s);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to store general register."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
store_regs (void)
|
||||
{
|
||||
int ret, regno, tid;
|
||||
elf_gregset_t regs;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
/* Fetch the general registers. */
|
||||
ret = ptrace (PTRACE_GETREGS, tid, 0, ®s);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch general registers."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++)
|
||||
{
|
||||
if (register_cached (regno))
|
||||
regcache_raw_collect (current_regcache, regno, (char *) ®s[regno]);
|
||||
}
|
||||
|
||||
if (arm_apcs_32 && register_cached (ARM_PS_REGNUM))
|
||||
regcache_raw_collect (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) ®s[ARM_CPSR_REGNUM]);
|
||||
|
||||
ret = ptrace (PTRACE_SETREGS, tid, 0, ®s);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to store general registers."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch registers from the child process. Fetch all registers if
|
||||
regno == -1, otherwise fetch all general registers or all floating
|
||||
point registers depending upon the value of regno. */
|
||||
|
||||
static void
|
||||
arm_linux_fetch_inferior_registers (int regno)
|
||||
{
|
||||
if (-1 == regno)
|
||||
{
|
||||
fetch_regs ();
|
||||
fetch_fpregs ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
|
||||
fetch_register (regno);
|
||||
|
||||
if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
|
||||
fetch_fpregister (regno);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store registers back into the inferior. Store all registers if
|
||||
regno == -1, otherwise store all general registers or all floating
|
||||
point registers depending upon the value of regno. */
|
||||
|
||||
static void
|
||||
arm_linux_store_inferior_registers (int regno)
|
||||
{
|
||||
if (-1 == regno)
|
||||
{
|
||||
store_regs ();
|
||||
store_fpregs ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((regno < ARM_F0_REGNUM) || (regno > ARM_FPS_REGNUM))
|
||||
store_register (regno);
|
||||
|
||||
if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
|
||||
store_fpregister (regno);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill register regno (if it is a general-purpose register) in
|
||||
*gregsetp with the appropriate value from GDB's register array.
|
||||
If regno is -1, do this for all registers. */
|
||||
|
||||
void
|
||||
fill_gregset (gdb_gregset_t *gregsetp, int regno)
|
||||
{
|
||||
if (-1 == regno)
|
||||
{
|
||||
int regnum;
|
||||
for (regnum = ARM_A1_REGNUM; regnum <= ARM_PC_REGNUM; regnum++)
|
||||
regcache_raw_collect (current_regcache, regnum,
|
||||
(char *) &(*gregsetp)[regnum]);
|
||||
}
|
||||
else if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
|
||||
regcache_raw_collect (current_regcache, regno,
|
||||
(char *) &(*gregsetp)[regno]);
|
||||
|
||||
if (ARM_PS_REGNUM == regno || -1 == regno)
|
||||
{
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_collect (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &(*gregsetp)[ARM_CPSR_REGNUM]);
|
||||
else
|
||||
regcache_raw_collect (current_regcache, ARM_PC_REGNUM,
|
||||
(char *) &(*gregsetp)[ARM_PC_REGNUM]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill GDB's register array with the general-purpose register values
|
||||
in *gregsetp. */
|
||||
|
||||
void
|
||||
supply_gregset (gdb_gregset_t *gregsetp)
|
||||
{
|
||||
int regno, reg_pc;
|
||||
|
||||
for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
|
||||
regcache_raw_supply (current_regcache, regno,
|
||||
(char *) &(*gregsetp)[regno]);
|
||||
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &(*gregsetp)[ARM_CPSR_REGNUM]);
|
||||
else
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &(*gregsetp)[ARM_PC_REGNUM]);
|
||||
|
||||
reg_pc = ADDR_BITS_REMOVE ((CORE_ADDR)(*gregsetp)[ARM_PC_REGNUM]);
|
||||
regcache_raw_supply (current_regcache, ARM_PC_REGNUM, (char *) ®_pc);
|
||||
}
|
||||
|
||||
/* Fill register regno (if it is a floating-point register) in
|
||||
*fpregsetp with the appropriate value from GDB's register array.
|
||||
If regno is -1, do this for all registers. */
|
||||
|
||||
void
|
||||
fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
|
||||
{
|
||||
FPA11 *fp = (FPA11 *) fpregsetp;
|
||||
|
||||
if (-1 == regno)
|
||||
{
|
||||
int regnum;
|
||||
for (regnum = ARM_F0_REGNUM; regnum <= ARM_F7_REGNUM; regnum++)
|
||||
store_nwfpe_register (regnum, fp);
|
||||
}
|
||||
else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
|
||||
{
|
||||
store_nwfpe_register (regno, fp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store fpsr. */
|
||||
if (ARM_FPS_REGNUM == regno || -1 == regno)
|
||||
regcache_raw_collect (current_regcache, ARM_FPS_REGNUM,
|
||||
(char *) &fp->fpsr);
|
||||
}
|
||||
|
||||
/* Fill GDB's register array with the floating-point register values
|
||||
in *fpregsetp. */
|
||||
|
||||
void
|
||||
supply_fpregset (gdb_fpregset_t *fpregsetp)
|
||||
{
|
||||
int regno;
|
||||
FPA11 *fp = (FPA11 *) fpregsetp;
|
||||
|
||||
/* Fetch fpsr. */
|
||||
regcache_raw_supply (current_regcache, ARM_FPS_REGNUM, (char *) &fp->fpsr);
|
||||
|
||||
/* Fetch the floating point registers. */
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
{
|
||||
fetch_nwfpe_register (regno, fp);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
arm_linux_kernel_u_size (void)
|
||||
{
|
||||
return (sizeof (struct user));
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_linux_version (unsigned int *vmajor,
|
||||
unsigned int *vminor,
|
||||
unsigned int *vrelease)
|
||||
{
|
||||
struct utsname info;
|
||||
char *pmajor, *pminor, *prelease, *tail;
|
||||
|
||||
if (-1 == uname (&info))
|
||||
{
|
||||
warning (_("Unable to determine GNU/Linux version."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pmajor = strtok (info.release, ".");
|
||||
pminor = strtok (NULL, ".");
|
||||
prelease = strtok (NULL, ".");
|
||||
|
||||
*vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
|
||||
*vminor = (unsigned int) strtoul (pminor, &tail, 0);
|
||||
*vrelease = (unsigned int) strtoul (prelease, &tail, 0);
|
||||
|
||||
return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
|
||||
}
|
||||
|
||||
void _initialize_arm_linux_nat (void);
|
||||
|
||||
void
|
||||
_initialize_arm_linux_nat (void)
|
||||
{
|
||||
struct target_ops *t;
|
||||
|
||||
os_version = get_linux_version (&os_major, &os_minor, &os_release);
|
||||
|
||||
/* Fill in the generic GNU/Linux methods. */
|
||||
t = linux_target ();
|
||||
|
||||
/* Add our register access methods. */
|
||||
t->to_fetch_registers = arm_linux_fetch_inferior_registers;
|
||||
t->to_store_registers = arm_linux_store_inferior_registers;
|
||||
|
||||
/* Register the target. */
|
||||
add_target (t);
|
||||
}
|
||||
@@ -1,379 +0,0 @@
|
||||
/* GNU/Linux on ARM target support.
|
||||
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "target.h"
|
||||
#include "value.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "floatformat.h"
|
||||
#include "gdbcore.h"
|
||||
#include "frame.h"
|
||||
#include "regcache.h"
|
||||
#include "doublest.h"
|
||||
#include "solib-svr4.h"
|
||||
#include "osabi.h"
|
||||
#include "trad-frame.h"
|
||||
#include "tramp-frame.h"
|
||||
|
||||
#include "arm-tdep.h"
|
||||
#include "glibc-tdep.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
/* Under ARM GNU/Linux the traditional way of performing a breakpoint
|
||||
is to execute a particular software interrupt, rather than use a
|
||||
particular undefined instruction to provoke a trap. Upon exection
|
||||
of the software interrupt the kernel stops the inferior with a
|
||||
SIGTRAP, and wakes the debugger. */
|
||||
|
||||
static const char arm_linux_arm_le_breakpoint[] = { 0x01, 0x00, 0x9f, 0xef };
|
||||
|
||||
static const char arm_linux_arm_be_breakpoint[] = { 0xef, 0x9f, 0x00, 0x01 };
|
||||
|
||||
/* However, the EABI syscall interface (new in Nov. 2005) does not look at
|
||||
the operand of the swi if old-ABI compatibility is disabled. Therefore,
|
||||
use an undefined instruction instead. This is supported as of kernel
|
||||
version 2.5.70 (May 2003), so should be a safe assumption for EABI
|
||||
binaries. */
|
||||
|
||||
static const char eabi_linux_arm_le_breakpoint[] = { 0xf0, 0x01, 0xf0, 0xe7 };
|
||||
|
||||
static const char eabi_linux_arm_be_breakpoint[] = { 0xe7, 0xf0, 0x01, 0xf0 };
|
||||
|
||||
/* All the kernels which support Thumb support using a specific undefined
|
||||
instruction for the Thumb breakpoint. */
|
||||
|
||||
static const char arm_linux_thumb_be_breakpoint[] = {0xde, 0x01};
|
||||
|
||||
static const char arm_linux_thumb_le_breakpoint[] = {0x01, 0xde};
|
||||
|
||||
/* Description of the longjmp buffer. */
|
||||
#define ARM_LINUX_JB_ELEMENT_SIZE INT_REGISTER_SIZE
|
||||
#define ARM_LINUX_JB_PC 21
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
/* FIXME rearnsha/2002-02-23: This function shouldn't be necessary.
|
||||
The ARM generic one should be able to handle the model used by
|
||||
linux and the low-level formatting of the registers should be
|
||||
hidden behind the regcache abstraction. */
|
||||
static void
|
||||
arm_linux_extract_return_value (struct type *type,
|
||||
char regbuf[],
|
||||
char *valbuf)
|
||||
{
|
||||
/* ScottB: This needs to be looked at to handle the different
|
||||
floating point emulators on ARM GNU/Linux. Right now the code
|
||||
assumes that fetch inferior registers does the right thing for
|
||||
GDB. I suspect this won't handle NWFPE registers correctly, nor
|
||||
will the default ARM version (arm_extract_return_value()). */
|
||||
|
||||
int regnum = ((TYPE_CODE_FLT == TYPE_CODE (type))
|
||||
? ARM_F0_REGNUM : ARM_A1_REGNUM);
|
||||
memcpy (valbuf, ®buf[DEPRECATED_REGISTER_BYTE (regnum)], TYPE_LENGTH (type));
|
||||
}
|
||||
|
||||
/*
|
||||
Dynamic Linking on ARM GNU/Linux
|
||||
--------------------------------
|
||||
|
||||
Note: PLT = procedure linkage table
|
||||
GOT = global offset table
|
||||
|
||||
As much as possible, ELF dynamic linking defers the resolution of
|
||||
jump/call addresses until the last minute. The technique used is
|
||||
inspired by the i386 ELF design, and is based on the following
|
||||
constraints.
|
||||
|
||||
1) The calling technique should not force a change in the assembly
|
||||
code produced for apps; it MAY cause changes in the way assembly
|
||||
code is produced for position independent code (i.e. shared
|
||||
libraries).
|
||||
|
||||
2) The technique must be such that all executable areas must not be
|
||||
modified; and any modified areas must not be executed.
|
||||
|
||||
To do this, there are three steps involved in a typical jump:
|
||||
|
||||
1) in the code
|
||||
2) through the PLT
|
||||
3) using a pointer from the GOT
|
||||
|
||||
When the executable or library is first loaded, each GOT entry is
|
||||
initialized to point to the code which implements dynamic name
|
||||
resolution and code finding. This is normally a function in the
|
||||
program interpreter (on ARM GNU/Linux this is usually
|
||||
ld-linux.so.2, but it does not have to be). On the first
|
||||
invocation, the function is located and the GOT entry is replaced
|
||||
with the real function address. Subsequent calls go through steps
|
||||
1, 2 and 3 and end up calling the real code.
|
||||
|
||||
1) In the code:
|
||||
|
||||
b function_call
|
||||
bl function_call
|
||||
|
||||
This is typical ARM code using the 26 bit relative branch or branch
|
||||
and link instructions. The target of the instruction
|
||||
(function_call is usually the address of the function to be called.
|
||||
In position independent code, the target of the instruction is
|
||||
actually an entry in the PLT when calling functions in a shared
|
||||
library. Note that this call is identical to a normal function
|
||||
call, only the target differs.
|
||||
|
||||
2) In the PLT:
|
||||
|
||||
The PLT is a synthetic area, created by the linker. It exists in
|
||||
both executables and libraries. It is an array of stubs, one per
|
||||
imported function call. It looks like this:
|
||||
|
||||
PLT[0]:
|
||||
str lr, [sp, #-4]! @push the return address (lr)
|
||||
ldr lr, [pc, #16] @load from 6 words ahead
|
||||
add lr, pc, lr @form an address for GOT[0]
|
||||
ldr pc, [lr, #8]! @jump to the contents of that addr
|
||||
|
||||
The return address (lr) is pushed on the stack and used for
|
||||
calculations. The load on the second line loads the lr with
|
||||
&GOT[3] - . - 20. The addition on the third leaves:
|
||||
|
||||
lr = (&GOT[3] - . - 20) + (. + 8)
|
||||
lr = (&GOT[3] - 12)
|
||||
lr = &GOT[0]
|
||||
|
||||
On the fourth line, the pc and lr are both updated, so that:
|
||||
|
||||
pc = GOT[2]
|
||||
lr = &GOT[0] + 8
|
||||
= &GOT[2]
|
||||
|
||||
NOTE: PLT[0] borrows an offset .word from PLT[1]. This is a little
|
||||
"tight", but allows us to keep all the PLT entries the same size.
|
||||
|
||||
PLT[n+1]:
|
||||
ldr ip, [pc, #4] @load offset from gotoff
|
||||
add ip, pc, ip @add the offset to the pc
|
||||
ldr pc, [ip] @jump to that address
|
||||
gotoff: .word GOT[n+3] - .
|
||||
|
||||
The load on the first line, gets an offset from the fourth word of
|
||||
the PLT entry. The add on the second line makes ip = &GOT[n+3],
|
||||
which contains either a pointer to PLT[0] (the fixup trampoline) or
|
||||
a pointer to the actual code.
|
||||
|
||||
3) In the GOT:
|
||||
|
||||
The GOT contains helper pointers for both code (PLT) fixups and
|
||||
data fixups. The first 3 entries of the GOT are special. The next
|
||||
M entries (where M is the number of entries in the PLT) belong to
|
||||
the PLT fixups. The next D (all remaining) entries belong to
|
||||
various data fixups. The actual size of the GOT is 3 + M + D.
|
||||
|
||||
The GOT is also a synthetic area, created by the linker. It exists
|
||||
in both executables and libraries. When the GOT is first
|
||||
initialized , all the GOT entries relating to PLT fixups are
|
||||
pointing to code back at PLT[0].
|
||||
|
||||
The special entries in the GOT are:
|
||||
|
||||
GOT[0] = linked list pointer used by the dynamic loader
|
||||
GOT[1] = pointer to the reloc table for this module
|
||||
GOT[2] = pointer to the fixup/resolver code
|
||||
|
||||
The first invocation of function call comes through and uses the
|
||||
fixup/resolver code. On the entry to the fixup/resolver code:
|
||||
|
||||
ip = &GOT[n+3]
|
||||
lr = &GOT[2]
|
||||
stack[0] = return address (lr) of the function call
|
||||
[r0, r1, r2, r3] are still the arguments to the function call
|
||||
|
||||
This is enough information for the fixup/resolver code to work
|
||||
with. Before the fixup/resolver code returns, it actually calls
|
||||
the requested function and repairs &GOT[n+3]. */
|
||||
|
||||
/* The constants below were determined by examining the following files
|
||||
in the linux kernel sources:
|
||||
|
||||
arch/arm/kernel/signal.c
|
||||
- see SWI_SYS_SIGRETURN and SWI_SYS_RT_SIGRETURN
|
||||
include/asm-arm/unistd.h
|
||||
- see __NR_sigreturn, __NR_rt_sigreturn, and __NR_SYSCALL_BASE */
|
||||
|
||||
#define ARM_LINUX_SIGRETURN_INSTR 0xef900077
|
||||
#define ARM_LINUX_RT_SIGRETURN_INSTR 0xef9000ad
|
||||
|
||||
/* For ARM EABI, recognize the pattern that glibc uses... alternatively,
|
||||
we could arrange to do this by function name, but they are not always
|
||||
exported. */
|
||||
#define ARM_SET_R7_SIGRETURN 0xe3a07077
|
||||
#define ARM_SET_R7_RT_SIGRETURN 0xe3a070ad
|
||||
#define ARM_EABI_SYSCALL 0xef000000
|
||||
|
||||
static void
|
||||
arm_linux_sigtramp_cache (struct frame_info *next_frame,
|
||||
struct trad_frame_cache *this_cache,
|
||||
CORE_ADDR func, int regs_offset)
|
||||
{
|
||||
CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
|
||||
CORE_ADDR base = sp + regs_offset;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
trad_frame_set_reg_addr (this_cache, i, base + i * 4);
|
||||
|
||||
trad_frame_set_reg_addr (this_cache, ARM_PS_REGNUM, base + 16 * 4);
|
||||
|
||||
/* The VFP or iWMMXt registers may be saved on the stack, but there's
|
||||
no reliable way to restore them (yet). */
|
||||
|
||||
/* Save a frame ID. */
|
||||
trad_frame_set_id (this_cache, frame_id_build (sp, func));
|
||||
}
|
||||
|
||||
static void
|
||||
arm_linux_sigreturn_init (const struct tramp_frame *self,
|
||||
struct frame_info *next_frame,
|
||||
struct trad_frame_cache *this_cache,
|
||||
CORE_ADDR func)
|
||||
{
|
||||
arm_linux_sigtramp_cache (next_frame, this_cache, func,
|
||||
0x0c /* Offset to registers. */);
|
||||
}
|
||||
|
||||
static void
|
||||
arm_linux_rt_sigreturn_init (const struct tramp_frame *self,
|
||||
struct frame_info *next_frame,
|
||||
struct trad_frame_cache *this_cache,
|
||||
CORE_ADDR func)
|
||||
{
|
||||
arm_linux_sigtramp_cache (next_frame, this_cache, func,
|
||||
0x88 /* Offset to ucontext_t. */
|
||||
+ 0x14 /* Offset to sigcontext. */
|
||||
+ 0x0c /* Offset to registers. */);
|
||||
}
|
||||
|
||||
static struct tramp_frame arm_linux_sigreturn_tramp_frame = {
|
||||
SIGTRAMP_FRAME,
|
||||
4,
|
||||
{
|
||||
{ ARM_LINUX_SIGRETURN_INSTR, -1 },
|
||||
{ TRAMP_SENTINEL_INSN }
|
||||
},
|
||||
arm_linux_sigreturn_init
|
||||
};
|
||||
|
||||
static struct tramp_frame arm_linux_rt_sigreturn_tramp_frame = {
|
||||
SIGTRAMP_FRAME,
|
||||
4,
|
||||
{
|
||||
{ ARM_LINUX_RT_SIGRETURN_INSTR, -1 },
|
||||
{ TRAMP_SENTINEL_INSN }
|
||||
},
|
||||
arm_linux_rt_sigreturn_init
|
||||
};
|
||||
|
||||
static struct tramp_frame arm_eabi_linux_sigreturn_tramp_frame = {
|
||||
SIGTRAMP_FRAME,
|
||||
4,
|
||||
{
|
||||
{ ARM_SET_R7_SIGRETURN, -1 },
|
||||
{ ARM_EABI_SYSCALL, -1 },
|
||||
{ TRAMP_SENTINEL_INSN }
|
||||
},
|
||||
arm_linux_sigreturn_init
|
||||
};
|
||||
|
||||
static struct tramp_frame arm_eabi_linux_rt_sigreturn_tramp_frame = {
|
||||
SIGTRAMP_FRAME,
|
||||
4,
|
||||
{
|
||||
{ ARM_SET_R7_RT_SIGRETURN, -1 },
|
||||
{ ARM_EABI_SYSCALL, -1 },
|
||||
{ TRAMP_SENTINEL_INSN }
|
||||
},
|
||||
arm_linux_rt_sigreturn_init
|
||||
};
|
||||
|
||||
static void
|
||||
arm_linux_init_abi (struct gdbarch_info info,
|
||||
struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
tdep->lowest_pc = 0x8000;
|
||||
if (info.byte_order == BFD_ENDIAN_BIG)
|
||||
{
|
||||
if (tdep->arm_abi == ARM_ABI_AAPCS)
|
||||
tdep->arm_breakpoint = eabi_linux_arm_be_breakpoint;
|
||||
else
|
||||
tdep->arm_breakpoint = arm_linux_arm_be_breakpoint;
|
||||
tdep->thumb_breakpoint = arm_linux_thumb_be_breakpoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tdep->arm_abi == ARM_ABI_AAPCS)
|
||||
tdep->arm_breakpoint = eabi_linux_arm_le_breakpoint;
|
||||
else
|
||||
tdep->arm_breakpoint = arm_linux_arm_le_breakpoint;
|
||||
tdep->thumb_breakpoint = arm_linux_thumb_le_breakpoint;
|
||||
}
|
||||
tdep->arm_breakpoint_size = sizeof (arm_linux_arm_le_breakpoint);
|
||||
tdep->thumb_breakpoint_size = sizeof (arm_linux_thumb_le_breakpoint);
|
||||
|
||||
if (tdep->fp_model == ARM_FLOAT_AUTO)
|
||||
tdep->fp_model = ARM_FLOAT_FPA;
|
||||
|
||||
tdep->jb_pc = ARM_LINUX_JB_PC;
|
||||
tdep->jb_elt_size = ARM_LINUX_JB_ELEMENT_SIZE;
|
||||
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
|
||||
|
||||
/* The following override shouldn't be needed. */
|
||||
set_gdbarch_deprecated_extract_return_value (gdbarch, arm_linux_extract_return_value);
|
||||
|
||||
/* Shared library handling. */
|
||||
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
|
||||
set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
|
||||
|
||||
/* Enable TLS support. */
|
||||
set_gdbarch_fetch_tls_load_module_address (gdbarch,
|
||||
svr4_fetch_objfile_link_map);
|
||||
|
||||
tramp_frame_prepend_unwinder (gdbarch,
|
||||
&arm_linux_sigreturn_tramp_frame);
|
||||
tramp_frame_prepend_unwinder (gdbarch,
|
||||
&arm_linux_rt_sigreturn_tramp_frame);
|
||||
tramp_frame_prepend_unwinder (gdbarch,
|
||||
&arm_eabi_linux_sigreturn_tramp_frame);
|
||||
tramp_frame_prepend_unwinder (gdbarch,
|
||||
&arm_eabi_linux_rt_sigreturn_tramp_frame);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_arm_linux_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_LINUX,
|
||||
arm_linux_init_abi);
|
||||
}
|
||||
2980
gdb/arm-tdep.c
2980
gdb/arm-tdep.c
File diff suppressed because it is too large
Load Diff
159
gdb/arm-tdep.h
159
gdb/arm-tdep.h
@@ -1,159 +0,0 @@
|
||||
/* Common target dependent code for GDB on ARM systems.
|
||||
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Register numbers of various important registers. Note that some of
|
||||
these values are "real" register numbers, and correspond to the
|
||||
general registers of the machine, and some are "phony" register
|
||||
numbers which are too large to be actual register numbers as far as
|
||||
the user is concerned but do serve to get the desired values when
|
||||
passed to read_register. */
|
||||
|
||||
enum gdb_regnum {
|
||||
ARM_A1_REGNUM = 0, /* first integer-like argument */
|
||||
ARM_A4_REGNUM = 3, /* last integer-like argument */
|
||||
ARM_AP_REGNUM = 11,
|
||||
ARM_SP_REGNUM = 13, /* Contains address of top of stack */
|
||||
ARM_LR_REGNUM = 14, /* address to return to from a function call */
|
||||
ARM_PC_REGNUM = 15, /* Contains program counter */
|
||||
ARM_F0_REGNUM = 16, /* first floating point register */
|
||||
ARM_F3_REGNUM = 19, /* last floating point argument register */
|
||||
ARM_F7_REGNUM = 23, /* last floating point register */
|
||||
ARM_FPS_REGNUM = 24, /* floating point status register */
|
||||
ARM_PS_REGNUM = 25, /* Contains processor status */
|
||||
ARM_FP_REGNUM = 11, /* Frame register in ARM code, if used. */
|
||||
THUMB_FP_REGNUM = 7, /* Frame register in Thumb code, if used. */
|
||||
ARM_NUM_ARG_REGS = 4,
|
||||
ARM_LAST_ARG_REGNUM = ARM_A4_REGNUM,
|
||||
ARM_NUM_FP_ARG_REGS = 4,
|
||||
ARM_LAST_FP_ARG_REGNUM = ARM_F3_REGNUM
|
||||
};
|
||||
|
||||
/* Size of integer registers. */
|
||||
#define INT_REGISTER_SIZE 4
|
||||
|
||||
/* Say how long FP registers are. Used for documentation purposes and
|
||||
code readability in this header. IEEE extended doubles are 80
|
||||
bits. DWORD aligned they use 96 bits. */
|
||||
#define FP_REGISTER_SIZE 12
|
||||
|
||||
/* Status registers are the same size as general purpose registers.
|
||||
Used for documentation purposes and code readability in this
|
||||
header. */
|
||||
#define STATUS_REGISTER_SIZE 4
|
||||
|
||||
/* Number of machine registers. The only define actually required
|
||||
is NUM_REGS. The other definitions are used for documentation
|
||||
purposes and code readability. */
|
||||
/* For 26 bit ARM code, a fake copy of the PC is placed in register 25 (PS)
|
||||
(and called PS for processor status) so the status bits can be cleared
|
||||
from the PC (register 15). For 32 bit ARM code, a copy of CPSR is placed
|
||||
in PS. */
|
||||
#define NUM_FREGS 8 /* Number of floating point registers. */
|
||||
#define NUM_SREGS 2 /* Number of status registers. */
|
||||
#define NUM_GREGS 16 /* Number of general purpose registers. */
|
||||
|
||||
|
||||
/* Instruction condition field values. */
|
||||
#define INST_EQ 0x0
|
||||
#define INST_NE 0x1
|
||||
#define INST_CS 0x2
|
||||
#define INST_CC 0x3
|
||||
#define INST_MI 0x4
|
||||
#define INST_PL 0x5
|
||||
#define INST_VS 0x6
|
||||
#define INST_VC 0x7
|
||||
#define INST_HI 0x8
|
||||
#define INST_LS 0x9
|
||||
#define INST_GE 0xa
|
||||
#define INST_LT 0xb
|
||||
#define INST_GT 0xc
|
||||
#define INST_LE 0xd
|
||||
#define INST_AL 0xe
|
||||
#define INST_NV 0xf
|
||||
|
||||
#define FLAG_N 0x80000000
|
||||
#define FLAG_Z 0x40000000
|
||||
#define FLAG_C 0x20000000
|
||||
#define FLAG_V 0x10000000
|
||||
|
||||
/* Type of floating-point code in use by inferior. There are really 3 models
|
||||
that are traditionally supported (plus the endianness issue), but gcc can
|
||||
only generate 2 of those. The third is APCS_FLOAT, where arguments to
|
||||
functions are passed in floating-point registers.
|
||||
|
||||
In addition to the traditional models, VFP adds two more.
|
||||
|
||||
If you update this enum, don't forget to update fp_model_strings in
|
||||
arm-tdep.c. */
|
||||
|
||||
enum arm_float_model
|
||||
{
|
||||
ARM_FLOAT_AUTO, /* Automatic detection. Do not set in tdep. */
|
||||
ARM_FLOAT_SOFT_FPA, /* Traditional soft-float (mixed-endian on LE ARM). */
|
||||
ARM_FLOAT_FPA, /* FPA co-processor. GCC calling convention. */
|
||||
ARM_FLOAT_SOFT_VFP, /* Soft-float with pure-endian doubles. */
|
||||
ARM_FLOAT_VFP, /* Full VFP calling convention. */
|
||||
ARM_FLOAT_LAST /* Keep at end. */
|
||||
};
|
||||
|
||||
/* ABI used by the inferior. */
|
||||
enum arm_abi_kind
|
||||
{
|
||||
ARM_ABI_AUTO,
|
||||
ARM_ABI_APCS,
|
||||
ARM_ABI_AAPCS,
|
||||
ARM_ABI_LAST
|
||||
};
|
||||
|
||||
/* Target-dependent structure in gdbarch. */
|
||||
struct gdbarch_tdep
|
||||
{
|
||||
/* The ABI for this architecture. It should never be set to
|
||||
ARM_ABI_AUTO. */
|
||||
enum arm_abi_kind arm_abi;
|
||||
|
||||
enum arm_float_model fp_model; /* Floating point calling conventions. */
|
||||
|
||||
CORE_ADDR lowest_pc; /* Lowest address at which instructions
|
||||
will appear. */
|
||||
|
||||
const char *arm_breakpoint; /* Breakpoint pattern for an ARM insn. */
|
||||
int arm_breakpoint_size; /* And its size. */
|
||||
const char *thumb_breakpoint; /* Breakpoint pattern for an ARM insn. */
|
||||
int thumb_breakpoint_size; /* And its size. */
|
||||
|
||||
int jb_pc; /* Offset to PC value in jump buffer.
|
||||
If this is negative, longjmp support
|
||||
will be disabled. */
|
||||
size_t jb_elt_size; /* And the size of each entry in the buf. */
|
||||
};
|
||||
|
||||
#ifndef LOWEST_PC
|
||||
#define LOWEST_PC (gdbarch_tdep (current_gdbarch)->lowest_pc)
|
||||
#endif
|
||||
|
||||
/* Prototypes for internal interfaces needed by more than one MD file. */
|
||||
int arm_pc_is_thumb_dummy (CORE_ADDR);
|
||||
|
||||
int arm_pc_is_thumb (CORE_ADDR);
|
||||
|
||||
CORE_ADDR thumb_get_next_pc (CORE_ADDR);
|
||||
|
||||
CORE_ADDR arm_get_next_pc (CORE_ADDR);
|
||||
@@ -1,497 +0,0 @@
|
||||
/* Native-dependent code for BSD Unix running on ARM's, for GDB.
|
||||
|
||||
Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996, 1999, 2002, 2004
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "inferior.h"
|
||||
#include "regcache.h"
|
||||
#include "target.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
#include <machine/frame.h>
|
||||
|
||||
#include "arm-tdep.h"
|
||||
#include "inf-ptrace.h"
|
||||
|
||||
extern int arm_apcs_32;
|
||||
|
||||
static void
|
||||
supply_gregset (struct reg *gregset)
|
||||
{
|
||||
int regno;
|
||||
CORE_ADDR r_pc;
|
||||
|
||||
/* Integer registers. */
|
||||
for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
|
||||
regcache_raw_supply (current_regcache, regno, (char *) &gregset->r[regno]);
|
||||
|
||||
regcache_raw_supply (current_regcache, ARM_SP_REGNUM,
|
||||
(char *) &gregset->r_sp);
|
||||
regcache_raw_supply (current_regcache, ARM_LR_REGNUM,
|
||||
(char *) &gregset->r_lr);
|
||||
/* This is ok: we're running native... */
|
||||
r_pc = ADDR_BITS_REMOVE (gregset->r_pc);
|
||||
regcache_raw_supply (current_regcache, ARM_PC_REGNUM, (char *) &r_pc);
|
||||
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &gregset->r_cpsr);
|
||||
else
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &gregset->r_pc);
|
||||
}
|
||||
|
||||
static void
|
||||
supply_fparegset (struct fpreg *fparegset)
|
||||
{
|
||||
int regno;
|
||||
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
regcache_raw_supply (current_regcache, regno,
|
||||
(char *) &fparegset->fpr[regno - ARM_F0_REGNUM]);
|
||||
|
||||
regcache_raw_supply (current_regcache, ARM_FPS_REGNUM,
|
||||
(char *) &fparegset->fpr_fpsr);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_register (int regno)
|
||||
{
|
||||
struct reg inferior_registers;
|
||||
int ret;
|
||||
|
||||
ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("unable to fetch general register"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (regno)
|
||||
{
|
||||
case ARM_SP_REGNUM:
|
||||
regcache_raw_supply (current_regcache, ARM_SP_REGNUM,
|
||||
(char *) &inferior_registers.r_sp);
|
||||
break;
|
||||
|
||||
case ARM_LR_REGNUM:
|
||||
regcache_raw_supply (current_regcache, ARM_LR_REGNUM,
|
||||
(char *) &inferior_registers.r_lr);
|
||||
break;
|
||||
|
||||
case ARM_PC_REGNUM:
|
||||
/* This is ok: we're running native... */
|
||||
inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc);
|
||||
regcache_raw_supply (current_regcache, ARM_PC_REGNUM,
|
||||
(char *) &inferior_registers.r_pc);
|
||||
break;
|
||||
|
||||
case ARM_PS_REGNUM:
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &inferior_registers.r_cpsr);
|
||||
else
|
||||
regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &inferior_registers.r_pc);
|
||||
break;
|
||||
|
||||
default:
|
||||
regcache_raw_supply (current_regcache, regno,
|
||||
(char *) &inferior_registers.r[regno]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_regs (void)
|
||||
{
|
||||
struct reg inferior_registers;
|
||||
int ret;
|
||||
int regno;
|
||||
|
||||
ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("unable to fetch general registers"));
|
||||
return;
|
||||
}
|
||||
|
||||
supply_gregset (&inferior_registers);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_fp_register (int regno)
|
||||
{
|
||||
struct fpreg inferior_fp_registers;
|
||||
int ret;
|
||||
|
||||
ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("unable to fetch floating-point register"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (regno)
|
||||
{
|
||||
case ARM_FPS_REGNUM:
|
||||
regcache_raw_supply (current_regcache, ARM_FPS_REGNUM,
|
||||
(char *) &inferior_fp_registers.fpr_fpsr);
|
||||
break;
|
||||
|
||||
default:
|
||||
regcache_raw_supply (current_regcache, regno,
|
||||
(char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_fp_regs (void)
|
||||
{
|
||||
struct fpreg inferior_fp_registers;
|
||||
int ret;
|
||||
int regno;
|
||||
|
||||
ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("unable to fetch general registers"));
|
||||
return;
|
||||
}
|
||||
|
||||
supply_fparegset (&inferior_fp_registers);
|
||||
}
|
||||
|
||||
static void
|
||||
armnbsd_fetch_registers (int regno)
|
||||
{
|
||||
if (regno >= 0)
|
||||
{
|
||||
if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
|
||||
fetch_register (regno);
|
||||
else
|
||||
fetch_fp_register (regno);
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch_regs ();
|
||||
fetch_fp_regs ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
store_register (int regno)
|
||||
{
|
||||
struct reg inferior_registers;
|
||||
int ret;
|
||||
|
||||
ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("unable to fetch general registers"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (regno)
|
||||
{
|
||||
case ARM_SP_REGNUM:
|
||||
regcache_raw_collect (current_regcache, ARM_SP_REGNUM,
|
||||
(char *) &inferior_registers.r_sp);
|
||||
break;
|
||||
|
||||
case ARM_LR_REGNUM:
|
||||
regcache_raw_collect (current_regcache, ARM_LR_REGNUM,
|
||||
(char *) &inferior_registers.r_lr);
|
||||
break;
|
||||
|
||||
case ARM_PC_REGNUM:
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_collect (current_regcache, ARM_PC_REGNUM,
|
||||
(char *) &inferior_registers.r_pc);
|
||||
else
|
||||
{
|
||||
unsigned pc_val;
|
||||
|
||||
regcache_raw_collect (current_regcache, ARM_PC_REGNUM,
|
||||
(char *) &pc_val);
|
||||
|
||||
pc_val = ADDR_BITS_REMOVE (pc_val);
|
||||
inferior_registers.r_pc
|
||||
^= ADDR_BITS_REMOVE (inferior_registers.r_pc);
|
||||
inferior_registers.r_pc |= pc_val;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARM_PS_REGNUM:
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_collect (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &inferior_registers.r_cpsr);
|
||||
else
|
||||
{
|
||||
unsigned psr_val;
|
||||
|
||||
regcache_raw_collect (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &psr_val);
|
||||
|
||||
psr_val ^= ADDR_BITS_REMOVE (psr_val);
|
||||
inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc);
|
||||
inferior_registers.r_pc |= psr_val;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
regcache_raw_collect (current_regcache, regno,
|
||||
(char *) &inferior_registers.r[regno]);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
warning (_("unable to write register %d to inferior"), regno);
|
||||
}
|
||||
|
||||
static void
|
||||
store_regs (void)
|
||||
{
|
||||
struct reg inferior_registers;
|
||||
int ret;
|
||||
int regno;
|
||||
|
||||
|
||||
for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
|
||||
regcache_raw_collect (current_regcache, regno,
|
||||
(char *) &inferior_registers.r[regno]);
|
||||
|
||||
regcache_raw_collect (current_regcache, ARM_SP_REGNUM,
|
||||
(char *) &inferior_registers.r_sp);
|
||||
regcache_raw_collect (current_regcache, ARM_LR_REGNUM,
|
||||
(char *) &inferior_registers.r_lr);
|
||||
|
||||
if (arm_apcs_32)
|
||||
{
|
||||
regcache_raw_collect (current_regcache, ARM_PC_REGNUM,
|
||||
(char *) &inferior_registers.r_pc);
|
||||
regcache_raw_collect (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &inferior_registers.r_cpsr);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned pc_val;
|
||||
unsigned psr_val;
|
||||
|
||||
regcache_raw_collect (current_regcache, ARM_PC_REGNUM,
|
||||
(char *) &pc_val);
|
||||
regcache_raw_collect (current_regcache, ARM_PS_REGNUM,
|
||||
(char *) &psr_val);
|
||||
|
||||
pc_val = ADDR_BITS_REMOVE (pc_val);
|
||||
psr_val ^= ADDR_BITS_REMOVE (psr_val);
|
||||
|
||||
inferior_registers.r_pc = pc_val | psr_val;
|
||||
}
|
||||
|
||||
ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
warning (_("unable to store general registers"));
|
||||
}
|
||||
|
||||
static void
|
||||
store_fp_register (int regno)
|
||||
{
|
||||
struct fpreg inferior_fp_registers;
|
||||
int ret;
|
||||
|
||||
ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("unable to fetch floating-point registers"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (regno)
|
||||
{
|
||||
case ARM_FPS_REGNUM:
|
||||
regcache_raw_collect (current_regcache, ARM_FPS_REGNUM,
|
||||
(char *) &inferior_fp_registers.fpr_fpsr);
|
||||
break;
|
||||
|
||||
default:
|
||||
regcache_raw_collect (current_regcache, regno,
|
||||
(char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
warning (_("unable to write register %d to inferior"), regno);
|
||||
}
|
||||
|
||||
static void
|
||||
store_fp_regs (void)
|
||||
{
|
||||
struct fpreg inferior_fp_registers;
|
||||
int ret;
|
||||
int regno;
|
||||
|
||||
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
regcache_raw_collect (current_regcache, regno,
|
||||
(char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
|
||||
|
||||
regcache_raw_collect (current_regcache, ARM_FPS_REGNUM,
|
||||
(char *) &inferior_fp_registers.fpr_fpsr);
|
||||
|
||||
ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
|
||||
(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
|
||||
|
||||
if (ret < 0)
|
||||
warning (_("unable to store floating-point registers"));
|
||||
}
|
||||
|
||||
static void
|
||||
armnbsd_store_registers (int regno)
|
||||
{
|
||||
if (regno >= 0)
|
||||
{
|
||||
if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
|
||||
store_register (regno);
|
||||
else
|
||||
store_fp_register (regno);
|
||||
}
|
||||
else
|
||||
{
|
||||
store_regs ();
|
||||
store_fp_regs ();
|
||||
}
|
||||
}
|
||||
|
||||
struct md_core
|
||||
{
|
||||
struct reg intreg;
|
||||
struct fpreg freg;
|
||||
};
|
||||
|
||||
static void
|
||||
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
|
||||
int which, CORE_ADDR ignore)
|
||||
{
|
||||
struct md_core *core_reg = (struct md_core *) core_reg_sect;
|
||||
int regno;
|
||||
CORE_ADDR r_pc;
|
||||
|
||||
supply_gregset (&core_reg->intreg);
|
||||
supply_fparegset (&core_reg->freg);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size,
|
||||
int which, CORE_ADDR ignore)
|
||||
{
|
||||
struct reg gregset;
|
||||
struct fpreg fparegset;
|
||||
|
||||
switch (which)
|
||||
{
|
||||
case 0: /* Integer registers. */
|
||||
if (core_reg_size != sizeof (struct reg))
|
||||
warning (_("wrong size of register set in core file"));
|
||||
else
|
||||
{
|
||||
/* The memcpy may be unnecessary, but we can't really be sure
|
||||
of the alignment of the data in the core file. */
|
||||
memcpy (&gregset, core_reg_sect, sizeof (gregset));
|
||||
supply_gregset (&gregset);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (core_reg_size != sizeof (struct fpreg))
|
||||
warning (_("wrong size of FPA register set in core file"));
|
||||
else
|
||||
{
|
||||
/* The memcpy may be unnecessary, but we can't really be sure
|
||||
of the alignment of the data in the core file. */
|
||||
memcpy (&fparegset, core_reg_sect, sizeof (fparegset));
|
||||
supply_fparegset (&fparegset);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Don't know what kind of register request this is; just ignore it. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct core_fns arm_netbsd_core_fns =
|
||||
{
|
||||
bfd_target_unknown_flavour, /* core_flovour. */
|
||||
default_check_format, /* check_format. */
|
||||
default_core_sniffer, /* core_sniffer. */
|
||||
fetch_core_registers, /* core_read_registers. */
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct core_fns arm_netbsd_elfcore_fns =
|
||||
{
|
||||
bfd_target_elf_flavour, /* core_flovour. */
|
||||
default_check_format, /* check_format. */
|
||||
default_core_sniffer, /* core_sniffer. */
|
||||
fetch_elfcore_registers, /* core_read_registers. */
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_arm_netbsd_nat (void)
|
||||
{
|
||||
struct target_ops *t;
|
||||
|
||||
t = inf_ptrace_target ();
|
||||
t->to_fetch_registers = armnbsd_fetch_registers;
|
||||
t->to_store_registers = armnbsd_store_registers;
|
||||
add_target (t);
|
||||
|
||||
deprecated_add_core_fns (&arm_netbsd_core_fns);
|
||||
deprecated_add_core_fns (&arm_netbsd_elfcore_fns);
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/* Target-specific functions for ARM running under NetBSD.
|
||||
|
||||
Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "osabi.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "arm-tdep.h"
|
||||
#include "nbsd-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
/* Description of the longjmp buffer. */
|
||||
#define ARM_NBSD_JB_PC 24
|
||||
#define ARM_NBSD_JB_ELEMENT_SIZE INT_REGISTER_SIZE
|
||||
|
||||
/* For compatibility with previous implemenations of GDB on arm/NetBSD,
|
||||
override the default little-endian breakpoint. */
|
||||
static const char arm_nbsd_arm_le_breakpoint[] = {0x11, 0x00, 0x00, 0xe6};
|
||||
static const char arm_nbsd_arm_be_breakpoint[] = {0xe6, 0x00, 0x00, 0x11};
|
||||
static const char arm_nbsd_thumb_le_breakpoint[] = {0xfe, 0xde};
|
||||
static const char arm_nbsd_thumb_be_breakpoint[] = {0xde, 0xfe};
|
||||
|
||||
static void
|
||||
arm_netbsd_init_abi_common (struct gdbarch_info info,
|
||||
struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
tdep->lowest_pc = 0x8000;
|
||||
switch (info.byte_order)
|
||||
{
|
||||
case BFD_ENDIAN_LITTLE:
|
||||
tdep->arm_breakpoint = arm_nbsd_arm_le_breakpoint;
|
||||
tdep->thumb_breakpoint = arm_nbsd_thumb_le_breakpoint;
|
||||
tdep->arm_breakpoint_size = sizeof (arm_nbsd_arm_le_breakpoint);
|
||||
tdep->thumb_breakpoint_size = sizeof (arm_nbsd_thumb_le_breakpoint);
|
||||
break;
|
||||
|
||||
case BFD_ENDIAN_BIG:
|
||||
tdep->arm_breakpoint = arm_nbsd_arm_be_breakpoint;
|
||||
tdep->thumb_breakpoint = arm_nbsd_thumb_be_breakpoint;
|
||||
tdep->arm_breakpoint_size = sizeof (arm_nbsd_arm_be_breakpoint);
|
||||
tdep->thumb_breakpoint_size = sizeof (arm_nbsd_thumb_be_breakpoint);
|
||||
break;
|
||||
|
||||
default:
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("arm_gdbarch_init: bad byte order for float format"));
|
||||
}
|
||||
|
||||
tdep->jb_pc = ARM_NBSD_JB_PC;
|
||||
tdep->jb_elt_size = ARM_NBSD_JB_ELEMENT_SIZE;
|
||||
}
|
||||
|
||||
static void
|
||||
arm_netbsd_aout_init_abi (struct gdbarch_info info,
|
||||
struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
arm_netbsd_init_abi_common (info, gdbarch);
|
||||
if (tdep->fp_model == ARM_FLOAT_AUTO)
|
||||
tdep->fp_model = ARM_FLOAT_SOFT_FPA;
|
||||
}
|
||||
|
||||
static void
|
||||
arm_netbsd_elf_init_abi (struct gdbarch_info info,
|
||||
struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
arm_netbsd_init_abi_common (info, gdbarch);
|
||||
|
||||
set_solib_svr4_fetch_link_map_offsets (gdbarch,
|
||||
nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
|
||||
|
||||
if (tdep->fp_model == ARM_FLOAT_AUTO)
|
||||
tdep->fp_model = ARM_FLOAT_SOFT_VFP;
|
||||
}
|
||||
|
||||
static enum gdb_osabi
|
||||
arm_netbsd_aout_osabi_sniffer (bfd *abfd)
|
||||
{
|
||||
if (strcmp (bfd_get_target (abfd), "a.out-arm-netbsd") == 0)
|
||||
return GDB_OSABI_NETBSD_AOUT;
|
||||
|
||||
return GDB_OSABI_UNKNOWN;
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_arm_netbsd_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi_sniffer (bfd_arch_arm, bfd_target_aout_flavour,
|
||||
arm_netbsd_aout_osabi_sniffer);
|
||||
|
||||
gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NETBSD_AOUT,
|
||||
arm_netbsd_aout_init_abi);
|
||||
gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NETBSD_ELF,
|
||||
arm_netbsd_elf_init_abi);
|
||||
}
|
||||
300
gdb/auxv.c
300
gdb/auxv.c
@@ -1,300 +0,0 @@
|
||||
/* Auxiliary vector support for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "target.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "command.h"
|
||||
#include "inferior.h"
|
||||
#include "valprint.h"
|
||||
#include "gdb_assert.h"
|
||||
|
||||
#include "auxv.h"
|
||||
#include "elf/common.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
/* This function is called like a to_xfer_partial hook,
|
||||
but must be called with TARGET_OBJECT_AUXV.
|
||||
It handles access via /proc/PID/auxv, which is the common method.
|
||||
This function is appropriate for doing:
|
||||
#define NATIVE_XFER_AUXV procfs_xfer_auxv
|
||||
for a native target that uses inftarg.c's child_xfer_partial hook. */
|
||||
|
||||
LONGEST
|
||||
procfs_xfer_auxv (struct target_ops *ops,
|
||||
int /* enum target_object */ object,
|
||||
const char *annex,
|
||||
gdb_byte *readbuf,
|
||||
const gdb_byte *writebuf,
|
||||
ULONGEST offset,
|
||||
LONGEST len)
|
||||
{
|
||||
char *pathname;
|
||||
int fd;
|
||||
LONGEST n;
|
||||
|
||||
gdb_assert (object == TARGET_OBJECT_AUXV);
|
||||
gdb_assert (readbuf || writebuf);
|
||||
|
||||
pathname = xstrprintf ("/proc/%d/auxv", PIDGET (inferior_ptid));
|
||||
fd = open (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY);
|
||||
xfree (pathname);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
if (offset != (ULONGEST) 0
|
||||
&& lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
|
||||
n = -1;
|
||||
else if (readbuf != NULL)
|
||||
n = read (fd, readbuf, len);
|
||||
else
|
||||
n = write (fd, writebuf, len);
|
||||
|
||||
(void) close (fd);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Read all the auxv data into a contiguous xmalloc'd buffer,
|
||||
stored in *DATA. Return the size in bytes of this data.
|
||||
If zero, there is no data and *DATA is null.
|
||||
if < 0, there was an error and *DATA is null. */
|
||||
LONGEST
|
||||
target_auxv_read (struct target_ops *ops, gdb_byte **data)
|
||||
{
|
||||
size_t auxv_alloc = 512, auxv_pos = 0;
|
||||
gdb_byte *auxv = xmalloc (auxv_alloc);
|
||||
int n;
|
||||
|
||||
while (1)
|
||||
{
|
||||
n = target_read_partial (ops, TARGET_OBJECT_AUXV,
|
||||
NULL, &auxv[auxv_pos], 0,
|
||||
auxv_alloc - auxv_pos);
|
||||
if (n <= 0)
|
||||
break;
|
||||
auxv_pos += n;
|
||||
if (auxv_pos < auxv_alloc) /* Read all there was. */
|
||||
break;
|
||||
gdb_assert (auxv_pos == auxv_alloc);
|
||||
auxv_alloc *= 2;
|
||||
auxv = xrealloc (auxv, auxv_alloc);
|
||||
}
|
||||
|
||||
if (auxv_pos == 0)
|
||||
{
|
||||
xfree (auxv);
|
||||
*data = NULL;
|
||||
return n;
|
||||
}
|
||||
|
||||
*data = auxv;
|
||||
return auxv_pos;
|
||||
}
|
||||
|
||||
/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
|
||||
Return 0 if *READPTR is already at the end of the buffer.
|
||||
Return -1 if there is insufficient buffer for a whole entry.
|
||||
Return 1 if an entry was read into *TYPEP and *VALP. */
|
||||
int
|
||||
target_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
|
||||
gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
|
||||
{
|
||||
const int sizeof_auxv_field = TYPE_LENGTH (builtin_type_void_data_ptr);
|
||||
gdb_byte *ptr = *readptr;
|
||||
|
||||
if (endptr == ptr)
|
||||
return 0;
|
||||
|
||||
if (endptr - ptr < sizeof_auxv_field * 2)
|
||||
return -1;
|
||||
|
||||
*typep = extract_unsigned_integer (ptr, sizeof_auxv_field);
|
||||
ptr += sizeof_auxv_field;
|
||||
*valp = extract_unsigned_integer (ptr, sizeof_auxv_field);
|
||||
ptr += sizeof_auxv_field;
|
||||
|
||||
*readptr = ptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Extract the auxiliary vector entry with a_type matching MATCH.
|
||||
Return zero if no such entry was found, or -1 if there was
|
||||
an error getting the information. On success, return 1 after
|
||||
storing the entry's value field in *VALP. */
|
||||
int
|
||||
target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
|
||||
{
|
||||
CORE_ADDR type, val;
|
||||
gdb_byte *data;
|
||||
int n = target_auxv_read (ops, &data);
|
||||
gdb_byte *ptr = data;
|
||||
int ents = 0;
|
||||
|
||||
if (n <= 0)
|
||||
return n;
|
||||
|
||||
while (1)
|
||||
switch (target_auxv_parse (ops, &ptr, data + n, &type, &val))
|
||||
{
|
||||
case 1: /* Here's an entry, check it. */
|
||||
if (type == match)
|
||||
{
|
||||
xfree (data);
|
||||
*valp = val;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 0: /* End of the vector. */
|
||||
xfree (data);
|
||||
return 0;
|
||||
default: /* Bogosity. */
|
||||
xfree (data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
|
||||
/* Print the contents of the target's AUXV on the specified file. */
|
||||
int
|
||||
fprint_target_auxv (struct ui_file *file, struct target_ops *ops)
|
||||
{
|
||||
CORE_ADDR type, val;
|
||||
gdb_byte *data;
|
||||
int len = target_auxv_read (ops, &data);
|
||||
gdb_byte *ptr = data;
|
||||
int ents = 0;
|
||||
|
||||
if (len <= 0)
|
||||
return len;
|
||||
|
||||
while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0)
|
||||
{
|
||||
extern int addressprint;
|
||||
const char *name = "???";
|
||||
const char *description = "";
|
||||
enum { dec, hex, str } flavor = hex;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
#define TAG(tag, text, kind) \
|
||||
case tag: name = #tag; description = text; flavor = kind; break
|
||||
TAG (AT_NULL, _("End of vector"), hex);
|
||||
TAG (AT_IGNORE, _("Entry should be ignored"), hex);
|
||||
TAG (AT_EXECFD, _("File descriptor of program"), dec);
|
||||
TAG (AT_PHDR, _("Program headers for program"), hex);
|
||||
TAG (AT_PHENT, _("Size of program header entry"), dec);
|
||||
TAG (AT_PHNUM, _("Number of program headers"), dec);
|
||||
TAG (AT_PAGESZ, _("System page size"), dec);
|
||||
TAG (AT_BASE, _("Base address of interpreter"), hex);
|
||||
TAG (AT_FLAGS, _("Flags"), hex);
|
||||
TAG (AT_ENTRY, _("Entry point of program"), hex);
|
||||
TAG (AT_NOTELF, _("Program is not ELF"), dec);
|
||||
TAG (AT_UID, _("Real user ID"), dec);
|
||||
TAG (AT_EUID, _("Effective user ID"), dec);
|
||||
TAG (AT_GID, _("Real group ID"), dec);
|
||||
TAG (AT_EGID, _("Effective group ID"), dec);
|
||||
TAG (AT_CLKTCK, _("Frequency of times()"), dec);
|
||||
TAG (AT_PLATFORM, _("String identifying platform"), str);
|
||||
TAG (AT_HWCAP, _("Machine-dependent CPU capability hints"), hex);
|
||||
TAG (AT_FPUCW, _("Used FPU control word"), dec);
|
||||
TAG (AT_DCACHEBSIZE, _("Data cache block size"), dec);
|
||||
TAG (AT_ICACHEBSIZE, _("Instruction cache block size"), dec);
|
||||
TAG (AT_UCACHEBSIZE, _("Unified cache block size"), dec);
|
||||
TAG (AT_IGNOREPPC, _("Entry should be ignored"), dec);
|
||||
TAG (AT_SYSINFO, _("Special system info/entry points"), hex);
|
||||
TAG (AT_SYSINFO_EHDR, _("System-supplied DSO's ELF header"), hex);
|
||||
TAG (AT_SECURE, _("Boolean, was exec setuid-like?"), dec);
|
||||
TAG (AT_SUN_UID, _("Effective user ID"), dec);
|
||||
TAG (AT_SUN_RUID, _("Real user ID"), dec);
|
||||
TAG (AT_SUN_GID, _("Effective group ID"), dec);
|
||||
TAG (AT_SUN_RGID, _("Real group ID"), dec);
|
||||
TAG (AT_SUN_LDELF, _("Dynamic linker's ELF header"), hex);
|
||||
TAG (AT_SUN_LDSHDR, _("Dynamic linker's section headers"), hex);
|
||||
TAG (AT_SUN_LDNAME, _("String giving name of dynamic linker"), str);
|
||||
TAG (AT_SUN_LPAGESZ, _("Large pagesize"), dec);
|
||||
TAG (AT_SUN_PLATFORM, _("Platform name string"), str);
|
||||
TAG (AT_SUN_HWCAP, _("Machine-dependent CPU capability hints"), hex);
|
||||
TAG (AT_SUN_IFLUSH, _("Should flush icache?"), dec);
|
||||
TAG (AT_SUN_CPU, _("CPU name string"), str);
|
||||
TAG (AT_SUN_EMUL_ENTRY, _("COFF entry point address"), hex);
|
||||
TAG (AT_SUN_EMUL_EXECFD, _("COFF executable file descriptor"), dec);
|
||||
TAG (AT_SUN_EXECNAME,
|
||||
_("Canonicalized file name given to execve"), str);
|
||||
TAG (AT_SUN_MMU, _("String for name of MMU module"), str);
|
||||
TAG (AT_SUN_LDDATA, _("Dynamic linker's data segment address"), hex);
|
||||
}
|
||||
|
||||
fprintf_filtered (file, "%-4s %-20s %-30s ",
|
||||
paddr_d (type), name, description);
|
||||
switch (flavor)
|
||||
{
|
||||
case dec:
|
||||
fprintf_filtered (file, "%s\n", paddr_d (val));
|
||||
break;
|
||||
case hex:
|
||||
fprintf_filtered (file, "0x%s\n", paddr_nz (val));
|
||||
break;
|
||||
case str:
|
||||
if (addressprint)
|
||||
fprintf_filtered (file, "0x%s", paddr_nz (val));
|
||||
val_print_string (val, -1, 1, file);
|
||||
fprintf_filtered (file, "\n");
|
||||
break;
|
||||
}
|
||||
++ents;
|
||||
}
|
||||
|
||||
xfree (data);
|
||||
|
||||
return ents;
|
||||
}
|
||||
|
||||
static void
|
||||
info_auxv_command (char *cmd, int from_tty)
|
||||
{
|
||||
if (! target_has_stack)
|
||||
error (_("The program has no auxiliary information now."));
|
||||
else
|
||||
{
|
||||
int ents = fprint_target_auxv (gdb_stdout, ¤t_target);
|
||||
if (ents < 0)
|
||||
error (_("No auxiliary vector found, or failed reading it."));
|
||||
else if (ents == 0)
|
||||
error (_("Auxiliary vector is empty."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern initialize_file_ftype _initialize_auxv; /* -Wmissing-prototypes; */
|
||||
|
||||
void
|
||||
_initialize_auxv (void)
|
||||
{
|
||||
add_info ("auxv", info_auxv_command,
|
||||
_("Display the inferior's auxiliary vector.\n\
|
||||
This is information provided by the operating system at program startup."));
|
||||
}
|
||||
75
gdb/auxv.h
75
gdb/auxv.h
@@ -1,75 +0,0 @@
|
||||
/* Auxiliary vector support for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef AUXV_H
|
||||
#define AUXV_H
|
||||
|
||||
/* See "include/elf/common.h" for the definition of valid AT_* values. */
|
||||
|
||||
|
||||
/* Avoid miscellaneous includes in this file, so that it can be
|
||||
included by nm-*.h for the procfs_xfer_auxv decl if that is
|
||||
used in NATIVE_XFER_AUXV. */
|
||||
struct target_ops; /* Forward declaration. */
|
||||
|
||||
|
||||
/* Read all the auxv data into a contiguous xmalloc'd buffer,
|
||||
stored in *DATA. Return the size in bytes of this data.
|
||||
If zero, there is no data and *DATA is null.
|
||||
if < 0, there was an error and *DATA is null. */
|
||||
extern LONGEST target_auxv_read (struct target_ops *ops, gdb_byte **data);
|
||||
|
||||
/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
|
||||
Return 0 if *READPTR is already at the end of the buffer.
|
||||
Return -1 if there is insufficient buffer for a whole entry.
|
||||
Return 1 if an entry was read into *TYPEP and *VALP. */
|
||||
extern int target_auxv_parse (struct target_ops *ops,
|
||||
gdb_byte **readptr, gdb_byte *endptr,
|
||||
CORE_ADDR *typep, CORE_ADDR *valp);
|
||||
|
||||
/* Extract the auxiliary vector entry with a_type matching MATCH.
|
||||
Return zero if no such entry was found, or -1 if there was
|
||||
an error getting the information. On success, return 1 after
|
||||
storing the entry's value field in *VALP. */
|
||||
extern int target_auxv_search (struct target_ops *ops,
|
||||
CORE_ADDR match, CORE_ADDR *valp);
|
||||
|
||||
/* Print the contents of the target's AUXV on the specified file. */
|
||||
extern int fprint_target_auxv (struct ui_file *file, struct target_ops *ops);
|
||||
|
||||
|
||||
/* This function is called like a to_xfer_partial hook,
|
||||
but must be called with TARGET_OBJECT_AUXV.
|
||||
It handles access via /proc/PID/auxv, which is the common method.
|
||||
This function is appropriate for doing:
|
||||
#define NATIVE_XFER_AUXV procfs_xfer_auxv
|
||||
for a native target that uses inftarg.c's child_xfer_partial hook. */
|
||||
|
||||
extern LONGEST procfs_xfer_auxv (struct target_ops *ops,
|
||||
int /* enum target_object */ object,
|
||||
const char *annex,
|
||||
gdb_byte *readbuf,
|
||||
const gdb_byte *writebuf,
|
||||
ULONGEST offset,
|
||||
LONGEST len);
|
||||
|
||||
|
||||
#endif
|
||||
1416
gdb/avr-tdep.c
1416
gdb/avr-tdep.c
File diff suppressed because it is too large
Load Diff
1854
gdb/ax-gdb.c
1854
gdb/ax-gdb.c
File diff suppressed because it is too large
Load Diff
113
gdb/ax-gdb.h
113
gdb/ax-gdb.h
@@ -1,113 +0,0 @@
|
||||
/* GDB-specific functions for operating on agent expressions
|
||||
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef AX_GDB_H
|
||||
#define AX_GDB_H
|
||||
|
||||
struct expression;
|
||||
|
||||
/* Types and enums */
|
||||
|
||||
/* GDB stores expressions in the form of a flattened tree (struct
|
||||
expression), so we just walk that tree and generate agent bytecodes
|
||||
as we go along.
|
||||
|
||||
GDB's normal evaluation uses struct value, which contains the
|
||||
expression's value as well as its address or the register it came
|
||||
from. The `+' operator uses the value, whereas the unary `&'
|
||||
operator will use the address portion. The `=' operator will use
|
||||
the address or register number of its left hand side.
|
||||
|
||||
The issues are different when generating agent bytecode. Given a
|
||||
variable reference expression, we should not necessarily generate
|
||||
code to fetch its value, because the next operator may be `=' or
|
||||
unary `&'. Instead, when we recurse on a subexpression, we
|
||||
indicate whether we want that expression to produce an lvalue or an
|
||||
rvalue. If we requested an lvalue, then the recursive call tells
|
||||
us whether it generated code to compute an address on the stack, or
|
||||
whether the lvalue lives in a register.
|
||||
|
||||
The `axs' prefix here means `agent expression, static', because
|
||||
this is all static analysis of the expression, i.e. analysis which
|
||||
doesn't depend on the contents of memory and registers. */
|
||||
|
||||
|
||||
/* Different kinds of agent expression static values. */
|
||||
enum axs_lvalue_kind
|
||||
{
|
||||
/* We generated code to compute the subexpression's value.
|
||||
Constants and arithmetic operators yield this. */
|
||||
axs_rvalue,
|
||||
|
||||
/* We generated code to yield the subexpression's value's address on
|
||||
the top of the stack. If the caller needs an rvalue, it should
|
||||
call require_rvalue to produce the rvalue from this address. */
|
||||
axs_lvalue_memory,
|
||||
|
||||
/* We didn't generate any code, and the stack is undisturbed,
|
||||
because the subexpression's value lives in a register; u.reg is
|
||||
the register number. If the caller needs an rvalue, it should
|
||||
call require_rvalue to produce the rvalue from this register
|
||||
number. */
|
||||
axs_lvalue_register
|
||||
};
|
||||
|
||||
/* Structure describing what we got from a subexpression. Think of
|
||||
this as parallel to value.h's enum lval_type, except that we're
|
||||
describing a value which will exist when the expression is
|
||||
evaluated in the future, not a value we have in our hand. */
|
||||
struct axs_value
|
||||
{
|
||||
enum axs_lvalue_kind kind; /* see above */
|
||||
|
||||
/* The type of the subexpression. Even if lvalue == axs_lvalue_memory,
|
||||
this is the type of the value itself; the value on the stack is a
|
||||
"pointer to" an object of this type. */
|
||||
struct type *type;
|
||||
|
||||
union
|
||||
{
|
||||
/* if kind == axs_lvalue_register, this is the register number */
|
||||
int reg;
|
||||
}
|
||||
u;
|
||||
};
|
||||
|
||||
|
||||
/* Translating GDB expressions into agent expressions. */
|
||||
|
||||
/* Given a GDB expression EXPR, translate it into the agent bytecode,
|
||||
and return it. FLAGS are from enum expr_to_agent_flags. */
|
||||
extern struct agent_expr *expr_to_agent (struct expression *EXPR,
|
||||
struct axs_value *VALUE);
|
||||
|
||||
/* Given a GDB expression EXPR denoting an lvalue in memory, produce a
|
||||
string of agent bytecode which will leave its address and size on
|
||||
the top of stack. Return the agent expression. */
|
||||
extern struct agent_expr *expr_to_address_and_size (struct expression *EXPR);
|
||||
|
||||
/* Given a GDB expression EXPR, return bytecode to trace its value.
|
||||
The result will use the `trace' and `trace_quick' bytecodes to
|
||||
record the value of all memory touched by the expression, and leave
|
||||
no values on the stack. The caller can then use the ax_reqs
|
||||
function to discover which registers the expression uses. */
|
||||
extern struct agent_expr *gen_trace_for_expr (CORE_ADDR, struct expression *);
|
||||
|
||||
#endif /* AX_GDB_H */
|
||||
544
gdb/ax-general.c
544
gdb/ax-general.c
@@ -1,544 +0,0 @@
|
||||
/* Functions for manipulating expressions designed to be executed on the agent
|
||||
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* Despite what the above comment says about this file being part of
|
||||
GDB, we would like to keep these functions free of GDB
|
||||
dependencies, since we want to be able to use them in contexts
|
||||
outside of GDB (test suites, the stub, etc.) */
|
||||
|
||||
#include "defs.h"
|
||||
#include "ax.h"
|
||||
|
||||
#include "value.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
static void grow_expr (struct agent_expr *x, int n);
|
||||
|
||||
static void append_const (struct agent_expr *x, LONGEST val, int n);
|
||||
|
||||
static LONGEST read_const (struct agent_expr *x, int o, int n);
|
||||
|
||||
static void generic_ext (struct agent_expr *x, enum agent_op op, int n);
|
||||
|
||||
/* Functions for building expressions. */
|
||||
|
||||
/* Allocate a new, empty agent expression. */
|
||||
struct agent_expr *
|
||||
new_agent_expr (CORE_ADDR scope)
|
||||
{
|
||||
struct agent_expr *x = xmalloc (sizeof (*x));
|
||||
x->len = 0;
|
||||
x->size = 1; /* Change this to a larger value once
|
||||
reallocation code is tested. */
|
||||
x->buf = xmalloc (x->size);
|
||||
x->scope = scope;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Free a agent expression. */
|
||||
void
|
||||
free_agent_expr (struct agent_expr *x)
|
||||
{
|
||||
xfree (x->buf);
|
||||
xfree (x);
|
||||
}
|
||||
|
||||
static void
|
||||
do_free_agent_expr_cleanup (void *x)
|
||||
{
|
||||
free_agent_expr (x);
|
||||
}
|
||||
|
||||
struct cleanup *
|
||||
make_cleanup_free_agent_expr (struct agent_expr *x)
|
||||
{
|
||||
return make_cleanup (do_free_agent_expr_cleanup, x);
|
||||
}
|
||||
|
||||
|
||||
/* Make sure that X has room for at least N more bytes. This doesn't
|
||||
affect the length, just the allocated size. */
|
||||
static void
|
||||
grow_expr (struct agent_expr *x, int n)
|
||||
{
|
||||
if (x->len + n > x->size)
|
||||
{
|
||||
x->size *= 2;
|
||||
if (x->size < x->len + n)
|
||||
x->size = x->len + n + 10;
|
||||
x->buf = xrealloc (x->buf, x->size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Append the low N bytes of VAL as an N-byte integer to the
|
||||
expression X, in big-endian order. */
|
||||
static void
|
||||
append_const (struct agent_expr *x, LONGEST val, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
grow_expr (x, n);
|
||||
for (i = n - 1; i >= 0; i--)
|
||||
{
|
||||
x->buf[x->len + i] = val & 0xff;
|
||||
val >>= 8;
|
||||
}
|
||||
x->len += n;
|
||||
}
|
||||
|
||||
|
||||
/* Extract an N-byte big-endian unsigned integer from expression X at
|
||||
offset O. */
|
||||
static LONGEST
|
||||
read_const (struct agent_expr *x, int o, int n)
|
||||
{
|
||||
int i;
|
||||
LONGEST accum = 0;
|
||||
|
||||
/* Make sure we're not reading off the end of the expression. */
|
||||
if (o + n > x->len)
|
||||
error (_("GDB bug: ax-general.c (read_const): incomplete constant"));
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
accum = (accum << 8) | x->buf[o + i];
|
||||
|
||||
return accum;
|
||||
}
|
||||
|
||||
|
||||
/* Append a simple operator OP to EXPR. */
|
||||
void
|
||||
ax_simple (struct agent_expr *x, enum agent_op op)
|
||||
{
|
||||
grow_expr (x, 1);
|
||||
x->buf[x->len++] = op;
|
||||
}
|
||||
|
||||
|
||||
/* Append a sign-extension or zero-extension instruction to EXPR, to
|
||||
extend an N-bit value. */
|
||||
static void
|
||||
generic_ext (struct agent_expr *x, enum agent_op op, int n)
|
||||
{
|
||||
/* N must fit in a byte. */
|
||||
if (n < 0 || n > 255)
|
||||
error (_("GDB bug: ax-general.c (generic_ext): bit count out of range"));
|
||||
/* That had better be enough range. */
|
||||
if (sizeof (LONGEST) * 8 > 255)
|
||||
error (_("GDB bug: ax-general.c (generic_ext): opcode has inadequate range"));
|
||||
|
||||
grow_expr (x, 2);
|
||||
x->buf[x->len++] = op;
|
||||
x->buf[x->len++] = n;
|
||||
}
|
||||
|
||||
|
||||
/* Append a sign-extension instruction to EXPR, to extend an N-bit value. */
|
||||
void
|
||||
ax_ext (struct agent_expr *x, int n)
|
||||
{
|
||||
generic_ext (x, aop_ext, n);
|
||||
}
|
||||
|
||||
|
||||
/* Append a zero-extension instruction to EXPR, to extend an N-bit value. */
|
||||
void
|
||||
ax_zero_ext (struct agent_expr *x, int n)
|
||||
{
|
||||
generic_ext (x, aop_zero_ext, n);
|
||||
}
|
||||
|
||||
|
||||
/* Append a trace_quick instruction to EXPR, to record N bytes. */
|
||||
void
|
||||
ax_trace_quick (struct agent_expr *x, int n)
|
||||
{
|
||||
/* N must fit in a byte. */
|
||||
if (n < 0 || n > 255)
|
||||
error (_("GDB bug: ax-general.c (ax_trace_quick): size out of range for trace_quick"));
|
||||
|
||||
grow_expr (x, 2);
|
||||
x->buf[x->len++] = aop_trace_quick;
|
||||
x->buf[x->len++] = n;
|
||||
}
|
||||
|
||||
|
||||
/* Append a goto op to EXPR. OP is the actual op (must be aop_goto or
|
||||
aop_if_goto). We assume we don't know the target offset yet,
|
||||
because it's probably a forward branch, so we leave space in EXPR
|
||||
for the target, and return the offset in EXPR of that space, so we
|
||||
can backpatch it once we do know the target offset. Use ax_label
|
||||
to do the backpatching. */
|
||||
int
|
||||
ax_goto (struct agent_expr *x, enum agent_op op)
|
||||
{
|
||||
grow_expr (x, 3);
|
||||
x->buf[x->len + 0] = op;
|
||||
x->buf[x->len + 1] = 0xff;
|
||||
x->buf[x->len + 2] = 0xff;
|
||||
x->len += 3;
|
||||
return x->len - 2;
|
||||
}
|
||||
|
||||
/* Suppose a given call to ax_goto returns some value PATCH. When you
|
||||
know the offset TARGET that goto should jump to, call
|
||||
ax_label (EXPR, PATCH, TARGET)
|
||||
to patch TARGET into the ax_goto instruction. */
|
||||
void
|
||||
ax_label (struct agent_expr *x, int patch, int target)
|
||||
{
|
||||
/* Make sure the value is in range. Don't accept 0xffff as an
|
||||
offset; that's our magic sentinel value for unpatched branches. */
|
||||
if (target < 0 || target >= 0xffff)
|
||||
error (_("GDB bug: ax-general.c (ax_label): label target out of range"));
|
||||
|
||||
x->buf[patch] = (target >> 8) & 0xff;
|
||||
x->buf[patch + 1] = target & 0xff;
|
||||
}
|
||||
|
||||
|
||||
/* Assemble code to push a constant on the stack. */
|
||||
void
|
||||
ax_const_l (struct agent_expr *x, LONGEST l)
|
||||
{
|
||||
static enum agent_op ops[]
|
||||
=
|
||||
{aop_const8, aop_const16, aop_const32, aop_const64};
|
||||
int size;
|
||||
int op;
|
||||
|
||||
/* How big is the number? 'op' keeps track of which opcode to use.
|
||||
Notice that we don't really care whether the original number was
|
||||
signed or unsigned; we always reproduce the value exactly, and
|
||||
use the shortest representation. */
|
||||
for (op = 0, size = 8; size < 64; size *= 2, op++)
|
||||
if (-((LONGEST) 1 << size) <= l && l < ((LONGEST) 1 << size))
|
||||
break;
|
||||
|
||||
/* Emit the right opcode... */
|
||||
ax_simple (x, ops[op]);
|
||||
|
||||
/* Emit the low SIZE bytes as an unsigned number. We know that
|
||||
sign-extending this will yield l. */
|
||||
append_const (x, l, size / 8);
|
||||
|
||||
/* Now, if it was negative, and not full-sized, sign-extend it. */
|
||||
if (l < 0 && size < 64)
|
||||
ax_ext (x, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ax_const_d (struct agent_expr *x, LONGEST d)
|
||||
{
|
||||
/* FIXME: floating-point support not present yet. */
|
||||
error (_("GDB bug: ax-general.c (ax_const_d): floating point not supported yet"));
|
||||
}
|
||||
|
||||
|
||||
/* Assemble code to push the value of register number REG on the
|
||||
stack. */
|
||||
void
|
||||
ax_reg (struct agent_expr *x, int reg)
|
||||
{
|
||||
/* Make sure the register number is in range. */
|
||||
if (reg < 0 || reg > 0xffff)
|
||||
error (_("GDB bug: ax-general.c (ax_reg): register number out of range"));
|
||||
grow_expr (x, 3);
|
||||
x->buf[x->len] = aop_reg;
|
||||
x->buf[x->len + 1] = (reg >> 8) & 0xff;
|
||||
x->buf[x->len + 2] = (reg) & 0xff;
|
||||
x->len += 3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Functions for disassembling agent expressions, and otherwise
|
||||
debugging the expression compiler. */
|
||||
|
||||
struct aop_map aop_map[] =
|
||||
{
|
||||
{0, 0, 0, 0, 0},
|
||||
{"float", 0, 0, 0, 0}, /* 0x01 */
|
||||
{"add", 0, 0, 2, 1}, /* 0x02 */
|
||||
{"sub", 0, 0, 2, 1}, /* 0x03 */
|
||||
{"mul", 0, 0, 2, 1}, /* 0x04 */
|
||||
{"div_signed", 0, 0, 2, 1}, /* 0x05 */
|
||||
{"div_unsigned", 0, 0, 2, 1}, /* 0x06 */
|
||||
{"rem_signed", 0, 0, 2, 1}, /* 0x07 */
|
||||
{"rem_unsigned", 0, 0, 2, 1}, /* 0x08 */
|
||||
{"lsh", 0, 0, 2, 1}, /* 0x09 */
|
||||
{"rsh_signed", 0, 0, 2, 1}, /* 0x0a */
|
||||
{"rsh_unsigned", 0, 0, 2, 1}, /* 0x0b */
|
||||
{"trace", 0, 0, 2, 0}, /* 0x0c */
|
||||
{"trace_quick", 1, 0, 1, 1}, /* 0x0d */
|
||||
{"log_not", 0, 0, 1, 1}, /* 0x0e */
|
||||
{"bit_and", 0, 0, 2, 1}, /* 0x0f */
|
||||
{"bit_or", 0, 0, 2, 1}, /* 0x10 */
|
||||
{"bit_xor", 0, 0, 2, 1}, /* 0x11 */
|
||||
{"bit_not", 0, 0, 1, 1}, /* 0x12 */
|
||||
{"equal", 0, 0, 2, 1}, /* 0x13 */
|
||||
{"less_signed", 0, 0, 2, 1}, /* 0x14 */
|
||||
{"less_unsigned", 0, 0, 2, 1}, /* 0x15 */
|
||||
{"ext", 1, 0, 1, 1}, /* 0x16 */
|
||||
{"ref8", 0, 8, 1, 1}, /* 0x17 */
|
||||
{"ref16", 0, 16, 1, 1}, /* 0x18 */
|
||||
{"ref32", 0, 32, 1, 1}, /* 0x19 */
|
||||
{"ref64", 0, 64, 1, 1}, /* 0x1a */
|
||||
{"ref_float", 0, 0, 1, 1}, /* 0x1b */
|
||||
{"ref_double", 0, 0, 1, 1}, /* 0x1c */
|
||||
{"ref_long_double", 0, 0, 1, 1}, /* 0x1d */
|
||||
{"l_to_d", 0, 0, 1, 1}, /* 0x1e */
|
||||
{"d_to_l", 0, 0, 1, 1}, /* 0x1f */
|
||||
{"if_goto", 2, 0, 1, 0}, /* 0x20 */
|
||||
{"goto", 2, 0, 0, 0}, /* 0x21 */
|
||||
{"const8", 1, 8, 0, 1}, /* 0x22 */
|
||||
{"const16", 2, 16, 0, 1}, /* 0x23 */
|
||||
{"const32", 4, 32, 0, 1}, /* 0x24 */
|
||||
{"const64", 8, 64, 0, 1}, /* 0x25 */
|
||||
{"reg", 2, 0, 0, 1}, /* 0x26 */
|
||||
{"end", 0, 0, 0, 0}, /* 0x27 */
|
||||
{"dup", 0, 0, 1, 2}, /* 0x28 */
|
||||
{"pop", 0, 0, 1, 0}, /* 0x29 */
|
||||
{"zero_ext", 1, 0, 1, 1}, /* 0x2a */
|
||||
{"swap", 0, 0, 2, 2}, /* 0x2b */
|
||||
{0, 0, 0, 0, 0}, /* 0x2c */
|
||||
{0, 0, 0, 0, 0}, /* 0x2d */
|
||||
{0, 0, 0, 0, 0}, /* 0x2e */
|
||||
{0, 0, 0, 0, 0}, /* 0x2f */
|
||||
{"trace16", 2, 0, 1, 1}, /* 0x30 */
|
||||
};
|
||||
|
||||
|
||||
/* Disassemble the expression EXPR, writing to F. */
|
||||
void
|
||||
ax_print (struct ui_file *f, struct agent_expr *x)
|
||||
{
|
||||
int i;
|
||||
int is_float = 0;
|
||||
|
||||
/* Check the size of the name array against the number of entries in
|
||||
the enum, to catch additions that people didn't sync. */
|
||||
if ((sizeof (aop_map) / sizeof (aop_map[0]))
|
||||
!= aop_last)
|
||||
error (_("GDB bug: ax-general.c (ax_print): opcode map out of sync"));
|
||||
|
||||
for (i = 0; i < x->len;)
|
||||
{
|
||||
enum agent_op op = x->buf[i];
|
||||
|
||||
if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
|
||||
|| !aop_map[op].name)
|
||||
{
|
||||
fprintf_filtered (f, _("%3d <bad opcode %02x>\n"), i, op);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (i + 1 + aop_map[op].op_size > x->len)
|
||||
{
|
||||
fprintf_filtered (f, _("%3d <incomplete opcode %s>\n"),
|
||||
i, aop_map[op].name);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf_filtered (f, "%3d %s", i, aop_map[op].name);
|
||||
if (aop_map[op].op_size > 0)
|
||||
{
|
||||
fputs_filtered (" ", f);
|
||||
|
||||
print_longest (f, 'd', 0,
|
||||
read_const (x, i + 1, aop_map[op].op_size));
|
||||
}
|
||||
fprintf_filtered (f, "\n");
|
||||
i += 1 + aop_map[op].op_size;
|
||||
|
||||
is_float = (op == aop_float);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Given an agent expression AX, fill in an agent_reqs structure REQS
|
||||
describing it. */
|
||||
void
|
||||
ax_reqs (struct agent_expr *ax, struct agent_reqs *reqs)
|
||||
{
|
||||
int i;
|
||||
int height;
|
||||
|
||||
/* Bit vector for registers used. */
|
||||
int reg_mask_len = 1;
|
||||
unsigned char *reg_mask = xmalloc (reg_mask_len * sizeof (reg_mask[0]));
|
||||
|
||||
/* Jump target table. targets[i] is non-zero iff we have found a
|
||||
jump to offset i. */
|
||||
char *targets = (char *) alloca (ax->len * sizeof (targets[0]));
|
||||
|
||||
/* Instruction boundary table. boundary[i] is non-zero iff our scan
|
||||
has reached an instruction starting at offset i. */
|
||||
char *boundary = (char *) alloca (ax->len * sizeof (boundary[0]));
|
||||
|
||||
/* Stack height record. If either targets[i] or boundary[i] is
|
||||
non-zero, heights[i] is the height the stack should have before
|
||||
executing the bytecode at that point. */
|
||||
int *heights = (int *) alloca (ax->len * sizeof (heights[0]));
|
||||
|
||||
/* Pointer to a description of the present op. */
|
||||
struct aop_map *op;
|
||||
|
||||
memset (reg_mask, 0, reg_mask_len * sizeof (reg_mask[0]));
|
||||
memset (targets, 0, ax->len * sizeof (targets[0]));
|
||||
memset (boundary, 0, ax->len * sizeof (boundary[0]));
|
||||
|
||||
reqs->max_height = reqs->min_height = height = 0;
|
||||
reqs->flaw = agent_flaw_none;
|
||||
reqs->max_data_size = 0;
|
||||
|
||||
for (i = 0; i < ax->len; i += 1 + op->op_size)
|
||||
{
|
||||
if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
|
||||
{
|
||||
reqs->flaw = agent_flaw_bad_instruction;
|
||||
xfree (reg_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
op = &aop_map[ax->buf[i]];
|
||||
|
||||
if (!op->name)
|
||||
{
|
||||
reqs->flaw = agent_flaw_bad_instruction;
|
||||
xfree (reg_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
if (i + 1 + op->op_size > ax->len)
|
||||
{
|
||||
reqs->flaw = agent_flaw_incomplete_instruction;
|
||||
xfree (reg_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If this instruction is a forward jump target, does the
|
||||
current stack height match the stack height at the jump
|
||||
source? */
|
||||
if (targets[i] && (heights[i] != height))
|
||||
{
|
||||
reqs->flaw = agent_flaw_height_mismatch;
|
||||
xfree (reg_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
boundary[i] = 1;
|
||||
heights[i] = height;
|
||||
|
||||
height -= op->consumed;
|
||||
if (height < reqs->min_height)
|
||||
reqs->min_height = height;
|
||||
height += op->produced;
|
||||
if (height > reqs->max_height)
|
||||
reqs->max_height = height;
|
||||
|
||||
if (op->data_size > reqs->max_data_size)
|
||||
reqs->max_data_size = op->data_size;
|
||||
|
||||
/* For jump instructions, check that the target is a valid
|
||||
offset. If it is, record the fact that that location is a
|
||||
jump target, and record the height we expect there. */
|
||||
if (aop_goto == op - aop_map
|
||||
|| aop_if_goto == op - aop_map)
|
||||
{
|
||||
int target = read_const (ax, i + 1, 2);
|
||||
if (target < 0 || target >= ax->len)
|
||||
{
|
||||
reqs->flaw = agent_flaw_bad_jump;
|
||||
xfree (reg_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do we have any information about what the stack height
|
||||
should be at the target? */
|
||||
if (targets[target] || boundary[target])
|
||||
{
|
||||
if (heights[target] != height)
|
||||
{
|
||||
reqs->flaw = agent_flaw_height_mismatch;
|
||||
xfree (reg_mask);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Record the target, along with the stack height we expect. */
|
||||
targets[target] = 1;
|
||||
heights[target] = height;
|
||||
}
|
||||
|
||||
/* For unconditional jumps with a successor, check that the
|
||||
successor is a target, and pick up its stack height. */
|
||||
if (aop_goto == op - aop_map
|
||||
&& i + 3 < ax->len)
|
||||
{
|
||||
if (!targets[i + 3])
|
||||
{
|
||||
reqs->flaw = agent_flaw_hole;
|
||||
xfree (reg_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
height = heights[i + 3];
|
||||
}
|
||||
|
||||
/* For reg instructions, record the register in the bit mask. */
|
||||
if (aop_reg == op - aop_map)
|
||||
{
|
||||
int reg = read_const (ax, i + 1, 2);
|
||||
int byte = reg / 8;
|
||||
|
||||
/* Grow the bit mask if necessary. */
|
||||
if (byte >= reg_mask_len)
|
||||
{
|
||||
/* It's not appropriate to double here. This isn't a
|
||||
string buffer. */
|
||||
int new_len = byte + 1;
|
||||
reg_mask = xrealloc (reg_mask,
|
||||
new_len * sizeof (reg_mask[0]));
|
||||
memset (reg_mask + reg_mask_len, 0,
|
||||
(new_len - reg_mask_len) * sizeof (reg_mask[0]));
|
||||
reg_mask_len = new_len;
|
||||
}
|
||||
|
||||
reg_mask[byte] |= 1 << (reg % 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that all the targets are on boundaries. */
|
||||
for (i = 0; i < ax->len; i++)
|
||||
if (targets[i] && !boundary[i])
|
||||
{
|
||||
reqs->flaw = agent_flaw_bad_jump;
|
||||
xfree (reg_mask);
|
||||
return;
|
||||
}
|
||||
|
||||
reqs->final_height = height;
|
||||
reqs->reg_mask_len = reg_mask_len;
|
||||
reqs->reg_mask = reg_mask;
|
||||
}
|
||||
292
gdb/ax.h
292
gdb/ax.h
@@ -1,292 +0,0 @@
|
||||
/* Definitions for expressions designed to be executed on the agent
|
||||
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef AGENTEXPR_H
|
||||
#define AGENTEXPR_H
|
||||
|
||||
#include "doublest.h" /* For DOUBLEST. */
|
||||
|
||||
/* It's sometimes useful to be able to debug programs that you can't
|
||||
really stop for more than a fraction of a second. To this end, the
|
||||
user can specify a tracepoint (like a breakpoint, but you don't
|
||||
stop at it), and specify a bunch of expressions to record the
|
||||
values of when that tracepoint is reached. As the program runs,
|
||||
GDB collects the values. At any point (possibly while values are
|
||||
still being collected), the user can display the collected values.
|
||||
|
||||
This is used with remote debugging; we don't really support it on
|
||||
native configurations.
|
||||
|
||||
This means that expressions are being evaluated by the remote agent,
|
||||
which doesn't have any access to the symbol table information, and
|
||||
needs to be small and simple.
|
||||
|
||||
The agent_expr routines and datatypes are a bytecode language
|
||||
designed to be executed by the agent. Agent expressions work in
|
||||
terms of fixed-width values, operators, memory references, and
|
||||
register references. You can evaluate a agent expression just given
|
||||
a bunch of memory and register values to sniff at; you don't need
|
||||
any symbolic information like variable names, types, etc.
|
||||
|
||||
GDB translates source expressions, whose meaning depends on
|
||||
symbolic information, into agent bytecode expressions, whose meaning
|
||||
is independent of symbolic information. This means the agent can
|
||||
evaluate them on the fly without reference to data only available
|
||||
to the host GDB. */
|
||||
|
||||
|
||||
/* Agent expression data structures. */
|
||||
|
||||
/* The type of an element of the agent expression stack.
|
||||
The bytecode operation indicates which element we should access;
|
||||
the value itself has no typing information. GDB generates all
|
||||
bytecode streams, so we don't have to worry about type errors. */
|
||||
|
||||
union agent_val
|
||||
{
|
||||
LONGEST l;
|
||||
DOUBLEST d;
|
||||
};
|
||||
|
||||
/* A buffer containing a agent expression. */
|
||||
struct agent_expr
|
||||
{
|
||||
unsigned char *buf;
|
||||
int len; /* number of characters used */
|
||||
int size; /* allocated size */
|
||||
CORE_ADDR scope;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* The actual values of the various bytecode operations.
|
||||
|
||||
Other independent implementations of the agent bytecode engine will
|
||||
rely on the exact values of these enums, and may not be recompiled
|
||||
when we change this table. The numeric values should remain fixed
|
||||
whenever possible. Thus, we assign them values explicitly here (to
|
||||
allow gaps to form safely), and the disassembly table in
|
||||
agentexpr.h behaves like an opcode map. If you want to see them
|
||||
grouped logically, see doc/agentexpr.texi. */
|
||||
|
||||
enum agent_op
|
||||
{
|
||||
aop_float = 0x01,
|
||||
aop_add = 0x02,
|
||||
aop_sub = 0x03,
|
||||
aop_mul = 0x04,
|
||||
aop_div_signed = 0x05,
|
||||
aop_div_unsigned = 0x06,
|
||||
aop_rem_signed = 0x07,
|
||||
aop_rem_unsigned = 0x08,
|
||||
aop_lsh = 0x09,
|
||||
aop_rsh_signed = 0x0a,
|
||||
aop_rsh_unsigned = 0x0b,
|
||||
aop_trace = 0x0c,
|
||||
aop_trace_quick = 0x0d,
|
||||
aop_log_not = 0x0e,
|
||||
aop_bit_and = 0x0f,
|
||||
aop_bit_or = 0x10,
|
||||
aop_bit_xor = 0x11,
|
||||
aop_bit_not = 0x12,
|
||||
aop_equal = 0x13,
|
||||
aop_less_signed = 0x14,
|
||||
aop_less_unsigned = 0x15,
|
||||
aop_ext = 0x16,
|
||||
aop_ref8 = 0x17,
|
||||
aop_ref16 = 0x18,
|
||||
aop_ref32 = 0x19,
|
||||
aop_ref64 = 0x1a,
|
||||
aop_ref_float = 0x1b,
|
||||
aop_ref_double = 0x1c,
|
||||
aop_ref_long_double = 0x1d,
|
||||
aop_l_to_d = 0x1e,
|
||||
aop_d_to_l = 0x1f,
|
||||
aop_if_goto = 0x20,
|
||||
aop_goto = 0x21,
|
||||
aop_const8 = 0x22,
|
||||
aop_const16 = 0x23,
|
||||
aop_const32 = 0x24,
|
||||
aop_const64 = 0x25,
|
||||
aop_reg = 0x26,
|
||||
aop_end = 0x27,
|
||||
aop_dup = 0x28,
|
||||
aop_pop = 0x29,
|
||||
aop_zero_ext = 0x2a,
|
||||
aop_swap = 0x2b,
|
||||
aop_trace16 = 0x30,
|
||||
aop_last
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Functions for building expressions. */
|
||||
|
||||
/* Allocate a new, empty agent expression. */
|
||||
extern struct agent_expr *new_agent_expr (CORE_ADDR);
|
||||
|
||||
/* Free a agent expression. */
|
||||
extern void free_agent_expr (struct agent_expr *);
|
||||
extern struct cleanup *make_cleanup_free_agent_expr (struct agent_expr *);
|
||||
|
||||
/* Append a simple operator OP to EXPR. */
|
||||
extern void ax_simple (struct agent_expr *EXPR, enum agent_op OP);
|
||||
|
||||
/* Append the floating-point prefix, for the next bytecode. */
|
||||
#define ax_float(EXPR) (ax_simple ((EXPR), aop_float))
|
||||
|
||||
/* Append a sign-extension instruction to EXPR, to extend an N-bit value. */
|
||||
extern void ax_ext (struct agent_expr *EXPR, int N);
|
||||
|
||||
/* Append a zero-extension instruction to EXPR, to extend an N-bit value. */
|
||||
extern void ax_zero_ext (struct agent_expr *EXPR, int N);
|
||||
|
||||
/* Append a trace_quick instruction to EXPR, to record N bytes. */
|
||||
extern void ax_trace_quick (struct agent_expr *EXPR, int N);
|
||||
|
||||
/* Append a goto op to EXPR. OP is the actual op (must be aop_goto or
|
||||
aop_if_goto). We assume we don't know the target offset yet,
|
||||
because it's probably a forward branch, so we leave space in EXPR
|
||||
for the target, and return the offset in EXPR of that space, so we
|
||||
can backpatch it once we do know the target offset. Use ax_label
|
||||
to do the backpatching. */
|
||||
extern int ax_goto (struct agent_expr *EXPR, enum agent_op OP);
|
||||
|
||||
/* Suppose a given call to ax_goto returns some value PATCH. When you
|
||||
know the offset TARGET that goto should jump to, call
|
||||
ax_label (EXPR, PATCH, TARGET)
|
||||
to patch TARGET into the ax_goto instruction. */
|
||||
extern void ax_label (struct agent_expr *EXPR, int patch, int target);
|
||||
|
||||
/* Assemble code to push a constant on the stack. */
|
||||
extern void ax_const_l (struct agent_expr *EXPR, LONGEST l);
|
||||
extern void ax_const_d (struct agent_expr *EXPR, LONGEST d);
|
||||
|
||||
/* Assemble code to push the value of register number REG on the
|
||||
stack. */
|
||||
extern void ax_reg (struct agent_expr *EXPR, int REG);
|
||||
|
||||
|
||||
/* Functions for printing out expressions, and otherwise debugging
|
||||
things. */
|
||||
|
||||
/* Disassemble the expression EXPR, writing to F. */
|
||||
extern void ax_print (struct ui_file *f, struct agent_expr * EXPR);
|
||||
|
||||
/* An entry in the opcode map. */
|
||||
struct aop_map
|
||||
{
|
||||
|
||||
/* The name of the opcode. Null means that this entry is not a
|
||||
valid opcode --- a hole in the opcode space. */
|
||||
char *name;
|
||||
|
||||
/* All opcodes take no operands from the bytecode stream, or take
|
||||
unsigned integers of various sizes. If this is a positive number
|
||||
n, then the opcode is followed by an n-byte operand, which should
|
||||
be printed as an unsigned integer. If this is zero, then the
|
||||
opcode takes no operands from the bytecode stream.
|
||||
|
||||
If we get more complicated opcodes in the future, don't add other
|
||||
magic values of this; that's a crock. Add an `enum encoding'
|
||||
field to this, or something like that. */
|
||||
int op_size;
|
||||
|
||||
/* The size of the data operated upon, in bits, for bytecodes that
|
||||
care about that (ref and const). Zero for all others. */
|
||||
int data_size;
|
||||
|
||||
/* Number of stack elements consumed, and number produced. */
|
||||
int consumed, produced;
|
||||
};
|
||||
|
||||
/* Map of the bytecodes, indexed by bytecode number. */
|
||||
extern struct aop_map aop_map[];
|
||||
|
||||
/* Different kinds of flaws an agent expression might have, as
|
||||
detected by agent_reqs. */
|
||||
enum agent_flaws
|
||||
{
|
||||
agent_flaw_none = 0, /* code is good */
|
||||
|
||||
/* There is an invalid instruction in the stream. */
|
||||
agent_flaw_bad_instruction,
|
||||
|
||||
/* There is an incomplete instruction at the end of the expression. */
|
||||
agent_flaw_incomplete_instruction,
|
||||
|
||||
/* agent_reqs was unable to prove that every jump target is to a
|
||||
valid offset. Valid offsets are within the bounds of the
|
||||
expression, and to a valid instruction boundary. */
|
||||
agent_flaw_bad_jump,
|
||||
|
||||
/* agent_reqs was unable to prove to its satisfaction that, for each
|
||||
jump target location, the stack will have the same height whether
|
||||
that location is reached via a jump or by straight execution. */
|
||||
agent_flaw_height_mismatch,
|
||||
|
||||
/* agent_reqs was unable to prove that every instruction following
|
||||
an unconditional jump was the target of some other jump. */
|
||||
agent_flaw_hole
|
||||
};
|
||||
|
||||
/* Structure describing the requirements of a bytecode expression. */
|
||||
struct agent_reqs
|
||||
{
|
||||
|
||||
/* If the following is not equal to agent_flaw_none, the rest of the
|
||||
information in this structure is suspect. */
|
||||
enum agent_flaws flaw;
|
||||
|
||||
/* Number of elements left on stack at end; may be negative if expr
|
||||
only consumes elements. */
|
||||
int final_height;
|
||||
|
||||
/* Maximum and minimum stack height, relative to initial height. */
|
||||
int max_height, min_height;
|
||||
|
||||
/* Largest `ref' or `const' opcode used, in bits. Zero means the
|
||||
expression has no such instructions. */
|
||||
int max_data_size;
|
||||
|
||||
/* Bit vector of registers used. Register R is used iff
|
||||
|
||||
reg_mask[R / 8] & (1 << (R % 8))
|
||||
|
||||
is non-zero. Note! You may not assume that this bitmask is long
|
||||
enough to hold bits for all the registers of the machine; the
|
||||
agent expression code has no idea how many registers the machine
|
||||
has. However, the bitmask is reg_mask_len bytes long, so the
|
||||
valid register numbers run from 0 to reg_mask_len * 8 - 1.
|
||||
|
||||
We're assuming eight-bit bytes. So sue me.
|
||||
|
||||
The caller should free reg_list when done. */
|
||||
int reg_mask_len;
|
||||
unsigned char *reg_mask;
|
||||
};
|
||||
|
||||
|
||||
/* Given an agent expression AX, fill in an agent_reqs structure REQS
|
||||
describing it. */
|
||||
extern void ax_reqs (struct agent_expr *ax, struct agent_reqs *reqs);
|
||||
|
||||
#endif /* AGENTEXPR_H */
|
||||
442
gdb/bcache.c
442
gdb/bcache.c
@@ -1,442 +0,0 @@
|
||||
/* Implement a cached obstack.
|
||||
Written by Fred Fish <fnf@cygnus.com>
|
||||
Rewritten by Jim Blandy <jimb@cygnus.com>
|
||||
|
||||
Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdb_obstack.h"
|
||||
#include "bcache.h"
|
||||
#include "gdb_string.h" /* For memcpy declaration */
|
||||
#include "gdb_assert.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* The type used to hold a single bcache string. The user data is
|
||||
stored in d.data. Since it can be any type, it needs to have the
|
||||
same alignment as the most strict alignment of any type on the host
|
||||
machine. I don't know of any really correct way to do this in
|
||||
stock ANSI C, so just do it the same way obstack.h does. */
|
||||
|
||||
struct bstring
|
||||
{
|
||||
/* Hash chain. */
|
||||
struct bstring *next;
|
||||
/* Assume the data length is no more than 64k. */
|
||||
unsigned short length;
|
||||
/* The half hash hack. This contains the upper 16 bits of the hash
|
||||
value and is used as a pre-check when comparing two strings and
|
||||
avoids the need to do length or memcmp calls. It proves to be
|
||||
roughly 100% effective. */
|
||||
unsigned short half_hash;
|
||||
|
||||
union
|
||||
{
|
||||
char data[1];
|
||||
double dummy;
|
||||
}
|
||||
d;
|
||||
};
|
||||
|
||||
|
||||
/* The structure for a bcache itself. The bcache is initialized, in
|
||||
bcache_xmalloc(), by filling it with zeros and then setting the
|
||||
corresponding obstack's malloc() and free() methods. */
|
||||
|
||||
struct bcache
|
||||
{
|
||||
/* All the bstrings are allocated here. */
|
||||
struct obstack cache;
|
||||
|
||||
/* How many hash buckets we're using. */
|
||||
unsigned int num_buckets;
|
||||
|
||||
/* Hash buckets. This table is allocated using malloc, so when we
|
||||
grow the table we can return the old table to the system. */
|
||||
struct bstring **bucket;
|
||||
|
||||
/* Statistics. */
|
||||
unsigned long unique_count; /* number of unique strings */
|
||||
long total_count; /* total number of strings cached, including dups */
|
||||
long unique_size; /* size of unique strings, in bytes */
|
||||
long total_size; /* total number of bytes cached, including dups */
|
||||
long structure_size; /* total size of bcache, including infrastructure */
|
||||
/* Number of times that the hash table is expanded and hence
|
||||
re-built, and the corresponding number of times that a string is
|
||||
[re]hashed as part of entering it into the expanded table. The
|
||||
total number of hashes can be computed by adding TOTAL_COUNT to
|
||||
expand_hash_count. */
|
||||
unsigned long expand_count;
|
||||
unsigned long expand_hash_count;
|
||||
/* Number of times that the half-hash compare hit (compare the upper
|
||||
16 bits of hash values) hit, but the corresponding combined
|
||||
length/data compare missed. */
|
||||
unsigned long half_hash_miss_count;
|
||||
};
|
||||
|
||||
/* The old hash function was stolen from SDBM. This is what DB 3.0 uses now,
|
||||
* and is better than the old one.
|
||||
*/
|
||||
|
||||
unsigned long
|
||||
hash(const void *addr, int length)
|
||||
{
|
||||
const unsigned char *k, *e;
|
||||
unsigned long h;
|
||||
|
||||
k = (const unsigned char *)addr;
|
||||
e = k+length;
|
||||
for (h=0; k< e;++k)
|
||||
{
|
||||
h *=16777619;
|
||||
h ^= *k;
|
||||
}
|
||||
return (h);
|
||||
}
|
||||
|
||||
/* Growing the bcache's hash table. */
|
||||
|
||||
/* If the average chain length grows beyond this, then we want to
|
||||
resize our hash table. */
|
||||
#define CHAIN_LENGTH_THRESHOLD (5)
|
||||
|
||||
static void
|
||||
expand_hash_table (struct bcache *bcache)
|
||||
{
|
||||
/* A table of good hash table sizes. Whenever we grow, we pick the
|
||||
next larger size from this table. sizes[i] is close to 1 << (i+10),
|
||||
so we roughly double the table size each time. After we fall off
|
||||
the end of this table, we just double. Don't laugh --- there have
|
||||
been executables sighted with a gigabyte of debug info. */
|
||||
static unsigned long sizes[] = {
|
||||
1021, 2053, 4099, 8191, 16381, 32771,
|
||||
65537, 131071, 262144, 524287, 1048573, 2097143,
|
||||
4194301, 8388617, 16777213, 33554467, 67108859, 134217757,
|
||||
268435459, 536870923, 1073741827, 2147483659UL
|
||||
};
|
||||
unsigned int new_num_buckets;
|
||||
struct bstring **new_buckets;
|
||||
unsigned int i;
|
||||
|
||||
/* Count the stats. Every unique item needs to be re-hashed and
|
||||
re-entered. */
|
||||
bcache->expand_count++;
|
||||
bcache->expand_hash_count += bcache->unique_count;
|
||||
|
||||
/* Find the next size. */
|
||||
new_num_buckets = bcache->num_buckets * 2;
|
||||
for (i = 0; i < (sizeof (sizes) / sizeof (sizes[0])); i++)
|
||||
if (sizes[i] > bcache->num_buckets)
|
||||
{
|
||||
new_num_buckets = sizes[i];
|
||||
break;
|
||||
}
|
||||
|
||||
/* Allocate the new table. */
|
||||
{
|
||||
size_t new_size = new_num_buckets * sizeof (new_buckets[0]);
|
||||
new_buckets = (struct bstring **) xmalloc (new_size);
|
||||
memset (new_buckets, 0, new_size);
|
||||
|
||||
bcache->structure_size -= (bcache->num_buckets
|
||||
* sizeof (bcache->bucket[0]));
|
||||
bcache->structure_size += new_size;
|
||||
}
|
||||
|
||||
/* Rehash all existing strings. */
|
||||
for (i = 0; i < bcache->num_buckets; i++)
|
||||
{
|
||||
struct bstring *s, *next;
|
||||
|
||||
for (s = bcache->bucket[i]; s; s = next)
|
||||
{
|
||||
struct bstring **new_bucket;
|
||||
next = s->next;
|
||||
|
||||
new_bucket = &new_buckets[(hash (&s->d.data, s->length)
|
||||
% new_num_buckets)];
|
||||
s->next = *new_bucket;
|
||||
*new_bucket = s;
|
||||
}
|
||||
}
|
||||
|
||||
/* Plug in the new table. */
|
||||
if (bcache->bucket)
|
||||
xfree (bcache->bucket);
|
||||
bcache->bucket = new_buckets;
|
||||
bcache->num_buckets = new_num_buckets;
|
||||
}
|
||||
|
||||
|
||||
/* Looking up things in the bcache. */
|
||||
|
||||
/* The number of bytes needed to allocate a struct bstring whose data
|
||||
is N bytes long. */
|
||||
#define BSTRING_SIZE(n) (offsetof (struct bstring, d.data) + (n))
|
||||
|
||||
/* Find a copy of the LENGTH bytes at ADDR in BCACHE. If BCACHE has
|
||||
never seen those bytes before, add a copy of them to BCACHE. In
|
||||
either case, return a pointer to BCACHE's copy of that string. */
|
||||
static void *
|
||||
bcache_data (const void *addr, int length, struct bcache *bcache)
|
||||
{
|
||||
unsigned long full_hash;
|
||||
unsigned short half_hash;
|
||||
int hash_index;
|
||||
struct bstring *s;
|
||||
|
||||
/* If our average chain length is too high, expand the hash table. */
|
||||
if (bcache->unique_count >= bcache->num_buckets * CHAIN_LENGTH_THRESHOLD)
|
||||
expand_hash_table (bcache);
|
||||
|
||||
bcache->total_count++;
|
||||
bcache->total_size += length;
|
||||
|
||||
full_hash = hash (addr, length);
|
||||
half_hash = (full_hash >> 16);
|
||||
hash_index = full_hash % bcache->num_buckets;
|
||||
|
||||
/* Search the hash bucket for a string identical to the caller's.
|
||||
As a short-circuit first compare the upper part of each hash
|
||||
values. */
|
||||
for (s = bcache->bucket[hash_index]; s; s = s->next)
|
||||
{
|
||||
if (s->half_hash == half_hash)
|
||||
{
|
||||
if (s->length == length
|
||||
&& ! memcmp (&s->d.data, addr, length))
|
||||
return &s->d.data;
|
||||
else
|
||||
bcache->half_hash_miss_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* The user's string isn't in the list. Insert it after *ps. */
|
||||
{
|
||||
struct bstring *new
|
||||
= obstack_alloc (&bcache->cache, BSTRING_SIZE (length));
|
||||
memcpy (&new->d.data, addr, length);
|
||||
new->length = length;
|
||||
new->next = bcache->bucket[hash_index];
|
||||
new->half_hash = half_hash;
|
||||
bcache->bucket[hash_index] = new;
|
||||
|
||||
bcache->unique_count++;
|
||||
bcache->unique_size += length;
|
||||
bcache->structure_size += BSTRING_SIZE (length);
|
||||
|
||||
return &new->d.data;
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
deprecated_bcache (const void *addr, int length, struct bcache *bcache)
|
||||
{
|
||||
return bcache_data (addr, length, bcache);
|
||||
}
|
||||
|
||||
const void *
|
||||
bcache (const void *addr, int length, struct bcache *bcache)
|
||||
{
|
||||
return bcache_data (addr, length, bcache);
|
||||
}
|
||||
|
||||
/* Allocating and freeing bcaches. */
|
||||
|
||||
struct bcache *
|
||||
bcache_xmalloc (void)
|
||||
{
|
||||
/* Allocate the bcache pre-zeroed. */
|
||||
struct bcache *b = XCALLOC (1, struct bcache);
|
||||
/* We could use obstack_specify_allocation here instead, but
|
||||
gdb_obstack.h specifies the allocation/deallocation
|
||||
functions. */
|
||||
obstack_init (&b->cache);
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Free all the storage associated with BCACHE. */
|
||||
void
|
||||
bcache_xfree (struct bcache *bcache)
|
||||
{
|
||||
if (bcache == NULL)
|
||||
return;
|
||||
obstack_free (&bcache->cache, 0);
|
||||
xfree (bcache->bucket);
|
||||
xfree (bcache);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Printing statistics. */
|
||||
|
||||
static int
|
||||
compare_ints (const void *ap, const void *bp)
|
||||
{
|
||||
/* Because we know we're comparing two ints which are positive,
|
||||
there's no danger of overflow here. */
|
||||
return * (int *) ap - * (int *) bp;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_percentage (int portion, int total)
|
||||
{
|
||||
if (total == 0)
|
||||
/* i18n: Like "Percentage of duplicates, by count: (not applicable)" */
|
||||
printf_filtered (_("(not applicable)\n"));
|
||||
else
|
||||
printf_filtered ("%3d%%\n", (int) (portion * 100.0 / total));
|
||||
}
|
||||
|
||||
|
||||
/* Print statistics on BCACHE's memory usage and efficacity at
|
||||
eliminating duplication. NAME should describe the kind of data
|
||||
BCACHE holds. Statistics are printed using `printf_filtered' and
|
||||
its ilk. */
|
||||
void
|
||||
print_bcache_statistics (struct bcache *c, char *type)
|
||||
{
|
||||
int occupied_buckets;
|
||||
int max_chain_length;
|
||||
int median_chain_length;
|
||||
int max_entry_size;
|
||||
int median_entry_size;
|
||||
|
||||
/* Count the number of occupied buckets, tally the various string
|
||||
lengths, and measure chain lengths. */
|
||||
{
|
||||
unsigned int b;
|
||||
int *chain_length = XCALLOC (c->num_buckets + 1, int);
|
||||
int *entry_size = XCALLOC (c->unique_count + 1, int);
|
||||
int stringi = 0;
|
||||
|
||||
occupied_buckets = 0;
|
||||
|
||||
for (b = 0; b < c->num_buckets; b++)
|
||||
{
|
||||
struct bstring *s = c->bucket[b];
|
||||
|
||||
chain_length[b] = 0;
|
||||
|
||||
if (s)
|
||||
{
|
||||
occupied_buckets++;
|
||||
|
||||
while (s)
|
||||
{
|
||||
gdb_assert (b < c->num_buckets);
|
||||
chain_length[b]++;
|
||||
gdb_assert (stringi < c->unique_count);
|
||||
entry_size[stringi++] = s->length;
|
||||
s = s->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* To compute the median, we need the set of chain lengths sorted. */
|
||||
qsort (chain_length, c->num_buckets, sizeof (chain_length[0]),
|
||||
compare_ints);
|
||||
qsort (entry_size, c->unique_count, sizeof (entry_size[0]),
|
||||
compare_ints);
|
||||
|
||||
if (c->num_buckets > 0)
|
||||
{
|
||||
max_chain_length = chain_length[c->num_buckets - 1];
|
||||
median_chain_length = chain_length[c->num_buckets / 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
max_chain_length = 0;
|
||||
median_chain_length = 0;
|
||||
}
|
||||
if (c->unique_count > 0)
|
||||
{
|
||||
max_entry_size = entry_size[c->unique_count - 1];
|
||||
median_entry_size = entry_size[c->unique_count / 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
max_entry_size = 0;
|
||||
median_entry_size = 0;
|
||||
}
|
||||
|
||||
xfree (chain_length);
|
||||
xfree (entry_size);
|
||||
}
|
||||
|
||||
printf_filtered (_(" Cached '%s' statistics:\n"), type);
|
||||
printf_filtered (_(" Total object count: %ld\n"), c->total_count);
|
||||
printf_filtered (_(" Unique object count: %lu\n"), c->unique_count);
|
||||
printf_filtered (_(" Percentage of duplicates, by count: "));
|
||||
print_percentage (c->total_count - c->unique_count, c->total_count);
|
||||
printf_filtered ("\n");
|
||||
|
||||
printf_filtered (_(" Total object size: %ld\n"), c->total_size);
|
||||
printf_filtered (_(" Unique object size: %ld\n"), c->unique_size);
|
||||
printf_filtered (_(" Percentage of duplicates, by size: "));
|
||||
print_percentage (c->total_size - c->unique_size, c->total_size);
|
||||
printf_filtered ("\n");
|
||||
|
||||
printf_filtered (_(" Max entry size: %d\n"), max_entry_size);
|
||||
printf_filtered (_(" Average entry size: "));
|
||||
if (c->unique_count > 0)
|
||||
printf_filtered ("%ld\n", c->unique_size / c->unique_count);
|
||||
else
|
||||
/* i18n: "Average entry size: (not applicable)" */
|
||||
printf_filtered (_("(not applicable)\n"));
|
||||
printf_filtered (_(" Median entry size: %d\n"), median_entry_size);
|
||||
printf_filtered ("\n");
|
||||
|
||||
printf_filtered (_(" Total memory used by bcache, including overhead: %ld\n"),
|
||||
c->structure_size);
|
||||
printf_filtered (_(" Percentage memory overhead: "));
|
||||
print_percentage (c->structure_size - c->unique_size, c->unique_size);
|
||||
printf_filtered (_(" Net memory savings: "));
|
||||
print_percentage (c->total_size - c->structure_size, c->total_size);
|
||||
printf_filtered ("\n");
|
||||
|
||||
printf_filtered (_(" Hash table size: %3d\n"), c->num_buckets);
|
||||
printf_filtered (_(" Hash table expands: %lu\n"),
|
||||
c->expand_count);
|
||||
printf_filtered (_(" Hash table hashes: %lu\n"),
|
||||
c->total_count + c->expand_hash_count);
|
||||
printf_filtered (_(" Half hash misses: %lu\n"),
|
||||
c->half_hash_miss_count);
|
||||
printf_filtered (_(" Hash table population: "));
|
||||
print_percentage (occupied_buckets, c->num_buckets);
|
||||
printf_filtered (_(" Median hash chain length: %3d\n"),
|
||||
median_chain_length);
|
||||
printf_filtered (_(" Average hash chain length: "));
|
||||
if (c->num_buckets > 0)
|
||||
printf_filtered ("%3lu\n", c->unique_count / c->num_buckets);
|
||||
else
|
||||
/* i18n: "Average hash chain length: (not applicable)" */
|
||||
printf_filtered (_("(not applicable)\n"));
|
||||
printf_filtered (_(" Maximum hash chain length: %3d\n"), max_chain_length);
|
||||
printf_filtered ("\n");
|
||||
}
|
||||
|
||||
int
|
||||
bcache_memory_used (struct bcache *bcache)
|
||||
{
|
||||
return obstack_memory_used (&bcache->cache);
|
||||
}
|
||||
170
gdb/bcache.h
170
gdb/bcache.h
@@ -1,170 +0,0 @@
|
||||
/* Include file cached obstack implementation.
|
||||
Written by Fred Fish <fnf@cygnus.com>
|
||||
Rewritten by Jim Blandy <jimb@cygnus.com>
|
||||
|
||||
Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef BCACHE_H
|
||||
#define BCACHE_H 1
|
||||
|
||||
/* A bcache is a data structure for factoring out duplication in
|
||||
read-only structures. You give the bcache some string of bytes S.
|
||||
If the bcache already contains a copy of S, it hands you back a
|
||||
pointer to its copy. Otherwise, it makes a fresh copy of S, and
|
||||
hands you back a pointer to that. In either case, you can throw
|
||||
away your copy of S, and use the bcache's.
|
||||
|
||||
The "strings" in question are arbitrary strings of bytes --- they
|
||||
can contain zero bytes. You pass in the length explicitly when you
|
||||
call the bcache function.
|
||||
|
||||
This means that you can put ordinary C objects in a bcache.
|
||||
However, if you do this, remember that structs can contain `holes'
|
||||
between members, added for alignment. These bytes usually contain
|
||||
garbage. If you try to bcache two objects which are identical from
|
||||
your code's point of view, but have different garbage values in the
|
||||
structure's holes, then the bcache will treat them as separate
|
||||
strings, and you won't get the nice elimination of duplicates you
|
||||
were hoping for. So, remember to memset your structures full of
|
||||
zeros before bcaching them!
|
||||
|
||||
You shouldn't modify the strings you get from a bcache, because:
|
||||
|
||||
- You don't necessarily know who you're sharing space with. If I
|
||||
stick eight bytes of text in a bcache, and then stick an eight-byte
|
||||
structure in the same bcache, there's no guarantee those two
|
||||
objects don't actually comprise the same sequence of bytes. If
|
||||
they happen to, the bcache will use a single byte string for both
|
||||
of them. Then, modifying the structure will change the string. In
|
||||
bizarre ways.
|
||||
|
||||
- Even if you know for some other reason that all that's okay,
|
||||
there's another problem. A bcache stores all its strings in a hash
|
||||
table. If you modify a string's contents, you will probably change
|
||||
its hash value. This means that the modified string is now in the
|
||||
wrong place in the hash table, and future bcache probes will never
|
||||
find it. So by mutating a string, you give up any chance of
|
||||
sharing its space with future duplicates.
|
||||
|
||||
|
||||
Size of bcache VS hashtab:
|
||||
|
||||
For bcache, the most critical cost is size (or more exactly the
|
||||
overhead added by the bcache). It turns out that the bcache is
|
||||
remarkably efficient.
|
||||
|
||||
Assuming a 32-bit system (the hash table slots are 4 bytes),
|
||||
ignoring alignment, and limit strings to 255 bytes (1 byte length)
|
||||
we get ...
|
||||
|
||||
bcache: This uses a separate linked list to track the hash chain.
|
||||
The numbers show roughly 100% occupancy of the hash table and an
|
||||
average chain length of 4. Spreading the slot cost over the 4
|
||||
chain elements:
|
||||
|
||||
4 (slot) / 4 (chain length) + 1 (length) + 4 (chain) = 6 bytes
|
||||
|
||||
hashtab: This uses a more traditional re-hash algorithm where the
|
||||
chain is maintained within the hash table. The table occupancy is
|
||||
kept below 75% but we'll assume its perfect:
|
||||
|
||||
4 (slot) x 4/3 (occupancy) + 1 (length) = 6 1/3 bytes
|
||||
|
||||
So a perfect hashtab has just slightly larger than an average
|
||||
bcache.
|
||||
|
||||
It turns out that an average hashtab is far worse. Two things
|
||||
hurt:
|
||||
|
||||
- Hashtab's occupancy is more like 50% (it ranges between 38% and
|
||||
75%) giving a per slot cost of 4x2 vs 4x4/3.
|
||||
|
||||
- the string structure needs to be aligned to 8 bytes which for
|
||||
hashtab wastes 7 bytes, while for bcache wastes only 3.
|
||||
|
||||
This gives:
|
||||
|
||||
hashtab: 4 x 2 + 1 + 7 = 16 bytes
|
||||
|
||||
bcache 4 / 4 + 1 + 4 + 3 = 9 bytes
|
||||
|
||||
The numbers of GDB debugging GDB support this. ~40% vs ~70% overhead.
|
||||
|
||||
|
||||
Speed of bcache VS hashtab (the half hash hack):
|
||||
|
||||
While hashtab has a typical chain length of 1, bcache has a chain
|
||||
length of round 4. This means that the bcache will require
|
||||
something like double the number of compares after that initial
|
||||
hash. In both cases the comparison takes the form:
|
||||
|
||||
a.length == b.length && memcmp (a.data, b.data, a.length) == 0
|
||||
|
||||
That is lengths are checked before doing the memcmp.
|
||||
|
||||
For GDB debugging GDB, it turned out that all lengths were 24 bytes
|
||||
(no C++ so only psymbols were cached) and hence, all compares
|
||||
required a call to memcmp. As a hack, two bytes of padding
|
||||
(mentioned above) are used to store the upper 16 bits of the
|
||||
string's hash value and then that is used in the comparison vis:
|
||||
|
||||
a.half_hash == b.half_hash && a.length == b.length && memcmp
|
||||
(a.data, b.data, a.length)
|
||||
|
||||
The numbers from GDB debugging GDB show this to be a remarkable
|
||||
100% effective (only necessary length and memcmp tests being
|
||||
performed).
|
||||
|
||||
Mind you, looking at the wall clock, the same GDB debugging GDB
|
||||
showed only marginal speed up (0.780 vs 0.773s). Seems GDB is too
|
||||
busy doing something else :-(
|
||||
|
||||
*/
|
||||
|
||||
|
||||
struct bcache;
|
||||
|
||||
/* Find a copy of the LENGTH bytes at ADDR in BCACHE. If BCACHE has
|
||||
never seen those bytes before, add a copy of them to BCACHE. In
|
||||
either case, return a pointer to BCACHE's copy of that string.
|
||||
Since the cached value is ment to be read-only, return a const
|
||||
buffer. */
|
||||
extern void *deprecated_bcache (const void *addr, int length,
|
||||
struct bcache *bcache);
|
||||
extern const void *bcache (const void *addr, int length,
|
||||
struct bcache *bcache);
|
||||
|
||||
/* Free all the storage used by BCACHE. */
|
||||
extern void bcache_xfree (struct bcache *bcache);
|
||||
|
||||
/* Create a new bcache object. */
|
||||
extern struct bcache *bcache_xmalloc (void);
|
||||
|
||||
/* Print statistics on BCACHE's memory usage and efficacity at
|
||||
eliminating duplication. TYPE should be a string describing the
|
||||
kind of data BCACHE holds. Statistics are printed using
|
||||
`printf_filtered' and its ilk. */
|
||||
extern void print_bcache_statistics (struct bcache *bcache, char *type);
|
||||
extern int bcache_memory_used (struct bcache *bcache);
|
||||
|
||||
/* The hash function */
|
||||
extern unsigned long hash(const void *addr, int length);
|
||||
|
||||
#endif /* BCACHE_H */
|
||||
132
gdb/bfd-target.c
132
gdb/bfd-target.c
@@ -1,132 +0,0 @@
|
||||
/* Very simple "bfd" target, for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2003, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "target.h"
|
||||
#include "bfd-target.h"
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
/* Locate all mappable sections of a BFD file, filling in a target
|
||||
section for each. */
|
||||
|
||||
struct section_closure
|
||||
{
|
||||
struct section_table *end;
|
||||
};
|
||||
|
||||
static void
|
||||
add_to_section_table (struct bfd *abfd, struct bfd_section *asect,
|
||||
void *closure)
|
||||
{
|
||||
struct section_closure *pp = closure;
|
||||
flagword aflag;
|
||||
|
||||
/* NOTE: cagney/2003-10-22: Is this pruning useful? */
|
||||
aflag = bfd_get_section_flags (abfd, asect);
|
||||
if (!(aflag & SEC_ALLOC))
|
||||
return;
|
||||
if (bfd_section_size (abfd, asect) == 0)
|
||||
return;
|
||||
pp->end->bfd = abfd;
|
||||
pp->end->the_bfd_section = asect;
|
||||
pp->end->addr = bfd_section_vma (abfd, asect);
|
||||
pp->end->endaddr = pp->end->addr + bfd_section_size (abfd, asect);
|
||||
pp->end++;
|
||||
}
|
||||
|
||||
void
|
||||
build_target_sections_from_bfd (struct target_ops *targ, struct bfd *abfd)
|
||||
{
|
||||
unsigned count;
|
||||
struct section_table *start;
|
||||
struct section_closure cl;
|
||||
|
||||
count = bfd_count_sections (abfd);
|
||||
target_resize_to_sections (targ, count);
|
||||
start = targ->to_sections;
|
||||
cl.end = targ->to_sections;
|
||||
bfd_map_over_sections (abfd, add_to_section_table, &cl);
|
||||
gdb_assert (cl.end - start <= count);
|
||||
}
|
||||
|
||||
LONGEST
|
||||
target_bfd_xfer_partial (struct target_ops *ops,
|
||||
enum target_object object,
|
||||
const char *annex, gdb_byte *readbuf,
|
||||
const gdb_byte *writebuf,
|
||||
ULONGEST offset, LONGEST len)
|
||||
{
|
||||
switch (object)
|
||||
{
|
||||
case TARGET_OBJECT_MEMORY:
|
||||
{
|
||||
struct section_table *s = target_section_by_addr (ops, offset);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
/* If the length extends beyond the section, truncate it. Be
|
||||
careful to not suffer from overflow (wish S contained a
|
||||
length). */
|
||||
if ((offset - s->addr + len) > (s->endaddr - s->addr))
|
||||
len = (s->endaddr - s->addr) - (offset - s->addr);
|
||||
if (readbuf != NULL
|
||||
&& !bfd_get_section_contents (s->bfd, s->the_bfd_section,
|
||||
readbuf, offset - s->addr, len))
|
||||
return -1;
|
||||
#if 1
|
||||
if (writebuf != NULL)
|
||||
return -1;
|
||||
#else
|
||||
/* FIXME: cagney/2003-10-31: The BFD interface doesn't yet
|
||||
take a const buffer. */
|
||||
if (writebuf != NULL
|
||||
&& !bfd_set_section_contents (s->bfd, s->the_bfd_section,
|
||||
writebuf, offset - s->addr, len))
|
||||
return -1;
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
target_bfd_xclose (struct target_ops *t, int quitting)
|
||||
{
|
||||
bfd_close (t->to_data);
|
||||
xfree (t->to_sections);
|
||||
xfree (t);
|
||||
}
|
||||
|
||||
struct target_ops *
|
||||
target_bfd_reopen (struct bfd *bfd)
|
||||
{
|
||||
struct target_ops *t = XZALLOC (struct target_ops);
|
||||
t->to_shortname = "bfd";
|
||||
t->to_longname = _("BFD backed target");
|
||||
t->to_doc = _("You should never see this");
|
||||
t->to_xfer_partial = target_bfd_xfer_partial;
|
||||
t->to_xclose = target_bfd_xclose;
|
||||
t->to_data = bfd;
|
||||
build_target_sections_from_bfd (t, bfd);
|
||||
return t;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/* Very simple "bfd" target, for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef BFD_TARGET_H
|
||||
#define BFD_TARGET_H
|
||||
|
||||
struct bfd;
|
||||
struct target_ops;
|
||||
|
||||
/* Given an existing BFD, re-open it as a "struct target_ops". On
|
||||
close, it will also close the corresponding BFD (which is like
|
||||
freopen and fdopen). */
|
||||
struct target_ops *target_bfd_reopen (struct bfd *bfd);
|
||||
|
||||
/* Map over ABFD's sections, creating corresponding entries in the
|
||||
target's section table. */
|
||||
|
||||
void build_target_sections_from_bfd (struct target_ops *targ,
|
||||
struct bfd *abfd);
|
||||
|
||||
#endif
|
||||
295
gdb/block.c
295
gdb/block.c
@@ -1,295 +0,0 @@
|
||||
/* Block-related functions for the GNU debugger, GDB.
|
||||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "block.h"
|
||||
#include "symtab.h"
|
||||
#include "symfile.h"
|
||||
#include "gdb_obstack.h"
|
||||
#include "cp-support.h"
|
||||
|
||||
/* This is used by struct block to store namespace-related info for
|
||||
C++ files, namely using declarations and the current namespace in
|
||||
scope. */
|
||||
|
||||
struct block_namespace_info
|
||||
{
|
||||
const char *scope;
|
||||
struct using_direct *using;
|
||||
};
|
||||
|
||||
static void block_initialize_namespace (struct block *block,
|
||||
struct obstack *obstack);
|
||||
|
||||
/* Return Nonzero if block a is lexically nested within block b,
|
||||
or if a and b have the same pc range.
|
||||
Return zero otherwise. */
|
||||
|
||||
int
|
||||
contained_in (const struct block *a, const struct block *b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return 0;
|
||||
return BLOCK_START (a) >= BLOCK_START (b)
|
||||
&& BLOCK_END (a) <= BLOCK_END (b);
|
||||
}
|
||||
|
||||
|
||||
/* Return the symbol for the function which contains a specified
|
||||
lexical block, described by a struct block BL. */
|
||||
|
||||
struct symbol *
|
||||
block_function (const struct block *bl)
|
||||
{
|
||||
while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0)
|
||||
bl = BLOCK_SUPERBLOCK (bl);
|
||||
|
||||
return BLOCK_FUNCTION (bl);
|
||||
}
|
||||
|
||||
/* Return the blockvector immediately containing the innermost lexical block
|
||||
containing the specified pc value and section, or 0 if there is none.
|
||||
PINDEX is a pointer to the index value of the block. If PINDEX
|
||||
is NULL, we don't pass this information back to the caller. */
|
||||
|
||||
struct blockvector *
|
||||
blockvector_for_pc_sect (CORE_ADDR pc, struct bfd_section *section,
|
||||
int *pindex, struct symtab *symtab)
|
||||
{
|
||||
struct block *b;
|
||||
int bot, top, half;
|
||||
struct blockvector *bl;
|
||||
|
||||
if (symtab == 0) /* if no symtab specified by caller */
|
||||
{
|
||||
/* First search all symtabs for one whose file contains our pc */
|
||||
symtab = find_pc_sect_symtab (pc, section);
|
||||
if (symtab == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bl = BLOCKVECTOR (symtab);
|
||||
b = BLOCKVECTOR_BLOCK (bl, 0);
|
||||
|
||||
/* Then search that symtab for the smallest block that wins. */
|
||||
/* Use binary search to find the last block that starts before PC. */
|
||||
|
||||
bot = 0;
|
||||
top = BLOCKVECTOR_NBLOCKS (bl);
|
||||
|
||||
while (top - bot > 1)
|
||||
{
|
||||
half = (top - bot + 1) >> 1;
|
||||
b = BLOCKVECTOR_BLOCK (bl, bot + half);
|
||||
if (BLOCK_START (b) <= pc)
|
||||
bot += half;
|
||||
else
|
||||
top = bot + half;
|
||||
}
|
||||
|
||||
/* Now search backward for a block that ends after PC. */
|
||||
|
||||
while (bot >= 0)
|
||||
{
|
||||
b = BLOCKVECTOR_BLOCK (bl, bot);
|
||||
if (BLOCK_END (b) > pc)
|
||||
{
|
||||
if (pindex)
|
||||
*pindex = bot;
|
||||
return bl;
|
||||
}
|
||||
bot--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the blockvector immediately containing the innermost lexical block
|
||||
containing the specified pc value, or 0 if there is none.
|
||||
Backward compatibility, no section. */
|
||||
|
||||
struct blockvector *
|
||||
blockvector_for_pc (CORE_ADDR pc, int *pindex)
|
||||
{
|
||||
return blockvector_for_pc_sect (pc, find_pc_mapped_section (pc),
|
||||
pindex, NULL);
|
||||
}
|
||||
|
||||
/* Return the innermost lexical block containing the specified pc value
|
||||
in the specified section, or 0 if there is none. */
|
||||
|
||||
struct block *
|
||||
block_for_pc_sect (CORE_ADDR pc, struct bfd_section *section)
|
||||
{
|
||||
struct blockvector *bl;
|
||||
int index;
|
||||
|
||||
bl = blockvector_for_pc_sect (pc, section, &index, NULL);
|
||||
if (bl)
|
||||
return BLOCKVECTOR_BLOCK (bl, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the innermost lexical block containing the specified pc value,
|
||||
or 0 if there is none. Backward compatibility, no section. */
|
||||
|
||||
struct block *
|
||||
block_for_pc (CORE_ADDR pc)
|
||||
{
|
||||
return block_for_pc_sect (pc, find_pc_mapped_section (pc));
|
||||
}
|
||||
|
||||
/* Now come some functions designed to deal with C++ namespace issues.
|
||||
The accessors are safe to use even in the non-C++ case. */
|
||||
|
||||
/* This returns the namespace that BLOCK is enclosed in, or "" if it
|
||||
isn't enclosed in a namespace at all. This travels the chain of
|
||||
superblocks looking for a scope, if necessary. */
|
||||
|
||||
const char *
|
||||
block_scope (const struct block *block)
|
||||
{
|
||||
for (; block != NULL; block = BLOCK_SUPERBLOCK (block))
|
||||
{
|
||||
if (BLOCK_NAMESPACE (block) != NULL
|
||||
&& BLOCK_NAMESPACE (block)->scope != NULL)
|
||||
return BLOCK_NAMESPACE (block)->scope;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Set BLOCK's scope member to SCOPE; if needed, allocate memory via
|
||||
OBSTACK. (It won't make a copy of SCOPE, however, so that already
|
||||
has to be allocated correctly.) */
|
||||
|
||||
void
|
||||
block_set_scope (struct block *block, const char *scope,
|
||||
struct obstack *obstack)
|
||||
{
|
||||
block_initialize_namespace (block, obstack);
|
||||
|
||||
BLOCK_NAMESPACE (block)->scope = scope;
|
||||
}
|
||||
|
||||
/* This returns the first using directives associated to BLOCK, if
|
||||
any. */
|
||||
|
||||
/* FIXME: carlton/2003-04-23: This uses the fact that we currently
|
||||
only have using directives in static blocks, because we only
|
||||
generate using directives from anonymous namespaces. Eventually,
|
||||
when we support using directives everywhere, we'll want to replace
|
||||
this by some iterator functions. */
|
||||
|
||||
struct using_direct *
|
||||
block_using (const struct block *block)
|
||||
{
|
||||
const struct block *static_block = block_static_block (block);
|
||||
|
||||
if (static_block == NULL
|
||||
|| BLOCK_NAMESPACE (static_block) == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return BLOCK_NAMESPACE (static_block)->using;
|
||||
}
|
||||
|
||||
/* Set BLOCK's using member to USING; if needed, allocate memory via
|
||||
OBSTACK. (It won't make a copy of USING, however, so that already
|
||||
has to be allocated correctly.) */
|
||||
|
||||
void
|
||||
block_set_using (struct block *block,
|
||||
struct using_direct *using,
|
||||
struct obstack *obstack)
|
||||
{
|
||||
block_initialize_namespace (block, obstack);
|
||||
|
||||
BLOCK_NAMESPACE (block)->using = using;
|
||||
}
|
||||
|
||||
/* If BLOCK_NAMESPACE (block) is NULL, allocate it via OBSTACK and
|
||||
ititialize its members to zero. */
|
||||
|
||||
static void
|
||||
block_initialize_namespace (struct block *block, struct obstack *obstack)
|
||||
{
|
||||
if (BLOCK_NAMESPACE (block) == NULL)
|
||||
{
|
||||
BLOCK_NAMESPACE (block)
|
||||
= obstack_alloc (obstack, sizeof (struct block_namespace_info));
|
||||
BLOCK_NAMESPACE (block)->scope = NULL;
|
||||
BLOCK_NAMESPACE (block)->using = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the static block associated to BLOCK. Return NULL if block
|
||||
is NULL or if block is a global block. */
|
||||
|
||||
const struct block *
|
||||
block_static_block (const struct block *block)
|
||||
{
|
||||
if (block == NULL || BLOCK_SUPERBLOCK (block) == NULL)
|
||||
return NULL;
|
||||
|
||||
while (BLOCK_SUPERBLOCK (BLOCK_SUPERBLOCK (block)) != NULL)
|
||||
block = BLOCK_SUPERBLOCK (block);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/* Return the static block associated to BLOCK. Return NULL if block
|
||||
is NULL. */
|
||||
|
||||
const struct block *
|
||||
block_global_block (const struct block *block)
|
||||
{
|
||||
if (block == NULL)
|
||||
return NULL;
|
||||
|
||||
while (BLOCK_SUPERBLOCK (block) != NULL)
|
||||
block = BLOCK_SUPERBLOCK (block);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/* Allocate a block on OBSTACK, and initialize its elements to
|
||||
zero/NULL. This is useful for creating "dummy" blocks that don't
|
||||
correspond to actual source files.
|
||||
|
||||
Warning: it sets the block's BLOCK_DICT to NULL, which isn't a
|
||||
valid value. If you really don't want the block to have a
|
||||
dictionary, then you should subsequently set its BLOCK_DICT to
|
||||
dict_create_linear (obstack, NULL). */
|
||||
|
||||
struct block *
|
||||
allocate_block (struct obstack *obstack)
|
||||
{
|
||||
struct block *bl = obstack_alloc (obstack, sizeof (struct block));
|
||||
|
||||
BLOCK_START (bl) = 0;
|
||||
BLOCK_END (bl) = 0;
|
||||
BLOCK_FUNCTION (bl) = NULL;
|
||||
BLOCK_SUPERBLOCK (bl) = NULL;
|
||||
BLOCK_DICT (bl) = NULL;
|
||||
BLOCK_NAMESPACE (bl) = NULL;
|
||||
BLOCK_GCC_COMPILED (bl) = 0;
|
||||
|
||||
return bl;
|
||||
}
|
||||
174
gdb/block.h
174
gdb/block.h
@@ -1,174 +0,0 @@
|
||||
/* Code dealing with blocks for GDB.
|
||||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef BLOCK_H
|
||||
#define BLOCK_H
|
||||
|
||||
/* Opaque declarations. */
|
||||
|
||||
struct symbol;
|
||||
struct symtab;
|
||||
struct block_namespace_info;
|
||||
struct using_direct;
|
||||
struct obstack;
|
||||
struct dictionary;
|
||||
|
||||
/* All of the name-scope contours of the program
|
||||
are represented by `struct block' objects.
|
||||
All of these objects are pointed to by the blockvector.
|
||||
|
||||
Each block represents one name scope.
|
||||
Each lexical context has its own block.
|
||||
|
||||
The blockvector begins with some special blocks.
|
||||
The GLOBAL_BLOCK contains all the symbols defined in this compilation
|
||||
whose scope is the entire program linked together.
|
||||
The STATIC_BLOCK contains all the symbols whose scope is the
|
||||
entire compilation excluding other separate compilations.
|
||||
Blocks starting with the FIRST_LOCAL_BLOCK are not special.
|
||||
|
||||
Each block records a range of core addresses for the code that
|
||||
is in the scope of the block. The STATIC_BLOCK and GLOBAL_BLOCK
|
||||
give, for the range of code, the entire range of code produced
|
||||
by the compilation that the symbol segment belongs to.
|
||||
|
||||
The blocks appear in the blockvector
|
||||
in order of increasing starting-address,
|
||||
and, within that, in order of decreasing ending-address.
|
||||
|
||||
This implies that within the body of one function
|
||||
the blocks appear in the order of a depth-first tree walk. */
|
||||
|
||||
struct block
|
||||
{
|
||||
|
||||
/* Addresses in the executable code that are in this block. */
|
||||
|
||||
CORE_ADDR startaddr;
|
||||
CORE_ADDR endaddr;
|
||||
|
||||
/* The symbol that names this block, if the block is the body of a
|
||||
function; otherwise, zero. */
|
||||
|
||||
struct symbol *function;
|
||||
|
||||
/* The `struct block' for the containing block, or 0 if none.
|
||||
|
||||
The superblock of a top-level local block (i.e. a function in the
|
||||
case of C) is the STATIC_BLOCK. The superblock of the
|
||||
STATIC_BLOCK is the GLOBAL_BLOCK. */
|
||||
|
||||
struct block *superblock;
|
||||
|
||||
/* This is used to store the symbols in the block. */
|
||||
|
||||
struct dictionary *dict;
|
||||
|
||||
/* Used for language-specific info. */
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/* Contains information about namespace-related info relevant to
|
||||
this block: using directives and the current namespace
|
||||
scope. */
|
||||
|
||||
struct block_namespace_info *namespace;
|
||||
}
|
||||
cplus_specific;
|
||||
}
|
||||
language_specific;
|
||||
|
||||
/* Version of GCC used to compile the function corresponding
|
||||
to this block, or 0 if not compiled with GCC. When possible,
|
||||
GCC should be compatible with the native compiler, or if that
|
||||
is not feasible, the differences should be fixed during symbol
|
||||
reading. As of 16 Apr 93, this flag is never used to distinguish
|
||||
between gcc2 and the native compiler.
|
||||
|
||||
If there is no function corresponding to this block, this meaning
|
||||
of this flag is undefined. */
|
||||
|
||||
unsigned char gcc_compile_flag;
|
||||
};
|
||||
|
||||
#define BLOCK_START(bl) (bl)->startaddr
|
||||
#define BLOCK_END(bl) (bl)->endaddr
|
||||
#define BLOCK_FUNCTION(bl) (bl)->function
|
||||
#define BLOCK_SUPERBLOCK(bl) (bl)->superblock
|
||||
#define BLOCK_GCC_COMPILED(bl) (bl)->gcc_compile_flag
|
||||
#define BLOCK_DICT(bl) (bl)->dict
|
||||
#define BLOCK_NAMESPACE(bl) (bl)->language_specific.cplus_specific.namespace
|
||||
|
||||
/* Macro to loop through all symbols in a block BL, in no particular
|
||||
order. ITER helps keep track of the iteration, and should be a
|
||||
struct dict_iterator. SYM points to the current symbol. */
|
||||
|
||||
#define ALL_BLOCK_SYMBOLS(block, iter, sym) \
|
||||
ALL_DICT_SYMBOLS (BLOCK_DICT (block), iter, sym)
|
||||
|
||||
struct blockvector
|
||||
{
|
||||
/* Number of blocks in the list. */
|
||||
int nblocks;
|
||||
/* The blocks themselves. */
|
||||
struct block *block[1];
|
||||
};
|
||||
|
||||
#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks
|
||||
#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n]
|
||||
|
||||
/* Special block numbers */
|
||||
|
||||
enum { GLOBAL_BLOCK = 0, STATIC_BLOCK = 1, FIRST_LOCAL_BLOCK = 2 };
|
||||
|
||||
extern struct symbol *block_function (const struct block *);
|
||||
|
||||
extern int contained_in (const struct block *, const struct block *);
|
||||
|
||||
extern struct blockvector *blockvector_for_pc (CORE_ADDR, int *);
|
||||
|
||||
extern struct blockvector *blockvector_for_pc_sect (CORE_ADDR, asection *,
|
||||
int *, struct symtab *);
|
||||
|
||||
extern struct block *block_for_pc (CORE_ADDR);
|
||||
|
||||
extern struct block *block_for_pc_sect (CORE_ADDR, asection *);
|
||||
|
||||
extern const char *block_scope (const struct block *block);
|
||||
|
||||
extern void block_set_scope (struct block *block, const char *scope,
|
||||
struct obstack *obstack);
|
||||
|
||||
extern struct using_direct *block_using (const struct block *block);
|
||||
|
||||
extern void block_set_using (struct block *block,
|
||||
struct using_direct *using,
|
||||
struct obstack *obstack);
|
||||
|
||||
extern const struct block *block_static_block (const struct block *block);
|
||||
|
||||
extern const struct block *block_global_block (const struct block *block);
|
||||
|
||||
extern struct block *allocate_block (struct obstack *obstack);
|
||||
|
||||
#endif /* BLOCK_H */
|
||||
364
gdb/blockframe.c
364
gdb/blockframe.c
@@ -1,364 +0,0 @@
|
||||
/* Get info from stack frames; convert between frames, blocks,
|
||||
functions and pc values.
|
||||
|
||||
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
|
||||
1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "symtab.h"
|
||||
#include "bfd.h"
|
||||
#include "objfiles.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "value.h" /* for read_register */
|
||||
#include "target.h" /* for target_has_stack */
|
||||
#include "inferior.h" /* for read_pc */
|
||||
#include "annotate.h"
|
||||
#include "regcache.h"
|
||||
#include "gdb_assert.h"
|
||||
#include "dummy-frame.h"
|
||||
#include "command.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "block.h"
|
||||
|
||||
/* Prototypes for exported functions. */
|
||||
|
||||
void _initialize_blockframe (void);
|
||||
|
||||
/* Return the innermost lexical block in execution
|
||||
in a specified stack frame. The frame address is assumed valid.
|
||||
|
||||
If ADDR_IN_BLOCK is non-zero, set *ADDR_IN_BLOCK to the exact code
|
||||
address we used to choose the block. We use this to find a source
|
||||
line, to decide which macro definitions are in scope.
|
||||
|
||||
The value returned in *ADDR_IN_BLOCK isn't necessarily the frame's
|
||||
PC, and may not really be a valid PC at all. For example, in the
|
||||
caller of a function declared to never return, the code at the
|
||||
return address will never be reached, so the call instruction may
|
||||
be the very last instruction in the block. So the address we use
|
||||
to choose the block is actually one byte before the return address
|
||||
--- hopefully pointing us at the call instruction, or its delay
|
||||
slot instruction. */
|
||||
|
||||
struct block *
|
||||
get_frame_block (struct frame_info *frame, CORE_ADDR *addr_in_block)
|
||||
{
|
||||
const CORE_ADDR pc = get_frame_address_in_block (frame);
|
||||
|
||||
if (addr_in_block)
|
||||
*addr_in_block = pc;
|
||||
|
||||
return block_for_pc (pc);
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
get_pc_function_start (CORE_ADDR pc)
|
||||
{
|
||||
struct block *bl;
|
||||
struct minimal_symbol *msymbol;
|
||||
|
||||
bl = block_for_pc (pc);
|
||||
if (bl)
|
||||
{
|
||||
struct symbol *symbol = block_function (bl);
|
||||
|
||||
if (symbol)
|
||||
{
|
||||
bl = SYMBOL_BLOCK_VALUE (symbol);
|
||||
return BLOCK_START (bl);
|
||||
}
|
||||
}
|
||||
|
||||
msymbol = lookup_minimal_symbol_by_pc (pc);
|
||||
if (msymbol)
|
||||
{
|
||||
CORE_ADDR fstart = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
|
||||
if (find_pc_section (fstart))
|
||||
return fstart;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the symbol for the function executing in frame FRAME. */
|
||||
|
||||
struct symbol *
|
||||
get_frame_function (struct frame_info *frame)
|
||||
{
|
||||
struct block *bl = get_frame_block (frame, 0);
|
||||
if (bl == 0)
|
||||
return 0;
|
||||
return block_function (bl);
|
||||
}
|
||||
|
||||
|
||||
/* Return the function containing pc value PC in section SECTION.
|
||||
Returns 0 if function is not known. */
|
||||
|
||||
struct symbol *
|
||||
find_pc_sect_function (CORE_ADDR pc, struct bfd_section *section)
|
||||
{
|
||||
struct block *b = block_for_pc_sect (pc, section);
|
||||
if (b == 0)
|
||||
return 0;
|
||||
return block_function (b);
|
||||
}
|
||||
|
||||
/* Return the function containing pc value PC.
|
||||
Returns 0 if function is not known. Backward compatibility, no section */
|
||||
|
||||
struct symbol *
|
||||
find_pc_function (CORE_ADDR pc)
|
||||
{
|
||||
return find_pc_sect_function (pc, find_pc_mapped_section (pc));
|
||||
}
|
||||
|
||||
/* These variables are used to cache the most recent result
|
||||
* of find_pc_partial_function. */
|
||||
|
||||
static CORE_ADDR cache_pc_function_low = 0;
|
||||
static CORE_ADDR cache_pc_function_high = 0;
|
||||
static char *cache_pc_function_name = 0;
|
||||
static struct bfd_section *cache_pc_function_section = NULL;
|
||||
|
||||
/* Clear cache, e.g. when symbol table is discarded. */
|
||||
|
||||
void
|
||||
clear_pc_function_cache (void)
|
||||
{
|
||||
cache_pc_function_low = 0;
|
||||
cache_pc_function_high = 0;
|
||||
cache_pc_function_name = (char *) 0;
|
||||
cache_pc_function_section = NULL;
|
||||
}
|
||||
|
||||
/* Finds the "function" (text symbol) that is smaller than PC but
|
||||
greatest of all of the potential text symbols in SECTION. Sets
|
||||
*NAME and/or *ADDRESS conditionally if that pointer is non-null.
|
||||
If ENDADDR is non-null, then set *ENDADDR to be the end of the
|
||||
function (exclusive), but passing ENDADDR as non-null means that
|
||||
the function might cause symbols to be read. This function either
|
||||
succeeds or fails (not halfway succeeds). If it succeeds, it sets
|
||||
*NAME, *ADDRESS, and *ENDADDR to real information and returns 1.
|
||||
If it fails, it sets *NAME, *ADDRESS, and *ENDADDR to zero and
|
||||
returns 0. */
|
||||
|
||||
/* Backward compatibility, no section argument. */
|
||||
|
||||
int
|
||||
find_pc_partial_function (CORE_ADDR pc, char **name, CORE_ADDR *address,
|
||||
CORE_ADDR *endaddr)
|
||||
{
|
||||
struct bfd_section *section;
|
||||
struct partial_symtab *pst;
|
||||
struct symbol *f;
|
||||
struct minimal_symbol *msymbol;
|
||||
struct partial_symbol *psb;
|
||||
struct obj_section *osect;
|
||||
int i;
|
||||
CORE_ADDR mapped_pc;
|
||||
|
||||
/* To ensure that the symbol returned belongs to the correct setion
|
||||
(and that the last [random] symbol from the previous section
|
||||
isn't returned) try to find the section containing PC. First try
|
||||
the overlay code (which by default returns NULL); and second try
|
||||
the normal section code (which almost always succeeds). */
|
||||
section = find_pc_overlay (pc);
|
||||
if (section == NULL)
|
||||
{
|
||||
struct obj_section *obj_section = find_pc_section (pc);
|
||||
if (obj_section == NULL)
|
||||
section = NULL;
|
||||
else
|
||||
section = obj_section->the_bfd_section;
|
||||
}
|
||||
|
||||
mapped_pc = overlay_mapped_address (pc, section);
|
||||
|
||||
if (mapped_pc >= cache_pc_function_low
|
||||
&& mapped_pc < cache_pc_function_high
|
||||
&& section == cache_pc_function_section)
|
||||
goto return_cached_value;
|
||||
|
||||
msymbol = lookup_minimal_symbol_by_pc_section (mapped_pc, section);
|
||||
pst = find_pc_sect_psymtab (mapped_pc, section);
|
||||
if (pst)
|
||||
{
|
||||
/* Need to read the symbols to get a good value for the end address. */
|
||||
if (endaddr != NULL && !pst->readin)
|
||||
{
|
||||
/* Need to get the terminal in case symbol-reading produces
|
||||
output. */
|
||||
target_terminal_ours_for_output ();
|
||||
PSYMTAB_TO_SYMTAB (pst);
|
||||
}
|
||||
|
||||
if (pst->readin)
|
||||
{
|
||||
/* Checking whether the msymbol has a larger value is for the
|
||||
"pathological" case mentioned in print_frame_info. */
|
||||
f = find_pc_sect_function (mapped_pc, section);
|
||||
if (f != NULL
|
||||
&& (msymbol == NULL
|
||||
|| (BLOCK_START (SYMBOL_BLOCK_VALUE (f))
|
||||
>= SYMBOL_VALUE_ADDRESS (msymbol))))
|
||||
{
|
||||
cache_pc_function_low = BLOCK_START (SYMBOL_BLOCK_VALUE (f));
|
||||
cache_pc_function_high = BLOCK_END (SYMBOL_BLOCK_VALUE (f));
|
||||
cache_pc_function_name = DEPRECATED_SYMBOL_NAME (f);
|
||||
cache_pc_function_section = section;
|
||||
goto return_cached_value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Now that static symbols go in the minimal symbol table, perhaps
|
||||
we could just ignore the partial symbols. But at least for now
|
||||
we use the partial or minimal symbol, whichever is larger. */
|
||||
psb = find_pc_sect_psymbol (pst, mapped_pc, section);
|
||||
|
||||
if (psb
|
||||
&& (msymbol == NULL ||
|
||||
(SYMBOL_VALUE_ADDRESS (psb)
|
||||
>= SYMBOL_VALUE_ADDRESS (msymbol))))
|
||||
{
|
||||
/* This case isn't being cached currently. */
|
||||
if (address)
|
||||
*address = SYMBOL_VALUE_ADDRESS (psb);
|
||||
if (name)
|
||||
*name = DEPRECATED_SYMBOL_NAME (psb);
|
||||
/* endaddr non-NULL can't happen here. */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not in the normal symbol tables, see if the pc is in a known section.
|
||||
If it's not, then give up. This ensures that anything beyond the end
|
||||
of the text seg doesn't appear to be part of the last function in the
|
||||
text segment. */
|
||||
|
||||
osect = find_pc_sect_section (mapped_pc, section);
|
||||
|
||||
if (!osect)
|
||||
msymbol = NULL;
|
||||
|
||||
/* Must be in the minimal symbol table. */
|
||||
if (msymbol == NULL)
|
||||
{
|
||||
/* No available symbol. */
|
||||
if (name != NULL)
|
||||
*name = 0;
|
||||
if (address != NULL)
|
||||
*address = 0;
|
||||
if (endaddr != NULL)
|
||||
*endaddr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cache_pc_function_low = SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
cache_pc_function_name = DEPRECATED_SYMBOL_NAME (msymbol);
|
||||
cache_pc_function_section = section;
|
||||
|
||||
/* Use the lesser of the next minimal symbol in the same section, or
|
||||
the end of the section, as the end of the function. */
|
||||
|
||||
/* Step over other symbols at this same address, and symbols in
|
||||
other sections, to find the next symbol in this section with
|
||||
a different address. */
|
||||
|
||||
for (i = 1; DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL; i++)
|
||||
{
|
||||
if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol)
|
||||
&& SYMBOL_BFD_SECTION (msymbol + i) == SYMBOL_BFD_SECTION (msymbol))
|
||||
break;
|
||||
}
|
||||
|
||||
if (DEPRECATED_SYMBOL_NAME (msymbol + i) != NULL
|
||||
&& SYMBOL_VALUE_ADDRESS (msymbol + i) < osect->endaddr)
|
||||
cache_pc_function_high = SYMBOL_VALUE_ADDRESS (msymbol + i);
|
||||
else
|
||||
/* We got the start address from the last msymbol in the objfile.
|
||||
So the end address is the end of the section. */
|
||||
cache_pc_function_high = osect->endaddr;
|
||||
|
||||
return_cached_value:
|
||||
|
||||
if (address)
|
||||
{
|
||||
if (pc_in_unmapped_range (pc, section))
|
||||
*address = overlay_unmapped_address (cache_pc_function_low, section);
|
||||
else
|
||||
*address = cache_pc_function_low;
|
||||
}
|
||||
|
||||
if (name)
|
||||
*name = cache_pc_function_name;
|
||||
|
||||
if (endaddr)
|
||||
{
|
||||
if (pc_in_unmapped_range (pc, section))
|
||||
{
|
||||
/* Because the high address is actually beyond the end of
|
||||
the function (and therefore possibly beyond the end of
|
||||
the overlay), we must actually convert (high - 1) and
|
||||
then add one to that. */
|
||||
|
||||
*endaddr = 1 + overlay_unmapped_address (cache_pc_function_high - 1,
|
||||
section);
|
||||
}
|
||||
else
|
||||
*endaddr = cache_pc_function_high;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return the innermost stack frame executing inside of BLOCK,
|
||||
or NULL if there is no such frame. If BLOCK is NULL, just return NULL. */
|
||||
|
||||
struct frame_info *
|
||||
block_innermost_frame (struct block *block)
|
||||
{
|
||||
struct frame_info *frame;
|
||||
CORE_ADDR start;
|
||||
CORE_ADDR end;
|
||||
CORE_ADDR calling_pc;
|
||||
|
||||
if (block == NULL)
|
||||
return NULL;
|
||||
|
||||
start = BLOCK_START (block);
|
||||
end = BLOCK_END (block);
|
||||
|
||||
frame = NULL;
|
||||
while (1)
|
||||
{
|
||||
frame = get_prev_frame (frame);
|
||||
if (frame == NULL)
|
||||
return NULL;
|
||||
calling_pc = get_frame_address_in_block (frame);
|
||||
if (calling_pc >= start && calling_pc < end)
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
8041
gdb/breakpoint.c
8041
gdb/breakpoint.c
File diff suppressed because it is too large
Load Diff
808
gdb/breakpoint.h
808
gdb/breakpoint.h
@@ -1,808 +0,0 @@
|
||||
/* Data structures associated with breakpoints in GDB.
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
2002, 2003, 2004
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#if !defined (BREAKPOINT_H)
|
||||
#define BREAKPOINT_H 1
|
||||
|
||||
#include "frame.h"
|
||||
#include "value.h"
|
||||
|
||||
#include "gdb-events.h"
|
||||
|
||||
struct value;
|
||||
struct block;
|
||||
|
||||
/* This is the maximum number of bytes a breakpoint instruction can take.
|
||||
Feel free to increase it. It's just used in a few places to size
|
||||
arrays that should be independent of the target architecture. */
|
||||
|
||||
#define BREAKPOINT_MAX 16
|
||||
|
||||
/* Type of breakpoint. */
|
||||
/* FIXME In the future, we should fold all other breakpoint-like things into
|
||||
here. This includes:
|
||||
|
||||
* single-step (for machines where we have to simulate single stepping)
|
||||
(probably, though perhaps it is better for it to look as much as
|
||||
possible like a single-step to wait_for_inferior). */
|
||||
|
||||
enum bptype
|
||||
{
|
||||
bp_none = 0, /* Eventpoint has been deleted. */
|
||||
bp_breakpoint, /* Normal breakpoint */
|
||||
bp_hardware_breakpoint, /* Hardware assisted breakpoint */
|
||||
bp_until, /* used by until command */
|
||||
bp_finish, /* used by finish command */
|
||||
bp_watchpoint, /* Watchpoint */
|
||||
bp_hardware_watchpoint, /* Hardware assisted watchpoint */
|
||||
bp_read_watchpoint, /* read watchpoint, (hardware assisted) */
|
||||
bp_access_watchpoint, /* access watchpoint, (hardware assisted) */
|
||||
bp_longjmp, /* secret breakpoint to find longjmp() */
|
||||
bp_longjmp_resume, /* secret breakpoint to escape longjmp() */
|
||||
|
||||
/* Used by wait_for_inferior for stepping over subroutine calls, for
|
||||
stepping over signal handlers, and for skipping prologues. */
|
||||
bp_step_resume,
|
||||
|
||||
/* Used by wait_for_inferior for stepping over signal handlers. */
|
||||
bp_through_sigtramp,
|
||||
|
||||
/* Used to detect when a watchpoint expression has gone out of
|
||||
scope. These breakpoints are usually not visible to the user.
|
||||
|
||||
This breakpoint has some interesting properties:
|
||||
|
||||
1) There's always a 1:1 mapping between watchpoints
|
||||
on local variables and watchpoint_scope breakpoints.
|
||||
|
||||
2) It automatically deletes itself and the watchpoint it's
|
||||
associated with when hit.
|
||||
|
||||
3) It can never be disabled. */
|
||||
bp_watchpoint_scope,
|
||||
|
||||
/* The breakpoint at the end of a call dummy. */
|
||||
/* FIXME: What if the function we are calling longjmp()s out of the
|
||||
call, or the user gets out with the "return" command? We currently
|
||||
have no way of cleaning up the breakpoint in these (obscure) situations.
|
||||
(Probably can solve this by noticing longjmp, "return", etc., it's
|
||||
similar to noticing when a watchpoint on a local variable goes out
|
||||
of scope (with hardware support for watchpoints)). */
|
||||
bp_call_dummy,
|
||||
|
||||
/* Some dynamic linkers (HP, maybe Solaris) can arrange for special
|
||||
code in the inferior to run when significant events occur in the
|
||||
dynamic linker (for example a library is loaded or unloaded).
|
||||
|
||||
By placing a breakpoint in this magic code GDB will get control
|
||||
when these significant events occur. GDB can then re-examine
|
||||
the dynamic linker's data structures to discover any newly loaded
|
||||
dynamic libraries. */
|
||||
bp_shlib_event,
|
||||
|
||||
/* Some multi-threaded systems can arrange for a location in the
|
||||
inferior to be executed when certain thread-related events occur
|
||||
(such as thread creation or thread death).
|
||||
|
||||
By placing a breakpoint at one of these locations, GDB will get
|
||||
control when these events occur. GDB can then update its thread
|
||||
lists etc. */
|
||||
|
||||
bp_thread_event,
|
||||
|
||||
/* On the same principal, an overlay manager can arrange to call a
|
||||
magic location in the inferior whenever there is an interesting
|
||||
change in overlay status. GDB can update its overlay tables
|
||||
and fiddle with breakpoints in overlays when this breakpoint
|
||||
is hit. */
|
||||
|
||||
bp_overlay_event,
|
||||
|
||||
/* These breakpoints are used to implement the "catch load" command
|
||||
on platforms whose dynamic linkers support such functionality. */
|
||||
bp_catch_load,
|
||||
|
||||
/* These breakpoints are used to implement the "catch unload" command
|
||||
on platforms whose dynamic linkers support such functionality. */
|
||||
bp_catch_unload,
|
||||
|
||||
/* These are not really breakpoints, but are catchpoints that
|
||||
implement the "catch fork", "catch vfork" and "catch exec" commands
|
||||
on platforms whose kernel support such functionality. (I.e.,
|
||||
kernels which can raise an event when a fork or exec occurs, as
|
||||
opposed to the debugger setting breakpoints on functions named
|
||||
"fork" or "exec".) */
|
||||
bp_catch_fork,
|
||||
bp_catch_vfork,
|
||||
bp_catch_exec,
|
||||
|
||||
/* These are catchpoints to implement "catch catch" and "catch throw"
|
||||
commands for C++ exception handling. */
|
||||
bp_catch_catch,
|
||||
bp_catch_throw
|
||||
|
||||
|
||||
};
|
||||
|
||||
/* States of enablement of breakpoint. */
|
||||
|
||||
enum enable_state
|
||||
{
|
||||
bp_disabled, /* The eventpoint is inactive, and cannot trigger. */
|
||||
bp_enabled, /* The eventpoint is active, and can trigger. */
|
||||
bp_shlib_disabled, /* The eventpoint's address is in an unloaded solib.
|
||||
The eventpoint will be automatically enabled
|
||||
and reset when that solib is loaded. */
|
||||
bp_call_disabled, /* The eventpoint has been disabled while a call
|
||||
into the inferior is "in flight", because some
|
||||
eventpoints interfere with the implementation of
|
||||
a call on some targets. The eventpoint will be
|
||||
automatically enabled and reset when the call
|
||||
"lands" (either completes, or stops at another
|
||||
eventpoint). */
|
||||
bp_permanent /* There is a breakpoint instruction hard-wired into
|
||||
the target's code. Don't try to write another
|
||||
breakpoint instruction on top of it, or restore
|
||||
its value. Step over it using the architecture's
|
||||
SKIP_INSN macro. */
|
||||
};
|
||||
|
||||
|
||||
/* Disposition of breakpoint. Ie: what to do after hitting it. */
|
||||
|
||||
enum bpdisp
|
||||
{
|
||||
disp_del, /* Delete it */
|
||||
disp_del_at_next_stop, /* Delete at next stop, whether hit or not */
|
||||
disp_disable, /* Disable it */
|
||||
disp_donttouch /* Leave it alone */
|
||||
};
|
||||
|
||||
enum target_hw_bp_type
|
||||
{
|
||||
hw_write = 0, /* Common HW watchpoint */
|
||||
hw_read = 1, /* Read HW watchpoint */
|
||||
hw_access = 2, /* Access HW watchpoint */
|
||||
hw_execute = 3 /* Execute HW breakpoint */
|
||||
};
|
||||
|
||||
/* GDB maintains two types of information about each breakpoint (or
|
||||
watchpoint, or other related event). The first type corresponds
|
||||
to struct breakpoint; this is a relatively high-level structure
|
||||
which contains the source location(s), stopping conditions, user
|
||||
commands to execute when the breakpoint is hit, and so forth.
|
||||
|
||||
The second type of information corresponds to struct bp_location.
|
||||
Each breakpoint has one or (eventually) more locations associated
|
||||
with it, which represent target-specific and machine-specific
|
||||
mechanisms for stopping the program. For instance, a watchpoint
|
||||
expression may require multiple hardware watchpoints in order to
|
||||
catch all changes in the value of the expression being watched. */
|
||||
|
||||
enum bp_loc_type
|
||||
{
|
||||
bp_loc_software_breakpoint,
|
||||
bp_loc_hardware_breakpoint,
|
||||
bp_loc_hardware_watchpoint,
|
||||
bp_loc_other /* Miscellaneous... */
|
||||
};
|
||||
|
||||
struct bp_location
|
||||
{
|
||||
/* Chain pointer to the next breakpoint location. */
|
||||
struct bp_location *next;
|
||||
|
||||
/* Type of this breakpoint location. */
|
||||
enum bp_loc_type loc_type;
|
||||
|
||||
/* Each breakpoint location must belong to exactly one higher-level
|
||||
breakpoint. This and the DUPLICATE flag are more straightforward
|
||||
than reference counting. */
|
||||
struct breakpoint *owner;
|
||||
|
||||
/* Nonzero if this breakpoint is now inserted. */
|
||||
char inserted;
|
||||
|
||||
/* Nonzero if this is not the first breakpoint in the list
|
||||
for the given address. */
|
||||
char duplicate;
|
||||
|
||||
/* If we someday support real thread-specific breakpoints, then
|
||||
the breakpoint location will need a thread identifier. */
|
||||
|
||||
/* Data for specific breakpoint types. These could be a union, but
|
||||
simplicity is more important than memory usage for breakpoints. */
|
||||
|
||||
/* Note that zero is a perfectly valid code address on some platforms
|
||||
(for example, the mn10200 (OBSOLETE) and mn10300 simulators). NULL
|
||||
is not a special value for this field. Valid for all types except
|
||||
bp_loc_other. */
|
||||
CORE_ADDR address;
|
||||
|
||||
/* For any breakpoint type with an address, this is the BFD section
|
||||
associated with the address. Used primarily for overlay debugging. */
|
||||
asection *section;
|
||||
|
||||
/* "Real" contents of byte where breakpoint has been inserted.
|
||||
Valid only when breakpoints are in the program. Under the complete
|
||||
control of the target insert_breakpoint and remove_breakpoint routines.
|
||||
No other code should assume anything about the value(s) here.
|
||||
Valid only for bp_loc_software_breakpoint. */
|
||||
gdb_byte shadow_contents[BREAKPOINT_MAX];
|
||||
|
||||
/* Address at which breakpoint was requested, either by the user or
|
||||
by GDB for internal breakpoints. This will usually be the same
|
||||
as ``address'' (above) except for cases in which
|
||||
ADJUST_BREAKPOINT_ADDRESS has computed a different address at
|
||||
which to place the breakpoint in order to comply with a
|
||||
processor's architectual constraints. */
|
||||
CORE_ADDR requested_address;
|
||||
};
|
||||
|
||||
/* This structure is a collection of function pointers that, if available,
|
||||
will be called instead of the performing the default action for this
|
||||
bptype. */
|
||||
|
||||
struct breakpoint_ops
|
||||
{
|
||||
/* The normal print routine for this breakpoint, called when we
|
||||
hit it. */
|
||||
enum print_stop_action (*print_it) (struct breakpoint *);
|
||||
|
||||
/* Display information about this breakpoint, for "info breakpoints". */
|
||||
void (*print_one) (struct breakpoint *, CORE_ADDR *);
|
||||
|
||||
/* Display information about this breakpoint after setting it (roughly
|
||||
speaking; this is called from "mention"). */
|
||||
void (*print_mention) (struct breakpoint *);
|
||||
};
|
||||
|
||||
/* Note that the ->silent field is not currently used by any commands
|
||||
(though the code is in there if it was to be, and set_raw_breakpoint
|
||||
does set it to 0). I implemented it because I thought it would be
|
||||
useful for a hack I had to put in; I'm going to leave it in because
|
||||
I can see how there might be times when it would indeed be useful */
|
||||
|
||||
/* This is for a breakpoint or a watchpoint. */
|
||||
|
||||
struct breakpoint
|
||||
{
|
||||
struct breakpoint *next;
|
||||
/* Type of breakpoint. */
|
||||
enum bptype type;
|
||||
/* Zero means disabled; remember the info but don't break here. */
|
||||
enum enable_state enable_state;
|
||||
/* What to do with this breakpoint after we hit it. */
|
||||
enum bpdisp disposition;
|
||||
/* Number assigned to distinguish breakpoints. */
|
||||
int number;
|
||||
|
||||
/* Location(s) associated with this high-level breakpoint. */
|
||||
struct bp_location *loc;
|
||||
|
||||
/* Line number of this address. */
|
||||
|
||||
int line_number;
|
||||
|
||||
/* Source file name of this address. */
|
||||
|
||||
char *source_file;
|
||||
|
||||
/* Non-zero means a silent breakpoint (don't print frame info
|
||||
if we stop here). */
|
||||
unsigned char silent;
|
||||
/* Number of stops at this breakpoint that should
|
||||
be continued automatically before really stopping. */
|
||||
int ignore_count;
|
||||
/* Chain of command lines to execute when this breakpoint is hit. */
|
||||
struct command_line *commands;
|
||||
/* Stack depth (address of frame). If nonzero, break only if fp
|
||||
equals this. */
|
||||
struct frame_id frame_id;
|
||||
/* Conditional. Break only if this expression's value is nonzero. */
|
||||
struct expression *cond;
|
||||
|
||||
/* String we used to set the breakpoint (malloc'd). */
|
||||
char *addr_string;
|
||||
/* Language we used to set the breakpoint. */
|
||||
enum language language;
|
||||
/* Input radix we used to set the breakpoint. */
|
||||
int input_radix;
|
||||
/* String form of the breakpoint condition (malloc'd), or NULL if there
|
||||
is no condition. */
|
||||
char *cond_string;
|
||||
/* String form of exp (malloc'd), or NULL if none. */
|
||||
char *exp_string;
|
||||
|
||||
/* The expression we are watching, or NULL if not a watchpoint. */
|
||||
struct expression *exp;
|
||||
/* The largest block within which it is valid, or NULL if it is
|
||||
valid anywhere (e.g. consists just of global symbols). */
|
||||
struct block *exp_valid_block;
|
||||
/* Value of the watchpoint the last time we checked it. */
|
||||
struct value *val;
|
||||
|
||||
/* Holds the value chain for a hardware watchpoint expression. */
|
||||
struct value *val_chain;
|
||||
|
||||
/* Holds the address of the related watchpoint_scope breakpoint
|
||||
when using watchpoints on local variables (might the concept
|
||||
of a related breakpoint be useful elsewhere, if not just call
|
||||
it the watchpoint_scope breakpoint or something like that. FIXME). */
|
||||
struct breakpoint *related_breakpoint;
|
||||
|
||||
/* Holds the frame address which identifies the frame this
|
||||
watchpoint should be evaluated in, or `null' if the watchpoint
|
||||
should be evaluated on the outermost frame. */
|
||||
struct frame_id watchpoint_frame;
|
||||
|
||||
/* Thread number for thread-specific breakpoint, or -1 if don't care */
|
||||
int thread;
|
||||
|
||||
/* Count of the number of times this breakpoint was taken, dumped
|
||||
with the info, but not used for anything else. Useful for
|
||||
seeing how many times you hit a break prior to the program
|
||||
aborting, so you can back up to just before the abort. */
|
||||
int hit_count;
|
||||
|
||||
/* Filename of a dynamically-linked library (dll), used for
|
||||
bp_catch_load and bp_catch_unload (malloc'd), or NULL if any
|
||||
library is significant. */
|
||||
char *dll_pathname;
|
||||
|
||||
/* Filename of a dll whose state change (e.g., load or unload)
|
||||
triggered this catchpoint. This field is only valid immediately
|
||||
after this catchpoint has triggered. */
|
||||
char *triggered_dll_pathname;
|
||||
|
||||
/* Process id of a child process whose forking triggered this
|
||||
catchpoint. This field is only valid immediately after this
|
||||
catchpoint has triggered. */
|
||||
int forked_inferior_pid;
|
||||
|
||||
/* Filename of a program whose exec triggered this catchpoint.
|
||||
This field is only valid immediately after this catchpoint has
|
||||
triggered. */
|
||||
char *exec_pathname;
|
||||
|
||||
/* Methods associated with this breakpoint. */
|
||||
struct breakpoint_ops *ops;
|
||||
|
||||
/* Was breakpoint issued from a tty? Saved for the use of pending breakpoints. */
|
||||
int from_tty;
|
||||
|
||||
/* Flag value for pending breakpoint.
|
||||
first bit : 0 non-temporary, 1 temporary.
|
||||
second bit : 0 normal breakpoint, 1 hardware breakpoint. */
|
||||
int flag;
|
||||
|
||||
/* Is breakpoint pending on shlib loads? */
|
||||
int pending;
|
||||
};
|
||||
|
||||
/* The following stuff is an abstract data type "bpstat" ("breakpoint
|
||||
status"). This provides the ability to determine whether we have
|
||||
stopped at a breakpoint, and what we should do about it. */
|
||||
|
||||
typedef struct bpstats *bpstat;
|
||||
|
||||
/* Interface: */
|
||||
/* Clear a bpstat so that it says we are not at any breakpoint.
|
||||
Also free any storage that is part of a bpstat. */
|
||||
extern void bpstat_clear (bpstat *);
|
||||
|
||||
/* Return a copy of a bpstat. Like "bs1 = bs2" but all storage that
|
||||
is part of the bpstat is copied as well. */
|
||||
extern bpstat bpstat_copy (bpstat);
|
||||
|
||||
extern bpstat bpstat_stop_status (CORE_ADDR pc, ptid_t ptid,
|
||||
int stopped_by_watchpoint);
|
||||
|
||||
/* This bpstat_what stuff tells wait_for_inferior what to do with a
|
||||
breakpoint (a challenging task). */
|
||||
|
||||
enum bpstat_what_main_action
|
||||
{
|
||||
/* Perform various other tests; that is, this bpstat does not
|
||||
say to perform any action (e.g. failed watchpoint and nothing
|
||||
else). */
|
||||
BPSTAT_WHAT_KEEP_CHECKING,
|
||||
|
||||
/* Rather than distinguish between noisy and silent stops here, it
|
||||
might be cleaner to have bpstat_print make that decision (also
|
||||
taking into account stop_print_frame and source_only). But the
|
||||
implications are a bit scary (interaction with auto-displays, etc.),
|
||||
so I won't try it. */
|
||||
|
||||
/* Stop silently. */
|
||||
BPSTAT_WHAT_STOP_SILENT,
|
||||
|
||||
/* Stop and print. */
|
||||
BPSTAT_WHAT_STOP_NOISY,
|
||||
|
||||
/* Remove breakpoints, single step once, then put them back in and
|
||||
go back to what we were doing. It's possible that this should be
|
||||
removed from the main_action and put into a separate field, to more
|
||||
cleanly handle BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE. */
|
||||
BPSTAT_WHAT_SINGLE,
|
||||
|
||||
/* Set longjmp_resume breakpoint, remove all other breakpoints,
|
||||
and continue. The "remove all other breakpoints" part is required
|
||||
if we are also stepping over another breakpoint as well as doing
|
||||
the longjmp handling. */
|
||||
BPSTAT_WHAT_SET_LONGJMP_RESUME,
|
||||
|
||||
/* Clear longjmp_resume breakpoint, then handle as
|
||||
BPSTAT_WHAT_KEEP_CHECKING. */
|
||||
BPSTAT_WHAT_CLEAR_LONGJMP_RESUME,
|
||||
|
||||
/* Clear longjmp_resume breakpoint, then handle as BPSTAT_WHAT_SINGLE. */
|
||||
BPSTAT_WHAT_CLEAR_LONGJMP_RESUME_SINGLE,
|
||||
|
||||
/* Clear step resume breakpoint, and keep checking. */
|
||||
BPSTAT_WHAT_STEP_RESUME,
|
||||
|
||||
/* Clear through_sigtramp breakpoint, muck with trap_expected, and keep
|
||||
checking. */
|
||||
BPSTAT_WHAT_THROUGH_SIGTRAMP,
|
||||
|
||||
/* Check the dynamic linker's data structures for new libraries, then
|
||||
keep checking. */
|
||||
BPSTAT_WHAT_CHECK_SHLIBS,
|
||||
|
||||
/* Check the dynamic linker's data structures for new libraries, then
|
||||
resume out of the dynamic linker's callback, stop and print. */
|
||||
BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK,
|
||||
|
||||
/* This is just used to keep track of how many enums there are. */
|
||||
BPSTAT_WHAT_LAST
|
||||
};
|
||||
|
||||
struct bpstat_what
|
||||
{
|
||||
enum bpstat_what_main_action main_action;
|
||||
|
||||
/* Did we hit a call dummy breakpoint? This only goes with a main_action
|
||||
of BPSTAT_WHAT_STOP_SILENT or BPSTAT_WHAT_STOP_NOISY (the concept of
|
||||
continuing from a call dummy without popping the frame is not a
|
||||
useful one). */
|
||||
int call_dummy;
|
||||
};
|
||||
|
||||
/* The possible return values for print_bpstat, print_it_normal,
|
||||
print_it_done, print_it_noop. */
|
||||
enum print_stop_action
|
||||
{
|
||||
PRINT_UNKNOWN = -1,
|
||||
PRINT_SRC_AND_LOC,
|
||||
PRINT_SRC_ONLY,
|
||||
PRINT_NOTHING
|
||||
};
|
||||
|
||||
/* Tell what to do about this bpstat. */
|
||||
struct bpstat_what bpstat_what (bpstat);
|
||||
|
||||
/* Find the bpstat associated with a breakpoint. NULL otherwise. */
|
||||
bpstat bpstat_find_breakpoint (bpstat, struct breakpoint *);
|
||||
|
||||
/* Find a step_resume breakpoint associated with this bpstat.
|
||||
(If there are multiple step_resume bp's on the list, this function
|
||||
will arbitrarily pick one.)
|
||||
|
||||
It is an error to use this function if BPSTAT doesn't contain a
|
||||
step_resume breakpoint.
|
||||
|
||||
See wait_for_inferior's use of this function.
|
||||
*/
|
||||
extern struct breakpoint *bpstat_find_step_resume_breakpoint (bpstat);
|
||||
|
||||
/* Nonzero if a signal that we got in wait() was due to circumstances
|
||||
explained by the BS. */
|
||||
/* Currently that is true if we have hit a breakpoint, or if there is
|
||||
a watchpoint enabled. */
|
||||
#define bpstat_explains_signal(bs) ((bs) != NULL)
|
||||
|
||||
/* Nonzero if we should step constantly (e.g. watchpoints on machines
|
||||
without hardware support). This isn't related to a specific bpstat,
|
||||
just to things like whether watchpoints are set. */
|
||||
extern int bpstat_should_step (void);
|
||||
|
||||
/* Nonzero if there are enabled hardware watchpoints. */
|
||||
extern int bpstat_have_active_hw_watchpoints (void);
|
||||
|
||||
/* Print a message indicating what happened. Returns nonzero to
|
||||
say that only the source line should be printed after this (zero
|
||||
return means print the frame as well as the source line). */
|
||||
extern enum print_stop_action bpstat_print (bpstat);
|
||||
|
||||
/* Return the breakpoint number of the first breakpoint we are stopped
|
||||
at. *BSP upon return is a bpstat which points to the remaining
|
||||
breakpoints stopped at (but which is not guaranteed to be good for
|
||||
anything but further calls to bpstat_num).
|
||||
Return 0 if passed a bpstat which does not indicate any breakpoints. */
|
||||
extern int bpstat_num (bpstat *);
|
||||
|
||||
/* Perform actions associated with having stopped at *BSP. Actually, we just
|
||||
use this for breakpoint commands. Perhaps other actions will go here
|
||||
later, but this is executed at a late time (from the command loop). */
|
||||
extern void bpstat_do_actions (bpstat *);
|
||||
|
||||
/* Modify BS so that the actions will not be performed. */
|
||||
extern void bpstat_clear_actions (bpstat);
|
||||
|
||||
/* Given a bpstat that records zero or more triggered eventpoints, this
|
||||
function returns another bpstat which contains only the catchpoints
|
||||
on that first list, if any.
|
||||
*/
|
||||
extern void bpstat_get_triggered_catchpoints (bpstat, bpstat *);
|
||||
|
||||
/* Implementation: */
|
||||
|
||||
/* Values used to tell the printing routine how to behave for this bpstat. */
|
||||
enum bp_print_how
|
||||
{
|
||||
/* This is used when we want to do a normal printing of the reason
|
||||
for stopping. The output will depend on the type of eventpoint
|
||||
we are dealing with. This is the default value, most commonly
|
||||
used. */
|
||||
print_it_normal,
|
||||
/* This is used when nothing should be printed for this bpstat entry. */
|
||||
print_it_noop,
|
||||
/* This is used when everything which needs to be printed has
|
||||
already been printed. But we still want to print the frame. */
|
||||
print_it_done
|
||||
};
|
||||
|
||||
struct bpstats
|
||||
{
|
||||
/* Linked list because there can be two breakpoints at the same
|
||||
place, and a bpstat reflects the fact that both have been hit. */
|
||||
bpstat next;
|
||||
/* Breakpoint that we are at. */
|
||||
struct breakpoint *breakpoint_at;
|
||||
/* Commands left to be done. */
|
||||
struct command_line *commands;
|
||||
/* Old value associated with a watchpoint. */
|
||||
struct value *old_val;
|
||||
|
||||
/* Nonzero if this breakpoint tells us to print the frame. */
|
||||
char print;
|
||||
|
||||
/* Nonzero if this breakpoint tells us to stop. */
|
||||
char stop;
|
||||
|
||||
/* Tell bpstat_print and print_bp_stop_message how to print stuff
|
||||
associated with this element of the bpstat chain. */
|
||||
enum bp_print_how print_it;
|
||||
};
|
||||
|
||||
enum inf_context
|
||||
{
|
||||
inf_starting,
|
||||
inf_running,
|
||||
inf_exited
|
||||
};
|
||||
|
||||
/* The possible return values for breakpoint_here_p.
|
||||
We guarantee that zero always means "no breakpoint here". */
|
||||
enum breakpoint_here
|
||||
{
|
||||
no_breakpoint_here = 0,
|
||||
ordinary_breakpoint_here,
|
||||
permanent_breakpoint_here
|
||||
};
|
||||
|
||||
|
||||
/* Prototypes for breakpoint-related functions. */
|
||||
|
||||
extern enum breakpoint_here breakpoint_here_p (CORE_ADDR);
|
||||
|
||||
extern int breakpoint_inserted_here_p (CORE_ADDR);
|
||||
|
||||
extern int software_breakpoint_inserted_here_p (CORE_ADDR);
|
||||
|
||||
extern int breakpoint_thread_match (CORE_ADDR, ptid_t);
|
||||
|
||||
extern void until_break_command (char *, int, int);
|
||||
|
||||
extern void breakpoint_re_set (void);
|
||||
|
||||
extern void breakpoint_re_set_thread (struct breakpoint *);
|
||||
|
||||
extern int ep_is_exception_catchpoint (struct breakpoint *);
|
||||
|
||||
extern struct breakpoint *set_momentary_breakpoint
|
||||
(struct symtab_and_line, struct frame_id, enum bptype);
|
||||
|
||||
extern void set_ignore_count (int, int, int);
|
||||
|
||||
extern void set_default_breakpoint (int, CORE_ADDR, struct symtab *, int);
|
||||
|
||||
extern void mark_breakpoints_out (void);
|
||||
|
||||
extern void breakpoint_init_inferior (enum inf_context);
|
||||
|
||||
extern struct cleanup *make_cleanup_delete_breakpoint (struct breakpoint *);
|
||||
|
||||
extern struct cleanup *make_exec_cleanup_delete_breakpoint (struct breakpoint *);
|
||||
|
||||
extern void delete_breakpoint (struct breakpoint *);
|
||||
|
||||
extern void breakpoint_auto_delete (bpstat);
|
||||
|
||||
extern void breakpoint_clear_ignore_counts (void);
|
||||
|
||||
extern void break_command (char *, int);
|
||||
|
||||
extern void hbreak_command_wrapper (char *, int);
|
||||
extern void thbreak_command_wrapper (char *, int);
|
||||
extern void rbreak_command_wrapper (char *, int);
|
||||
extern void watch_command_wrapper (char *, int);
|
||||
extern void awatch_command_wrapper (char *, int);
|
||||
extern void rwatch_command_wrapper (char *, int);
|
||||
extern void tbreak_command (char *, int);
|
||||
|
||||
extern int insert_breakpoints (void);
|
||||
|
||||
extern int remove_breakpoints (void);
|
||||
|
||||
/* This function can be used to physically insert eventpoints from the
|
||||
specified traced inferior process, without modifying the breakpoint
|
||||
package's state. This can be useful for those targets which support
|
||||
following the processes of a fork() or vfork() system call, when both
|
||||
of the resulting two processes are to be followed. */
|
||||
extern int reattach_breakpoints (int);
|
||||
|
||||
/* This function can be used to update the breakpoint package's state
|
||||
after an exec() system call has been executed.
|
||||
|
||||
This function causes the following:
|
||||
|
||||
- All eventpoints are marked "not inserted".
|
||||
- All eventpoints with a symbolic address are reset such that
|
||||
the symbolic address must be reevaluated before the eventpoints
|
||||
can be reinserted.
|
||||
- The solib breakpoints are explicitly removed from the breakpoint
|
||||
list.
|
||||
- A step-resume breakpoint, if any, is explicitly removed from the
|
||||
breakpoint list.
|
||||
- All eventpoints without a symbolic address are removed from the
|
||||
breakpoint list. */
|
||||
extern void update_breakpoints_after_exec (void);
|
||||
|
||||
/* This function can be used to physically remove hardware breakpoints
|
||||
and watchpoints from the specified traced inferior process, without
|
||||
modifying the breakpoint package's state. This can be useful for
|
||||
those targets which support following the processes of a fork() or
|
||||
vfork() system call, when one of the resulting two processes is to
|
||||
be detached and allowed to run free.
|
||||
|
||||
It is an error to use this function on the process whose id is
|
||||
inferior_ptid. */
|
||||
extern int detach_breakpoints (int);
|
||||
|
||||
extern void enable_longjmp_breakpoint (void);
|
||||
extern void disable_longjmp_breakpoint (void);
|
||||
extern void enable_overlay_breakpoints (void);
|
||||
extern void disable_overlay_breakpoints (void);
|
||||
|
||||
extern void set_longjmp_resume_breakpoint (CORE_ADDR, struct frame_id);
|
||||
/* These functions respectively disable or reenable all currently
|
||||
enabled watchpoints. When disabled, the watchpoints are marked
|
||||
call_disabled. When reenabled, they are marked enabled.
|
||||
|
||||
The intended client of these functions is call_function_by_hand.
|
||||
|
||||
The inferior must be stopped, and all breakpoints removed, when
|
||||
these functions are used.
|
||||
|
||||
The need for these functions is that on some targets (e.g., HP-UX),
|
||||
gdb is unable to unwind through the dummy frame that is pushed as
|
||||
part of the implementation of a call command. Watchpoints can
|
||||
cause the inferior to stop in places where this frame is visible,
|
||||
and that can cause execution control to become very confused.
|
||||
|
||||
Note that if a user sets breakpoints in an interactively called
|
||||
function, the call_disabled watchpoints will have been reenabled
|
||||
when the first such breakpoint is reached. However, on targets
|
||||
that are unable to unwind through the call dummy frame, watches
|
||||
of stack-based storage may then be deleted, because gdb will
|
||||
believe that their watched storage is out of scope. (Sigh.) */
|
||||
extern void disable_watchpoints_before_interactive_call_start (void);
|
||||
|
||||
extern void enable_watchpoints_after_interactive_call_stop (void);
|
||||
|
||||
|
||||
extern void clear_breakpoint_hit_counts (void);
|
||||
|
||||
extern int get_number (char **);
|
||||
|
||||
extern int get_number_or_range (char **);
|
||||
|
||||
/* The following are for displays, which aren't really breakpoints, but
|
||||
here is as good a place as any for them. */
|
||||
|
||||
extern void disable_current_display (void);
|
||||
|
||||
extern void do_displays (void);
|
||||
|
||||
extern void disable_display (int);
|
||||
|
||||
extern void clear_displays (void);
|
||||
|
||||
extern void disable_breakpoint (struct breakpoint *);
|
||||
|
||||
extern void enable_breakpoint (struct breakpoint *);
|
||||
|
||||
extern void make_breakpoint_permanent (struct breakpoint *);
|
||||
|
||||
extern struct breakpoint *create_solib_event_breakpoint (CORE_ADDR);
|
||||
|
||||
extern struct breakpoint *create_thread_event_breakpoint (CORE_ADDR);
|
||||
|
||||
extern void remove_solib_event_breakpoints (void);
|
||||
|
||||
extern void remove_thread_event_breakpoints (void);
|
||||
|
||||
extern void disable_breakpoints_in_shlibs (int silent);
|
||||
|
||||
extern void re_enable_breakpoints_in_shlibs (void);
|
||||
|
||||
extern void create_solib_load_event_breakpoint (char *, int, char *, char *);
|
||||
|
||||
extern void create_solib_unload_event_breakpoint (char *, int,
|
||||
char *, char *);
|
||||
|
||||
extern void create_fork_event_catchpoint (int, char *);
|
||||
|
||||
extern void create_vfork_event_catchpoint (int, char *);
|
||||
|
||||
extern void create_exec_event_catchpoint (int, char *);
|
||||
|
||||
/* This function returns TRUE if ep is a catchpoint. */
|
||||
extern int ep_is_catchpoint (struct breakpoint *);
|
||||
|
||||
/* This function returns TRUE if ep is a catchpoint of a
|
||||
shared library (aka dynamically-linked library) event,
|
||||
such as a library load or unload. */
|
||||
extern int ep_is_shlib_catchpoint (struct breakpoint *);
|
||||
|
||||
extern struct breakpoint *set_breakpoint_sal (struct symtab_and_line);
|
||||
|
||||
/* Enable breakpoints and delete when hit. Called with ARG == NULL
|
||||
deletes all breakpoints. */
|
||||
extern void delete_command (char *arg, int from_tty);
|
||||
|
||||
/* Pull all H/W watchpoints from the target. Return non-zero if the
|
||||
remove fails. */
|
||||
extern int remove_hw_watchpoints (void);
|
||||
|
||||
|
||||
/* Indicator of whether exception catchpoints should be nuked between
|
||||
runs of a program. */
|
||||
extern int deprecated_exception_catchpoints_are_fragile;
|
||||
|
||||
/* Indicator of when exception catchpoints set-up should be
|
||||
reinitialized -- e.g. when program is re-run. */
|
||||
extern int deprecated_exception_support_initialized;
|
||||
|
||||
#endif /* !defined (BREAKPOINT_H) */
|
||||
342
gdb/bsd-kvm.c
342
gdb/bsd-kvm.c
@@ -1,342 +0,0 @@
|
||||
/* BSD Kernel Data Access Library (libkvm) interface.
|
||||
|
||||
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "cli/cli-cmds.h"
|
||||
#include "command.h"
|
||||
#include "frame.h"
|
||||
#include "regcache.h"
|
||||
#include "target.h"
|
||||
#include "value.h"
|
||||
#include "gdbcore.h" /* for get_exec_file */
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include <fcntl.h>
|
||||
#include <kvm.h>
|
||||
#ifdef HAVE_NLIST_H
|
||||
#include <nlist.h>
|
||||
#endif
|
||||
#include <paths.h>
|
||||
#include "readline/readline.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "bsd-kvm.h"
|
||||
|
||||
/* Kernel memory device file. */
|
||||
static const char *bsd_kvm_corefile;
|
||||
|
||||
/* Kernel memory interface descriptor. */
|
||||
static kvm_t *core_kd;
|
||||
|
||||
/* Address of process control block. */
|
||||
static struct pcb *bsd_kvm_paddr;
|
||||
|
||||
/* Pointer to architecture-specific function that reconstructs the
|
||||
register state from PCB and supplies it to REGCACHE. */
|
||||
static int (*bsd_kvm_supply_pcb)(struct regcache *regcache, struct pcb *pcb);
|
||||
|
||||
/* Target ops for libkvm interface. */
|
||||
static struct target_ops bsd_kvm_ops;
|
||||
|
||||
static void
|
||||
bsd_kvm_open (char *filename, int from_tty)
|
||||
{
|
||||
char errbuf[_POSIX2_LINE_MAX];
|
||||
char *execfile = NULL;
|
||||
kvm_t *temp_kd;
|
||||
|
||||
target_preopen (from_tty);
|
||||
|
||||
if (filename)
|
||||
{
|
||||
char *temp;
|
||||
|
||||
filename = tilde_expand (filename);
|
||||
if (filename[0] != '/')
|
||||
{
|
||||
temp = concat (current_directory, "/", filename, (char *)NULL);
|
||||
xfree (filename);
|
||||
filename = temp;
|
||||
}
|
||||
}
|
||||
|
||||
execfile = get_exec_file (0);
|
||||
temp_kd = kvm_openfiles (execfile, filename, NULL, O_RDONLY, errbuf);
|
||||
if (temp_kd == NULL)
|
||||
error (("%s"), errbuf);
|
||||
|
||||
bsd_kvm_corefile = filename;
|
||||
unpush_target (&bsd_kvm_ops);
|
||||
core_kd = temp_kd;
|
||||
push_target (&bsd_kvm_ops);
|
||||
|
||||
target_fetch_registers (-1);
|
||||
|
||||
flush_cached_frames ();
|
||||
select_frame (get_current_frame ());
|
||||
print_stack_frame (get_selected_frame (NULL), -1, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_kvm_close (int quitting)
|
||||
{
|
||||
if (core_kd)
|
||||
{
|
||||
if (kvm_close (core_kd) == -1)
|
||||
warning (("%s"), kvm_geterr(core_kd));
|
||||
core_kd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static LONGEST
|
||||
bsd_kvm_xfer_memory (CORE_ADDR addr, ULONGEST len,
|
||||
gdb_byte *readbuf, const gdb_byte *writebuf)
|
||||
{
|
||||
ssize_t nbytes = len;
|
||||
|
||||
if (readbuf)
|
||||
nbytes = kvm_read (core_kd, addr, readbuf, nbytes);
|
||||
if (writebuf && nbytes > 0)
|
||||
nbytes = kvm_write (core_kd, addr, writebuf, nbytes);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static LONGEST
|
||||
bsd_kvm_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
const char *annex, gdb_byte *readbuf,
|
||||
const gdb_byte *writebuf,
|
||||
ULONGEST offset, LONGEST len)
|
||||
{
|
||||
switch (object)
|
||||
{
|
||||
case TARGET_OBJECT_MEMORY:
|
||||
return bsd_kvm_xfer_memory (offset, len, readbuf, writebuf);
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_kvm_files_info (struct target_ops *ops)
|
||||
{
|
||||
if (bsd_kvm_corefile && strcmp (bsd_kvm_corefile, _PATH_MEM) != 0)
|
||||
printf_filtered (_("\tUsing the kernel crash dump %s.\n"),
|
||||
bsd_kvm_corefile);
|
||||
else
|
||||
printf_filtered (_("\tUsing the currently running kernel.\n"));
|
||||
}
|
||||
|
||||
/* Fetch process control block at address PADDR. */
|
||||
|
||||
static int
|
||||
bsd_kvm_fetch_pcb (struct pcb *paddr)
|
||||
{
|
||||
struct pcb pcb;
|
||||
|
||||
if (kvm_read (core_kd, (unsigned long) paddr, &pcb, sizeof pcb) == -1)
|
||||
error (("%s"), kvm_geterr (core_kd));
|
||||
|
||||
gdb_assert (bsd_kvm_supply_pcb);
|
||||
return bsd_kvm_supply_pcb (current_regcache, &pcb);
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_kvm_fetch_registers (int regnum)
|
||||
{
|
||||
struct nlist nl[2];
|
||||
|
||||
if (bsd_kvm_paddr)
|
||||
{
|
||||
bsd_kvm_fetch_pcb (bsd_kvm_paddr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* On dumping core, BSD kernels store the faulting context (PCB)
|
||||
in the variable "dumppcb". */
|
||||
memset (nl, 0, sizeof nl);
|
||||
nl[0].n_name = "_dumppcb";
|
||||
|
||||
if (kvm_nlist (core_kd, nl) == -1)
|
||||
error (("%s"), kvm_geterr (core_kd));
|
||||
|
||||
if (nl[0].n_value != 0)
|
||||
{
|
||||
/* Found dumppcb. If it contains a valid context, return
|
||||
immediately. */
|
||||
if (bsd_kvm_fetch_pcb ((struct pcb *) nl[0].n_value))
|
||||
return;
|
||||
}
|
||||
|
||||
/* Traditional BSD kernels have a process proc0 that should always
|
||||
be present. The address of proc0's PCB is stored in the variable
|
||||
"proc0paddr". */
|
||||
|
||||
memset (nl, 0, sizeof nl);
|
||||
nl[0].n_name = "_proc0paddr";
|
||||
|
||||
if (kvm_nlist (core_kd, nl) == -1)
|
||||
error (("%s"), kvm_geterr (core_kd));
|
||||
|
||||
if (nl[0].n_value != 0)
|
||||
{
|
||||
struct pcb *paddr;
|
||||
|
||||
/* Found proc0paddr. */
|
||||
if (kvm_read (core_kd, nl[0].n_value, &paddr, sizeof paddr) == -1)
|
||||
error (("%s"), kvm_geterr (core_kd));
|
||||
|
||||
bsd_kvm_fetch_pcb (paddr);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_STRUCT_THREAD_TD_PCB
|
||||
/* In FreeBSD kernels for 5.0-RELEASE and later, the PCB no longer
|
||||
lives in `struct proc' but in `struct thread'. The `struct
|
||||
thread' for the initial thread for proc0 can be found in the
|
||||
variable "thread0". */
|
||||
|
||||
memset (nl, 0, sizeof nl);
|
||||
nl[0].n_name = "_thread0";
|
||||
|
||||
if (kvm_nlist (core_kd, nl) == -1)
|
||||
error (("%s"), kvm_geterr (core_kd));
|
||||
|
||||
if (nl[0].n_value != 0)
|
||||
{
|
||||
struct pcb *paddr;
|
||||
|
||||
/* Found thread0. */
|
||||
nl[0].n_value += offsetof (struct thread, td_pcb);
|
||||
if (kvm_read (core_kd, nl[0].n_value, &paddr, sizeof paddr) == -1)
|
||||
error (("%s"), kvm_geterr (core_kd));
|
||||
|
||||
bsd_kvm_fetch_pcb (paddr);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* i18n: PCB == "Process Control Block" */
|
||||
error (_("Cannot find a valid PCB"));
|
||||
}
|
||||
|
||||
|
||||
/* Kernel memory interface commands. */
|
||||
struct cmd_list_element *bsd_kvm_cmdlist;
|
||||
|
||||
static void
|
||||
bsd_kvm_cmd (char *arg, int fromtty)
|
||||
{
|
||||
/* ??? Should this become an alias for "target kvm"? */
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRUCT_THREAD_TD_PCB
|
||||
|
||||
static void
|
||||
bsd_kvm_proc_cmd (char *arg, int fromtty)
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
|
||||
if (arg == NULL)
|
||||
error_no_arg (_("proc address"));
|
||||
|
||||
if (core_kd == NULL)
|
||||
error (_("No kernel memory image."));
|
||||
|
||||
addr = parse_and_eval_address (arg);
|
||||
#ifdef HAVE_STRUCT_LWP
|
||||
addr += offsetof (struct lwp, l_addr);
|
||||
#else
|
||||
addr += offsetof (struct proc, p_addr);
|
||||
#endif
|
||||
|
||||
if (kvm_read (core_kd, addr, &bsd_kvm_paddr, sizeof bsd_kvm_paddr) == -1)
|
||||
error (("%s"), kvm_geterr (core_kd));
|
||||
|
||||
target_fetch_registers (-1);
|
||||
|
||||
flush_cached_frames ();
|
||||
select_frame (get_current_frame ());
|
||||
print_stack_frame (get_selected_frame (NULL), -1, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
bsd_kvm_pcb_cmd (char *arg, int fromtty)
|
||||
{
|
||||
if (arg == NULL)
|
||||
/* i18n: PCB == "Process Control Block" */
|
||||
error_no_arg (_("pcb address"));
|
||||
|
||||
if (core_kd == NULL)
|
||||
error (_("No kernel memory image."));
|
||||
|
||||
bsd_kvm_paddr = (struct pcb *)(u_long) parse_and_eval_address (arg);
|
||||
|
||||
target_fetch_registers (-1);
|
||||
|
||||
flush_cached_frames ();
|
||||
select_frame (get_current_frame ());
|
||||
print_stack_frame (get_selected_frame (NULL), -1, 1);
|
||||
}
|
||||
|
||||
/* Add the libkvm interface to the list of all possible targets and
|
||||
register CUPPLY_PCB as the architecture-specific process control
|
||||
block interpreter. */
|
||||
|
||||
void
|
||||
bsd_kvm_add_target (int (*supply_pcb)(struct regcache *, struct pcb *))
|
||||
{
|
||||
gdb_assert (bsd_kvm_supply_pcb == NULL);
|
||||
bsd_kvm_supply_pcb = supply_pcb;
|
||||
|
||||
bsd_kvm_ops.to_shortname = "kvm";
|
||||
bsd_kvm_ops.to_longname = _("Kernel memory interface");
|
||||
bsd_kvm_ops.to_doc = _("Use a kernel virtual memory image as a target.\n\
|
||||
Optionally specify the filename of a core dump.");
|
||||
bsd_kvm_ops.to_open = bsd_kvm_open;
|
||||
bsd_kvm_ops.to_close = bsd_kvm_close;
|
||||
bsd_kvm_ops.to_fetch_registers = bsd_kvm_fetch_registers;
|
||||
bsd_kvm_ops.to_xfer_partial = bsd_kvm_xfer_partial;
|
||||
bsd_kvm_ops.to_files_info = bsd_kvm_files_info;
|
||||
bsd_kvm_ops.to_stratum = process_stratum;
|
||||
bsd_kvm_ops.to_has_memory = 1;
|
||||
bsd_kvm_ops.to_has_stack = 1;
|
||||
bsd_kvm_ops.to_has_registers = 1;
|
||||
bsd_kvm_ops.to_magic = OPS_MAGIC;
|
||||
|
||||
add_target (&bsd_kvm_ops);
|
||||
|
||||
add_prefix_cmd ("kvm", class_obscure, bsd_kvm_cmd, _("\
|
||||
Generic command for manipulating the kernel memory interface."),
|
||||
&bsd_kvm_cmdlist, "kvm ", 0, &cmdlist);
|
||||
|
||||
#ifndef HAVE_STRUCT_THREAD_TD_PCB
|
||||
add_cmd ("proc", class_obscure, bsd_kvm_proc_cmd,
|
||||
_("Set current context from proc address"), &bsd_kvm_cmdlist);
|
||||
#endif
|
||||
add_cmd ("pcb", class_obscure, bsd_kvm_pcb_cmd,
|
||||
/* i18n: PCB == "Process Control Block" */
|
||||
_("Set current context from pcb address"), &bsd_kvm_cmdlist);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/* BSD Kernel Data Access Library (libkvm) interface.
|
||||
|
||||
Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef BSD_KVM_H
|
||||
#define BSD_KVM_H
|
||||
|
||||
struct pcb;
|
||||
struct regcache;
|
||||
|
||||
/* Add the libkvm interface to the list of all possible targets and
|
||||
register CUPPLY_PCB as the architecture-specific process control
|
||||
block interpreter. */
|
||||
|
||||
extern void
|
||||
bsd_kvm_add_target (int (*supply_pcb)(struct regcache *, struct pcb *));
|
||||
|
||||
#endif /* bsd-kvm.h */
|
||||
@@ -1,516 +0,0 @@
|
||||
/* BSD user-level threads support.
|
||||
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbcore.h"
|
||||
#include "gdbthread.h"
|
||||
#include "inferior.h"
|
||||
#include "objfiles.h"
|
||||
#include "observer.h"
|
||||
#include "regcache.h"
|
||||
#include "solib.h"
|
||||
#include "solist.h"
|
||||
#include "symfile.h"
|
||||
#include "target.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_obstack.h"
|
||||
|
||||
#include "bsd-uthread.h"
|
||||
|
||||
/* HACK: Save the bsd_uthreads ops returned by bsd_uthread_target. */
|
||||
static struct target_ops *bsd_uthread_ops_hack;
|
||||
|
||||
|
||||
/* Architecture-specific operations. */
|
||||
|
||||
/* Per-architecture data key. */
|
||||
static struct gdbarch_data *bsd_uthread_data;
|
||||
|
||||
struct bsd_uthread_ops
|
||||
{
|
||||
/* Supply registers for an inactive thread to a register cache. */
|
||||
void (*supply_uthread)(struct regcache *, int, CORE_ADDR);
|
||||
|
||||
/* Collect registers for an inactive thread from a register cache. */
|
||||
void (*collect_uthread)(const struct regcache *, int, CORE_ADDR);
|
||||
};
|
||||
|
||||
static void *
|
||||
bsd_uthread_init (struct obstack *obstack)
|
||||
{
|
||||
struct bsd_uthread_ops *ops;
|
||||
|
||||
ops = OBSTACK_ZALLOC (obstack, struct bsd_uthread_ops);
|
||||
return ops;
|
||||
}
|
||||
|
||||
/* Set the function that supplies registers from an inactive thread
|
||||
for architecture GDBARCH to SUPPLY_UTHREAD. */
|
||||
|
||||
void
|
||||
bsd_uthread_set_supply_uthread (struct gdbarch *gdbarch,
|
||||
void (*supply_uthread) (struct regcache *,
|
||||
int, CORE_ADDR))
|
||||
{
|
||||
struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
|
||||
ops->supply_uthread = supply_uthread;
|
||||
}
|
||||
|
||||
/* Set the function that collects registers for an inactive thread for
|
||||
architecture GDBARCH to SUPPLY_UTHREAD. */
|
||||
|
||||
void
|
||||
bsd_uthread_set_collect_uthread (struct gdbarch *gdbarch,
|
||||
void (*collect_uthread) (const struct regcache *,
|
||||
int, CORE_ADDR))
|
||||
{
|
||||
struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
|
||||
ops->collect_uthread = collect_uthread;
|
||||
}
|
||||
|
||||
/* Magic number to help recognize a valid thread structure. */
|
||||
#define BSD_UTHREAD_PTHREAD_MAGIC 0xd09ba115
|
||||
|
||||
/* Check whether the thread structure at ADDR is valid. */
|
||||
|
||||
static void
|
||||
bsd_uthread_check_magic (CORE_ADDR addr)
|
||||
{
|
||||
ULONGEST magic = read_memory_unsigned_integer (addr, 4);
|
||||
|
||||
if (magic != BSD_UTHREAD_PTHREAD_MAGIC)
|
||||
error (_("Bad magic"));
|
||||
}
|
||||
|
||||
/* Thread states. */
|
||||
#define BSD_UTHREAD_PS_RUNNING 0
|
||||
#define BSD_UTHREAD_PS_DEAD 18
|
||||
|
||||
/* Address of the pointer to the the thread structure for the running
|
||||
thread. */
|
||||
static CORE_ADDR bsd_uthread_thread_run_addr;
|
||||
|
||||
/* Address of the list of all threads. */
|
||||
static CORE_ADDR bsd_uthread_thread_list_addr;
|
||||
|
||||
/* Offsets of various "interesting" bits in the thread structure. */
|
||||
static int bsd_uthread_thread_state_offset = -1;
|
||||
static int bsd_uthread_thread_next_offset = -1;
|
||||
static int bsd_uthread_thread_ctx_offset;
|
||||
|
||||
/* Name of shared threads library. */
|
||||
static const char *bsd_uthread_solib_name;
|
||||
|
||||
/* Non-zero if the thread startum implemented by this module is active. */
|
||||
static int bsd_uthread_active;
|
||||
|
||||
static CORE_ADDR
|
||||
bsd_uthread_lookup_address (const char *name, struct objfile *objfile)
|
||||
{
|
||||
struct minimal_symbol *sym;
|
||||
|
||||
sym = lookup_minimal_symbol (name, NULL, objfile);
|
||||
if (sym)
|
||||
return SYMBOL_VALUE_ADDRESS (sym);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bsd_uthread_lookup_offset (const char *name, struct objfile *objfile)
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
|
||||
addr = bsd_uthread_lookup_address (name, objfile);
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
|
||||
return read_memory_unsigned_integer (addr, 4);
|
||||
}
|
||||
|
||||
/* If OBJFILE contains the symbols corresponding to one of the
|
||||
supported user-level threads libraries, activate the thread stratum
|
||||
implemented by this module. */
|
||||
|
||||
static int
|
||||
bsd_uthread_activate (struct objfile *objfile)
|
||||
{
|
||||
struct gdbarch *gdbarch = current_gdbarch;
|
||||
struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
|
||||
|
||||
/* Skip if the thread stratum has already been activated. */
|
||||
if (bsd_uthread_active)
|
||||
return 0;
|
||||
|
||||
/* There's no point in enabling this module if no
|
||||
architecture-specific operations are provided. */
|
||||
if (!ops->supply_uthread)
|
||||
return 0;
|
||||
|
||||
bsd_uthread_thread_run_addr =
|
||||
bsd_uthread_lookup_address ("_thread_run", objfile);
|
||||
if (bsd_uthread_thread_run_addr == 0)
|
||||
return 0;
|
||||
|
||||
bsd_uthread_thread_list_addr =
|
||||
bsd_uthread_lookup_address ("_thread_list", objfile);
|
||||
if (bsd_uthread_thread_list_addr == 0)
|
||||
return 0;
|
||||
|
||||
bsd_uthread_thread_state_offset =
|
||||
bsd_uthread_lookup_offset ("_thread_state_offset", objfile);
|
||||
if (bsd_uthread_thread_state_offset == 0)
|
||||
return 0;
|
||||
|
||||
bsd_uthread_thread_next_offset =
|
||||
bsd_uthread_lookup_offset ("_thread_next_offset", objfile);
|
||||
if (bsd_uthread_thread_next_offset == 0)
|
||||
return 0;
|
||||
|
||||
bsd_uthread_thread_ctx_offset =
|
||||
bsd_uthread_lookup_offset ("_thread_ctx_offset", objfile);
|
||||
|
||||
push_target (bsd_uthread_ops_hack);
|
||||
bsd_uthread_active = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Deactivate the thread stratum implemented by this module. */
|
||||
|
||||
static void
|
||||
bsd_uthread_deactivate (void)
|
||||
{
|
||||
/* Skip if the thread stratum has already been deactivated. */
|
||||
if (!bsd_uthread_active)
|
||||
return;
|
||||
|
||||
bsd_uthread_active = 0;
|
||||
unpush_target (bsd_uthread_ops_hack);
|
||||
|
||||
bsd_uthread_thread_run_addr = 0;
|
||||
bsd_uthread_thread_list_addr = 0;
|
||||
bsd_uthread_thread_state_offset = 0;
|
||||
bsd_uthread_thread_next_offset = 0;
|
||||
bsd_uthread_thread_ctx_offset = 0;
|
||||
bsd_uthread_solib_name = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
bsd_uthread_inferior_created (struct target_ops *ops, int from_tty)
|
||||
{
|
||||
bsd_uthread_activate (NULL);
|
||||
}
|
||||
|
||||
/* Likely candidates for the threads library. */
|
||||
static const char *bsd_uthread_solib_names[] =
|
||||
{
|
||||
"/usr/lib/libc_r.so", /* FreeBSD */
|
||||
"/usr/lib/libpthread.so", /* OpenBSD */
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
bsd_uthread_solib_loaded (struct so_list *so)
|
||||
{
|
||||
const char **names = bsd_uthread_solib_names;
|
||||
|
||||
for (names = bsd_uthread_solib_names; *names; names++)
|
||||
{
|
||||
if (strncmp (so->so_original_name, *names, strlen (*names)) == 0)
|
||||
{
|
||||
solib_read_symbols (so, so->from_tty);
|
||||
|
||||
if (bsd_uthread_activate (so->objfile))
|
||||
{
|
||||
bsd_uthread_solib_name == so->so_original_name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bsd_uthread_solib_unloaded (struct so_list *so)
|
||||
{
|
||||
if (!bsd_uthread_solib_name)
|
||||
return;
|
||||
|
||||
if (strcmp (so->so_original_name, bsd_uthread_solib_name) == 0)
|
||||
bsd_uthread_deactivate ();
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_uthread_mourn_inferior (void)
|
||||
{
|
||||
find_target_beneath (bsd_uthread_ops_hack)->to_mourn_inferior ();
|
||||
bsd_uthread_deactivate ();
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_uthread_fetch_registers (int regnum)
|
||||
{
|
||||
struct gdbarch *gdbarch = current_gdbarch;
|
||||
struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
|
||||
CORE_ADDR addr = ptid_get_tid (inferior_ptid);
|
||||
CORE_ADDR active_addr;
|
||||
|
||||
/* Always fetch the appropriate registers from the layer beneath. */
|
||||
find_target_beneath (bsd_uthread_ops_hack)->to_fetch_registers (regnum);
|
||||
|
||||
/* FIXME: That might have gotten us more than we asked for. Make
|
||||
sure we overwrite all relevant registers with values from the
|
||||
thread structure. This can go once we fix the underlying target. */
|
||||
regnum = -1;
|
||||
|
||||
active_addr = read_memory_typed_address (bsd_uthread_thread_run_addr,
|
||||
builtin_type_void_data_ptr);
|
||||
if (addr != 0 && addr != active_addr)
|
||||
{
|
||||
bsd_uthread_check_magic (addr);
|
||||
ops->supply_uthread (current_regcache, regnum,
|
||||
addr + bsd_uthread_thread_ctx_offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_uthread_store_registers (int regnum)
|
||||
{
|
||||
struct gdbarch *gdbarch = current_gdbarch;
|
||||
struct bsd_uthread_ops *ops = gdbarch_data (gdbarch, bsd_uthread_data);
|
||||
CORE_ADDR addr = ptid_get_tid (inferior_ptid);
|
||||
CORE_ADDR active_addr;
|
||||
|
||||
active_addr = read_memory_typed_address (bsd_uthread_thread_run_addr,
|
||||
builtin_type_void_data_ptr);
|
||||
if (addr != 0 && addr != active_addr)
|
||||
{
|
||||
bsd_uthread_check_magic (addr);
|
||||
ops->collect_uthread (current_regcache, regnum,
|
||||
addr + bsd_uthread_thread_ctx_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Updating the thread that is currently running; pass the
|
||||
request to the layer beneath. */
|
||||
find_target_beneath (bsd_uthread_ops_hack)->to_store_registers (regnum);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: This function is only there because otherwise GDB tries to
|
||||
invoke deprecate_xfer_memory. */
|
||||
|
||||
static LONGEST
|
||||
bsd_uthread_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
const char *annex, gdb_byte *readbuf,
|
||||
const gdb_byte *writebuf,
|
||||
ULONGEST offset, LONGEST len)
|
||||
{
|
||||
gdb_assert (ops->beneath->to_xfer_partial);
|
||||
return ops->beneath->to_xfer_partial (ops->beneath, object, annex, readbuf,
|
||||
writebuf, offset, len);
|
||||
}
|
||||
|
||||
static ptid_t
|
||||
bsd_uthread_wait (ptid_t ptid, struct target_waitstatus *status)
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
|
||||
/* Pass the request to the layer beneath. */
|
||||
ptid = find_target_beneath (bsd_uthread_ops_hack)->to_wait (ptid, status);
|
||||
|
||||
/* Fetch the corresponding thread ID, and augment the returned
|
||||
process ID with it. */
|
||||
addr = read_memory_typed_address (bsd_uthread_thread_run_addr,
|
||||
builtin_type_void_data_ptr);
|
||||
if (addr != 0)
|
||||
{
|
||||
gdb_byte buf[4];
|
||||
|
||||
/* FIXME: For executables linked statically with the threads
|
||||
library, we end up here before the program has actually been
|
||||
executed. In that case ADDR will be garbage since it has
|
||||
been read from the wrong virtual memory image. */
|
||||
if (target_read_memory (addr, buf, 4) == 0)
|
||||
{
|
||||
ULONGEST magic = extract_unsigned_integer (buf, 4);
|
||||
if (magic == BSD_UTHREAD_PTHREAD_MAGIC)
|
||||
ptid = ptid_build (ptid_get_pid (ptid), 0, addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* HACK: Twiddle INFERIOR_PTID such that the initial thread of a
|
||||
process isn't recognized as a new thread. */
|
||||
if (ptid_get_tid (ptid) != 0 && !in_thread_list (ptid)
|
||||
&& ptid_get_tid (inferior_ptid) == 0)
|
||||
{
|
||||
add_thread (ptid);
|
||||
inferior_ptid = ptid;
|
||||
}
|
||||
|
||||
return ptid;
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_uthread_resume (ptid_t ptid, int step, enum target_signal sig)
|
||||
{
|
||||
/* Pass the request to the layer beneath. */
|
||||
find_target_beneath (bsd_uthread_ops_hack)->to_resume (ptid, step, sig);
|
||||
}
|
||||
|
||||
static int
|
||||
bsd_uthread_thread_alive (ptid_t ptid)
|
||||
{
|
||||
CORE_ADDR addr = ptid_get_tid (inferior_ptid);
|
||||
|
||||
if (addr != 0)
|
||||
{
|
||||
int offset = bsd_uthread_thread_state_offset;
|
||||
ULONGEST state;
|
||||
|
||||
bsd_uthread_check_magic (addr);
|
||||
|
||||
state = read_memory_unsigned_integer (addr + offset, 4);
|
||||
if (state == BSD_UTHREAD_PS_DEAD)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return find_target_beneath (bsd_uthread_ops_hack)->to_thread_alive (ptid);
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_uthread_find_new_threads (void)
|
||||
{
|
||||
pid_t pid = ptid_get_pid (inferior_ptid);
|
||||
int offset = bsd_uthread_thread_next_offset;
|
||||
CORE_ADDR addr;
|
||||
|
||||
addr = read_memory_typed_address (bsd_uthread_thread_list_addr,
|
||||
builtin_type_void_data_ptr);
|
||||
while (addr != 0)
|
||||
{
|
||||
ptid_t ptid = ptid_build (pid, 0, addr);
|
||||
|
||||
if (!in_thread_list (ptid))
|
||||
add_thread (ptid);
|
||||
|
||||
addr = read_memory_typed_address (addr + offset,
|
||||
builtin_type_void_data_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Possible states a thread can be in. */
|
||||
static char *bsd_uthread_state[] =
|
||||
{
|
||||
"RUNNING",
|
||||
"SIGTHREAD",
|
||||
"MUTEX_WAIT",
|
||||
"COND_WAIT",
|
||||
"FDLR_WAIT",
|
||||
"FDLW_WAIT",
|
||||
"FDR_WAIT",
|
||||
"FDW_WAIT",
|
||||
"FILE_WAIT",
|
||||
"POLL_WAIT",
|
||||
"SELECT_WAIT",
|
||||
"SLEEP_WAIT",
|
||||
"WAIT_WAIT",
|
||||
"SIGSUSPEND",
|
||||
"SIGWAIT",
|
||||
"SPINBLOCK",
|
||||
"JOIN",
|
||||
"SUSPENDED",
|
||||
"DEAD",
|
||||
"DEADLOCK"
|
||||
};
|
||||
|
||||
/* Return a string describing th state of the thread specified by
|
||||
INFO. */
|
||||
|
||||
static char *
|
||||
bsd_uthread_extra_thread_info (struct thread_info *info)
|
||||
{
|
||||
CORE_ADDR addr = ptid_get_tid (info->ptid);
|
||||
|
||||
if (addr != 0)
|
||||
{
|
||||
int offset = bsd_uthread_thread_state_offset;
|
||||
ULONGEST state;
|
||||
|
||||
state = read_memory_unsigned_integer (addr + offset, 4);
|
||||
if (state < ARRAY_SIZE (bsd_uthread_state))
|
||||
return bsd_uthread_state[state];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
bsd_uthread_pid_to_str (ptid_t ptid)
|
||||
{
|
||||
if (ptid_get_tid (ptid) != 0)
|
||||
{
|
||||
static char buf[64];
|
||||
|
||||
xsnprintf (buf, sizeof buf, "process %d, thread 0x%lx",
|
||||
ptid_get_pid (ptid), ptid_get_tid (ptid));
|
||||
return buf;
|
||||
}
|
||||
|
||||
return normal_pid_to_str (ptid);
|
||||
}
|
||||
|
||||
struct target_ops *
|
||||
bsd_uthread_target (void)
|
||||
{
|
||||
struct target_ops *t = XZALLOC (struct target_ops);
|
||||
|
||||
t->to_shortname = "bsd-uthreads";
|
||||
t->to_longname = "BSD user-level threads";
|
||||
t->to_doc = "BSD user-level threads";
|
||||
t->to_mourn_inferior = bsd_uthread_mourn_inferior;
|
||||
t->to_fetch_registers = bsd_uthread_fetch_registers;
|
||||
t->to_store_registers = bsd_uthread_store_registers;
|
||||
t->to_xfer_partial = bsd_uthread_xfer_partial;
|
||||
t->to_wait = bsd_uthread_wait;
|
||||
t->to_resume = bsd_uthread_resume;
|
||||
t->to_thread_alive = bsd_uthread_thread_alive;
|
||||
t->to_find_new_threads = bsd_uthread_find_new_threads;
|
||||
t->to_extra_thread_info = bsd_uthread_extra_thread_info;
|
||||
t->to_pid_to_str = bsd_uthread_pid_to_str;
|
||||
t->to_stratum = thread_stratum;
|
||||
t->to_magic = OPS_MAGIC;
|
||||
bsd_uthread_ops_hack = t;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_bsd_uthread (void)
|
||||
{
|
||||
add_target (bsd_uthread_target ());
|
||||
|
||||
bsd_uthread_data = gdbarch_data_register_pre_init (bsd_uthread_init);
|
||||
|
||||
observer_attach_inferior_created (bsd_uthread_inferior_created);
|
||||
observer_attach_solib_loaded (bsd_uthread_solib_loaded);
|
||||
observer_attach_solib_unloaded (bsd_uthread_solib_unloaded);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/* BSD user-level threads support.
|
||||
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef BSD_UTHREAD_H
|
||||
#define BSD_UTHREAD_H 1
|
||||
|
||||
/* Set the function that supplies registers for an inactive thread for
|
||||
architecture GDBARCH to SUPPLY_UTHREAD. */
|
||||
|
||||
extern void bsd_uthread_set_supply_uthread (struct gdbarch *gdbarch,
|
||||
void (*supply_uthread) (struct regcache *,
|
||||
int, CORE_ADDR));
|
||||
|
||||
|
||||
/* Set the function that collects registers for an inactive thread for
|
||||
architecture GDBARCH to SUPPLY_UTHREAD. */
|
||||
|
||||
extern void bsd_uthread_set_collect_uthread (struct gdbarch *gdbarch,
|
||||
void (*collect_uthread) (const struct regcache *,
|
||||
int, CORE_ADDR));
|
||||
|
||||
#endif /* bsd-uthread.h */
|
||||
1150
gdb/buildsym.c
1150
gdb/buildsym.c
File diff suppressed because it is too large
Load Diff
293
gdb/buildsym.h
293
gdb/buildsym.h
@@ -1,293 +0,0 @@
|
||||
/* Build symbol tables in GDB's internal format.
|
||||
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1995, 1996,
|
||||
1997, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#if !defined (BUILDSYM_H)
|
||||
#define BUILDSYM_H 1
|
||||
|
||||
struct objfile;
|
||||
struct symbol;
|
||||
|
||||
/* This module provides definitions used for creating and adding to
|
||||
the symbol table. These routines are called from various symbol-
|
||||
file-reading routines.
|
||||
|
||||
They originated in dbxread.c of gdb-4.2, and were split out to
|
||||
make xcoffread.c more maintainable by sharing code.
|
||||
|
||||
Variables declared in this file can be defined by #define-ing the
|
||||
name EXTERN to null. It is used to declare variables that are
|
||||
normally extern, but which get defined in a single module using
|
||||
this technique. */
|
||||
|
||||
struct block;
|
||||
|
||||
#ifndef EXTERN
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#define HASHSIZE 127 /* Size of things hashed via
|
||||
hashname() */
|
||||
|
||||
/* Name of source file whose symbol data we are now processing. This
|
||||
comes from a symbol of type N_SO. */
|
||||
|
||||
EXTERN char *last_source_file;
|
||||
|
||||
/* Core address of start of text of current source file. This too
|
||||
comes from the N_SO symbol. */
|
||||
|
||||
EXTERN CORE_ADDR last_source_start_addr;
|
||||
|
||||
/* The list of sub-source-files within the current individual
|
||||
compilation. Each file gets its own symtab with its own linetable
|
||||
and associated info, but they all share one blockvector. */
|
||||
|
||||
struct subfile
|
||||
{
|
||||
struct subfile *next;
|
||||
char *name;
|
||||
char *dirname;
|
||||
struct linetable *line_vector;
|
||||
int line_vector_length;
|
||||
enum language language;
|
||||
char *debugformat;
|
||||
};
|
||||
|
||||
EXTERN struct subfile *subfiles;
|
||||
|
||||
EXTERN struct subfile *current_subfile;
|
||||
|
||||
/* Global variable which, when set, indicates that we are processing a
|
||||
.o file compiled with gcc */
|
||||
|
||||
EXTERN unsigned char processing_gcc_compilation;
|
||||
|
||||
/* When set, we are processing a .o file compiled by sun acc. This is
|
||||
misnamed; it refers to all stabs-in-elf implementations which use
|
||||
N_UNDF the way Sun does, including Solaris gcc. Hopefully all
|
||||
stabs-in-elf implementations ever invented will choose to be
|
||||
compatible. */
|
||||
|
||||
EXTERN unsigned char processing_acc_compilation;
|
||||
|
||||
/* Count symbols as they are processed, for error messages. */
|
||||
|
||||
EXTERN unsigned int symnum;
|
||||
|
||||
/* Record the symbols defined for each context in a list. We don't
|
||||
create a struct block for the context until we know how long to
|
||||
make it. */
|
||||
|
||||
#define PENDINGSIZE 100
|
||||
|
||||
struct pending
|
||||
{
|
||||
struct pending *next;
|
||||
int nsyms;
|
||||
struct symbol *symbol[PENDINGSIZE];
|
||||
};
|
||||
|
||||
/* Here are the three lists that symbols are put on. */
|
||||
|
||||
/* static at top level, and types */
|
||||
|
||||
EXTERN struct pending *file_symbols;
|
||||
|
||||
/* global functions and variables */
|
||||
|
||||
EXTERN struct pending *global_symbols;
|
||||
|
||||
/* everything local to lexical context */
|
||||
|
||||
EXTERN struct pending *local_symbols;
|
||||
|
||||
/* func params local to lexical context */
|
||||
|
||||
EXTERN struct pending *param_symbols;
|
||||
|
||||
/* Stack representing unclosed lexical contexts (that will become
|
||||
blocks, eventually). */
|
||||
|
||||
struct context_stack
|
||||
{
|
||||
/* Outer locals at the time we entered */
|
||||
|
||||
struct pending *locals;
|
||||
|
||||
/* Pending func params at the time we entered */
|
||||
|
||||
struct pending *params;
|
||||
|
||||
/* Pointer into blocklist as of entry */
|
||||
|
||||
struct pending_block *old_blocks;
|
||||
|
||||
/* Name of function, if any, defining context */
|
||||
|
||||
struct symbol *name;
|
||||
|
||||
/* PC where this context starts */
|
||||
|
||||
CORE_ADDR start_addr;
|
||||
|
||||
/* Temp slot for exception handling. */
|
||||
|
||||
CORE_ADDR end_addr;
|
||||
|
||||
/* For error-checking matching push/pop */
|
||||
|
||||
int depth;
|
||||
|
||||
};
|
||||
|
||||
EXTERN struct context_stack *context_stack;
|
||||
|
||||
/* Index of first unused entry in context stack. */
|
||||
|
||||
EXTERN int context_stack_depth;
|
||||
|
||||
/* Currently allocated size of context stack. */
|
||||
|
||||
EXTERN int context_stack_size;
|
||||
|
||||
/* Non-zero if the context stack is empty. */
|
||||
#define outermost_context_p() (context_stack_depth == 0)
|
||||
|
||||
/* Nonzero if within a function (so symbols should be local, if
|
||||
nothing says specifically). */
|
||||
|
||||
EXTERN int within_function;
|
||||
|
||||
/* List of blocks already made (lexical contexts already closed).
|
||||
This is used at the end to make the blockvector. */
|
||||
|
||||
struct pending_block
|
||||
{
|
||||
struct pending_block *next;
|
||||
struct block *block;
|
||||
};
|
||||
|
||||
/* Pointer to the head of a linked list of symbol blocks which have
|
||||
already been finalized (lexical contexts already closed) and which
|
||||
are just waiting to be built into a blockvector when finalizing the
|
||||
associated symtab. */
|
||||
|
||||
EXTERN struct pending_block *pending_blocks;
|
||||
|
||||
|
||||
struct subfile_stack
|
||||
{
|
||||
struct subfile_stack *next;
|
||||
char *name;
|
||||
};
|
||||
|
||||
EXTERN struct subfile_stack *subfile_stack;
|
||||
|
||||
#define next_symbol_text(objfile) (*next_symbol_text_func)(objfile)
|
||||
|
||||
/* Function to invoke get the next symbol. Return the symbol name. */
|
||||
|
||||
EXTERN char *(*next_symbol_text_func) (struct objfile *);
|
||||
|
||||
/* Vector of types defined so far, indexed by their type numbers.
|
||||
Used for both stabs and coff. (In newer sun systems, dbx uses a
|
||||
pair of numbers in parens, as in "(SUBFILENUM,NUMWITHINSUBFILE)".
|
||||
Then these numbers must be translated through the type_translations
|
||||
hash table to get the index into the type vector.) */
|
||||
|
||||
EXTERN struct type **type_vector;
|
||||
|
||||
/* Number of elements allocated for type_vector currently. */
|
||||
|
||||
EXTERN int type_vector_length;
|
||||
|
||||
/* Initial size of type vector. Is realloc'd larger if needed, and
|
||||
realloc'd down to the size actually used, when completed. */
|
||||
|
||||
#define INITIAL_TYPE_VECTOR_LENGTH 160
|
||||
|
||||
extern void add_free_pendings (struct pending *list);
|
||||
|
||||
extern void add_symbol_to_list (struct symbol *symbol,
|
||||
struct pending **listhead);
|
||||
|
||||
extern struct symbol *find_symbol_in_list (struct pending *list,
|
||||
char *name, int length);
|
||||
|
||||
extern void finish_block (struct symbol *symbol,
|
||||
struct pending **listhead,
|
||||
struct pending_block *old_blocks,
|
||||
CORE_ADDR start, CORE_ADDR end,
|
||||
struct objfile *objfile);
|
||||
|
||||
extern void really_free_pendings (void *dummy);
|
||||
|
||||
extern void start_subfile (char *name, char *dirname);
|
||||
|
||||
extern void patch_subfile_names (struct subfile *subfile, char *name);
|
||||
|
||||
extern void push_subfile (void);
|
||||
|
||||
extern char *pop_subfile (void);
|
||||
|
||||
extern struct symtab *end_symtab (CORE_ADDR end_addr,
|
||||
struct objfile *objfile, int section);
|
||||
|
||||
/* Defined in stabsread.c. */
|
||||
|
||||
extern void scan_file_globals (struct objfile *objfile);
|
||||
|
||||
extern void buildsym_new_init (void);
|
||||
|
||||
extern void buildsym_init (void);
|
||||
|
||||
extern struct context_stack *push_context (int desc, CORE_ADDR valu);
|
||||
|
||||
extern struct context_stack *pop_context (void);
|
||||
|
||||
extern void record_line (struct subfile *subfile, int line, CORE_ADDR pc);
|
||||
|
||||
extern void start_symtab (char *name, char *dirname, CORE_ADDR start_addr);
|
||||
|
||||
extern int hashname (char *name);
|
||||
|
||||
extern void free_pending_blocks (void);
|
||||
|
||||
/* FIXME: Note that this is used only in buildsym.c and dstread.c,
|
||||
which should be fixed to not need direct access to
|
||||
record_pending_block. */
|
||||
|
||||
extern void record_pending_block (struct objfile *objfile,
|
||||
struct block *block,
|
||||
struct pending_block *opblock);
|
||||
|
||||
extern void record_debugformat (char *format);
|
||||
|
||||
extern void merge_symbol_lists (struct pending **srclist,
|
||||
struct pending **targetlist);
|
||||
|
||||
/* The macro table for the compilation unit whose symbols we're
|
||||
currently reading. All the symtabs for this CU will point to this. */
|
||||
EXTERN struct macro_table *pending_macros;
|
||||
|
||||
#undef EXTERN
|
||||
|
||||
#endif /* defined (BUILDSYM_H) */
|
||||
1805
gdb/c-exp.y
1805
gdb/c-exp.y
File diff suppressed because it is too large
Load Diff
745
gdb/c-lang.c
745
gdb/c-lang.c
@@ -1,745 +0,0 @@
|
||||
/* C language support routines for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002,
|
||||
2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "symtab.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "expression.h"
|
||||
#include "parser-defs.h"
|
||||
#include "language.h"
|
||||
#include "c-lang.h"
|
||||
#include "valprint.h"
|
||||
#include "macroscope.h"
|
||||
#include "gdb_assert.h"
|
||||
#include "charset.h"
|
||||
#include "gdb_string.h"
|
||||
#include "demangle.h"
|
||||
#include "cp-support.h"
|
||||
|
||||
extern void _initialize_c_language (void);
|
||||
static void c_emit_char (int c, struct ui_file * stream, int quoter);
|
||||
|
||||
/* Print the character C on STREAM as part of the contents of a literal
|
||||
string whose delimiter is QUOTER. Note that that format for printing
|
||||
characters and strings is language specific. */
|
||||
|
||||
static void
|
||||
c_emit_char (int c, struct ui_file *stream, int quoter)
|
||||
{
|
||||
const char *escape;
|
||||
int host_char;
|
||||
|
||||
c &= 0xFF; /* Avoid sign bit follies */
|
||||
|
||||
escape = c_target_char_has_backslash_escape (c);
|
||||
if (escape)
|
||||
{
|
||||
if (quoter == '"' && strcmp (escape, "0") == 0)
|
||||
/* Print nulls embedded in double quoted strings as \000 to
|
||||
prevent ambiguity. */
|
||||
fprintf_filtered (stream, "\\000");
|
||||
else
|
||||
fprintf_filtered (stream, "\\%s", escape);
|
||||
}
|
||||
else if (target_char_to_host (c, &host_char)
|
||||
&& host_char_print_literally (host_char))
|
||||
{
|
||||
if (host_char == '\\' || host_char == quoter)
|
||||
fputs_filtered ("\\", stream);
|
||||
fprintf_filtered (stream, "%c", host_char);
|
||||
}
|
||||
else
|
||||
fprintf_filtered (stream, "\\%.3o", (unsigned int) c);
|
||||
}
|
||||
|
||||
void
|
||||
c_printchar (int c, struct ui_file *stream)
|
||||
{
|
||||
fputc_filtered ('\'', stream);
|
||||
LA_EMIT_CHAR (c, stream, '\'');
|
||||
fputc_filtered ('\'', stream);
|
||||
}
|
||||
|
||||
/* Print the character string STRING, printing at most LENGTH characters.
|
||||
LENGTH is -1 if the string is nul terminated. Each character is WIDTH bytes
|
||||
long. Printing stops early if the number hits print_max; repeat counts are
|
||||
printed as appropriate. Print ellipses at the end if we had to stop before
|
||||
printing LENGTH characters, or if FORCE_ELLIPSES. */
|
||||
|
||||
void
|
||||
c_printstr (struct ui_file *stream, const gdb_byte *string,
|
||||
unsigned int length, int width, int force_ellipses)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int things_printed = 0;
|
||||
int in_quotes = 0;
|
||||
int need_comma = 0;
|
||||
|
||||
/* If the string was not truncated due to `set print elements', and
|
||||
the last byte of it is a null, we don't print that, in traditional C
|
||||
style. */
|
||||
if (!force_ellipses
|
||||
&& length > 0
|
||||
&& (extract_unsigned_integer (string + (length - 1) * width, width)
|
||||
== '\0'))
|
||||
length--;
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
fputs_filtered ("\"\"", stream);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < length && things_printed < print_max; ++i)
|
||||
{
|
||||
/* Position of the character we are examining
|
||||
to see whether it is repeated. */
|
||||
unsigned int rep1;
|
||||
/* Number of repetitions we have detected so far. */
|
||||
unsigned int reps;
|
||||
unsigned long current_char;
|
||||
|
||||
QUIT;
|
||||
|
||||
if (need_comma)
|
||||
{
|
||||
fputs_filtered (", ", stream);
|
||||
need_comma = 0;
|
||||
}
|
||||
|
||||
current_char = extract_unsigned_integer (string + i * width, width);
|
||||
|
||||
rep1 = i + 1;
|
||||
reps = 1;
|
||||
while (rep1 < length
|
||||
&& extract_unsigned_integer (string + rep1 * width, width)
|
||||
== current_char)
|
||||
{
|
||||
++rep1;
|
||||
++reps;
|
||||
}
|
||||
|
||||
if (reps > repeat_count_threshold)
|
||||
{
|
||||
if (in_quotes)
|
||||
{
|
||||
if (inspect_it)
|
||||
fputs_filtered ("\\\", ", stream);
|
||||
else
|
||||
fputs_filtered ("\", ", stream);
|
||||
in_quotes = 0;
|
||||
}
|
||||
LA_PRINT_CHAR (current_char, stream);
|
||||
fprintf_filtered (stream, _(" <repeats %u times>"), reps);
|
||||
i = rep1 - 1;
|
||||
things_printed += repeat_count_threshold;
|
||||
need_comma = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!in_quotes)
|
||||
{
|
||||
if (inspect_it)
|
||||
fputs_filtered ("\\\"", stream);
|
||||
else
|
||||
fputs_filtered ("\"", stream);
|
||||
in_quotes = 1;
|
||||
}
|
||||
LA_EMIT_CHAR (current_char, stream, '"');
|
||||
++things_printed;
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate the quotes if necessary. */
|
||||
if (in_quotes)
|
||||
{
|
||||
if (inspect_it)
|
||||
fputs_filtered ("\\\"", stream);
|
||||
else
|
||||
fputs_filtered ("\"", stream);
|
||||
}
|
||||
|
||||
if (force_ellipses || i < length)
|
||||
fputs_filtered ("...", stream);
|
||||
}
|
||||
|
||||
/* Create a fundamental C type using default reasonable for the current
|
||||
target machine.
|
||||
|
||||
Some object/debugging file formats (DWARF version 1, COFF, etc) do not
|
||||
define fundamental types such as "int" or "double". Others (stabs or
|
||||
DWARF version 2, etc) do define fundamental types. For the formats which
|
||||
don't provide fundamental types, gdb can create such types using this
|
||||
function.
|
||||
|
||||
FIXME: Some compilers distinguish explicitly signed integral types
|
||||
(signed short, signed int, signed long) from "regular" integral types
|
||||
(short, int, long) in the debugging information. There is some dis-
|
||||
agreement as to how useful this feature is. In particular, gcc does
|
||||
not support this. Also, only some debugging formats allow the
|
||||
distinction to be passed on to a debugger. For now, we always just
|
||||
use "short", "int", or "long" as the type name, for both the implicit
|
||||
and explicitly signed types. This also makes life easier for the
|
||||
gdb test suite since we don't have to account for the differences
|
||||
in output depending upon what the compiler and debugging format
|
||||
support. We will probably have to re-examine the issue when gdb
|
||||
starts taking its fundamental type information directly from the
|
||||
debugging information supplied by the compiler. fnf@cygnus.com */
|
||||
|
||||
struct type *
|
||||
c_create_fundamental_type (struct objfile *objfile, int typeid)
|
||||
{
|
||||
struct type *type = NULL;
|
||||
|
||||
switch (typeid)
|
||||
{
|
||||
default:
|
||||
/* FIXME: For now, if we are asked to produce a type not in this
|
||||
language, create the equivalent of a C integer type with the
|
||||
name "<?type?>". When all the dust settles from the type
|
||||
reconstruction work, this should probably become an error. */
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_INT_BIT / TARGET_CHAR_BIT,
|
||||
0, "<?type?>", objfile);
|
||||
warning (_("internal error: no C/C++ fundamental type %d"), typeid);
|
||||
break;
|
||||
case FT_VOID:
|
||||
type = init_type (TYPE_CODE_VOID,
|
||||
TARGET_CHAR_BIT / TARGET_CHAR_BIT,
|
||||
0, "void", objfile);
|
||||
break;
|
||||
case FT_BOOLEAN:
|
||||
type = init_type (TYPE_CODE_BOOL,
|
||||
TARGET_CHAR_BIT / TARGET_CHAR_BIT,
|
||||
0, "bool", objfile);
|
||||
break;
|
||||
case FT_CHAR:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_CHAR_BIT / TARGET_CHAR_BIT,
|
||||
TYPE_FLAG_NOSIGN, "char", objfile);
|
||||
break;
|
||||
case FT_SIGNED_CHAR:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_CHAR_BIT / TARGET_CHAR_BIT,
|
||||
0, "signed char", objfile);
|
||||
break;
|
||||
case FT_UNSIGNED_CHAR:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_CHAR_BIT / TARGET_CHAR_BIT,
|
||||
TYPE_FLAG_UNSIGNED, "unsigned char", objfile);
|
||||
break;
|
||||
case FT_SHORT:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_SHORT_BIT / TARGET_CHAR_BIT,
|
||||
0, "short", objfile);
|
||||
break;
|
||||
case FT_SIGNED_SHORT:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_SHORT_BIT / TARGET_CHAR_BIT,
|
||||
0, "short", objfile); /* FIXME-fnf */
|
||||
break;
|
||||
case FT_UNSIGNED_SHORT:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_SHORT_BIT / TARGET_CHAR_BIT,
|
||||
TYPE_FLAG_UNSIGNED, "unsigned short", objfile);
|
||||
break;
|
||||
case FT_INTEGER:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_INT_BIT / TARGET_CHAR_BIT,
|
||||
0, "int", objfile);
|
||||
break;
|
||||
case FT_SIGNED_INTEGER:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_INT_BIT / TARGET_CHAR_BIT,
|
||||
0, "int", objfile); /* FIXME -fnf */
|
||||
break;
|
||||
case FT_UNSIGNED_INTEGER:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_INT_BIT / TARGET_CHAR_BIT,
|
||||
TYPE_FLAG_UNSIGNED, "unsigned int", objfile);
|
||||
break;
|
||||
case FT_LONG:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_LONG_BIT / TARGET_CHAR_BIT,
|
||||
0, "long", objfile);
|
||||
break;
|
||||
case FT_SIGNED_LONG:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_LONG_BIT / TARGET_CHAR_BIT,
|
||||
0, "long", objfile); /* FIXME -fnf */
|
||||
break;
|
||||
case FT_UNSIGNED_LONG:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_LONG_BIT / TARGET_CHAR_BIT,
|
||||
TYPE_FLAG_UNSIGNED, "unsigned long", objfile);
|
||||
break;
|
||||
case FT_LONG_LONG:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
|
||||
0, "long long", objfile);
|
||||
break;
|
||||
case FT_SIGNED_LONG_LONG:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
|
||||
0, "signed long long", objfile);
|
||||
break;
|
||||
case FT_UNSIGNED_LONG_LONG:
|
||||
type = init_type (TYPE_CODE_INT,
|
||||
TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
|
||||
TYPE_FLAG_UNSIGNED, "unsigned long long", objfile);
|
||||
break;
|
||||
case FT_FLOAT:
|
||||
type = init_type (TYPE_CODE_FLT,
|
||||
TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
|
||||
0, "float", objfile);
|
||||
break;
|
||||
case FT_DBL_PREC_FLOAT:
|
||||
type = init_type (TYPE_CODE_FLT,
|
||||
TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
|
||||
0, "double", objfile);
|
||||
break;
|
||||
case FT_EXT_PREC_FLOAT:
|
||||
type = init_type (TYPE_CODE_FLT,
|
||||
TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
|
||||
0, "long double", objfile);
|
||||
break;
|
||||
case FT_COMPLEX:
|
||||
type = init_type (TYPE_CODE_FLT,
|
||||
2 * TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
|
||||
0, "complex float", objfile);
|
||||
TYPE_TARGET_TYPE (type)
|
||||
= init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
|
||||
0, "float", objfile);
|
||||
break;
|
||||
case FT_DBL_PREC_COMPLEX:
|
||||
type = init_type (TYPE_CODE_FLT,
|
||||
2 * TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
|
||||
0, "complex double", objfile);
|
||||
TYPE_TARGET_TYPE (type)
|
||||
= init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
|
||||
0, "double", objfile);
|
||||
break;
|
||||
case FT_EXT_PREC_COMPLEX:
|
||||
type = init_type (TYPE_CODE_FLT,
|
||||
2 * TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
|
||||
0, "complex long double", objfile);
|
||||
TYPE_TARGET_TYPE (type)
|
||||
= init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
|
||||
0, "long double", objfile);
|
||||
break;
|
||||
case FT_TEMPLATE_ARG:
|
||||
type = init_type (TYPE_CODE_TEMPLATE_ARG,
|
||||
0,
|
||||
0, "<template arg>", objfile);
|
||||
break;
|
||||
}
|
||||
return (type);
|
||||
}
|
||||
|
||||
/* Preprocessing and parsing C and C++ expressions. */
|
||||
|
||||
|
||||
/* When we find that lexptr (the global var defined in parse.c) is
|
||||
pointing at a macro invocation, we expand the invocation, and call
|
||||
scan_macro_expansion to save the old lexptr here and point lexptr
|
||||
into the expanded text. When we reach the end of that, we call
|
||||
end_macro_expansion to pop back to the value we saved here. The
|
||||
macro expansion code promises to return only fully-expanded text,
|
||||
so we don't need to "push" more than one level.
|
||||
|
||||
This is disgusting, of course. It would be cleaner to do all macro
|
||||
expansion beforehand, and then hand that to lexptr. But we don't
|
||||
really know where the expression ends. Remember, in a command like
|
||||
|
||||
(gdb) break *ADDRESS if CONDITION
|
||||
|
||||
we evaluate ADDRESS in the scope of the current frame, but we
|
||||
evaluate CONDITION in the scope of the breakpoint's location. So
|
||||
it's simply wrong to try to macro-expand the whole thing at once. */
|
||||
static char *macro_original_text;
|
||||
static char *macro_expanded_text;
|
||||
|
||||
|
||||
void
|
||||
scan_macro_expansion (char *expansion)
|
||||
{
|
||||
/* We'd better not be trying to push the stack twice. */
|
||||
gdb_assert (! macro_original_text);
|
||||
gdb_assert (! macro_expanded_text);
|
||||
|
||||
/* Save the old lexptr value, so we can return to it when we're done
|
||||
parsing the expanded text. */
|
||||
macro_original_text = lexptr;
|
||||
lexptr = expansion;
|
||||
|
||||
/* Save the expanded text, so we can free it when we're finished. */
|
||||
macro_expanded_text = expansion;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scanning_macro_expansion (void)
|
||||
{
|
||||
return macro_original_text != 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
finished_macro_expansion (void)
|
||||
{
|
||||
/* There'd better be something to pop back to, and we better have
|
||||
saved a pointer to the start of the expanded text. */
|
||||
gdb_assert (macro_original_text);
|
||||
gdb_assert (macro_expanded_text);
|
||||
|
||||
/* Pop back to the original text. */
|
||||
lexptr = macro_original_text;
|
||||
macro_original_text = 0;
|
||||
|
||||
/* Free the expanded text. */
|
||||
xfree (macro_expanded_text);
|
||||
macro_expanded_text = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
scan_macro_cleanup (void *dummy)
|
||||
{
|
||||
if (macro_original_text)
|
||||
finished_macro_expansion ();
|
||||
}
|
||||
|
||||
|
||||
/* We set these global variables before calling c_parse, to tell it
|
||||
how it to find macro definitions for the expression at hand. */
|
||||
macro_lookup_ftype *expression_macro_lookup_func;
|
||||
void *expression_macro_lookup_baton;
|
||||
|
||||
|
||||
static struct macro_definition *
|
||||
null_macro_lookup (const char *name, void *baton)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
c_preprocess_and_parse (void)
|
||||
{
|
||||
/* Set up a lookup function for the macro expander. */
|
||||
struct macro_scope *scope = 0;
|
||||
struct cleanup *back_to = make_cleanup (free_current_contents, &scope);
|
||||
|
||||
if (expression_context_block)
|
||||
scope = sal_macro_scope (find_pc_line (expression_context_pc, 0));
|
||||
else
|
||||
scope = default_macro_scope ();
|
||||
|
||||
if (scope)
|
||||
{
|
||||
expression_macro_lookup_func = standard_macro_lookup;
|
||||
expression_macro_lookup_baton = (void *) scope;
|
||||
}
|
||||
else
|
||||
{
|
||||
expression_macro_lookup_func = null_macro_lookup;
|
||||
expression_macro_lookup_baton = 0;
|
||||
}
|
||||
|
||||
gdb_assert (! macro_original_text);
|
||||
make_cleanup (scan_macro_cleanup, 0);
|
||||
|
||||
{
|
||||
int result = c_parse ();
|
||||
do_cleanups (back_to);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Table mapping opcodes into strings for printing operators
|
||||
and precedences of the operators. */
|
||||
|
||||
const struct op_print c_op_print_tab[] =
|
||||
{
|
||||
{",", BINOP_COMMA, PREC_COMMA, 0},
|
||||
{"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
|
||||
{"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
|
||||
{"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
|
||||
{"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
|
||||
{"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
|
||||
{"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
|
||||
{"==", BINOP_EQUAL, PREC_EQUAL, 0},
|
||||
{"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
|
||||
{"<=", BINOP_LEQ, PREC_ORDER, 0},
|
||||
{">=", BINOP_GEQ, PREC_ORDER, 0},
|
||||
{">", BINOP_GTR, PREC_ORDER, 0},
|
||||
{"<", BINOP_LESS, PREC_ORDER, 0},
|
||||
{">>", BINOP_RSH, PREC_SHIFT, 0},
|
||||
{"<<", BINOP_LSH, PREC_SHIFT, 0},
|
||||
{"+", BINOP_ADD, PREC_ADD, 0},
|
||||
{"-", BINOP_SUB, PREC_ADD, 0},
|
||||
{"*", BINOP_MUL, PREC_MUL, 0},
|
||||
{"/", BINOP_DIV, PREC_MUL, 0},
|
||||
{"%", BINOP_REM, PREC_MUL, 0},
|
||||
{"@", BINOP_REPEAT, PREC_REPEAT, 0},
|
||||
{"-", UNOP_NEG, PREC_PREFIX, 0},
|
||||
{"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
|
||||
{"~", UNOP_COMPLEMENT, PREC_PREFIX, 0},
|
||||
{"*", UNOP_IND, PREC_PREFIX, 0},
|
||||
{"&", UNOP_ADDR, PREC_PREFIX, 0},
|
||||
{"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
|
||||
{"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
|
||||
{"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
|
||||
{NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
enum c_primitive_types {
|
||||
c_primitive_type_int,
|
||||
c_primitive_type_long,
|
||||
c_primitive_type_short,
|
||||
c_primitive_type_char,
|
||||
c_primitive_type_float,
|
||||
c_primitive_type_double,
|
||||
c_primitive_type_void,
|
||||
c_primitive_type_long_long,
|
||||
c_primitive_type_signed_char,
|
||||
c_primitive_type_unsigned_char,
|
||||
c_primitive_type_unsigned_short,
|
||||
c_primitive_type_unsigned_int,
|
||||
c_primitive_type_unsigned_long,
|
||||
c_primitive_type_unsigned_long_long,
|
||||
c_primitive_type_long_double,
|
||||
c_primitive_type_complex,
|
||||
c_primitive_type_double_complex,
|
||||
nr_c_primitive_types
|
||||
};
|
||||
|
||||
void
|
||||
c_language_arch_info (struct gdbarch *gdbarch,
|
||||
struct language_arch_info *lai)
|
||||
{
|
||||
const struct builtin_type *builtin = builtin_type (gdbarch);
|
||||
lai->string_char_type = builtin->builtin_char;
|
||||
lai->primitive_type_vector
|
||||
= GDBARCH_OBSTACK_CALLOC (gdbarch, nr_c_primitive_types + 1,
|
||||
struct type *);
|
||||
lai->primitive_type_vector [c_primitive_type_int] = builtin->builtin_int;
|
||||
lai->primitive_type_vector [c_primitive_type_long] = builtin->builtin_long;
|
||||
lai->primitive_type_vector [c_primitive_type_short] = builtin->builtin_short;
|
||||
lai->primitive_type_vector [c_primitive_type_char] = builtin->builtin_char;
|
||||
lai->primitive_type_vector [c_primitive_type_float] = builtin->builtin_float;
|
||||
lai->primitive_type_vector [c_primitive_type_double] = builtin->builtin_double;
|
||||
lai->primitive_type_vector [c_primitive_type_void] = builtin->builtin_void;
|
||||
lai->primitive_type_vector [c_primitive_type_long_long] = builtin->builtin_long_long;
|
||||
lai->primitive_type_vector [c_primitive_type_signed_char] = builtin->builtin_signed_char;
|
||||
lai->primitive_type_vector [c_primitive_type_unsigned_char] = builtin->builtin_unsigned_char;
|
||||
lai->primitive_type_vector [c_primitive_type_unsigned_short] = builtin->builtin_unsigned_short;
|
||||
lai->primitive_type_vector [c_primitive_type_unsigned_int] = builtin->builtin_unsigned_int;
|
||||
lai->primitive_type_vector [c_primitive_type_unsigned_long] = builtin->builtin_unsigned_long;
|
||||
lai->primitive_type_vector [c_primitive_type_unsigned_long_long] = builtin->builtin_unsigned_long_long;
|
||||
lai->primitive_type_vector [c_primitive_type_long_double] = builtin->builtin_long_double;
|
||||
lai->primitive_type_vector [c_primitive_type_complex] = builtin->builtin_complex;
|
||||
lai->primitive_type_vector [c_primitive_type_double_complex] = builtin->builtin_double_complex;
|
||||
};
|
||||
|
||||
const struct language_defn c_language_defn =
|
||||
{
|
||||
"c", /* Language name */
|
||||
language_c,
|
||||
NULL,
|
||||
range_check_off,
|
||||
type_check_off,
|
||||
case_sensitive_on,
|
||||
array_row_major,
|
||||
&exp_descriptor_standard,
|
||||
c_preprocess_and_parse,
|
||||
c_error,
|
||||
null_post_parser,
|
||||
c_printchar, /* Print a character constant */
|
||||
c_printstr, /* Function to print string constant */
|
||||
c_emit_char, /* Print a single char */
|
||||
c_create_fundamental_type, /* Create fundamental type in this language */
|
||||
c_print_type, /* Print a type using appropriate syntax */
|
||||
c_val_print, /* Print a value using appropriate syntax */
|
||||
c_value_print, /* Print a top-level value */
|
||||
NULL, /* Language specific skip_trampoline */
|
||||
NULL, /* value_of_this */
|
||||
basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
|
||||
basic_lookup_transparent_type,/* lookup_transparent_type */
|
||||
NULL, /* Language specific symbol demangler */
|
||||
NULL, /* Language specific class_name_from_physname */
|
||||
c_op_print_tab, /* expression operators for printing */
|
||||
1, /* c-style arrays */
|
||||
0, /* String lower bound */
|
||||
NULL,
|
||||
default_word_break_characters,
|
||||
c_language_arch_info,
|
||||
default_print_array_index,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
struct type **const (cplus_builtin_types[]) =
|
||||
{
|
||||
&builtin_type_int,
|
||||
&builtin_type_long,
|
||||
&builtin_type_short,
|
||||
&builtin_type_char,
|
||||
&builtin_type_float,
|
||||
&builtin_type_double,
|
||||
&builtin_type_void,
|
||||
&builtin_type_long_long,
|
||||
&builtin_type_signed_char,
|
||||
&builtin_type_unsigned_char,
|
||||
&builtin_type_unsigned_short,
|
||||
&builtin_type_unsigned_int,
|
||||
&builtin_type_unsigned_long,
|
||||
&builtin_type_unsigned_long_long,
|
||||
&builtin_type_long_double,
|
||||
&builtin_type_complex,
|
||||
&builtin_type_double_complex,
|
||||
&builtin_type_bool,
|
||||
0
|
||||
};
|
||||
|
||||
const struct language_defn cplus_language_defn =
|
||||
{
|
||||
"c++", /* Language name */
|
||||
language_cplus,
|
||||
cplus_builtin_types,
|
||||
range_check_off,
|
||||
type_check_off,
|
||||
case_sensitive_on,
|
||||
array_row_major,
|
||||
&exp_descriptor_standard,
|
||||
c_preprocess_and_parse,
|
||||
c_error,
|
||||
null_post_parser,
|
||||
c_printchar, /* Print a character constant */
|
||||
c_printstr, /* Function to print string constant */
|
||||
c_emit_char, /* Print a single char */
|
||||
c_create_fundamental_type, /* Create fundamental type in this language */
|
||||
c_print_type, /* Print a type using appropriate syntax */
|
||||
c_val_print, /* Print a value using appropriate syntax */
|
||||
c_value_print, /* Print a top-level value */
|
||||
NULL, /* Language specific skip_trampoline */
|
||||
value_of_this, /* value_of_this */
|
||||
cp_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
|
||||
cp_lookup_transparent_type, /* lookup_transparent_type */
|
||||
cplus_demangle, /* Language specific symbol demangler */
|
||||
cp_class_name_from_physname, /* Language specific class_name_from_physname */
|
||||
c_op_print_tab, /* expression operators for printing */
|
||||
1, /* c-style arrays */
|
||||
0, /* String lower bound */
|
||||
&builtin_type_char, /* Type of string elements */
|
||||
default_word_break_characters,
|
||||
NULL, /* FIXME: la_language_arch_info. */
|
||||
default_print_array_index,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
const struct language_defn asm_language_defn =
|
||||
{
|
||||
"asm", /* Language name */
|
||||
language_asm,
|
||||
NULL,
|
||||
range_check_off,
|
||||
type_check_off,
|
||||
case_sensitive_on,
|
||||
array_row_major,
|
||||
&exp_descriptor_standard,
|
||||
c_preprocess_and_parse,
|
||||
c_error,
|
||||
null_post_parser,
|
||||
c_printchar, /* Print a character constant */
|
||||
c_printstr, /* Function to print string constant */
|
||||
c_emit_char, /* Print a single char */
|
||||
c_create_fundamental_type, /* Create fundamental type in this language */
|
||||
c_print_type, /* Print a type using appropriate syntax */
|
||||
c_val_print, /* Print a value using appropriate syntax */
|
||||
c_value_print, /* Print a top-level value */
|
||||
NULL, /* Language specific skip_trampoline */
|
||||
NULL, /* value_of_this */
|
||||
basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
|
||||
basic_lookup_transparent_type,/* lookup_transparent_type */
|
||||
NULL, /* Language specific symbol demangler */
|
||||
NULL, /* Language specific class_name_from_physname */
|
||||
c_op_print_tab, /* expression operators for printing */
|
||||
1, /* c-style arrays */
|
||||
0, /* String lower bound */
|
||||
NULL,
|
||||
default_word_break_characters,
|
||||
c_language_arch_info, /* FIXME: la_language_arch_info. */
|
||||
default_print_array_index,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
/* The following language_defn does not represent a real language.
|
||||
It just provides a minimal support a-la-C that should allow users
|
||||
to do some simple operations when debugging applications that use
|
||||
a language currently not supported by GDB. */
|
||||
|
||||
const struct language_defn minimal_language_defn =
|
||||
{
|
||||
"minimal", /* Language name */
|
||||
language_minimal,
|
||||
NULL,
|
||||
range_check_off,
|
||||
type_check_off,
|
||||
case_sensitive_on,
|
||||
array_row_major,
|
||||
&exp_descriptor_standard,
|
||||
c_preprocess_and_parse,
|
||||
c_error,
|
||||
null_post_parser,
|
||||
c_printchar, /* Print a character constant */
|
||||
c_printstr, /* Function to print string constant */
|
||||
c_emit_char, /* Print a single char */
|
||||
c_create_fundamental_type, /* Create fundamental type in this language */
|
||||
c_print_type, /* Print a type using appropriate syntax */
|
||||
c_val_print, /* Print a value using appropriate syntax */
|
||||
c_value_print, /* Print a top-level value */
|
||||
NULL, /* Language specific skip_trampoline */
|
||||
NULL, /* value_of_this */
|
||||
basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
|
||||
basic_lookup_transparent_type,/* lookup_transparent_type */
|
||||
NULL, /* Language specific symbol demangler */
|
||||
NULL, /* Language specific class_name_from_physname */
|
||||
c_op_print_tab, /* expression operators for printing */
|
||||
1, /* c-style arrays */
|
||||
0, /* String lower bound */
|
||||
NULL,
|
||||
default_word_break_characters,
|
||||
c_language_arch_info,
|
||||
default_print_array_index,
|
||||
LANG_MAGIC
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_c_language (void)
|
||||
{
|
||||
add_language (&c_language_defn);
|
||||
add_language (&cplus_language_defn);
|
||||
add_language (&asm_language_defn);
|
||||
add_language (&minimal_language_defn);
|
||||
}
|
||||
96
gdb/c-lang.h
96
gdb/c-lang.h
@@ -1,96 +0,0 @@
|
||||
/* C language support definitions for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 1992, 1994, 1995, 1996, 1997, 1998, 2000, 2002, 2005 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
|
||||
#if !defined (C_LANG_H)
|
||||
#define C_LANG_H 1
|
||||
|
||||
struct ui_file;
|
||||
struct language_arch_info;
|
||||
|
||||
#include "value.h"
|
||||
#include "macroexp.h"
|
||||
|
||||
|
||||
extern int c_parse (void); /* Defined in c-exp.y */
|
||||
|
||||
extern void c_error (char *); /* Defined in c-exp.y */
|
||||
|
||||
/* Defined in c-typeprint.c */
|
||||
extern void c_print_type (struct type *, char *, struct ui_file *, int,
|
||||
int);
|
||||
|
||||
extern int c_val_print (struct type *, const gdb_byte *, int, CORE_ADDR,
|
||||
struct ui_file *, int, int, int,
|
||||
enum val_prettyprint);
|
||||
|
||||
extern int c_value_print (struct value *, struct ui_file *, int,
|
||||
enum val_prettyprint);
|
||||
|
||||
/* These are in c-lang.c: */
|
||||
|
||||
extern void c_printchar (int, struct ui_file *);
|
||||
|
||||
extern void c_printstr (struct ui_file * stream, const gdb_byte *string,
|
||||
unsigned int length, int width,
|
||||
int force_ellipses);
|
||||
|
||||
extern void scan_macro_expansion (char *expansion);
|
||||
extern int scanning_macro_expansion (void);
|
||||
extern void finished_macro_expansion (void);
|
||||
|
||||
extern macro_lookup_ftype *expression_macro_lookup_func;
|
||||
extern void *expression_macro_lookup_baton;
|
||||
|
||||
extern struct type *c_create_fundamental_type (struct objfile *, int);
|
||||
|
||||
extern void c_language_arch_info (struct gdbarch *gdbarch,
|
||||
struct language_arch_info *lai);
|
||||
|
||||
/* These are in c-typeprint.c: */
|
||||
|
||||
extern void c_type_print_base (struct type *, struct ui_file *, int, int);
|
||||
|
||||
/* These are in cp-valprint.c */
|
||||
|
||||
extern int vtblprint; /* Controls printing of vtbl's */
|
||||
|
||||
extern int static_field_print;
|
||||
|
||||
extern void cp_print_class_member (const gdb_byte *, struct type *,
|
||||
struct ui_file *, char *);
|
||||
|
||||
extern void cp_print_class_method (const gdb_byte *, struct type *,
|
||||
struct ui_file *);
|
||||
|
||||
extern void cp_print_value_fields (struct type *, struct type *,
|
||||
const gdb_byte *, int, CORE_ADDR,
|
||||
struct ui_file *, int,
|
||||
int, enum val_prettyprint,
|
||||
struct type **, int);
|
||||
|
||||
extern int cp_is_vtbl_ptr_type (struct type *);
|
||||
|
||||
extern int cp_is_vtbl_member (struct type *);
|
||||
|
||||
|
||||
#endif /* !defined (C_LANG_H) */
|
||||
1209
gdb/c-typeprint.c
1209
gdb/c-typeprint.c
File diff suppressed because it is too large
Load Diff
607
gdb/c-valprint.c
607
gdb/c-valprint.c
@@ -1,607 +0,0 @@
|
||||
/* Support for printing C values for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
|
||||
1997, 1998, 1999, 2000, 2001, 2003, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdb_string.h"
|
||||
#include "symtab.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "expression.h"
|
||||
#include "value.h"
|
||||
#include "valprint.h"
|
||||
#include "language.h"
|
||||
#include "c-lang.h"
|
||||
#include "cp-abi.h"
|
||||
#include "target.h"
|
||||
|
||||
|
||||
/* Print function pointer with inferior address ADDRESS onto stdio
|
||||
stream STREAM. */
|
||||
|
||||
static void
|
||||
print_function_pointer_address (CORE_ADDR address, struct ui_file *stream)
|
||||
{
|
||||
CORE_ADDR func_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
|
||||
address,
|
||||
¤t_target);
|
||||
|
||||
/* If the function pointer is represented by a description, print the
|
||||
address of the description. */
|
||||
if (addressprint && func_addr != address)
|
||||
{
|
||||
fputs_filtered ("@", stream);
|
||||
deprecated_print_address_numeric (address, 1, stream);
|
||||
fputs_filtered (": ", stream);
|
||||
}
|
||||
print_address_demangle (func_addr, stream, demangle);
|
||||
}
|
||||
|
||||
|
||||
/* Print data of type TYPE located at VALADDR (within GDB), which came from
|
||||
the inferior at address ADDRESS, onto stdio stream STREAM according to
|
||||
FORMAT (a letter or 0 for natural format). The data at VALADDR is in
|
||||
target byte order.
|
||||
|
||||
If the data are a string pointer, returns the number of string characters
|
||||
printed.
|
||||
|
||||
If DEREF_REF is nonzero, then dereference references, otherwise just print
|
||||
them like pointers.
|
||||
|
||||
The PRETTY parameter controls prettyprinting. */
|
||||
|
||||
int
|
||||
c_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
|
||||
CORE_ADDR address, struct ui_file *stream, int format,
|
||||
int deref_ref, int recurse, enum val_prettyprint pretty)
|
||||
{
|
||||
unsigned int i = 0; /* Number of characters printed */
|
||||
unsigned len;
|
||||
struct type *elttype;
|
||||
unsigned eltlen;
|
||||
LONGEST val;
|
||||
CORE_ADDR addr;
|
||||
|
||||
CHECK_TYPEDEF (type);
|
||||
switch (TYPE_CODE (type))
|
||||
{
|
||||
case TYPE_CODE_ARRAY:
|
||||
elttype = check_typedef (TYPE_TARGET_TYPE (type));
|
||||
if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
|
||||
{
|
||||
eltlen = TYPE_LENGTH (elttype);
|
||||
len = TYPE_LENGTH (type) / eltlen;
|
||||
if (prettyprint_arrays)
|
||||
{
|
||||
print_spaces_filtered (2 + 2 * recurse, stream);
|
||||
}
|
||||
/* For an array of chars, print with string syntax. */
|
||||
if (eltlen == 1 &&
|
||||
((TYPE_CODE (elttype) == TYPE_CODE_INT)
|
||||
|| ((current_language->la_language == language_m2)
|
||||
&& (TYPE_CODE (elttype) == TYPE_CODE_CHAR)))
|
||||
&& (format == 0 || format == 's'))
|
||||
{
|
||||
/* If requested, look for the first null char and only print
|
||||
elements up to it. */
|
||||
if (stop_print_at_null)
|
||||
{
|
||||
unsigned int temp_len;
|
||||
|
||||
/* Look for a NULL char. */
|
||||
for (temp_len = 0;
|
||||
(valaddr + embedded_offset)[temp_len]
|
||||
&& temp_len < len && temp_len < print_max;
|
||||
temp_len++);
|
||||
len = temp_len;
|
||||
}
|
||||
|
||||
LA_PRINT_STRING (stream, valaddr + embedded_offset, len, eltlen, 0);
|
||||
i = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf_filtered (stream, "{");
|
||||
/* If this is a virtual function table, print the 0th
|
||||
entry specially, and the rest of the members normally. */
|
||||
if (cp_is_vtbl_ptr_type (elttype))
|
||||
{
|
||||
i = 1;
|
||||
fprintf_filtered (stream, _("%d vtable entries"), len - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
val_print_array_elements (type, valaddr + embedded_offset, address, stream,
|
||||
format, deref_ref, recurse, pretty, i);
|
||||
fprintf_filtered (stream, "}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Array of unspecified length: treat like pointer to first elt. */
|
||||
addr = address;
|
||||
goto print_unpacked_pointer;
|
||||
|
||||
case TYPE_CODE_PTR:
|
||||
if (format && format != 's')
|
||||
{
|
||||
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
|
||||
break;
|
||||
}
|
||||
if (vtblprint && cp_is_vtbl_ptr_type (type))
|
||||
{
|
||||
/* Print the unmangled name if desired. */
|
||||
/* Print vtable entry - we only get here if we ARE using
|
||||
-fvtable_thunks. (Otherwise, look under TYPE_CODE_STRUCT.) */
|
||||
CORE_ADDR addr
|
||||
= extract_typed_address (valaddr + embedded_offset, type);
|
||||
print_function_pointer_address (addr, stream);
|
||||
break;
|
||||
}
|
||||
elttype = check_typedef (TYPE_TARGET_TYPE (type));
|
||||
if (TYPE_CODE (elttype) == TYPE_CODE_METHOD)
|
||||
{
|
||||
cp_print_class_method (valaddr + embedded_offset, type, stream);
|
||||
}
|
||||
else if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
|
||||
{
|
||||
cp_print_class_member (valaddr + embedded_offset,
|
||||
TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)),
|
||||
stream, "&");
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = unpack_pointer (type, valaddr + embedded_offset);
|
||||
print_unpacked_pointer:
|
||||
|
||||
if (TYPE_CODE (elttype) == TYPE_CODE_FUNC)
|
||||
{
|
||||
/* Try to print what function it points to. */
|
||||
print_function_pointer_address (addr, stream);
|
||||
/* Return value is irrelevant except for string pointers. */
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (addressprint && format != 's')
|
||||
{
|
||||
deprecated_print_address_numeric (addr, 1, stream);
|
||||
}
|
||||
|
||||
/* For a pointer to char or unsigned char, also print the string
|
||||
pointed to, unless pointer is null. */
|
||||
/* FIXME: need to handle wchar_t here... */
|
||||
|
||||
if (TYPE_LENGTH (elttype) == 1
|
||||
&& TYPE_CODE (elttype) == TYPE_CODE_INT
|
||||
&& (format == 0 || format == 's')
|
||||
&& addr != 0)
|
||||
{
|
||||
i = val_print_string (addr, -1, TYPE_LENGTH (elttype), stream);
|
||||
}
|
||||
else if (cp_is_vtbl_member (type))
|
||||
{
|
||||
/* print vtbl's nicely */
|
||||
CORE_ADDR vt_address = unpack_pointer (type, valaddr + embedded_offset);
|
||||
|
||||
struct minimal_symbol *msymbol =
|
||||
lookup_minimal_symbol_by_pc (vt_address);
|
||||
if ((msymbol != NULL) &&
|
||||
(vt_address == SYMBOL_VALUE_ADDRESS (msymbol)))
|
||||
{
|
||||
fputs_filtered (" <", stream);
|
||||
fputs_filtered (SYMBOL_PRINT_NAME (msymbol), stream);
|
||||
fputs_filtered (">", stream);
|
||||
}
|
||||
if (vt_address && vtblprint)
|
||||
{
|
||||
struct value *vt_val;
|
||||
struct symbol *wsym = (struct symbol *) NULL;
|
||||
struct type *wtype;
|
||||
struct block *block = (struct block *) NULL;
|
||||
int is_this_fld;
|
||||
|
||||
if (msymbol != NULL)
|
||||
wsym = lookup_symbol (DEPRECATED_SYMBOL_NAME (msymbol), block,
|
||||
VAR_DOMAIN, &is_this_fld, NULL);
|
||||
|
||||
if (wsym)
|
||||
{
|
||||
wtype = SYMBOL_TYPE (wsym);
|
||||
}
|
||||
else
|
||||
{
|
||||
wtype = TYPE_TARGET_TYPE (type);
|
||||
}
|
||||
vt_val = value_at (wtype, vt_address);
|
||||
common_val_print (vt_val, stream, format,
|
||||
deref_ref, recurse + 1, pretty);
|
||||
if (pretty)
|
||||
{
|
||||
fprintf_filtered (stream, "\n");
|
||||
print_spaces_filtered (2 + 2 * recurse, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return number of characters printed, including the terminating
|
||||
'\0' if we reached the end. val_print_string takes care including
|
||||
the terminating '\0' if necessary. */
|
||||
return i;
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CODE_MEMBER:
|
||||
error (_("not implemented: member type in c_val_print"));
|
||||
break;
|
||||
|
||||
case TYPE_CODE_REF:
|
||||
elttype = check_typedef (TYPE_TARGET_TYPE (type));
|
||||
if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER)
|
||||
{
|
||||
cp_print_class_member (valaddr + embedded_offset,
|
||||
TYPE_DOMAIN_TYPE (elttype),
|
||||
stream, "");
|
||||
break;
|
||||
}
|
||||
if (addressprint)
|
||||
{
|
||||
CORE_ADDR addr
|
||||
= extract_typed_address (valaddr + embedded_offset, type);
|
||||
fprintf_filtered (stream, "@");
|
||||
deprecated_print_address_numeric (addr, 1, stream);
|
||||
if (deref_ref)
|
||||
fputs_filtered (": ", stream);
|
||||
}
|
||||
/* De-reference the reference. */
|
||||
if (deref_ref)
|
||||
{
|
||||
if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
|
||||
{
|
||||
struct value *deref_val =
|
||||
value_at
|
||||
(TYPE_TARGET_TYPE (type),
|
||||
unpack_pointer (lookup_pointer_type (builtin_type_void),
|
||||
valaddr + embedded_offset));
|
||||
common_val_print (deref_val, stream, format, deref_ref,
|
||||
recurse, pretty);
|
||||
}
|
||||
else
|
||||
fputs_filtered ("???", stream);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CODE_UNION:
|
||||
if (recurse && !unionprint)
|
||||
{
|
||||
fprintf_filtered (stream, "{...}");
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
case TYPE_CODE_STRUCT:
|
||||
/*FIXME: Abstract this away */
|
||||
if (vtblprint && cp_is_vtbl_ptr_type (type))
|
||||
{
|
||||
/* Print the unmangled name if desired. */
|
||||
/* Print vtable entry - we only get here if NOT using
|
||||
-fvtable_thunks. (Otherwise, look under TYPE_CODE_PTR.) */
|
||||
int offset = (embedded_offset +
|
||||
TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8);
|
||||
struct type *field_type = TYPE_FIELD_TYPE (type, VTBL_FNADDR_OFFSET);
|
||||
CORE_ADDR addr
|
||||
= extract_typed_address (valaddr + offset, field_type);
|
||||
|
||||
print_function_pointer_address (addr, stream);
|
||||
}
|
||||
else
|
||||
cp_print_value_fields (type, type, valaddr, embedded_offset, address, stream, format,
|
||||
recurse, pretty, NULL, 0);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_ENUM:
|
||||
if (format)
|
||||
{
|
||||
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
|
||||
break;
|
||||
}
|
||||
len = TYPE_NFIELDS (type);
|
||||
val = unpack_long (type, valaddr + embedded_offset);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
QUIT;
|
||||
if (val == TYPE_FIELD_BITPOS (type, i))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < len)
|
||||
{
|
||||
fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
print_longest (stream, 'd', 0, val);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CODE_FLAGS:
|
||||
if (format)
|
||||
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
|
||||
else
|
||||
val_print_type_code_flags (type, valaddr + embedded_offset, stream);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_FUNC:
|
||||
if (format)
|
||||
{
|
||||
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
|
||||
break;
|
||||
}
|
||||
/* FIXME, we should consider, at least for ANSI C language, eliminating
|
||||
the distinction made between FUNCs and POINTERs to FUNCs. */
|
||||
fprintf_filtered (stream, "{");
|
||||
type_print (type, "", stream, -1);
|
||||
fprintf_filtered (stream, "} ");
|
||||
/* Try to print what function it points to, and its address. */
|
||||
print_address_demangle (address, stream, demangle);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_BOOL:
|
||||
format = format ? format : output_format;
|
||||
if (format)
|
||||
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
|
||||
else
|
||||
{
|
||||
val = unpack_long (type, valaddr + embedded_offset);
|
||||
if (val == 0)
|
||||
fputs_filtered ("false", stream);
|
||||
else if (val == 1)
|
||||
fputs_filtered ("true", stream);
|
||||
else
|
||||
print_longest (stream, 'd', 0, val);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CODE_RANGE:
|
||||
/* FIXME: create_range_type does not set the unsigned bit in a
|
||||
range type (I think it probably should copy it from the target
|
||||
type), so we won't print values which are too large to
|
||||
fit in a signed integer correctly. */
|
||||
/* FIXME: Doesn't handle ranges of enums correctly. (Can't just
|
||||
print with the target type, though, because the size of our type
|
||||
and the target type might differ). */
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case TYPE_CODE_INT:
|
||||
format = format ? format : output_format;
|
||||
if (format)
|
||||
{
|
||||
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
val_print_type_code_int (type, valaddr + embedded_offset, stream);
|
||||
/* C and C++ has no single byte int type, char is used instead.
|
||||
Since we don't know whether the value is really intended to
|
||||
be used as an integer or a character, print the character
|
||||
equivalent as well. */
|
||||
if (TYPE_LENGTH (type) == 1)
|
||||
{
|
||||
fputs_filtered (" ", stream);
|
||||
LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr + embedded_offset),
|
||||
stream);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CODE_CHAR:
|
||||
format = format ? format : output_format;
|
||||
if (format)
|
||||
{
|
||||
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = unpack_long (type, valaddr + embedded_offset);
|
||||
if (TYPE_UNSIGNED (type))
|
||||
fprintf_filtered (stream, "%u", (unsigned int) val);
|
||||
else
|
||||
fprintf_filtered (stream, "%d", (int) val);
|
||||
fputs_filtered (" ", stream);
|
||||
LA_PRINT_CHAR ((unsigned char) val, stream);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CODE_FLT:
|
||||
if (format)
|
||||
{
|
||||
print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
print_floating (valaddr + embedded_offset, type, stream);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CODE_METHOD:
|
||||
{
|
||||
struct value *v = value_at (type, address);
|
||||
cp_print_class_method (value_contents (value_addr (v)),
|
||||
lookup_pointer_type (type), stream);
|
||||
break;
|
||||
}
|
||||
|
||||
case TYPE_CODE_VOID:
|
||||
fprintf_filtered (stream, "void");
|
||||
break;
|
||||
|
||||
case TYPE_CODE_ERROR:
|
||||
fprintf_filtered (stream, _("<error type>"));
|
||||
break;
|
||||
|
||||
case TYPE_CODE_UNDEF:
|
||||
/* This happens (without TYPE_FLAG_STUB set) on systems which don't use
|
||||
dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar"
|
||||
and no complete type for struct foo in that file. */
|
||||
fprintf_filtered (stream, _("<incomplete type>"));
|
||||
break;
|
||||
|
||||
case TYPE_CODE_COMPLEX:
|
||||
if (format)
|
||||
print_scalar_formatted (valaddr + embedded_offset,
|
||||
TYPE_TARGET_TYPE (type),
|
||||
format, 0, stream);
|
||||
else
|
||||
print_floating (valaddr + embedded_offset, TYPE_TARGET_TYPE (type),
|
||||
stream);
|
||||
fprintf_filtered (stream, " + ");
|
||||
if (format)
|
||||
print_scalar_formatted (valaddr + embedded_offset
|
||||
+ TYPE_LENGTH (TYPE_TARGET_TYPE (type)),
|
||||
TYPE_TARGET_TYPE (type),
|
||||
format, 0, stream);
|
||||
else
|
||||
print_floating (valaddr + embedded_offset
|
||||
+ TYPE_LENGTH (TYPE_TARGET_TYPE (type)),
|
||||
TYPE_TARGET_TYPE (type),
|
||||
stream);
|
||||
fprintf_filtered (stream, " * I");
|
||||
break;
|
||||
|
||||
default:
|
||||
error (_("Invalid C/C++ type code %d in symbol table."), TYPE_CODE (type));
|
||||
}
|
||||
gdb_flush (stream);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
c_value_print (struct value *val, struct ui_file *stream, int format,
|
||||
enum val_prettyprint pretty)
|
||||
{
|
||||
struct type *type, *real_type;
|
||||
int full, top, using_enc;
|
||||
|
||||
/* If it is a pointer, indicate what it points to.
|
||||
|
||||
Print type also if it is a reference.
|
||||
|
||||
C++: if it is a member pointer, we will take care
|
||||
of that when we print it. */
|
||||
|
||||
type = check_typedef (value_type (val));
|
||||
|
||||
if (TYPE_CODE (type) == TYPE_CODE_PTR
|
||||
|| TYPE_CODE (type) == TYPE_CODE_REF)
|
||||
{
|
||||
/* Hack: remove (char *) for char strings. Their
|
||||
type is indicated by the quoted string anyway. */
|
||||
if (TYPE_CODE (type) == TYPE_CODE_PTR
|
||||
&& TYPE_NAME (type) == NULL
|
||||
&& TYPE_NAME (TYPE_TARGET_TYPE (type)) != NULL
|
||||
&& strcmp (TYPE_NAME (TYPE_TARGET_TYPE (type)), "char") == 0)
|
||||
{
|
||||
/* Print nothing */
|
||||
}
|
||||
else if (objectprint && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS))
|
||||
{
|
||||
|
||||
if (TYPE_CODE(type) == TYPE_CODE_REF)
|
||||
{
|
||||
/* Copy value, change to pointer, so we don't get an
|
||||
* error about a non-pointer type in value_rtti_target_type
|
||||
*/
|
||||
struct value *temparg;
|
||||
temparg=value_copy(val);
|
||||
deprecated_set_value_type (temparg, lookup_pointer_type (TYPE_TARGET_TYPE(type)));
|
||||
val=temparg;
|
||||
}
|
||||
/* Pointer to class, check real type of object */
|
||||
fprintf_filtered (stream, "(");
|
||||
real_type = value_rtti_target_type (val, &full, &top, &using_enc);
|
||||
if (real_type)
|
||||
{
|
||||
/* RTTI entry found */
|
||||
if (TYPE_CODE (type) == TYPE_CODE_PTR)
|
||||
{
|
||||
/* create a pointer type pointing to the real type */
|
||||
type = lookup_pointer_type (real_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* create a reference type referencing the real type */
|
||||
type = lookup_reference_type (real_type);
|
||||
}
|
||||
/* JYG: Need to adjust pointer value. */
|
||||
/* NOTE: cagney/2005-01-02: THIS IS BOGUS. */
|
||||
value_contents_writeable (val)[0] -= top;
|
||||
|
||||
/* Note: When we look up RTTI entries, we don't get any
|
||||
information on const or volatile attributes */
|
||||
}
|
||||
type_print (type, "", stream, -1);
|
||||
fprintf_filtered (stream, ") ");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* normal case */
|
||||
fprintf_filtered (stream, "(");
|
||||
type_print (value_type (val), "", stream, -1);
|
||||
fprintf_filtered (stream, ") ");
|
||||
}
|
||||
}
|
||||
|
||||
if (objectprint && (TYPE_CODE (type) == TYPE_CODE_CLASS))
|
||||
{
|
||||
/* Attempt to determine real type of object */
|
||||
real_type = value_rtti_type (val, &full, &top, &using_enc);
|
||||
if (real_type)
|
||||
{
|
||||
/* We have RTTI information, so use it */
|
||||
val = value_full_object (val, real_type, full, top, using_enc);
|
||||
fprintf_filtered (stream, "(%s%s) ",
|
||||
TYPE_NAME (real_type),
|
||||
full ? "" : _(" [incomplete object]"));
|
||||
/* Print out object: enclosing type is same as real_type if full */
|
||||
return val_print (value_enclosing_type (val),
|
||||
value_contents_all (val), 0,
|
||||
VALUE_ADDRESS (val), stream, format, 1, 0, pretty);
|
||||
/* Note: When we look up RTTI entries, we don't get any information on
|
||||
const or volatile attributes */
|
||||
}
|
||||
else if (type != check_typedef (value_enclosing_type (val)))
|
||||
{
|
||||
/* No RTTI information, so let's do our best */
|
||||
fprintf_filtered (stream, "(%s ?) ",
|
||||
TYPE_NAME (value_enclosing_type (val)));
|
||||
return val_print (value_enclosing_type (val),
|
||||
value_contents_all (val), 0,
|
||||
VALUE_ADDRESS (val), stream, format, 1, 0, pretty);
|
||||
}
|
||||
/* Otherwise, we end up at the return outside this "if" */
|
||||
}
|
||||
|
||||
return val_print (type, value_contents_all (val),
|
||||
value_embedded_offset (val),
|
||||
VALUE_ADDRESS (val) + value_offset (val),
|
||||
stream, format, 1, 0, pretty);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/* ***DEPRECATED*** The gdblib files must not be calling/using things in any
|
||||
of the possible command languages. If necessary, a hook (that may be
|
||||
present or not) must be used and set to the appropriate routine by any
|
||||
command language that cares about it. If you are having to include this
|
||||
file you are possibly doing things the old way. This file will disapear.
|
||||
2000-12-01 fnasser@redhat.com */
|
||||
|
||||
/* Prototypes for GDB commands that are called internally by other functions.
|
||||
Copyright (C) 1992, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
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., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef CALL_CMDS_H
|
||||
#define CALL_CMDS_H
|
||||
|
||||
extern void initialize_all_files (void);
|
||||
|
||||
extern void core_file_command (char *, int);
|
||||
|
||||
extern void break_command (char *, int);
|
||||
|
||||
#endif
|
||||
1276
gdb/charset.c
1276
gdb/charset.c
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user