forked from Imagelibrary/binutils-gdb
Compare commits
1 Commits
users/hjl/
...
binutils-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7c73f57df |
52
djunpack.bat
52
djunpack.bat
@@ -1,52 +0,0 @@
|
||||
@echo off
|
||||
Rem
|
||||
Rem WARNING WARNING WARNING: This file needs to have DOS CRLF end-of-line
|
||||
Rem format, or else stock DOS/Windows shells will refuse to run it.
|
||||
Rem
|
||||
Rem This batch file unpacks the GDB distribution while simultaneously
|
||||
Rem renaming some of the files whose names are invalid on DOS or conflict
|
||||
Rem with other file names after truncation to DOS 8+3 namespace.
|
||||
Rem
|
||||
Rem Invoke like this:
|
||||
Rem
|
||||
Rem djunpack gdb-XYZ.tar
|
||||
Rem
|
||||
Rem where XYZ is the version number. If the argument includes leading
|
||||
Rem directories, it MUST use backslashes, not forward slashes.
|
||||
Rem
|
||||
Rem The following 2 lines need to be changed with each new GDB release, to
|
||||
Rem be identical to the name of the top-level directory where the GDB
|
||||
Rem distribution unpacks itself.
|
||||
set GDBVER=gdb-5.0
|
||||
if "%GDBVER%"=="gdb-5.0" GoTo EnvOk
|
||||
Rem If their environment space is too small, re-exec with a larger one
|
||||
command.com /e:4096 /c %0 %1
|
||||
GoTo End
|
||||
:EnvOk
|
||||
if not exist %1 GoTo NoArchive
|
||||
djtar -x -p -o %GDBVER%/gdb/config/djgpp/fnchange.lst %1 > fnchange.tmp
|
||||
Rem The following uses a feature of COPY whereby it does not copy
|
||||
Rem empty files. We need that because the previous line will create
|
||||
Rem an empty fnchange.tmp even if the command failed for some reason.
|
||||
copy fnchange.tmp junk.tmp > nul
|
||||
if not exist junk.tmp GoTo NoDjTar
|
||||
del junk.tmp
|
||||
sed -e 's,@V@,%GDBVER%,g' < fnchange.tmp > fnchange.lst
|
||||
Rem See the comment above about the reason for using COPY.
|
||||
copy fnchange.lst junk.tmp > nul
|
||||
if not exist junk.tmp GoTo NoSed
|
||||
del junk.tmp
|
||||
djtar -x -n fnchange.lst %1
|
||||
GoTo End
|
||||
:NoSed
|
||||
echo FAIL: Sed is not available.
|
||||
GoTo End
|
||||
:NoDjTar
|
||||
echo FAIL: DJTAR is not available or no fnchange.lst file in %1.
|
||||
GoTo End
|
||||
:NoArchive
|
||||
echo FAIL: the file %1 does not seem to exist.
|
||||
echo Remember that %1 cannot use forward slashes, only backslashes.
|
||||
GoTo End
|
||||
:End
|
||||
set GDBVER=
|
||||
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@sourceware.org. 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.
|
||||
7951
gdb/ChangeLog
7951
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
15228
gdb/ChangeLog-2004
15228
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
4734
gdb/ChangeLog-2006
4734
gdb/ChangeLog-2006
File diff suppressed because it is too large
Load Diff
10627
gdb/ChangeLog-2007
10627
gdb/ChangeLog-2007
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
638
gdb/MAINTAINERS
638
gdb/MAINTAINERS
@@ -1,638 +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.
|
||||
|
||||
For documentation changes, about the only kind of fix that is obvious
|
||||
is correction of a typo or bad English usage.
|
||||
|
||||
|
||||
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 (Mozilla)
|
||||
Andrew Cagney (Red Hat)
|
||||
Robert Dewar (AdaCore, NYU)
|
||||
Klee Dienes (Apple)
|
||||
Paul Hilfinger (UC Berkeley)
|
||||
Dan Jacobowitz (CodeSourcery)
|
||||
Stan Shebs (CodeSourcery)
|
||||
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@mozilla.com
|
||||
Joel Brobecker brobecker@adacore.com
|
||||
Kevin Buettner kevinb@redhat.com
|
||||
Andrew Cagney cagney@gnu.org
|
||||
Daniel Jacobowitz dan@debian.org
|
||||
Mark Kettenis kettenis@gnu.org
|
||||
Stan Shebs stan@codesourcery.com
|
||||
Michael Snyder msnyder@vmware.com
|
||||
Ulrich Weigand Ulrich.Weigand@de.ibm.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):
|
||||
|
||||
Randolph Chung <tausq@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 ,
|
||||
(sim does not build with -Werror)
|
||||
|
||||
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)
|
||||
|
||||
m32c --target=m32c-elf ,-Werror
|
||||
Jim Blandy, jimb@codesourcery.com
|
||||
|
||||
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
|
||||
|
||||
mep --target=mep-elf ,-Werror
|
||||
Kevin Buettner kevinb@redhat.com
|
||||
|
||||
mips --target=mips-elf ,-Werror
|
||||
|
||||
mn10300 --target=mn10300-elf broken
|
||||
(sim/ dies with make -j)
|
||||
Michael Snyder msnyder@vmware.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
|
||||
|
||||
score --target=score-elf
|
||||
Qinwei qinwei@sunnorth.com.cn
|
||||
|
||||
sh --target=sh-elf ,-Werror
|
||||
--target=sh64-elf ,-Werror
|
||||
|
||||
sparc --target=sparc64-solaris2.10 ,-Werror
|
||||
(--target=sparc-elf broken)
|
||||
|
||||
spu --target=spu-elf ,-Werror
|
||||
Ulrich Weigand uweigand@de.ibm.com
|
||||
|
||||
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
|
||||
|
||||
xtensa --target=xtensa-elf
|
||||
Maxim Grigoriev maxim2405@gmail.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
|
||||
GNU Hurd Alfred M. Szmidt ams@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@vmware.com
|
||||
threads Michael Snyder msnyder@vmware.com
|
||||
Mark Kettenis kettenis@gnu.org
|
||||
language support
|
||||
Ada Joel Brobecker brobecker@adacore.com
|
||||
Paul Hilfinger hilfinger@gnat.com
|
||||
C++ Daniel Jacobowitz dan@debian.org
|
||||
Objective C support Adam Fedor fedor@gnu.org
|
||||
shared libs Kevin Buettner kevinb@redhat.com
|
||||
MI interface Vladimir Prus vladimir@codesourcery.com
|
||||
|
||||
documentation Eli Zaretskii eliz@gnu.org
|
||||
(including NEWS)
|
||||
testsuite
|
||||
gdbtk (gdb.gdbtk) Keith Seitz keiths@redhat.com
|
||||
threads (gdb.threads) Michael Snyder msnyder@vmware.com
|
||||
trace (gdb.trace) Michael Snyder msnyder@vmware.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
|
||||
|
||||
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@axis.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
|
||||
NetBSD native & host Jason Thorpe thorpej@netbsd.org
|
||||
Pascal support Pierre Muller muller@sources.redhat.com
|
||||
avr Theodore A. Roth troth@openavr.org
|
||||
Modula-2 support Gaius Mulley gaius@glam.ac.uk
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Pedro Alves pedro_alves@portugalmail.pt
|
||||
David Anderson davea@sgi.com
|
||||
John David Anglin dave.anglin@nrc-cnrc.gc.ca
|
||||
Shrinivas Atre shrinivasa@kpitcummins.com
|
||||
Scott Bambrough scottb@netwinder.org
|
||||
Thiago Jung Bauermann bauerman@br.ibm.com
|
||||
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
|
||||
Julian Brown julian@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
|
||||
Ludovic Courtès ludo@gnu.org
|
||||
DJ Delorie dj@redhat.com
|
||||
Chris Demetriou cgd@google.com
|
||||
Philippe De Muyter phdm@macqel.be
|
||||
Dhananjay Deshpande dhananjayd@kpitcummins.com
|
||||
Markus Deuling deuling@de.ibm.com
|
||||
Klee Dienes kdienes@apple.com
|
||||
Gabriel Dos Reis gdr@integrable-solutions.net
|
||||
Richard Earnshaw rearnsha@arm.com
|
||||
Steve Ellcey sje@cup.hp.com
|
||||
Frank Ch. Eigler fche@redhat.com
|
||||
Ben Elliston bje@gnu.org
|
||||
Doug Evans dje@google.com
|
||||
Adam Fedor fedor@gnu.org
|
||||
Brian Ford ford@vss.fsi.com
|
||||
Orjan Friberg orjanf@axis.com
|
||||
Nathan Froyd froydnj@codesourcery.com
|
||||
Gary Funck gary@intrepid.com
|
||||
Paul Gilliam pgilliam@us.ibm.com
|
||||
Raoul Gough RaoulGough@yahoo.co.uk
|
||||
Anthony Green green@redhat.com
|
||||
Matthew Green mrg@eterna.com.au
|
||||
Maxim Grigoriev maxim2405@gmail.com
|
||||
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
|
||||
Nick Hudson nick.hudson@dsl.pipex.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
|
||||
Marc Khouzam marc.khouzam@ericsson.com
|
||||
Jim Kingdon kingdon@panix.com
|
||||
Jan Kratochvil jan.kratochvil@redhat.com
|
||||
Jonathan Larmour jlarmour@redhat.co.uk
|
||||
Jeff Law law@redhat.com
|
||||
David Lecomber david@streamline-computing.com
|
||||
Robert Lipe rjl@sco.com
|
||||
Sandra Loosemore sandra@codesourcery.com
|
||||
H.J. Lu hjl.tools@gmail.com
|
||||
Michal Ludvig mludvig@suse.cz
|
||||
Luis Machado luisgpm@br.ibm.com
|
||||
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
|
||||
Phil Muldoon pmuldoon@redhat.com
|
||||
Pierre Muller muller@sources.redhat.com
|
||||
Gaius Mulley gaius@glam.ac.uk
|
||||
Joseph Myers joseph@codesourcery.com
|
||||
Fernando Nasser fnasser@redhat.com
|
||||
Adam Nemet anemet@caviumnetworks.com
|
||||
Nathanael Nerode neroden@gcc.gnu.org
|
||||
Hans-Peter Nilsson hp@bitrange.com
|
||||
David O'Brien obrien@freebsd.org
|
||||
Alexandre Oliva aoliva@redhat.com
|
||||
Denis Pilat denis.pilat@st.com
|
||||
Vladimir Prus vladimir@codesourcery.com
|
||||
Qinwei qinwei@sunnorth.com.cn
|
||||
Frederic Riss frederic.riss@st.com
|
||||
Aleksandar Ristovski aristovski@qnx.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
|
||||
Maciej W. Rozycki macro@linux-mips.org
|
||||
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
|
||||
Carlos Eduardo Seo cseo@linux.vnet.ibm.com
|
||||
Stan Shebs stan@codesourcery.com
|
||||
Mark Shinwell shinwell@codesourcery.com
|
||||
Craig Silverstein csilvers@google.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@vmware.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
|
||||
Caroline Tice ctice@apple.com
|
||||
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
|
||||
Bob Wilson bob.wilson@acm.org
|
||||
Jim Wilson wilson@tuliptree.org
|
||||
Elena Zannoni ezannoni@redhat.com
|
||||
Eli Zaretskii eliz@gnu.org
|
||||
Wu Zhou woodzltc@cn.ibm.com
|
||||
Yoshinori Sato ysato@users.sourceforge.jp
|
||||
Hui Zhu teawater@gmail.com
|
||||
|
||||
|
||||
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, KOD) 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
|
||||
Fred Fish (global)
|
||||
|
||||
|
||||
|
||||
Folks that have been caught up in a paper trail:
|
||||
|
||||
David Carlton carlton@bactrian.org
|
||||
Ramana Radhakrishnan ramana.r@gmail.com
|
||||
|
||||
;; Local Variables:
|
||||
;; coding: utf-8
|
||||
;; End:
|
||||
1881
gdb/Makefile.in
1881
gdb/Makefile.in
File diff suppressed because it is too large
Load Diff
104
gdb/PROBLEMS
104
gdb/PROBLEMS
@@ -1,104 +0,0 @@
|
||||
|
||||
Known problems in GDB 6.5
|
||||
|
||||
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.
|
||||
|
||||
threads/2137: Native Solaris Thread Debugging broken.
|
||||
|
||||
Use GDB 6.4 if thread debugging is needed on Solaris.
|
||||
560
gdb/README
560
gdb/README
@@ -1,560 +0,0 @@
|
||||
README for gdb-6.3 release
|
||||
Updated 20, November, 2006
|
||||
|
||||
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 also requires an ISO
|
||||
C standard library. The GDB remote server, gdbserver, builds with some
|
||||
non-ISO standard libraries - e.g. for Windows CE.
|
||||
|
||||
GDB uses Expat, an XML parsing library, to implement some target-specific
|
||||
features. Expat will be linked in if it is available at build time, or
|
||||
those features will be disabled. The latest version of Expat should be
|
||||
available from `http://expat.sourceforge.net'.
|
||||
|
||||
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.
|
||||
The file gdb/gdbserver/README includes further notes on gdbserver; in
|
||||
particular, it explains how to build gdbserver for cross-debugging
|
||||
(where gdbserver runs on the target machine, which is of a different
|
||||
architecture than the host machine running GDB).
|
||||
|
||||
There are a number of remote interfaces for talking to existing ROM
|
||||
monitors and other hardware:
|
||||
|
||||
remote-mips.c MIPS remote debugging protocol
|
||||
remote-sds.c PowerPC SDS monitor
|
||||
remote-sim.c Generalized simulator protocol
|
||||
|
||||
|
||||
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:
|
||||
338
gdb/acinclude.m4
338
gdb/acinclude.m4
@@ -1,338 +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
|
||||
sinclude(../config/acinclude.m4)
|
||||
|
||||
dnl This gets autoconf bugfixes
|
||||
sinclude(../config/override.m4)
|
||||
|
||||
sinclude(../config/gettext-sister.m4)
|
||||
|
||||
dnl For AC_LIB_HAVE_LINKFLAGS.
|
||||
sinclude(../config/lib-ld.m4)
|
||||
sinclude(../config/lib-prefix.m4)
|
||||
sinclude(../config/lib-link.m4)
|
||||
|
||||
dnl For ACX_PKGVERSION and ACX_BUGURL.
|
||||
sinclude(../config/acx.m4)
|
||||
|
||||
dnl for TCL definitions
|
||||
sinclude(../config/tcl.m4)
|
||||
|
||||
dnl For dependency tracking macros.
|
||||
sinclude([../config/depstand.m4])
|
||||
|
||||
#
|
||||
# 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)
|
||||
])
|
||||
|
||||
## ----------------------------------------- ##
|
||||
## ANSIfy the C compiler whenever possible. ##
|
||||
## From Franc,ois Pinard ##
|
||||
## ----------------------------------------- ##
|
||||
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2001, 2008 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
|
||||
])
|
||||
|
||||
dnl Find the location of the private Tcl headers
|
||||
dnl When Tcl is installed, this is TCL_INCLUDE_SPEC/tcl-private/generic
|
||||
dnl When Tcl is in the build tree, this is not needed.
|
||||
dnl
|
||||
dnl Note: you must use first use SC_LOAD_TCLCONFIG!
|
||||
AC_DEFUN([CY_AC_TCL_PRIVATE_HEADERS], [
|
||||
AC_MSG_CHECKING([for Tcl private headers])
|
||||
private_dir=""
|
||||
dir=`echo ${TCL_INCLUDE_SPEC}/tcl-private/generic | sed -e s/-I//`
|
||||
if test -f ${dir}/tclInt.h ; then
|
||||
private_dir=${dir}
|
||||
fi
|
||||
|
||||
if test x"${private_dir}" = x; then
|
||||
AC_ERROR(could not find private Tcl headers)
|
||||
else
|
||||
TCL_PRIVATE_INCLUDE="-I${private_dir}"
|
||||
AC_MSG_RESULT(${private_dir})
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Find the location of the private Tk headers
|
||||
dnl When Tk is installed, this is TK_INCLUDE_SPEC/tk-private/generic
|
||||
dnl When Tk is in the build tree, this not needed.
|
||||
dnl
|
||||
dnl Note: you must first use SC_LOAD_TKCONFIG
|
||||
AC_DEFUN([CY_AC_TK_PRIVATE_HEADERS], [
|
||||
AC_MSG_CHECKING([for Tk private headers])
|
||||
private_dir=""
|
||||
dir=`echo ${TK_INCLUDE_SPEC}/tk-private/generic | sed -e s/-I//`
|
||||
if test -f ${dir}/tkInt.h; then
|
||||
private_dir=${dir}
|
||||
fi
|
||||
|
||||
if test x"${private_dir}" = x; then
|
||||
AC_ERROR(could not find Tk private headers)
|
||||
else
|
||||
TK_PRIVATE_INCLUDE="-I${private_dir}"
|
||||
AC_MSG_RESULT(${private_dir})
|
||||
fi
|
||||
])
|
||||
892
gdb/aclocal.m4
vendored
892
gdb/aclocal.m4
vendored
@@ -1,892 +0,0 @@
|
||||
# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005 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.
|
||||
|
||||
# Copyright (C) 2002, 2003, 2005 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.
|
||||
|
||||
# AM_AUTOMAKE_VERSION(VERSION)
|
||||
# ----------------------------
|
||||
# Automake X.Y traces this macro to ensure aclocal.m4 has been
|
||||
# generated from the m4 files accompanying Automake X.Y.
|
||||
AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
|
||||
|
||||
# AM_SET_CURRENT_AUTOMAKE_VERSION
|
||||
# -------------------------------
|
||||
# Call AM_AUTOMAKE_VERSION so it can be traced.
|
||||
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
|
||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||
[AM_AUTOMAKE_VERSION([1.9.6])])
|
||||
|
||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 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.
|
||||
|
||||
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
|
||||
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
|
||||
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
|
||||
#
|
||||
# Of course, Automake must honor this variable whenever it calls a
|
||||
# tool from the auxiliary directory. The problem is that $srcdir (and
|
||||
# therefore $ac_aux_dir as well) can be either absolute or relative,
|
||||
# depending on how configure is run. This is pretty annoying, since
|
||||
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
|
||||
# source directory, any form will work fine, but in subdirectories a
|
||||
# relative path needs to be adjusted first.
|
||||
#
|
||||
# $ac_aux_dir/missing
|
||||
# fails when called from a subdirectory if $ac_aux_dir is relative
|
||||
# $top_srcdir/$ac_aux_dir/missing
|
||||
# fails if $ac_aux_dir is absolute,
|
||||
# fails when called from a subdirectory in a VPATH build with
|
||||
# a relative $ac_aux_dir
|
||||
#
|
||||
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
|
||||
# are both prefixed by $srcdir. In an in-source build this is usually
|
||||
# harmless because $srcdir is `.', but things will broke when you
|
||||
# start a VPATH build or use an absolute $srcdir.
|
||||
#
|
||||
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
|
||||
# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
|
||||
# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
|
||||
# and then we would define $MISSING as
|
||||
# MISSING="\${SHELL} $am_aux_dir/missing"
|
||||
# This will work as long as MISSING is not called from configure, because
|
||||
# unfortunately $(top_srcdir) has no meaning in configure.
|
||||
# However there are other variables, like CC, which are often used in
|
||||
# configure, and could therefore not use this "fixed" $ac_aux_dir.
|
||||
#
|
||||
# Another solution, used here, is to always expand $ac_aux_dir to an
|
||||
# absolute PATH. The drawback is that using absolute paths prevent a
|
||||
# configured tree to be moved without reconfiguration.
|
||||
|
||||
AC_DEFUN([AM_AUX_DIR_EXPAND],
|
||||
[dnl Rely on autoconf to set up CDPATH properly.
|
||||
AC_PREREQ([2.50])dnl
|
||||
# expand $ac_aux_dir to an absolute path
|
||||
am_aux_dir=`cd $ac_aux_dir && pwd`
|
||||
])
|
||||
|
||||
# AM_CONDITIONAL -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
|
||||
# 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.
|
||||
|
||||
# serial 7
|
||||
|
||||
# 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])])
|
||||
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# 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.
|
||||
|
||||
# serial 8
|
||||
|
||||
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
|
||||
# written in clear, in which case automake, when reading aclocal.m4,
|
||||
# will think it sees a *use*, and therefore will trigger all it's
|
||||
# C support machinery. Also note that it means that autoscan, seeing
|
||||
# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
|
||||
|
||||
|
||||
# _AM_DEPENDENCIES(NAME)
|
||||
# ----------------------
|
||||
# See how the compiler implements dependency checking.
|
||||
# NAME is "CC", "CXX", "GCJ", or "OBJC".
|
||||
# We try a few techniques and use that to set a single cache variable.
|
||||
#
|
||||
# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
|
||||
# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
|
||||
# dependency, and given that the user is not expected to run this macro,
|
||||
# just rely on AC_PROG_CC.
|
||||
AC_DEFUN([_AM_DEPENDENCIES],
|
||||
[AC_REQUIRE([AM_SET_DEPDIR])dnl
|
||||
AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
|
||||
AC_REQUIRE([AM_MAKE_INCLUDE])dnl
|
||||
AC_REQUIRE([AM_DEP_TRACK])dnl
|
||||
|
||||
ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
|
||||
[$1], CXX, [depcc="$CXX" am_compiler_list=],
|
||||
[$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
|
||||
[$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
|
||||
[depcc="$$1" am_compiler_list=])
|
||||
|
||||
AC_CACHE_CHECK([dependency style of $depcc],
|
||||
[am_cv_$1_dependencies_compiler_type],
|
||||
[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
|
||||
# We make a subdir and do the tests there. Otherwise we can end up
|
||||
# making bogus files that we don't know about and never remove. For
|
||||
# instance it was reported that on HP-UX the gcc test will end up
|
||||
# making a dummy file named `D' -- because `-MD' means `put the output
|
||||
# in D'.
|
||||
mkdir conftest.dir
|
||||
# Copy depcomp to subdir because otherwise we won't find it if we're
|
||||
# using a relative directory.
|
||||
cp "$am_depcomp" conftest.dir
|
||||
cd conftest.dir
|
||||
# We will build objects and dependencies in a subdirectory because
|
||||
# it helps to detect inapplicable dependency modes. For instance
|
||||
# both Tru64's cc and ICC support -MD to output dependencies as a
|
||||
# side effect of compilation, but ICC will put the dependencies in
|
||||
# the current directory while Tru64 will put them in the object
|
||||
# directory.
|
||||
mkdir sub
|
||||
|
||||
am_cv_$1_dependencies_compiler_type=none
|
||||
if test "$am_compiler_list" = ""; then
|
||||
am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
|
||||
fi
|
||||
for depmode in $am_compiler_list; do
|
||||
# Setup a source with many dependencies, because some compilers
|
||||
# like to wrap large dependency lists on column 80 (with \), and
|
||||
# we should not choose a depcomp mode which is confused by this.
|
||||
#
|
||||
# We need to recreate these files for each test, as the compiler may
|
||||
# overwrite some of them when testing with obscure command lines.
|
||||
# This happens at least with the AIX C compiler.
|
||||
: > sub/conftest.c
|
||||
for i in 1 2 3 4 5 6; do
|
||||
echo '#include "conftst'$i'.h"' >> sub/conftest.c
|
||||
# Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
|
||||
# Solaris 8's {/usr,}/bin/sh.
|
||||
touch sub/conftst$i.h
|
||||
done
|
||||
echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
|
||||
|
||||
case $depmode in
|
||||
nosideeffect)
|
||||
# after this tag, mechanisms are not by side-effect, so they'll
|
||||
# only be used when explicitly requested
|
||||
if test "x$enable_dependency_tracking" = xyes; then
|
||||
continue
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
none) break ;;
|
||||
esac
|
||||
# We check with `-c' and `-o' for the sake of the "dashmstdout"
|
||||
# mode. It turns out that the SunPro C++ compiler does not properly
|
||||
# handle `-M -o', and we need to detect this.
|
||||
if depmode=$depmode \
|
||||
source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
|
||||
depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
|
||||
$SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
|
||||
>/dev/null 2>conftest.err &&
|
||||
grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
|
||||
grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
|
||||
${MAKE-make} -s -f confmf > /dev/null 2>&1; then
|
||||
# icc doesn't choke on unknown options, it will just issue warnings
|
||||
# or remarks (even with -Werror). So we grep stderr for any message
|
||||
# that says an option was ignored or not supported.
|
||||
# When given -MP, icc 7.0 and 7.1 complain thusly:
|
||||
# icc: Command line warning: ignoring option '-M'; no argument required
|
||||
# The diagnosis changed in icc 8.0:
|
||||
# icc: Command line remark: option '-MP' not supported
|
||||
if (grep 'ignoring option' conftest.err ||
|
||||
grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
|
||||
am_cv_$1_dependencies_compiler_type=$depmode
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
cd ..
|
||||
rm -rf conftest.dir
|
||||
else
|
||||
am_cv_$1_dependencies_compiler_type=none
|
||||
fi
|
||||
])
|
||||
AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
|
||||
AM_CONDITIONAL([am__fastdep$1], [
|
||||
test "x$enable_dependency_tracking" != xno \
|
||||
&& test "$am_cv_$1_dependencies_compiler_type" = gcc3])
|
||||
])
|
||||
|
||||
|
||||
# AM_SET_DEPDIR
|
||||
# -------------
|
||||
# Choose a directory name for dependency files.
|
||||
# This macro is AC_REQUIREd in _AM_DEPENDENCIES
|
||||
AC_DEFUN([AM_SET_DEPDIR],
|
||||
[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||
AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
|
||||
])
|
||||
|
||||
|
||||
# AM_DEP_TRACK
|
||||
# ------------
|
||||
AC_DEFUN([AM_DEP_TRACK],
|
||||
[AC_ARG_ENABLE(dependency-tracking,
|
||||
[ --disable-dependency-tracking speeds up one-time build
|
||||
--enable-dependency-tracking do not reject slow dependency extractors])
|
||||
if test "x$enable_dependency_tracking" != xno; then
|
||||
am_depcomp="$ac_aux_dir/depcomp"
|
||||
AMDEPBACKSLASH='\'
|
||||
fi
|
||||
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
|
||||
AC_SUBST([AMDEPBACKSLASH])
|
||||
])
|
||||
|
||||
# Generate code to set up dependency tracking. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# 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.
|
||||
|
||||
#serial 3
|
||||
|
||||
# _AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
# ------------------------------
|
||||
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[for mf in $CONFIG_FILES; do
|
||||
# Strip MF so we end up with the name of the file.
|
||||
mf=`echo "$mf" | sed -e 's/:.*$//'`
|
||||
# Check whether this is an Automake generated Makefile or not.
|
||||
# We used to match only the files named `Makefile.in', but
|
||||
# some people rename them; so instead we look at the file content.
|
||||
# Grep'ing the first line is not enough: some people post-process
|
||||
# each Makefile.in and add a new line on top of each file to say so.
|
||||
# So let's grep whole file.
|
||||
if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
|
||||
dirpart=`AS_DIRNAME("$mf")`
|
||||
else
|
||||
continue
|
||||
fi
|
||||
# Extract the definition of DEPDIR, am__include, and am__quote
|
||||
# from the Makefile without running `make'.
|
||||
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
|
||||
test -z "$DEPDIR" && continue
|
||||
am__include=`sed -n 's/^am__include = //p' < "$mf"`
|
||||
test -z "am__include" && continue
|
||||
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
|
||||
# When using ansi2knr, U may be empty or an underscore; expand it
|
||||
U=`sed -n 's/^U = //p' < "$mf"`
|
||||
# Find all dependency output files, they are included files with
|
||||
# $(DEPDIR) in their names. We invoke sed twice because it is the
|
||||
# simplest approach to changing $(DEPDIR) to its actual value in the
|
||||
# expansion.
|
||||
for file in `sed -n "
|
||||
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
|
||||
sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
|
||||
# Make sure the directory exists.
|
||||
test -f "$dirpart/$file" && continue
|
||||
fdir=`AS_DIRNAME(["$file"])`
|
||||
AS_MKDIR_P([$dirpart/$fdir])
|
||||
# echo "creating $dirpart/$file"
|
||||
echo '# dummy' > "$dirpart/$file"
|
||||
done
|
||||
done
|
||||
])# _AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
|
||||
|
||||
# AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
# -----------------------------
|
||||
# This macro should only be invoked once -- use via AC_REQUIRE.
|
||||
#
|
||||
# This code is only required when automatic dependency tracking
|
||||
# is enabled. FIXME. This creates each `.P' file that we will
|
||||
# need in order to bootstrap the dependency handling code.
|
||||
AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[AC_CONFIG_COMMANDS([depfiles],
|
||||
[test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
|
||||
])
|
||||
|
||||
# Do all the work for Automake. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# 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.
|
||||
|
||||
# serial 12
|
||||
|
||||
# This macro actually does too much. Some checks are only needed if
|
||||
# your package does certain things. But this isn't really a big deal.
|
||||
|
||||
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
|
||||
# AM_INIT_AUTOMAKE([OPTIONS])
|
||||
# -----------------------------------------------
|
||||
# The call with PACKAGE and VERSION arguments is the old style
|
||||
# call (pre autoconf-2.50), which is being phased out. PACKAGE
|
||||
# and VERSION should now be passed to AC_INIT and removed from
|
||||
# the call to AM_INIT_AUTOMAKE.
|
||||
# We support both call styles for the transition. After
|
||||
# the next Automake release, Autoconf can make the AC_INIT
|
||||
# arguments mandatory, and then we can depend on a new Autoconf
|
||||
# release and drop the old call support.
|
||||
AC_DEFUN([AM_INIT_AUTOMAKE],
|
||||
[AC_PREREQ([2.58])dnl
|
||||
dnl Autoconf wants to disallow AM_ names. We explicitly allow
|
||||
dnl the ones we care about.
|
||||
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
|
||||
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
|
||||
AC_REQUIRE([AC_PROG_INSTALL])dnl
|
||||
# test to see if srcdir already configured
|
||||
if test "`cd $srcdir && pwd`" != "`pwd`" &&
|
||||
test -f $srcdir/config.status; then
|
||||
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
|
||||
fi
|
||||
|
||||
# test whether we have cygpath
|
||||
if test -z "$CYGPATH_W"; then
|
||||
if (cygpath --version) >/dev/null 2>/dev/null; then
|
||||
CYGPATH_W='cygpath -w'
|
||||
else
|
||||
CYGPATH_W=echo
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([CYGPATH_W])
|
||||
|
||||
# Define the identity of the package.
|
||||
dnl Distinguish between old-style and new-style calls.
|
||||
m4_ifval([$2],
|
||||
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
|
||||
AC_SUBST([PACKAGE], [$1])dnl
|
||||
AC_SUBST([VERSION], [$2])],
|
||||
[_AM_SET_OPTIONS([$1])dnl
|
||||
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
|
||||
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
|
||||
|
||||
_AM_IF_OPTION([no-define],,
|
||||
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
|
||||
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
|
||||
|
||||
# Some tools Automake needs.
|
||||
AC_REQUIRE([AM_SANITY_CHECK])dnl
|
||||
AC_REQUIRE([AC_ARG_PROGRAM])dnl
|
||||
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOCONF, autoconf)
|
||||
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOHEADER, autoheader)
|
||||
AM_MISSING_PROG(MAKEINFO, makeinfo)
|
||||
AM_PROG_INSTALL_SH
|
||||
AM_PROG_INSTALL_STRIP
|
||||
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
|
||||
# We need awk for the "check" target. The system "awk" is bad on
|
||||
# some platforms.
|
||||
AC_REQUIRE([AC_PROG_AWK])dnl
|
||||
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
|
||||
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
|
||||
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
|
||||
[_AM_PROG_TAR([v7])])])
|
||||
_AM_IF_OPTION([no-dependencies],,
|
||||
[AC_PROVIDE_IFELSE([AC_PROG_CC],
|
||||
[_AM_DEPENDENCIES(CC)],
|
||||
[define([AC_PROG_CC],
|
||||
defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
|
||||
AC_PROVIDE_IFELSE([AC_PROG_CXX],
|
||||
[_AM_DEPENDENCIES(CXX)],
|
||||
[define([AC_PROG_CXX],
|
||||
defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
# When config.status generates a header, we must update the stamp-h file.
|
||||
# This file resides in the same directory as the config header
|
||||
# that is generated. The stamp files are numbered to have different names.
|
||||
|
||||
# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
|
||||
# loop where config.status creates the headers, so we can generate
|
||||
# our stamp files there.
|
||||
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
|
||||
[# Compute $1's index in $config_headers.
|
||||
_am_stamp_count=1
|
||||
for _am_header in $config_headers :; do
|
||||
case $_am_header in
|
||||
$1 | $1:* )
|
||||
break ;;
|
||||
* )
|
||||
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
|
||||
esac
|
||||
done
|
||||
echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 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.
|
||||
|
||||
# AM_PROG_INSTALL_SH
|
||||
# ------------------
|
||||
# Define $install_sh.
|
||||
AC_DEFUN([AM_PROG_INSTALL_SH],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
install_sh=${install_sh-"$am_aux_dir/install-sh"}
|
||||
AC_SUBST(install_sh)])
|
||||
|
||||
# Copyright (C) 2003, 2005 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.
|
||||
|
||||
# serial 2
|
||||
|
||||
# Check whether the underlying file-system supports filenames
|
||||
# with a leading dot. For instance MS-DOS doesn't.
|
||||
AC_DEFUN([AM_SET_LEADING_DOT],
|
||||
[rm -rf .tst 2>/dev/null
|
||||
mkdir .tst 2>/dev/null
|
||||
if test -d .tst; then
|
||||
am__leading_dot=.
|
||||
else
|
||||
am__leading_dot=_
|
||||
fi
|
||||
rmdir .tst 2>/dev/null
|
||||
AC_SUBST([am__leading_dot])])
|
||||
|
||||
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
|
||||
# From Jim Meyering
|
||||
|
||||
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# 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.
|
||||
|
||||
# serial 4
|
||||
|
||||
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])
|
||||
|
||||
# Check to see how 'make' treats includes. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005 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.
|
||||
|
||||
# serial 3
|
||||
|
||||
# AM_MAKE_INCLUDE()
|
||||
# -----------------
|
||||
# Check to see how make treats includes.
|
||||
AC_DEFUN([AM_MAKE_INCLUDE],
|
||||
[am_make=${MAKE-make}
|
||||
cat > confinc << 'END'
|
||||
am__doit:
|
||||
@echo done
|
||||
.PHONY: am__doit
|
||||
END
|
||||
# If we don't find an include directive, just comment out the code.
|
||||
AC_MSG_CHECKING([for style of include used by $am_make])
|
||||
am__include="#"
|
||||
am__quote=
|
||||
_am_result=none
|
||||
# First try GNU make style include.
|
||||
echo "include confinc" > confmf
|
||||
# We grep out `Entering directory' and `Leaving directory'
|
||||
# messages which can occur if `w' ends up in MAKEFLAGS.
|
||||
# In particular we don't look at `^make:' because GNU make might
|
||||
# be invoked under some other name (usually "gmake"), in which
|
||||
# case it prints its new name instead of `make'.
|
||||
if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
|
||||
am__include=include
|
||||
am__quote=
|
||||
_am_result=GNU
|
||||
fi
|
||||
# Now try BSD make style include.
|
||||
if test "$am__include" = "#"; then
|
||||
echo '.include "confinc"' > confmf
|
||||
if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
|
||||
am__include=.include
|
||||
am__quote="\""
|
||||
_am_result=BSD
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([am__include])
|
||||
AC_SUBST([am__quote])
|
||||
AC_MSG_RESULT([$_am_result])
|
||||
rm -f confinc confmf
|
||||
])
|
||||
|
||||
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
|
||||
# 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.
|
||||
|
||||
# serial 4
|
||||
|
||||
# AM_MISSING_PROG(NAME, PROGRAM)
|
||||
# ------------------------------
|
||||
AC_DEFUN([AM_MISSING_PROG],
|
||||
[AC_REQUIRE([AM_MISSING_HAS_RUN])
|
||||
$1=${$1-"${am_missing_run}$2"}
|
||||
AC_SUBST($1)])
|
||||
|
||||
|
||||
# AM_MISSING_HAS_RUN
|
||||
# ------------------
|
||||
# Define MISSING if not defined so far and test if it supports --run.
|
||||
# If it does, set am_missing_run to use it, otherwise, to nothing.
|
||||
AC_DEFUN([AM_MISSING_HAS_RUN],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
|
||||
# Use eval to expand $SHELL
|
||||
if eval "$MISSING --run true"; then
|
||||
am_missing_run="$MISSING --run "
|
||||
else
|
||||
am_missing_run=
|
||||
AC_MSG_WARN([`missing' script is too old or missing])
|
||||
fi
|
||||
])
|
||||
|
||||
# Copyright (C) 2003, 2004, 2005 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.
|
||||
|
||||
# AM_PROG_MKDIR_P
|
||||
# ---------------
|
||||
# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
|
||||
#
|
||||
# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
|
||||
# created by `make install' are always world readable, even if the
|
||||
# installer happens to have an overly restrictive umask (e.g. 077).
|
||||
# This was a mistake. There are at least two reasons why we must not
|
||||
# use `-m 0755':
|
||||
# - it causes special bits like SGID to be ignored,
|
||||
# - it may be too restrictive (some setups expect 775 directories).
|
||||
#
|
||||
# Do not use -m 0755 and let people choose whatever they expect by
|
||||
# setting umask.
|
||||
#
|
||||
# We cannot accept any implementation of `mkdir' that recognizes `-p'.
|
||||
# Some implementations (such as Solaris 8's) are not thread-safe: if a
|
||||
# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
|
||||
# concurrently, both version can detect that a/ is missing, but only
|
||||
# one can create it and the other will error out. Consequently we
|
||||
# restrict ourselves to GNU make (using the --version option ensures
|
||||
# this.)
|
||||
AC_DEFUN([AM_PROG_MKDIR_P],
|
||||
[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
|
||||
# We used to keeping the `.' as first argument, in order to
|
||||
# allow $(mkdir_p) to be used without argument. As in
|
||||
# $(mkdir_p) $(somedir)
|
||||
# where $(somedir) is conditionally defined. However this is wrong
|
||||
# for two reasons:
|
||||
# 1. if the package is installed by a user who cannot write `.'
|
||||
# make install will fail,
|
||||
# 2. the above comment should most certainly read
|
||||
# $(mkdir_p) $(DESTDIR)$(somedir)
|
||||
# so it does not work when $(somedir) is undefined and
|
||||
# $(DESTDIR) is not.
|
||||
# To support the latter case, we have to write
|
||||
# test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
|
||||
# so the `.' trick is pointless.
|
||||
mkdir_p='mkdir -p --'
|
||||
else
|
||||
# On NextStep and OpenStep, the `mkdir' command does not
|
||||
# recognize any option. It will interpret all options as
|
||||
# directories to create, and then abort because `.' already
|
||||
# exists.
|
||||
for d in ./-p ./--version;
|
||||
do
|
||||
test -d $d && rmdir $d
|
||||
done
|
||||
# $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
|
||||
if test -f "$ac_aux_dir/mkinstalldirs"; then
|
||||
mkdir_p='$(mkinstalldirs)'
|
||||
else
|
||||
mkdir_p='$(install_sh) -d'
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([mkdir_p])])
|
||||
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005 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.
|
||||
|
||||
# serial 3
|
||||
|
||||
# _AM_MANGLE_OPTION(NAME)
|
||||
# -----------------------
|
||||
AC_DEFUN([_AM_MANGLE_OPTION],
|
||||
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
# _AM_SET_OPTION(NAME)
|
||||
# ------------------------------
|
||||
# Set option NAME. Presently that only means defining a flag for this option.
|
||||
AC_DEFUN([_AM_SET_OPTION],
|
||||
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
|
||||
|
||||
# _AM_SET_OPTIONS(OPTIONS)
|
||||
# ----------------------------------
|
||||
# OPTIONS is a space-separated list of Automake options.
|
||||
AC_DEFUN([_AM_SET_OPTIONS],
|
||||
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
|
||||
|
||||
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
|
||||
# -------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
AC_DEFUN([_AM_IF_OPTION],
|
||||
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
|
||||
|
||||
# Check to make sure that the build environment is sane. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
|
||||
# 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.
|
||||
|
||||
# serial 4
|
||||
|
||||
# AM_SANITY_CHECK
|
||||
# ---------------
|
||||
AC_DEFUN([AM_SANITY_CHECK],
|
||||
[AC_MSG_CHECKING([whether build environment is sane])
|
||||
# Just in case
|
||||
sleep 1
|
||||
echo timestamp > conftest.file
|
||||
# Do `set' in a subshell so we don't clobber the current shell's
|
||||
# arguments. Must try -L first in case configure is actually a
|
||||
# symlink; some systems play weird games with the mod time of symlinks
|
||||
# (eg FreeBSD returns the mod time of the symlink's containing
|
||||
# directory).
|
||||
if (
|
||||
set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
|
||||
if test "$[*]" = "X"; then
|
||||
# -L didn't work.
|
||||
set X `ls -t $srcdir/configure conftest.file`
|
||||
fi
|
||||
rm -f conftest.file
|
||||
if test "$[*]" != "X $srcdir/configure conftest.file" \
|
||||
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
|
||||
|
||||
# If neither matched, then we have a broken ls. This can happen
|
||||
# if, for instance, CONFIG_SHELL is bash and it inherits a
|
||||
# broken ls alias from the environment. This has actually
|
||||
# happened. Such a system could not be considered "sane".
|
||||
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
|
||||
alias in your environment])
|
||||
fi
|
||||
|
||||
test "$[2]" = conftest.file
|
||||
)
|
||||
then
|
||||
# Ok.
|
||||
:
|
||||
else
|
||||
AC_MSG_ERROR([newly created file is older than distributed files!
|
||||
Check your system clock])
|
||||
fi
|
||||
AC_MSG_RESULT(yes)])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 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.
|
||||
|
||||
# AM_PROG_INSTALL_STRIP
|
||||
# ---------------------
|
||||
# One issue with vendor `install' (even GNU) is that you can't
|
||||
# specify the program used to strip binaries. This is especially
|
||||
# annoying in cross-compiling environments, where the build's strip
|
||||
# is unlikely to handle the host's binaries.
|
||||
# Fortunately install-sh will honor a STRIPPROG variable, so we
|
||||
# always use install-sh in `make install-strip', and initialize
|
||||
# STRIPPROG with the value of the STRIP variable (set by the user).
|
||||
AC_DEFUN([AM_PROG_INSTALL_STRIP],
|
||||
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
|
||||
# Installed binaries are usually stripped using `strip' when the user
|
||||
# run `make install-strip'. However `strip' might not be the right
|
||||
# tool to use in cross-compilation environments, therefore Automake
|
||||
# will honor the `STRIP' environment variable to overrule this program.
|
||||
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
|
||||
if test "$cross_compiling" != no; then
|
||||
AC_CHECK_TOOL([STRIP], [strip], :)
|
||||
fi
|
||||
INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
|
||||
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
||||
|
||||
# Check how to create a tarball. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2004, 2005 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.
|
||||
|
||||
# serial 2
|
||||
|
||||
# _AM_PROG_TAR(FORMAT)
|
||||
# --------------------
|
||||
# Check how to create a tarball in format FORMAT.
|
||||
# FORMAT should be one of `v7', `ustar', or `pax'.
|
||||
#
|
||||
# Substitute a variable $(am__tar) that is a command
|
||||
# writing to stdout a FORMAT-tarball containing the directory
|
||||
# $tardir.
|
||||
# tardir=directory && $(am__tar) > result.tar
|
||||
#
|
||||
# Substitute a variable $(am__untar) that extract such
|
||||
# a tarball read from stdin.
|
||||
# $(am__untar) < result.tar
|
||||
AC_DEFUN([_AM_PROG_TAR],
|
||||
[# Always define AMTAR for backward compatibility.
|
||||
AM_MISSING_PROG([AMTAR], [tar])
|
||||
m4_if([$1], [v7],
|
||||
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
|
||||
[m4_case([$1], [ustar],, [pax],,
|
||||
[m4_fatal([Unknown tar format])])
|
||||
AC_MSG_CHECKING([how to create a $1 tar archive])
|
||||
# Loop over all known methods to create a tar archive until one works.
|
||||
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
|
||||
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
|
||||
# Do not fold the above two line into one, because Tru64 sh and
|
||||
# Solaris sh will not grok spaces in the rhs of `-'.
|
||||
for _am_tool in $_am_tools
|
||||
do
|
||||
case $_am_tool in
|
||||
gnutar)
|
||||
for _am_tar in tar gnutar gtar;
|
||||
do
|
||||
AM_RUN_LOG([$_am_tar --version]) && break
|
||||
done
|
||||
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
|
||||
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
|
||||
am__untar="$_am_tar -xf -"
|
||||
;;
|
||||
plaintar)
|
||||
# Must skip GNU tar: if it does not support --format= it doesn't create
|
||||
# ustar tarball either.
|
||||
(tar --version) >/dev/null 2>&1 && continue
|
||||
am__tar='tar chf - "$$tardir"'
|
||||
am__tar_='tar chf - "$tardir"'
|
||||
am__untar='tar xf -'
|
||||
;;
|
||||
pax)
|
||||
am__tar='pax -L -x $1 -w "$$tardir"'
|
||||
am__tar_='pax -L -x $1 -w "$tardir"'
|
||||
am__untar='pax -r'
|
||||
;;
|
||||
cpio)
|
||||
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
|
||||
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
|
||||
am__untar='cpio -i -H $1 -d'
|
||||
;;
|
||||
none)
|
||||
am__tar=false
|
||||
am__tar_=false
|
||||
am__untar=false
|
||||
;;
|
||||
esac
|
||||
|
||||
# If the value was cached, stop now. We just wanted to have am__tar
|
||||
# and am__untar set.
|
||||
test -n "${am_cv_prog_tar_$1}" && break
|
||||
|
||||
# tar/untar a dummy directory, and stop if the command works
|
||||
rm -rf conftest.dir
|
||||
mkdir conftest.dir
|
||||
echo GrepMe > conftest.dir/file
|
||||
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
|
||||
rm -rf conftest.dir
|
||||
if test -s conftest.tar; then
|
||||
AM_RUN_LOG([$am__untar <conftest.tar])
|
||||
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
|
||||
fi
|
||||
done
|
||||
rm -rf conftest.dir
|
||||
|
||||
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
|
||||
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
|
||||
AC_SUBST([am__tar])
|
||||
AC_SUBST([am__untar])
|
||||
]) # _AM_PROG_TAR
|
||||
|
||||
m4_include([gnulib/m4/extensions.m4])
|
||||
m4_include([gnulib/m4/gnulib-common.m4])
|
||||
m4_include([gnulib/m4/gnulib-comp.m4])
|
||||
m4_include([gnulib/m4/include_next.m4])
|
||||
m4_include([gnulib/m4/longlong.m4])
|
||||
m4_include([gnulib/m4/memchr.m4])
|
||||
m4_include([gnulib/m4/memcmp.m4])
|
||||
m4_include([gnulib/m4/memmem.m4])
|
||||
m4_include([gnulib/m4/onceonly_2_57.m4])
|
||||
m4_include([gnulib/m4/stdint.m4])
|
||||
m4_include([gnulib/m4/string_h.m4])
|
||||
m4_include([gnulib/m4/wchar.m4])
|
||||
m4_include([acinclude.m4])
|
||||
1535
gdb/ada-exp.y
1535
gdb/ada-exp.y
File diff suppressed because it is too large
Load Diff
10979
gdb/ada-lang.c
10979
gdb/ada-lang.c
File diff suppressed because it is too large
Load Diff
509
gdb/ada-lang.h
509
gdb/ada-lang.h
@@ -1,509 +0,0 @@
|
||||
/* Ada language support definitions for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
||||
2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 tuple, (symbol, block), representing one instance of a
|
||||
* symbol-lookup operation. */
|
||||
struct ada_symbol_info {
|
||||
struct symbol* sym;
|
||||
struct block* block;
|
||||
};
|
||||
|
||||
/* Denotes a type of renaming symbol (see ada_parse_renaming). */
|
||||
enum ada_renaming_category
|
||||
{
|
||||
/* Indicates a symbol that does not encode a renaming. */
|
||||
ADA_NOT_RENAMING,
|
||||
|
||||
/* For symbols declared
|
||||
Foo : TYPE renamed OBJECT; */
|
||||
ADA_OBJECT_RENAMING,
|
||||
|
||||
/* For symbols declared
|
||||
Foo : exception renames EXCEPTION; */
|
||||
ADA_EXCEPTION_RENAMING,
|
||||
/* For packages declared
|
||||
package Foo renames PACKAGE; */
|
||||
ADA_PACKAGE_RENAMING,
|
||||
/* For subprograms declared
|
||||
SUBPROGRAM_SPEC renames SUBPROGRAM;
|
||||
(Currently not used). */
|
||||
ADA_SUBPROGRAM_RENAMING
|
||||
};
|
||||
|
||||
/* 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);
|
||||
|
||||
struct value *ada_convert_actual (struct value *actual,
|
||||
struct type *formal_type0,
|
||||
CORE_ADDR *sp);
|
||||
|
||||
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 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 *);
|
||||
|
||||
extern struct symbol *
|
||||
ada_lookup_encoded_symbol (const char *, const struct block *,
|
||||
domain_enum namespace, struct block **);
|
||||
|
||||
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 *,
|
||||
int check_tag);
|
||||
|
||||
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 enum ada_renaming_category ada_parse_renaming (struct symbol *,
|
||||
const char **,
|
||||
int *, const char **);
|
||||
|
||||
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_reset_thread_registers (void);
|
||||
|
||||
extern int ada_build_task_list (void);
|
||||
|
||||
extern int ada_exception_catchpoint_p (struct breakpoint *b);
|
||||
|
||||
extern struct symtab_and_line
|
||||
ada_decode_exception_location (char *args, char **addr_string,
|
||||
char **exp_string, char **cond_string,
|
||||
struct expression **cond,
|
||||
struct breakpoint_ops **ops);
|
||||
|
||||
extern struct symtab_and_line
|
||||
ada_decode_assert_location (char *args, char **addr_string,
|
||||
struct breakpoint_ops **ops);
|
||||
|
||||
|
||||
#endif
|
||||
608
gdb/ada-lex.l
608
gdb/ada-lex.l
@@ -1,608 +0,0 @@
|
||||
/* FLEX lexer for Ada expressions, for GDB.
|
||||
Copyright (C) 1994, 1997, 1998, 2000, 2001, 2002, 2003, 2007, 2008
|
||||
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; }
|
||||
|
||||
/* BOOLEAN "KEYWORDS" */
|
||||
|
||||
/* True and False are not keywords in Ada, but rather enumeration constants.
|
||||
However, the boolean type is no longer represented as an enum, so True
|
||||
and False are no longer defined in symbol tables. We compromise by
|
||||
making them keywords (when bare). */
|
||||
|
||||
true { return TRUEKEYWORD; }
|
||||
false { return FALSEKEYWORD; }
|
||||
|
||||
/* 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';
|
||||
}
|
||||
|
||||
/* 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 >> (gdbarch_int_bit (current_gdbarch)-1)) == 0)
|
||||
yylval.typed_val.type = type_int ();
|
||||
else if ((result >> (gdbarch_long_bit (current_gdbarch)-1)) == 0)
|
||||
yylval.typed_val.type = type_long ();
|
||||
else if (((result >> (gdbarch_long_bit (current_gdbarch)-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) >= gdbarch_double_bit (current_gdbarch)
|
||||
/ TARGET_CHAR_BIT)
|
||||
yylval.typed_val_float.type = type_double ();
|
||||
if (sizeof(DOUBLEST) >= gdbarch_long_double_bit (current_gdbarch)
|
||||
/ 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,876 +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, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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;
|
||||
|
||||
if (ada_is_packed_array_type (type))
|
||||
type = ada_coerce_to_simple_array_type (type);
|
||||
|
||||
bitsize = 0;
|
||||
fprintf_filtered (stream, "array (");
|
||||
|
||||
n_indices = -1;
|
||||
if (show < 0)
|
||||
fprintf_filtered (stream, "...");
|
||||
else
|
||||
{
|
||||
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_STUB (type))
|
||||
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 (type0);
|
||||
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))
|
||||
{
|
||||
if (TYPE_CODE (type) == TYPE_CODE_PTR)
|
||||
{
|
||||
fprintf_filtered (stream, "access ");
|
||||
print_array_type (TYPE_TARGET_TYPE (type), stream, show, level);
|
||||
}
|
||||
else
|
||||
{
|
||||
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_BOOL:
|
||||
fprintf_filtered (stream, "(false, true)");
|
||||
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;
|
||||
}
|
||||
}
|
||||
1122
gdb/ada-valprint.c
1122
gdb/ada-valprint.c
File diff suppressed because it is too large
Load Diff
543
gdb/addrmap.c
543
gdb/addrmap.c
@@ -1,543 +0,0 @@
|
||||
/* addrmap.c --- implementation of address map data structure.
|
||||
|
||||
Copyright (C) 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "splay-tree.h"
|
||||
#include "gdb_obstack.h"
|
||||
#include "addrmap.h"
|
||||
#include "gdb_assert.h"
|
||||
|
||||
|
||||
|
||||
/* The "abstract class". */
|
||||
|
||||
/* Functions implementing the addrmap functions for a particular
|
||||
implementation. */
|
||||
struct addrmap_funcs
|
||||
{
|
||||
void (*set_empty) (struct addrmap *this,
|
||||
CORE_ADDR start, CORE_ADDR end_inclusive,
|
||||
void *obj);
|
||||
void *(*find) (struct addrmap *this, CORE_ADDR addr);
|
||||
struct addrmap *(*create_fixed) (struct addrmap *this,
|
||||
struct obstack *obstack);
|
||||
void (*relocate) (struct addrmap *this, CORE_ADDR offset);
|
||||
};
|
||||
|
||||
|
||||
struct addrmap
|
||||
{
|
||||
const struct addrmap_funcs *funcs;
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
addrmap_set_empty (struct addrmap *map,
|
||||
CORE_ADDR start, CORE_ADDR end_inclusive,
|
||||
void *obj)
|
||||
{
|
||||
map->funcs->set_empty (map, start, end_inclusive, obj);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
addrmap_find (struct addrmap *map, CORE_ADDR addr)
|
||||
{
|
||||
return map->funcs->find (map, addr);
|
||||
}
|
||||
|
||||
|
||||
struct addrmap *
|
||||
addrmap_create_fixed (struct addrmap *original, struct obstack *obstack)
|
||||
{
|
||||
return original->funcs->create_fixed (original, obstack);
|
||||
}
|
||||
|
||||
|
||||
/* Relocate all the addresses in MAP by OFFSET. (This can be applied
|
||||
to either mutable or immutable maps.) */
|
||||
void
|
||||
addrmap_relocate (struct addrmap *map, CORE_ADDR offset)
|
||||
{
|
||||
map->funcs->relocate (map, offset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Fixed address maps. */
|
||||
|
||||
/* A transition: a point in an address map where the value changes.
|
||||
The map maps ADDR to VALUE, but if ADDR > 0, it maps ADDR-1 to
|
||||
something else. */
|
||||
struct addrmap_transition
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
void *value;
|
||||
};
|
||||
|
||||
|
||||
struct addrmap_fixed
|
||||
{
|
||||
struct addrmap addrmap;
|
||||
|
||||
/* The number of transitions in TRANSITIONS. */
|
||||
size_t num_transitions;
|
||||
|
||||
/* An array of transitions, sorted by address. For every point in
|
||||
the map where either ADDR == 0 or ADDR is mapped to one value and
|
||||
ADDR - 1 is mapped to something different, we have an entry here
|
||||
containing ADDR and VALUE. (Note that this means we always have
|
||||
an entry for address 0). */
|
||||
struct addrmap_transition transitions[1];
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
addrmap_fixed_set_empty (struct addrmap *this,
|
||||
CORE_ADDR start, CORE_ADDR end_inclusive,
|
||||
void *obj)
|
||||
{
|
||||
internal_error (__FILE__, __LINE__,
|
||||
"addrmap_fixed_set_empty: "
|
||||
"fixed addrmaps can't be changed\n");
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
addrmap_fixed_find (struct addrmap *this, CORE_ADDR addr)
|
||||
{
|
||||
struct addrmap_fixed *map = (struct addrmap_fixed *) this;
|
||||
struct addrmap_transition *bottom = &map->transitions[0];
|
||||
struct addrmap_transition *top = &map->transitions[map->num_transitions - 1];
|
||||
|
||||
while (bottom < top)
|
||||
{
|
||||
/* This needs to round towards top, or else when top = bottom +
|
||||
1 (i.e., two entries are under consideration), then mid ==
|
||||
bottom, and then we may not narrow the range when (mid->addr
|
||||
< addr). */
|
||||
struct addrmap_transition *mid = top - (top - bottom) / 2;
|
||||
|
||||
if (mid->addr == addr)
|
||||
{
|
||||
bottom = mid;
|
||||
break;
|
||||
}
|
||||
else if (mid->addr < addr)
|
||||
/* We don't eliminate mid itself here, since each transition
|
||||
covers all subsequent addresses until the next. This is why
|
||||
we must round up in computing the midpoint. */
|
||||
bottom = mid;
|
||||
else
|
||||
top = mid - 1;
|
||||
}
|
||||
|
||||
return bottom->value;
|
||||
}
|
||||
|
||||
|
||||
static struct addrmap *
|
||||
addrmap_fixed_create_fixed (struct addrmap *this, struct obstack *obstack)
|
||||
{
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("addrmap_create_fixed is not implemented yet "
|
||||
"for fixed addrmaps"));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
addrmap_fixed_relocate (struct addrmap *this, CORE_ADDR offset)
|
||||
{
|
||||
struct addrmap_fixed *map = (struct addrmap_fixed *) this;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < map->num_transitions; i++)
|
||||
map->transitions[i].addr += offset;
|
||||
}
|
||||
|
||||
|
||||
static const struct addrmap_funcs addrmap_fixed_funcs =
|
||||
{
|
||||
addrmap_fixed_set_empty,
|
||||
addrmap_fixed_find,
|
||||
addrmap_fixed_create_fixed,
|
||||
addrmap_fixed_relocate
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Mutable address maps. */
|
||||
|
||||
struct addrmap_mutable
|
||||
{
|
||||
struct addrmap addrmap;
|
||||
|
||||
/* The obstack to use for allocations for this map. */
|
||||
struct obstack *obstack;
|
||||
|
||||
/* A splay tree, with a node for each transition; there is a
|
||||
transition at address T if T-1 and T map to different objects.
|
||||
|
||||
Any addresses below the first node map to NULL. (Unlike
|
||||
fixed maps, we have no entry at (CORE_ADDR) 0; it doesn't
|
||||
simplify enough.)
|
||||
|
||||
The last region is assumed to end at CORE_ADDR_MAX.
|
||||
|
||||
Since we can't know whether CORE_ADDR is larger or smaller than
|
||||
splay_tree_key (unsigned long) --- I think both are possible,
|
||||
given all combinations of 32- and 64-bit hosts and targets ---
|
||||
our keys are pointers to CORE_ADDR values. Since the splay tree
|
||||
library doesn't pass any closure pointer to the key free
|
||||
function, we can't keep a freelist for keys. Since mutable
|
||||
addrmaps are only used temporarily right now, we just leak keys
|
||||
from deleted nodes; they'll be freed when the obstack is freed. */
|
||||
splay_tree tree;
|
||||
|
||||
/* A freelist for splay tree nodes, allocated on obstack, and
|
||||
chained together by their 'right' pointers. */
|
||||
splay_tree_node free_nodes;
|
||||
};
|
||||
|
||||
|
||||
/* Allocate a copy of CORE_ADDR in MAP's obstack. */
|
||||
static splay_tree_key
|
||||
allocate_key (struct addrmap_mutable *map, CORE_ADDR addr)
|
||||
{
|
||||
CORE_ADDR *key = obstack_alloc (map->obstack, sizeof (*key));
|
||||
*key = addr;
|
||||
|
||||
return (splay_tree_key) key;
|
||||
}
|
||||
|
||||
|
||||
/* Type-correct wrappers for splay tree access. */
|
||||
static splay_tree_node
|
||||
addrmap_splay_tree_lookup (struct addrmap_mutable *map, CORE_ADDR addr)
|
||||
{
|
||||
return splay_tree_lookup (map->tree, (splay_tree_key) &addr);
|
||||
}
|
||||
|
||||
|
||||
static splay_tree_node
|
||||
addrmap_splay_tree_predecessor (struct addrmap_mutable *map, CORE_ADDR addr)
|
||||
{
|
||||
return splay_tree_predecessor (map->tree, (splay_tree_key) &addr);
|
||||
}
|
||||
|
||||
|
||||
static splay_tree_node
|
||||
addrmap_splay_tree_successor (struct addrmap_mutable *map, CORE_ADDR addr)
|
||||
{
|
||||
return splay_tree_successor (map->tree, (splay_tree_key) &addr);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
addrmap_splay_tree_remove (struct addrmap_mutable *map, CORE_ADDR addr)
|
||||
{
|
||||
splay_tree_remove (map->tree, (splay_tree_key) &addr);
|
||||
}
|
||||
|
||||
|
||||
static CORE_ADDR
|
||||
addrmap_node_key (splay_tree_node node)
|
||||
{
|
||||
return * (CORE_ADDR *) node->key;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
addrmap_node_value (splay_tree_node node)
|
||||
{
|
||||
return (void *) node->value;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
addrmap_node_set_value (splay_tree_node node, void *value)
|
||||
{
|
||||
node->value = (splay_tree_value) value;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
addrmap_splay_tree_insert (struct addrmap_mutable *map, CORE_ADDR key, void *value)
|
||||
{
|
||||
splay_tree_insert (map->tree,
|
||||
allocate_key (map, key),
|
||||
(splay_tree_value) value);
|
||||
}
|
||||
|
||||
|
||||
/* Without changing the mapping of any address, ensure that there is a
|
||||
tree node at ADDR, even if it would represent a "transition" from
|
||||
one value to the same value. */
|
||||
static void
|
||||
force_transition (struct addrmap_mutable *this, CORE_ADDR addr)
|
||||
{
|
||||
splay_tree_node n
|
||||
= addrmap_splay_tree_lookup (this, addr);
|
||||
|
||||
if (! n)
|
||||
{
|
||||
n = addrmap_splay_tree_predecessor (this, addr);
|
||||
addrmap_splay_tree_insert (this, addr,
|
||||
n ? addrmap_node_value (n) : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
addrmap_mutable_set_empty (struct addrmap *this,
|
||||
CORE_ADDR start, CORE_ADDR end_inclusive,
|
||||
void *obj)
|
||||
{
|
||||
struct addrmap_mutable *map = (struct addrmap_mutable *) this;
|
||||
splay_tree_node n, next;
|
||||
void *prior_value;
|
||||
|
||||
/* If we're being asked to set all empty portions of the given
|
||||
address range to empty, then probably the caller is confused.
|
||||
(If that turns out to be useful in some cases, then we can change
|
||||
this to simply return, since overriding NULL with NULL is a
|
||||
no-op.) */
|
||||
gdb_assert (obj);
|
||||
|
||||
/* We take a two-pass approach, for simplicity.
|
||||
- Establish transitions where we think we might need them.
|
||||
- First pass: change all NULL regions to OBJ.
|
||||
- Second pass: remove any unnecessary transitions. */
|
||||
|
||||
/* Establish transitions at the start and end. */
|
||||
force_transition (map, start);
|
||||
if (end_inclusive < CORE_ADDR_MAX)
|
||||
force_transition (map, end_inclusive + 1);
|
||||
|
||||
/* Walk the area, changing all NULL regions to OBJ. */
|
||||
for (n = addrmap_splay_tree_lookup (map, start), gdb_assert (n);
|
||||
n && addrmap_node_key (n) <= end_inclusive;
|
||||
n = addrmap_splay_tree_successor (map, addrmap_node_key (n)))
|
||||
{
|
||||
if (! addrmap_node_value (n))
|
||||
addrmap_node_set_value (n, obj);
|
||||
}
|
||||
|
||||
/* Walk the area again, removing transitions from any value to
|
||||
itself. Be sure to visit both the transitions we forced
|
||||
above. */
|
||||
n = addrmap_splay_tree_predecessor (map, start);
|
||||
prior_value = n ? addrmap_node_value (n) : NULL;
|
||||
for (n = addrmap_splay_tree_lookup (map, start), gdb_assert (n);
|
||||
n && (end_inclusive == CORE_ADDR_MAX
|
||||
|| addrmap_node_key (n) <= end_inclusive + 1);
|
||||
n = next)
|
||||
{
|
||||
next = addrmap_splay_tree_successor (map, addrmap_node_key (n));
|
||||
if (addrmap_node_value (n) == prior_value)
|
||||
addrmap_splay_tree_remove (map, addrmap_node_key (n));
|
||||
else
|
||||
prior_value = addrmap_node_value (n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
addrmap_mutable_find (struct addrmap *this, CORE_ADDR addr)
|
||||
{
|
||||
/* Not needed yet. */
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("addrmap_find is not implemented yet "
|
||||
"for mutable addrmaps"));
|
||||
}
|
||||
|
||||
|
||||
/* A function to pass to splay_tree_foreach to count the number of nodes
|
||||
in the tree. */
|
||||
static int
|
||||
splay_foreach_count (splay_tree_node n, void *closure)
|
||||
{
|
||||
size_t *count = (size_t *) closure;
|
||||
|
||||
(*count)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* A function to pass to splay_tree_foreach to copy entries into a
|
||||
fixed address map. */
|
||||
static int
|
||||
splay_foreach_copy (splay_tree_node n, void *closure)
|
||||
{
|
||||
struct addrmap_fixed *fixed = (struct addrmap_fixed *) closure;
|
||||
struct addrmap_transition *t = &fixed->transitions[fixed->num_transitions];
|
||||
|
||||
t->addr = addrmap_node_key (n);
|
||||
t->value = addrmap_node_value (n);
|
||||
fixed->num_transitions++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct addrmap *
|
||||
addrmap_mutable_create_fixed (struct addrmap *this, struct obstack *obstack)
|
||||
{
|
||||
struct addrmap_mutable *mutable = (struct addrmap_mutable *) this;
|
||||
struct addrmap_fixed *fixed;
|
||||
size_t num_transitions;
|
||||
|
||||
/* Count the number of transitions in the tree. */
|
||||
num_transitions = 0;
|
||||
splay_tree_foreach (mutable->tree, splay_foreach_count, &num_transitions);
|
||||
|
||||
/* Include an extra entry for the transition at zero (which fixed
|
||||
maps have, but mutable maps do not.) */
|
||||
num_transitions++;
|
||||
|
||||
fixed = obstack_alloc (obstack,
|
||||
(sizeof (*fixed)
|
||||
+ (num_transitions
|
||||
* sizeof (fixed->transitions[0]))));
|
||||
fixed->addrmap.funcs = &addrmap_fixed_funcs;
|
||||
fixed->num_transitions = 1;
|
||||
fixed->transitions[0].addr = 0;
|
||||
fixed->transitions[0].value = NULL;
|
||||
|
||||
/* Copy all entries from the splay tree to the array, in order
|
||||
of increasing address. */
|
||||
splay_tree_foreach (mutable->tree, splay_foreach_copy, fixed);
|
||||
|
||||
/* We should have filled the array. */
|
||||
gdb_assert (fixed->num_transitions == num_transitions);
|
||||
|
||||
return (struct addrmap *) fixed;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
addrmap_mutable_relocate (struct addrmap *this, CORE_ADDR offset)
|
||||
{
|
||||
/* Not needed yet. */
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("addrmap_relocate is not implemented yet "
|
||||
"for mutable addrmaps"));
|
||||
}
|
||||
|
||||
|
||||
static const struct addrmap_funcs addrmap_mutable_funcs =
|
||||
{
|
||||
addrmap_mutable_set_empty,
|
||||
addrmap_mutable_find,
|
||||
addrmap_mutable_create_fixed,
|
||||
addrmap_mutable_relocate
|
||||
};
|
||||
|
||||
|
||||
static void *
|
||||
splay_obstack_alloc (int size, void *closure)
|
||||
{
|
||||
struct addrmap_mutable *map = closure;
|
||||
splay_tree_node n;
|
||||
|
||||
/* We should only be asked to allocate nodes and larger things.
|
||||
(If, at some point in the future, this is no longer true, we can
|
||||
just round up the size to sizeof (*n).) */
|
||||
gdb_assert (size >= sizeof (*n));
|
||||
|
||||
if (map->free_nodes)
|
||||
{
|
||||
n = map->free_nodes;
|
||||
map->free_nodes = n->right;
|
||||
return n;
|
||||
}
|
||||
else
|
||||
return obstack_alloc (map->obstack, size);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
splay_obstack_free (void *obj, void *closure)
|
||||
{
|
||||
struct addrmap_mutable *map = closure;
|
||||
splay_tree_node n = obj;
|
||||
|
||||
/* We've asserted in the allocation function that we only allocate
|
||||
nodes or larger things, so it should be safe to put whatever
|
||||
we get passed back on the free list. */
|
||||
n->right = map->free_nodes;
|
||||
map->free_nodes = n;
|
||||
}
|
||||
|
||||
|
||||
/* Compare keys as CORE_ADDR * values. */
|
||||
static int
|
||||
splay_compare_CORE_ADDR_ptr (splay_tree_key ak, splay_tree_key bk)
|
||||
{
|
||||
CORE_ADDR a = * (CORE_ADDR *) ak;
|
||||
CORE_ADDR b = * (CORE_ADDR *) bk;
|
||||
|
||||
/* We can't just return a-b here, because of over/underflow. */
|
||||
if (a < b)
|
||||
return -1;
|
||||
else if (a == b)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
struct addrmap *
|
||||
addrmap_create_mutable (struct obstack *obstack)
|
||||
{
|
||||
struct addrmap_mutable *map = obstack_alloc (obstack, sizeof (*map));
|
||||
|
||||
map->addrmap.funcs = &addrmap_mutable_funcs;
|
||||
map->obstack = obstack;
|
||||
|
||||
/* splay_tree_new_with_allocator uses the provided allocation
|
||||
function to allocate the main splay_tree structure itself, so our
|
||||
free list has to be initialized before we create the tree. */
|
||||
map->free_nodes = NULL;
|
||||
|
||||
map->tree = splay_tree_new_with_allocator (splay_compare_CORE_ADDR_ptr,
|
||||
NULL, /* no delete key */
|
||||
NULL, /* no delete value */
|
||||
splay_obstack_alloc,
|
||||
splay_obstack_free,
|
||||
map);
|
||||
|
||||
return (struct addrmap *) map;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Initialization. */
|
||||
|
||||
void
|
||||
_initialize_addrmap (void)
|
||||
{
|
||||
/* Make sure splay trees can actually hold the values we want to
|
||||
store in them. */
|
||||
gdb_assert (sizeof (splay_tree_key) >= sizeof (CORE_ADDR *));
|
||||
gdb_assert (sizeof (splay_tree_value) >= sizeof (void *));
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/* addrmap.h --- interface to address map data structure.
|
||||
|
||||
Copyright (C) 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef ADDRMAP_H
|
||||
#define ADDRMAP_H
|
||||
|
||||
/* An address map is essentially a table mapping CORE_ADDRs onto GDB
|
||||
data structures, like blocks, symtabs, partial symtabs, and so on.
|
||||
An address map uses memory proportional to the number of
|
||||
transitions in the map, where a CORE_ADDR N is mapped to one
|
||||
object, and N+1 is mapped to a different object.
|
||||
|
||||
Address maps come in two flavors: fixed, and mutable. Mutable
|
||||
address maps consume more memory, but can be changed and extended.
|
||||
A fixed address map, once constructed (from a mutable address map),
|
||||
can't be edited. Both kinds of map are allocated in obstacks. */
|
||||
|
||||
/* The opaque type representing address maps. */
|
||||
struct addrmap;
|
||||
|
||||
/* Create a mutable address map which maps every address to NULL.
|
||||
Allocate entries in OBSTACK. */
|
||||
struct addrmap *addrmap_create_mutable (struct obstack *obstack);
|
||||
|
||||
/* In the mutable address map MAP, associate the addresses from START
|
||||
to END_INCLUSIVE that are currently associated with NULL with OBJ
|
||||
instead. Addresses mapped to an object other than NULL are left
|
||||
unchanged.
|
||||
|
||||
As the name suggests, END_INCLUSIVE is also mapped to OBJ. This
|
||||
convention is unusual, but it allows callers to accurately specify
|
||||
ranges that abut the top of the address space, and ranges that
|
||||
cover the entire address space.
|
||||
|
||||
This operation seems a bit complicated for a primitive: if it's
|
||||
needed, why not just have a simpler primitive operation that sets a
|
||||
range to a value, wiping out whatever was there before, and then
|
||||
let the caller construct more complicated operations from that,
|
||||
along with some others for traversal?
|
||||
|
||||
It turns out this is the mutation operation we want to use all the
|
||||
time, at least for now. Our immediate use for address maps is to
|
||||
represent lexical blocks whose address ranges are not contiguous.
|
||||
We walk the tree of lexical blocks present in the debug info, and
|
||||
only create 'struct block' objects after we've traversed all a
|
||||
block's children. If a lexical block declares no local variables
|
||||
(and isn't the lexical block for a function's body), we omit it
|
||||
from GDB's data structures entirely.
|
||||
|
||||
However, this menas that we don't decide to create a block (and
|
||||
thus record it in the address map) until after we've traversed its
|
||||
children. If we do decide to create the block, we do so at a time
|
||||
when all its children have already been recorded in the map. So
|
||||
this operation --- change only those addresses left unset --- is
|
||||
actually the operation we want to use every time.
|
||||
|
||||
It seems simpler to let the code which operates on the
|
||||
representation directly deal with the hair of implementing these
|
||||
semantics than to provide an interface which allows it to be
|
||||
implemented efficiently, but doesn't reveal too much of the
|
||||
representation. */
|
||||
void addrmap_set_empty (struct addrmap *map,
|
||||
CORE_ADDR start, CORE_ADDR end_inclusive,
|
||||
void *obj);
|
||||
|
||||
/* Return the object associated with ADDR in MAP. */
|
||||
void *addrmap_find (struct addrmap *map, CORE_ADDR addr);
|
||||
|
||||
/* Create a fixed address map which is a copy of the mutable address
|
||||
map ORIGINAL. Allocate entries in OBSTACK. */
|
||||
struct addrmap *addrmap_create_fixed (struct addrmap *original,
|
||||
struct obstack *obstack);
|
||||
|
||||
/* Relocate all the addresses in MAP by OFFSET. (This can be applied
|
||||
to either mutable or immutable maps.) */
|
||||
void addrmap_relocate (struct addrmap *map, CORE_ADDR offset);
|
||||
|
||||
#endif /* ADDRMAP_H */
|
||||
1814
gdb/aix-thread.c
1814
gdb/aix-thread.c
File diff suppressed because it is too large
Load Diff
@@ -1,103 +0,0 @@
|
||||
/* Low level Alpha GNU/Linux interface, for GDB when running native.
|
||||
Copyright (C) 2005, 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "target.h"
|
||||
#include "regcache.h"
|
||||
#include "linux-nat.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <alpha/ptrace.h>
|
||||
|
||||
#include <sys/procfs.h>
|
||||
#include "gregset.h"
|
||||
|
||||
/* The address of UNIQUE for ptrace. */
|
||||
#define ALPHA_UNIQUE_PTRACE_ADDR 65
|
||||
|
||||
|
||||
/*
|
||||
* See the comment in m68k-tdep.c regarding the utility of these functions.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
|
||||
{
|
||||
const long *regp = (const long *)gregsetp;
|
||||
|
||||
/* PC is in slot 32, UNIQUE is in slot 33. */
|
||||
alpha_supply_int_regs (regcache, -1, regp, regp + 31, regp + 32);
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (const struct regcache *regcache,
|
||||
gdb_gregset_t *gregsetp, int regno)
|
||||
{
|
||||
long *regp = (long *)gregsetp;
|
||||
|
||||
/* PC is in slot 32, UNIQUE is in slot 33. */
|
||||
alpha_fill_int_regs (regcache, regno, regp, regp + 31, regp + 32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we do the same thing for floating-point registers.
|
||||
* Again, see the comments in m68k-tdep.c.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
|
||||
{
|
||||
const long *regp = (const long *)fpregsetp;
|
||||
|
||||
/* FPCR is in slot 32. */
|
||||
alpha_supply_fp_regs (regcache, -1, regp, regp + 31);
|
||||
}
|
||||
|
||||
void
|
||||
fill_fpregset (const struct regcache *regcache,
|
||||
gdb_fpregset_t *fpregsetp, int regno)
|
||||
{
|
||||
long *regp = (long *)fpregsetp;
|
||||
|
||||
/* FPCR is in slot 32. */
|
||||
alpha_fill_fp_regs (regcache, regno, regp, regp + 31);
|
||||
}
|
||||
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_linux_register_u_offset (struct gdbarch *gdbarch, int regno, int store_p)
|
||||
{
|
||||
if (regno == gdbarch_pc_regnum (gdbarch))
|
||||
return PC;
|
||||
if (regno == ALPHA_UNIQUE_REGNUM)
|
||||
return ALPHA_UNIQUE_PTRACE_ADDR;
|
||||
if (regno < gdbarch_fp0_regnum (gdbarch))
|
||||
return GPR_BASE + regno;
|
||||
else
|
||||
return FPR_BASE + regno - gdbarch_fp0_regnum (gdbarch);
|
||||
}
|
||||
|
||||
void _initialialize_alpha_linux_nat (void);
|
||||
|
||||
void
|
||||
_initialize_alpha_linux_nat (void)
|
||||
{
|
||||
linux_nat_add_target (linux_trad_target (alpha_linux_register_u_offset));
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
/* Target-dependent code for GNU/Linux on Alpha.
|
||||
Copyright (C) 2002, 2003, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
#include "osabi.h"
|
||||
#include "solib-svr4.h"
|
||||
#include "symtab.h"
|
||||
#include "regset.h"
|
||||
#include "regcache.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 *this_frame)
|
||||
{
|
||||
CORE_ADDR pc;
|
||||
ULONGEST sp;
|
||||
long off;
|
||||
|
||||
pc = get_frame_pc (this_frame);
|
||||
sp = get_frame_register_unsigned (this_frame, ALPHA_SP_REGNUM);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Supply register REGNUM from the buffer specified by GREGS and LEN
|
||||
in the general-purpose register set REGSET to register cache
|
||||
REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
|
||||
|
||||
static void
|
||||
alpha_linux_supply_gregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *gregs, size_t len)
|
||||
{
|
||||
const gdb_byte *regs = gregs;
|
||||
int i;
|
||||
gdb_assert (len >= 32 * 8);
|
||||
|
||||
for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
|
||||
{
|
||||
if (regnum == i || regnum == -1)
|
||||
regcache_raw_supply (regcache, i, regs + i * 8);
|
||||
}
|
||||
|
||||
if (regnum == ALPHA_PC_REGNUM || regnum == -1)
|
||||
regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
|
||||
|
||||
if (regnum == ALPHA_UNIQUE_REGNUM || regnum == -1)
|
||||
regcache_raw_supply (regcache, ALPHA_UNIQUE_REGNUM,
|
||||
len >= 33 * 8 ? regs + 32 * 8 : NULL);
|
||||
}
|
||||
|
||||
/* Supply register REGNUM from the buffer specified by FPREGS and LEN
|
||||
in the floating-point register set REGSET to register cache
|
||||
REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
|
||||
|
||||
static void
|
||||
alpha_linux_supply_fpregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *fpregs, size_t len)
|
||||
{
|
||||
const gdb_byte *regs = fpregs;
|
||||
int i;
|
||||
gdb_assert (len >= 32 * 8);
|
||||
|
||||
for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
|
||||
{
|
||||
if (regnum == i || regnum == -1)
|
||||
regcache_raw_supply (regcache, i, regs + (i - ALPHA_FP0_REGNUM) * 8);
|
||||
}
|
||||
|
||||
if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
|
||||
regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, regs + 31 * 8);
|
||||
}
|
||||
|
||||
static struct regset alpha_linux_gregset =
|
||||
{
|
||||
NULL,
|
||||
alpha_linux_supply_gregset
|
||||
};
|
||||
|
||||
static struct regset alpha_linux_fpregset =
|
||||
{
|
||||
NULL,
|
||||
alpha_linux_supply_fpregset
|
||||
};
|
||||
|
||||
/* Return the appropriate register set for the core section identified
|
||||
by SECT_NAME and SECT_SIZE. */
|
||||
|
||||
const struct regset *
|
||||
alpha_linux_regset_from_core_section (struct gdbarch *gdbarch,
|
||||
const char *sect_name, size_t sect_size)
|
||||
{
|
||||
if (strcmp (sect_name, ".reg") == 0 && sect_size >= 32 * 8)
|
||||
return &alpha_linux_gregset;
|
||||
|
||||
if (strcmp (sect_name, ".reg2") == 0 && sect_size >= 32 * 8)
|
||||
return &alpha_linux_fpregset;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
|
||||
|
||||
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);
|
||||
|
||||
set_gdbarch_regset_from_core_section
|
||||
(gdbarch, alpha_linux_regset_from_core_section);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_alpha_linux_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_LINUX,
|
||||
alpha_linux_init_abi);
|
||||
}
|
||||
@@ -1,376 +0,0 @@
|
||||
/* Target-dependent mdebug code for the ALPHA architecture.
|
||||
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
2003, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 "gdb_string.h"
|
||||
#include "trad-frame.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;
|
||||
char *sh_name = NULL;
|
||||
|
||||
if (b)
|
||||
{
|
||||
CORE_ADDR startaddr;
|
||||
find_pc_partial_function (pc, &sh_name, &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);
|
||||
}
|
||||
|
||||
if (sym)
|
||||
{
|
||||
proc_desc = (struct mdebug_extra_func_info *) SYMBOL_VALUE (sym);
|
||||
|
||||
/* Correct incorrect setjmp procedure descriptor from the library
|
||||
to make backtrace through setjmp work. */
|
||||
if (proc_desc->pdr.pcreg == 0
|
||||
&& strcmp (sh_name, "setjmp") == 0)
|
||||
{
|
||||
proc_desc->pdr.pcreg = ALPHA_RA_REGNUM;
|
||||
proc_desc->pdr.regmask = 0x80000000;
|
||||
proc_desc->pdr.regoffset = -4;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
struct trad_frame_saved_reg *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 *this_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 = get_frame_pc (this_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 = trad_frame_alloc_saved_regs (this_frame);
|
||||
|
||||
/* The VFP of the frame is at FRAME_REG+FRAME_OFFSET. */
|
||||
vfp = get_frame_register_unsigned (this_frame, PROC_FRAME_REG (proc_desc));
|
||||
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].addr = reg_position;
|
||||
reg_position += 8;
|
||||
}
|
||||
|
||||
for (ireg = 0; ireg <= 31; ++ireg)
|
||||
if (mask & (1 << ireg))
|
||||
{
|
||||
info->saved_regs[ireg].addr = 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].addr = reg_position;
|
||||
reg_position += 8;
|
||||
}
|
||||
|
||||
/* The stack pointer of the previous frame is computed by popping
|
||||
the current stack frame. */
|
||||
if (!trad_frame_addr_p (info->saved_regs, ALPHA_SP_REGNUM))
|
||||
trad_frame_set_value (info->saved_regs, ALPHA_SP_REGNUM, vfp);
|
||||
|
||||
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 *this_frame,
|
||||
void **this_prologue_cache,
|
||||
struct frame_id *this_id)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
|
||||
|
||||
*this_id = frame_id_build (info->vfp, get_frame_func (this_frame));
|
||||
}
|
||||
|
||||
/* Retrieve the value of REGNUM in FRAME. Don't give up! */
|
||||
|
||||
static struct value *
|
||||
alpha_mdebug_frame_prev_register (struct frame_info *this_frame,
|
||||
void **this_prologue_cache, int regnum)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (this_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);
|
||||
|
||||
return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
|
||||
}
|
||||
|
||||
static int
|
||||
alpha_mdebug_frame_sniffer (const struct frame_unwind *self,
|
||||
struct frame_info *this_frame,
|
||||
void **this_cache)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_address_in_block (this_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 0;
|
||||
|
||||
/* 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 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct frame_unwind alpha_mdebug_frame_unwind = {
|
||||
NORMAL_FRAME,
|
||||
alpha_mdebug_frame_this_id,
|
||||
alpha_mdebug_frame_prev_register,
|
||||
NULL,
|
||||
alpha_mdebug_frame_sniffer
|
||||
};
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_mdebug_frame_base_address (struct frame_info *this_frame,
|
||||
void **this_prologue_cache)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
|
||||
|
||||
return info->vfp;
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_mdebug_frame_locals_address (struct frame_info *this_frame,
|
||||
void **this_prologue_cache)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (this_frame, this_prologue_cache);
|
||||
|
||||
return info->vfp - PROC_LOCALOFF (info->proc_desc);
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
alpha_mdebug_frame_args_address (struct frame_info *this_frame,
|
||||
void **this_prologue_cache)
|
||||
{
|
||||
struct alpha_mdebug_unwind_cache *info
|
||||
= alpha_mdebug_frame_unwind_cache (this_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 *this_frame)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_address_in_block (this_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_unwinder (gdbarch, &alpha_mdebug_frame_unwind);
|
||||
frame_base_append_sniffer (gdbarch, alpha_mdebug_frame_base_sniffer);
|
||||
}
|
||||
190
gdb/alpha-nat.c
190
gdb/alpha-nat.c
@@ -1,190 +0,0 @@
|
||||
/* Low level Alpha interface, for GDB when running native.
|
||||
Copyright (C) 1993, 1995, 1996, 1998, 1999, 2000, 2001, 2003, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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>
|
||||
#include <alpha/coreregs.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
|
||||
/* Extract the register values out of the core file and store
|
||||
them into REGCACHE.
|
||||
|
||||
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 (struct regcache *regcache,
|
||||
char *core_reg_sect, unsigned core_reg_size,
|
||||
int which, CORE_ADDR reg_addr)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
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 (gdbarch_cannot_fetch_register (gdbarch, regno))
|
||||
{
|
||||
regcache_raw_supply (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 (regcache, regno, NULL);
|
||||
continue;
|
||||
}
|
||||
if (bad_reg < 0)
|
||||
bad_reg = regno;
|
||||
}
|
||||
else
|
||||
{
|
||||
regcache_raw_supply (regcache, regno, core_reg_sect + addr);
|
||||
}
|
||||
}
|
||||
if (bad_reg >= 0)
|
||||
{
|
||||
error (_("Register %s not found in core file."),
|
||||
gdbarch_register_name (gdbarch, bad_reg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include <sys/procfs.h>
|
||||
/* Prototypes for supply_gregset etc. */
|
||||
#include "gregset.h"
|
||||
|
||||
/*
|
||||
* See the comment in m68k-tdep.c regarding the utility of these functions.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
|
||||
{
|
||||
const long *regp = gregsetp->regs;
|
||||
|
||||
/* PC is in slot 32. */
|
||||
alpha_supply_int_regs (regcache, -1, regp, regp + 31, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (const struct regcache *regcache,
|
||||
gdb_gregset_t *gregsetp, int regno)
|
||||
{
|
||||
long *regp = gregsetp->regs;
|
||||
|
||||
/* PC is in slot 32. */
|
||||
alpha_fill_int_regs (regcache, regno, regp, regp + 31, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we do the same thing for floating-point registers.
|
||||
* Again, see the comments in m68k-tdep.c.
|
||||
*/
|
||||
|
||||
void
|
||||
supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
|
||||
{
|
||||
const long *regp = fpregsetp->regs;
|
||||
|
||||
/* FPCR is in slot 32. */
|
||||
alpha_supply_fp_regs (regcache, -1, regp, regp + 31);
|
||||
}
|
||||
|
||||
void
|
||||
fill_fpregset (const struct regcache *regcache,
|
||||
gdb_fpregset_t *fpregsetp, int regno)
|
||||
{
|
||||
long *regp = fpregsetp->regs;
|
||||
|
||||
/* FPCR is in slot 32. */
|
||||
alpha_fill_fp_regs (regcache, regno, regp, regp + 31);
|
||||
}
|
||||
|
||||
|
||||
/* 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 */
|
||||
};
|
||||
|
||||
void
|
||||
_initialize_core_alpha (void)
|
||||
{
|
||||
deprecated_add_core_fns (&alpha_osf_core_fns);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/* Target-dependent code for OSF/1 on Alpha.
|
||||
Copyright (C) 2002, 2003, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 *this_frame)
|
||||
{
|
||||
struct frame_info *next_frame = get_next_frame (this_frame);
|
||||
struct frame_id next_id = null_frame_id;
|
||||
|
||||
if (next_frame != NULL)
|
||||
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);
|
||||
}
|
||||
1634
gdb/alpha-tdep.c
1634
gdb/alpha-tdep.c
File diff suppressed because it is too large
Load Diff
121
gdb/alpha-tdep.h
121
gdb/alpha-tdep.h
@@ -1,121 +0,0 @@
|
||||
/* Common target dependent code for GDB on Alpha systems.
|
||||
Copyright (C) 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2002, 2003, 2007,
|
||||
2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef ALPHA_TDEP_H
|
||||
#define ALPHA_TDEP_H
|
||||
|
||||
struct regcache;
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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_S0_REGNUM 9 /* First saved register */
|
||||
#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 */
|
||||
|
||||
/* Instruction size. */
|
||||
#define ALPHA_INSN_SIZE 4
|
||||
|
||||
/* 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);
|
||||
|
||||
/* If TYPE will be returned in memory, return true. */
|
||||
int (*return_in_memory) (struct type *type);
|
||||
|
||||
/* 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 int alpha_software_single_step (struct frame_info *frame);
|
||||
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 (struct regcache *, int, const void *,
|
||||
const void *, const void *);
|
||||
extern void alpha_fill_int_regs (const struct regcache *, int,
|
||||
void *, void *, void *);
|
||||
extern void alpha_supply_fp_regs (struct regcache *, int,
|
||||
const void *, const void *);
|
||||
extern void alpha_fill_fp_regs (const struct regcache *,
|
||||
int, void *, void *);
|
||||
|
||||
#endif /* ALPHA_TDEP_H */
|
||||
@@ -1,202 +0,0 @@
|
||||
/* Native-dependent code for Alpha BSD's.
|
||||
|
||||
Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 (struct regcache *regcache, const gregset_t *gregsetp)
|
||||
{
|
||||
alphabsd_supply_reg (regcache, (const char *) gregsetp, -1);
|
||||
}
|
||||
|
||||
void
|
||||
fill_gregset (const struct regcache *regcache, gregset_t *gregsetp, int regno)
|
||||
{
|
||||
alphabsd_fill_reg (regcache, (char *) gregsetp, regno);
|
||||
}
|
||||
|
||||
void
|
||||
supply_fpregset (struct regcache *regcache, const fpregset_t *fpregsetp)
|
||||
{
|
||||
alphabsd_supply_fpreg (regcache, (const char *) fpregsetp, -1);
|
||||
}
|
||||
|
||||
void
|
||||
fill_fpregset (const struct regcache *regcache, fpregset_t *fpregsetp, int regno)
|
||||
{
|
||||
alphabsd_fill_fpreg (regcache, (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 (struct regcache *regcache, 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 (regcache, (char *) &gregs, regno);
|
||||
if (regno != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (regno == -1 || regno >= gdbarch_fp0_regnum (get_regcache_arch (regcache)))
|
||||
{
|
||||
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 (regcache, (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 (struct regcache *regcache, 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 (regcache, (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 >= gdbarch_fp0_regnum (get_regcache_arch (regcache)))
|
||||
{
|
||||
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 (regcache, (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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Support for debugging kernel virtual memory images. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/signal.h>
|
||||
#include <machine/pcb.h>
|
||||
|
||||
#include "bsd-kvm.h"
|
||||
|
||||
static int
|
||||
alphabsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
|
||||
{
|
||||
int regnum;
|
||||
|
||||
/* The following is true for OpenBSD 3.9:
|
||||
|
||||
The pcb contains the register state at the context switch inside
|
||||
cpu_switch(). */
|
||||
|
||||
/* The stack pointer shouldn't be zero. */
|
||||
if (pcb->pcb_hw.apcb_ksp == 0)
|
||||
return 0;
|
||||
|
||||
regcache_raw_supply (regcache, ALPHA_SP_REGNUM, &pcb->pcb_hw.apcb_ksp);
|
||||
|
||||
for (regnum = ALPHA_S0_REGNUM; regnum < ALPHA_A0_REGNUM; regnum++)
|
||||
regcache_raw_supply (regcache, regnum,
|
||||
&pcb->pcb_context[regnum - ALPHA_S0_REGNUM]);
|
||||
regcache_raw_supply (regcache, ALPHA_RA_REGNUM, &pcb->pcb_context[7]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Support debugging kernel virtual memory images. */
|
||||
bsd_kvm_add_target (alphabsd_supply_pcb);
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/* Common target dependent code Alpha BSD's.
|
||||
|
||||
Copyright (C) 2000, 2001, 2002, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "regcache.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 (struct regcache *regcache, const char *regs, int regno)
|
||||
{
|
||||
/* PC is at slot 32; UNIQUE not present. */
|
||||
alpha_supply_int_regs (regcache, regno, regs, regs + 31 * 8, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
alphabsd_fill_reg (const struct regcache *regcache, char *regs, int regno)
|
||||
{
|
||||
/* PC is at slot 32; UNIQUE not present. */
|
||||
alpha_fill_int_regs (regcache, regno, regs, regs + 31 * 8, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
alphabsd_supply_fpreg (struct regcache *regcache, const char *fpregs, int regno)
|
||||
{
|
||||
/* FPCR is at slot 33; slot 32 unused. */
|
||||
alpha_supply_fp_regs (regcache, regno, fpregs, fpregs + 32 * 8);
|
||||
}
|
||||
|
||||
void
|
||||
alphabsd_fill_fpreg (const struct regcache *regcache, char *fpregs, int regno)
|
||||
{
|
||||
/* FPCR is at slot 33; slot 32 unused. */
|
||||
alpha_fill_fp_regs (regcache, regno, fpregs, fpregs + 32 * 8);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/* Common target dependent code for Alpha BSD's.
|
||||
|
||||
Copyright (C) 2002, 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef ALPHABSD_TDEP_H
|
||||
#define ALPHABSD_TDEP_H
|
||||
|
||||
struct regcache;
|
||||
|
||||
void alphabsd_supply_reg (struct regcache *, const char *, int);
|
||||
void alphabsd_fill_reg (const struct regcache *, char *, int);
|
||||
|
||||
void alphabsd_supply_fpreg (struct regcache *, const char *, int);
|
||||
void alphabsd_fill_fpreg (const struct regcache *, char *, int);
|
||||
|
||||
|
||||
/* Functions exported from alphanbsd-tdep.c. */
|
||||
|
||||
/* Return the appropriate register set for the core section identified
|
||||
by SECT_NAME and SECT_SIZE. */
|
||||
extern const struct regset *
|
||||
alphanbsd_regset_from_core_section (struct gdbarch *gdbarch,
|
||||
const char *sect_name, size_t len);
|
||||
|
||||
#endif /* alphabsd-tdep.h */
|
||||
@@ -1,127 +0,0 @@
|
||||
/* Target-dependent code for FreeBSD/alpha.
|
||||
|
||||
Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "value.h"
|
||||
#include "osabi.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
static int
|
||||
alphafbsd_return_in_memory (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 THIS_FRAME is the frame of a BSD sigtramp routine,
|
||||
return the address of the associated sigcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
alphafbsd_sigcontext_addr (struct frame_info *this_frame)
|
||||
{
|
||||
return get_frame_register_unsigned (this_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);
|
||||
|
||||
tdep->dynamic_sigtramp_offset = alphafbsd_sigtramp_offset;
|
||||
tdep->sigcontext_addr = alphafbsd_sigcontext_addr;
|
||||
tdep->pc_in_sigtramp = alphafbsd_pc_in_sigtramp;
|
||||
tdep->return_in_memory = alphafbsd_return_in_memory;
|
||||
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,316 +0,0 @@
|
||||
/* Target-dependent code for NetBSD/alpha.
|
||||
|
||||
Copyright (C) 2002, 2003, 2004, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "osabi.h"
|
||||
#include "regcache.h"
|
||||
#include "regset.h"
|
||||
#include "value.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
#include "alphabsd-tdep.h"
|
||||
#include "nbsd-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
#include "target.h"
|
||||
|
||||
/* Core file support. */
|
||||
|
||||
/* Even though NetBSD/alpha used ELF since day one, it used the
|
||||
traditional a.out-style core dump format before NetBSD 1.6. */
|
||||
|
||||
/* Sizeof `struct reg' in <machine/reg.h>. */
|
||||
#define ALPHANBSD_SIZEOF_GREGS (32 * 8)
|
||||
|
||||
/* Sizeof `struct fpreg' in <machine/reg.h. */
|
||||
#define ALPHANBSD_SIZEOF_FPREGS ((32 * 8) + 8)
|
||||
|
||||
/* Supply register REGNUM from the buffer specified by FPREGS and LEN
|
||||
in the floating-point register set REGSET to register cache
|
||||
REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
|
||||
|
||||
static void
|
||||
alphanbsd_supply_fpregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *fpregs, size_t len)
|
||||
{
|
||||
const gdb_byte *regs = fpregs;
|
||||
int i;
|
||||
|
||||
gdb_assert (len >= ALPHANBSD_SIZEOF_FPREGS);
|
||||
|
||||
for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
|
||||
{
|
||||
if (regnum == i || regnum == -1)
|
||||
regcache_raw_supply (regcache, i, regs + (i - ALPHA_FP0_REGNUM) * 8);
|
||||
}
|
||||
|
||||
if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
|
||||
regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, regs + 32 * 8);
|
||||
}
|
||||
|
||||
/* Supply register REGNUM from the buffer specified by GREGS and LEN
|
||||
in the general-purpose register set REGSET to register cache
|
||||
REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
|
||||
|
||||
static void
|
||||
alphanbsd_supply_gregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *gregs, size_t len)
|
||||
{
|
||||
const gdb_byte *regs = gregs;
|
||||
int i;
|
||||
|
||||
gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
|
||||
|
||||
for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
|
||||
{
|
||||
if (regnum == i || regnum == -1)
|
||||
regcache_raw_supply (regcache, i, regs + i * 8);
|
||||
}
|
||||
|
||||
if (regnum == ALPHA_PC_REGNUM || regnum == -1)
|
||||
regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
|
||||
}
|
||||
|
||||
/* Supply register REGNUM from the buffer specified by GREGS and LEN
|
||||
in the general-purpose register set REGSET to register cache
|
||||
REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
|
||||
|
||||
static void
|
||||
alphanbsd_aout_supply_gregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *gregs, size_t len)
|
||||
{
|
||||
const gdb_byte *regs = gregs;
|
||||
int i;
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(regmap); i++)
|
||||
{
|
||||
if (regnum == i || regnum == -1)
|
||||
regcache_raw_supply (regcache, i, regs + regmap[i] * 8);
|
||||
}
|
||||
|
||||
if (regnum == ALPHA_PC_REGNUM || regnum == -1)
|
||||
regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
|
||||
|
||||
if (len >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
|
||||
{
|
||||
regs += ALPHANBSD_SIZEOF_GREGS;
|
||||
len -= ALPHANBSD_SIZEOF_GREGS;
|
||||
alphanbsd_supply_fpregset (regset, regcache, regnum, regs, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* NetBSD/alpha register sets. */
|
||||
|
||||
static struct regset alphanbsd_gregset =
|
||||
{
|
||||
NULL,
|
||||
alphanbsd_supply_gregset
|
||||
};
|
||||
|
||||
static struct regset alphanbsd_fpregset =
|
||||
{
|
||||
NULL,
|
||||
alphanbsd_supply_fpregset
|
||||
};
|
||||
|
||||
static struct regset alphanbsd_aout_gregset =
|
||||
{
|
||||
NULL,
|
||||
alphanbsd_aout_supply_gregset
|
||||
};
|
||||
|
||||
/* Return the appropriate register set for the core section identified
|
||||
by SECT_NAME and SECT_SIZE. */
|
||||
|
||||
const struct regset *
|
||||
alphanbsd_regset_from_core_section (struct gdbarch *gdbarch,
|
||||
const char *sect_name, size_t sect_size)
|
||||
{
|
||||
if (strcmp (sect_name, ".reg") == 0 && sect_size >= ALPHANBSD_SIZEOF_GREGS)
|
||||
{
|
||||
if (sect_size >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
|
||||
return &alphanbsd_aout_gregset;
|
||||
else
|
||||
return &alphanbsd_gregset;
|
||||
}
|
||||
|
||||
if (strcmp (sect_name, ".reg2") == 0 && sect_size >= ALPHANBSD_SIZEOF_FPREGS)
|
||||
return &alphanbsd_fpregset;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Signal trampolines. */
|
||||
|
||||
/* 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)
|
||||
|
||||
static LONGEST
|
||||
alphanbsd_sigtramp_offset (CORE_ADDR pc)
|
||||
{
|
||||
unsigned char ret[RETCODE_SIZE], w[4];
|
||||
LONGEST off;
|
||||
int i;
|
||||
|
||||
if (target_read_memory (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 (target_read_memory (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. */
|
||||
if (!get_next_frame (frame))
|
||||
return 0;
|
||||
return get_frame_base (get_next_frame (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);
|
||||
|
||||
/* NetBSD/alpha has SVR4-style shared libraries. */
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_lp64_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;
|
||||
|
||||
set_gdbarch_regset_from_core_section
|
||||
(gdbarch, alphanbsd_regset_from_core_section);
|
||||
}
|
||||
|
||||
|
||||
static enum gdb_osabi
|
||||
alphanbsd_core_osabi_sniffer (bfd *abfd)
|
||||
{
|
||||
if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
|
||||
return GDB_OSABI_NETBSD_ELF;
|
||||
|
||||
return GDB_OSABI_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_alphanbsd_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_alphanbsd_tdep (void)
|
||||
{
|
||||
/* BFD doesn't set a flavour for NetBSD style a.out core files. */
|
||||
gdbarch_register_osabi_sniffer (bfd_arch_alpha, bfd_target_unknown_flavour,
|
||||
alphanbsd_core_osabi_sniffer);
|
||||
|
||||
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF,
|
||||
alphanbsd_init_abi);
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
/* Target-dependent code for OpenBSD/alpha.
|
||||
|
||||
Copyright (C) 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "osabi.h"
|
||||
|
||||
#include "obsd-tdep.h"
|
||||
#include "alpha-tdep.h"
|
||||
#include "alphabsd-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
/* Signal trampolines. */
|
||||
|
||||
/* The OpenBSD kernel maps the signal trampoline at some random
|
||||
location in user space, which means that the traditional BSD way of
|
||||
detecting it won't work.
|
||||
|
||||
The signal trampoline will be mapped at an address that is page
|
||||
aligned. We recognize the signal trampoline by looking for the
|
||||
sigreturn system call. */
|
||||
|
||||
static const int alphaobsd_page_size = 8192;
|
||||
|
||||
static LONGEST
|
||||
alphaobsd_sigtramp_offset (CORE_ADDR pc)
|
||||
{
|
||||
return (pc & (alphaobsd_page_size - 1));
|
||||
}
|
||||
|
||||
static int
|
||||
alphaobsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
|
||||
{
|
||||
CORE_ADDR start_pc = (pc & ~(alphaobsd_page_size - 1));
|
||||
unsigned insn;
|
||||
|
||||
if (name)
|
||||
return 0;
|
||||
|
||||
/* Check for "". */
|
||||
insn = alpha_read_insn (start_pc + 5 * ALPHA_INSN_SIZE);
|
||||
if (insn != 0x201f0067)
|
||||
return 0;
|
||||
|
||||
/* Check for "". */
|
||||
insn = alpha_read_insn (start_pc + 6 * ALPHA_INSN_SIZE);
|
||||
if (insn != 0x00000083)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static CORE_ADDR
|
||||
alphaobsd_sigcontext_addr (struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_pc (this_frame);
|
||||
|
||||
if (alphaobsd_sigtramp_offset (pc) < 3 * ALPHA_INSN_SIZE)
|
||||
{
|
||||
/* On entry, a pointer the `struct sigcontext' is passed in %a2. */
|
||||
return get_frame_register_unsigned (this_frame, ALPHA_A0_REGNUM + 2);
|
||||
}
|
||||
else if (alphaobsd_sigtramp_offset (pc) < 4 * ALPHA_INSN_SIZE)
|
||||
{
|
||||
/* It is stored on the stack Before calling the signal handler. */
|
||||
CORE_ADDR sp;
|
||||
sp = get_frame_register_unsigned (this_frame, ALPHA_SP_REGNUM);
|
||||
return get_frame_memory_unsigned (this_frame, sp, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It is reloaded into %a0 for the sigreturn(2) call. */
|
||||
return get_frame_register_unsigned (this_frame, ALPHA_A0_REGNUM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
alphaobsd_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);
|
||||
|
||||
/* OpenBSD/alpha 3.0 and earlier does not provide single step
|
||||
support via ptrace(2); use software single-stepping for now. */
|
||||
set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
|
||||
|
||||
/* OpenBSD/alpha has SVR4-style shared libraries. */
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_lp64_fetch_link_map_offsets);
|
||||
set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
|
||||
|
||||
tdep->dynamic_sigtramp_offset = alphaobsd_sigtramp_offset;
|
||||
tdep->pc_in_sigtramp = alphaobsd_pc_in_sigtramp;
|
||||
tdep->sigcontext_addr = alphaobsd_sigcontext_addr;
|
||||
|
||||
tdep->jb_pc = 2;
|
||||
tdep->jb_elt_size = 8;
|
||||
|
||||
set_gdbarch_regset_from_core_section
|
||||
(gdbarch, alphanbsd_regset_from_core_section);
|
||||
}
|
||||
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_alphaobsd_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_alphaobsd_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OPENBSD_ELF,
|
||||
alphaobsd_init_abi);
|
||||
}
|
||||
@@ -1,437 +0,0 @@
|
||||
/* Native-dependent code for GNU/Linux x86-64.
|
||||
|
||||
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
#include "regcache.h"
|
||||
#include "linux-nat.h"
|
||||
#include "amd64-linux-tdep.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 */
|
||||
-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, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
ORIG_RAX * 8
|
||||
};
|
||||
|
||||
|
||||
/* 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 (struct regcache *regcache, const elf_gregset_t *gregsetp)
|
||||
{
|
||||
amd64_supply_native_gregset (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 (const struct regcache *regcache,
|
||||
elf_gregset_t *gregsetp, int regnum)
|
||||
{
|
||||
amd64_collect_native_gregset (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 (struct regcache *regcache, const elf_fpregset_t *fpregsetp)
|
||||
{
|
||||
amd64_supply_fxsave (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 (const struct regcache *regcache,
|
||||
elf_fpregset_t *fpregsetp, int regnum)
|
||||
{
|
||||
amd64_collect_fxsave (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 (struct regcache *regcache, int regnum)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
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 (gdbarch, 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 (regcache, ®s, -1);
|
||||
if (regnum != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, 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 (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 (struct regcache *regcache, int regnum)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
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 (gdbarch, 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 (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 (gdbarch, 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 (regcache, regnum, &fpregs);
|
||||
|
||||
if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
|
||||
perror_with_name (_("Couldn't write floating point status"));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Support for debug registers. */
|
||||
|
||||
static unsigned long amd64_linux_dr[DR_CONTROL + 1];
|
||||
|
||||
static unsigned long
|
||||
amd64_linux_dr_get (ptid_t ptid, int regnum)
|
||||
{
|
||||
int tid;
|
||||
unsigned long value;
|
||||
|
||||
tid = TIDGET (ptid);
|
||||
if (tid == 0)
|
||||
tid = PIDGET (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 vector. For now, just return zero if the
|
||||
ptrace call fails. */
|
||||
errno = 0;
|
||||
value = ptrace (PTRACE_PEEKUSER, 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 (ptid_t ptid, int regnum, unsigned long value)
|
||||
{
|
||||
int tid;
|
||||
|
||||
tid = TIDGET (ptid);
|
||||
if (tid == 0)
|
||||
tid = PIDGET (ptid);
|
||||
|
||||
errno = 0;
|
||||
ptrace (PTRACE_POKEUSER, 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)
|
||||
{
|
||||
struct lwp_info *lp;
|
||||
ptid_t ptid;
|
||||
|
||||
amd64_linux_dr[DR_CONTROL] = control;
|
||||
ALL_LWPS (lp, ptid)
|
||||
amd64_linux_dr_set (ptid, DR_CONTROL, control);
|
||||
}
|
||||
|
||||
void
|
||||
amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
|
||||
{
|
||||
struct lwp_info *lp;
|
||||
ptid_t ptid;
|
||||
|
||||
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
|
||||
|
||||
amd64_linux_dr[DR_FIRSTADDR + regnum] = addr;
|
||||
ALL_LWPS (lp, ptid)
|
||||
amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
|
||||
}
|
||||
|
||||
void
|
||||
amd64_linux_dr_reset_addr (int regnum)
|
||||
{
|
||||
amd64_linux_dr_set_addr (regnum, 0);
|
||||
}
|
||||
|
||||
unsigned long
|
||||
amd64_linux_dr_get_status (void)
|
||||
{
|
||||
return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
|
||||
}
|
||||
|
||||
static void
|
||||
amd64_linux_new_thread (ptid_t ptid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
|
||||
amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]);
|
||||
|
||||
amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]);
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
amd64_native_gregset64_num_regs = AMD64_LINUX_NUM_REGS;
|
||||
|
||||
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 ();
|
||||
|
||||
i386_use_watchpoints (t);
|
||||
|
||||
/* 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. */
|
||||
linux_nat_add_target (t);
|
||||
linux_nat_set_new_thread (t, amd64_linux_new_thread);
|
||||
}
|
||||
@@ -1,300 +0,0 @@
|
||||
/* Target-dependent code for GNU/Linux x86-64.
|
||||
|
||||
Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "regcache.h"
|
||||
#include "osabi.h"
|
||||
#include "symtab.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "reggroups.h"
|
||||
#include "amd64-linux-tdep.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 *this_frame)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_pc (this_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 (this_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 (this_frame, pc, buf, sizeof buf))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
|
||||
return 0;
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
/* Return whether THIS_FRAME corresponds to a GNU/Linux sigtramp
|
||||
routine. */
|
||||
|
||||
static int
|
||||
amd64_linux_sigtramp_p (struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_pc (this_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 (this_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 THIS_FRAME is a GNU/Linux sigtramp routine, return the
|
||||
address of the associated sigcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64_linux_sigcontext_addr (struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR sp;
|
||||
gdb_byte buf[8];
|
||||
|
||||
get_frame_register (this_frame, AMD64_RSP_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 */
|
||||
};
|
||||
|
||||
/* Replacement register functions which know about %orig_rax. */
|
||||
|
||||
static const char *
|
||||
amd64_linux_register_name (struct gdbarch *gdbarch, int reg)
|
||||
{
|
||||
if (reg == AMD64_LINUX_ORIG_RAX_REGNUM)
|
||||
return "orig_rax";
|
||||
|
||||
return amd64_register_name (gdbarch, reg);
|
||||
}
|
||||
|
||||
static struct type *
|
||||
amd64_linux_register_type (struct gdbarch *gdbarch, int reg)
|
||||
{
|
||||
if (reg == AMD64_LINUX_ORIG_RAX_REGNUM)
|
||||
return builtin_type_int64;
|
||||
|
||||
return amd64_register_type (gdbarch, reg);
|
||||
}
|
||||
|
||||
static int
|
||||
amd64_linux_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
|
||||
struct reggroup *group)
|
||||
{
|
||||
if (regnum == AMD64_LINUX_ORIG_RAX_REGNUM)
|
||||
return (group == system_reggroup
|
||||
|| group == save_reggroup
|
||||
|| group == restore_reggroup);
|
||||
return default_register_reggroup_p (gdbarch, regnum, group);
|
||||
}
|
||||
|
||||
/* Set the program counter for process PTID to PC. */
|
||||
|
||||
static void
|
||||
amd64_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
|
||||
{
|
||||
regcache_cooked_write_unsigned (regcache, AMD64_RIP_REGNUM, pc);
|
||||
|
||||
/* We must be careful with modifying the program counter. If we
|
||||
just interrupted a system call, the kernel might try to restart
|
||||
it when we resume the inferior. On restarting the system call,
|
||||
the kernel will try backing up the program counter even though it
|
||||
no longer points at the system call. This typically results in a
|
||||
SIGSEGV or SIGILL. We can prevent this by writing `-1' in the
|
||||
"orig_rax" pseudo-register.
|
||||
|
||||
Note that "orig_rax" is saved when setting up a dummy call frame.
|
||||
This means that it is properly restored when that frame is
|
||||
popped, and that the interrupted system call will be restarted
|
||||
when we resume the inferior on return from a function call from
|
||||
within GDB. In all other cases the system call will not be
|
||||
restarted. */
|
||||
regcache_cooked_write_unsigned (regcache, AMD64_LINUX_ORIG_RAX_REGNUM, -1);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* Add the %orig_rax register used for syscall restarting. */
|
||||
set_gdbarch_write_pc (gdbarch, amd64_linux_write_pc);
|
||||
set_gdbarch_num_regs (gdbarch, AMD64_LINUX_NUM_REGS);
|
||||
set_gdbarch_register_name (gdbarch, amd64_linux_register_name);
|
||||
set_gdbarch_register_type (gdbarch, amd64_linux_register_type);
|
||||
set_gdbarch_register_reggroup_p (gdbarch, amd64_linux_register_reggroup_p);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* Target-dependent code for GNU/Linux AMD64.
|
||||
|
||||
Copyright (C) 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef AMD64_LINUX_TDEP_H
|
||||
#define AMD64_LINUX_TDEP_H
|
||||
|
||||
/* Like for i386 GNU/Linux, there is an extra "register"
|
||||
used to control syscall restarting. */
|
||||
|
||||
/* Register number for the "orig_rax" register. If this register
|
||||
contains a value >= 0 it is interpreted as the system call number
|
||||
that the kernel is supposed to restart. */
|
||||
#define AMD64_LINUX_ORIG_RAX_REGNUM (AMD64_MXCSR_REGNUM + 1)
|
||||
|
||||
/* Total number of registers for GNU/Linux. */
|
||||
#define AMD64_LINUX_NUM_REGS (AMD64_LINUX_ORIG_RAX_REGNUM + 1)
|
||||
|
||||
#endif /* amd64-linux-tdep.h */
|
||||
161
gdb/amd64-nat.c
161
gdb/amd64-nat.c
@@ -1,161 +0,0 @@
|
||||
/* Native-dependent code for AMD64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 (struct gdbarch *gdbarch, 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 (gdbarch) == 32)
|
||||
{
|
||||
reg_offset = amd64_native_gregset32_reg_offset;
|
||||
num_regs = amd64_native_gregset32_num_regs;
|
||||
}
|
||||
|
||||
if (num_regs > gdbarch_num_regs (gdbarch))
|
||||
num_regs = gdbarch_num_regs (gdbarch);
|
||||
|
||||
if (regnum < num_regs && regnum < gdbarch_num_regs (gdbarch))
|
||||
return reg_offset[regnum];
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return whether the native general-purpose register set supplies
|
||||
register REGNUM. */
|
||||
|
||||
int
|
||||
amd64_native_gregset_supplies_p (struct gdbarch *gdbarch, int regnum)
|
||||
{
|
||||
return (amd64_native_gregset_reg_offset (gdbarch, 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 > gdbarch_num_regs (gdbarch))
|
||||
num_regs = gdbarch_num_regs (gdbarch);
|
||||
|
||||
for (i = 0; i < num_regs; i++)
|
||||
{
|
||||
if (regnum == -1 || regnum == i)
|
||||
{
|
||||
int offset = amd64_native_gregset_reg_offset (gdbarch, 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 (gdbarch, 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 (gdbarch, i), 0, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (num_regs > gdbarch_num_regs (gdbarch))
|
||||
num_regs = gdbarch_num_regs (gdbarch);
|
||||
|
||||
for (i = 0; i < num_regs; i++)
|
||||
{
|
||||
if (regnum == -1 || regnum == i)
|
||||
{
|
||||
int offset = amd64_native_gregset_reg_offset (gdbarch, i);
|
||||
|
||||
if (offset != -1)
|
||||
regcache_raw_collect (regcache, i, regs + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/* Native-dependent code for AMD64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 (struct gdbarch *gdbarch,
|
||||
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,127 +0,0 @@
|
||||
/* Target-dependent code for AMD64 Solaris.
|
||||
|
||||
Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 THIS_FRAME corresponds to a Solaris sigtramp
|
||||
routine. */
|
||||
|
||||
static int
|
||||
amd64_sol2_sigtramp_p (struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_pc (this_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 *this_frame)
|
||||
{
|
||||
CORE_ADDR sp, ucontext_addr;
|
||||
|
||||
sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
|
||||
ucontext_addr = get_frame_memory_unsigned (this_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);
|
||||
}
|
||||
1428
gdb/amd64-tdep.c
1428
gdb/amd64-tdep.c
File diff suppressed because it is too large
Load Diff
105
gdb/amd64-tdep.h
105
gdb/amd64-tdep.h
@@ -1,105 +0,0 @@
|
||||
/* Target-dependent definitions for AMD64.
|
||||
|
||||
Copyright (C) 2001, 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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, /* %r8 */
|
||||
AMD64_R9_REGNUM, /* %r9 */
|
||||
AMD64_R10_REGNUM, /* %r10 */
|
||||
AMD64_R11_REGNUM, /* %r11 */
|
||||
AMD64_R12_REGNUM, /* %r12 */
|
||||
AMD64_R13_REGNUM, /* %r13 */
|
||||
AMD64_R14_REGNUM, /* %r14 */
|
||||
AMD64_R15_REGNUM, /* %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);
|
||||
|
||||
/* Functions from amd64-tdep.c which may be needed on architectures
|
||||
with extra registers. */
|
||||
|
||||
extern const char *amd64_register_name (struct gdbarch *gdbarch, int regnum);
|
||||
extern struct type *amd64_register_type (struct gdbarch *gdbarch, int regnum);
|
||||
|
||||
/* 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,125 +0,0 @@
|
||||
/* Native-dependent code for AMD64 BSD's.
|
||||
|
||||
Copyright (C) 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 (struct regcache *regcache, int regnum)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
|
||||
if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, 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 (regcache, ®s, -1);
|
||||
if (regnum != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, 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 (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 (struct regcache *regcache, int regnum)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
|
||||
if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, 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 (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 (gdbarch, 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 (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,233 +0,0 @@
|
||||
/* Native-dependent code for FreeBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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,221 +0,0 @@
|
||||
/* Target-dependent code for FreeBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 THIS_FRAME is for a BSD sigtramp routine, return the
|
||||
address of the associated sigcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64fbsd_sigcontext_addr (struct frame_info *this_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 (this_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 = 0x7fffffffffc0ULL;
|
||||
CORE_ADDR amd64fbsd_sigtramp_end_addr = 0x7fffffffffe0ULL;
|
||||
|
||||
/* 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,75 +0,0 @@
|
||||
/* Native-dependent code for NetBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "target.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
|
||||
#include "nbsd-nat.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)
|
||||
{
|
||||
struct target_ops *t;
|
||||
|
||||
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;
|
||||
|
||||
/* Add some extra features to the common *BSD/amd64 target. */
|
||||
t = amd64bsd_target ();
|
||||
t->to_pid_to_exec_file = nbsd_pid_to_exec_file;
|
||||
add_target (t);
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
/* Target-dependent code for NetBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 THIS_FRAME corresponds to a NetBSD sigtramp
|
||||
routine. */
|
||||
|
||||
static int
|
||||
amd64nbsd_sigtramp_p (struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_pc (this_frame);
|
||||
char *name;
|
||||
|
||||
find_pc_partial_function (pc, &name, NULL, NULL);
|
||||
return nbsd_pc_in_sigtramp (pc, name);
|
||||
}
|
||||
|
||||
/* Assuming THIS_FRAME corresponds to a NetBSD sigtramp routine,
|
||||
return the address of the associated mcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64nbsd_mcontext_addr (struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
|
||||
/* The register %r15 points at `struct ucontext' upon entry of a
|
||||
signal trampoline. */
|
||||
addr = get_frame_register_unsigned (this_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,145 +0,0 @@
|
||||
/* Native-dependent code for OpenBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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,490 +0,0 @@
|
||||
/* Target-dependent code for OpenBSD/amd64.
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 THIS_FRAME corresponds to an OpenBSD sigtramp
|
||||
routine. */
|
||||
|
||||
static int
|
||||
amd64obsd_sigtramp_p (struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_pc (this_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 (this_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 THIS_FRAME is for a BSD sigtramp routine, return the
|
||||
address of the associated sigcontext structure. */
|
||||
|
||||
static CORE_ADDR
|
||||
amd64obsd_sigcontext_addr (struct frame_info *this_frame)
|
||||
{
|
||||
CORE_ADDR pc = get_frame_pc (this_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 get_frame_register_unsigned (this_frame, AMD64_RDI_REGNUM);
|
||||
else
|
||||
return get_frame_register_unsigned (this_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 *this_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 (this_frame);
|
||||
*this_cache = cache;
|
||||
|
||||
func = get_frame_func (this_frame);
|
||||
sp = get_frame_register_unsigned (this_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 *this_frame,
|
||||
void **this_cache, struct frame_id *this_id)
|
||||
{
|
||||
struct trad_frame_cache *cache =
|
||||
amd64obsd_trapframe_cache (this_frame, this_cache);
|
||||
|
||||
trad_frame_get_id (cache, this_id);
|
||||
}
|
||||
|
||||
static struct value *
|
||||
amd64obsd_trapframe_prev_register (struct frame_info *this_frame,
|
||||
void **this_cache, int regnum)
|
||||
{
|
||||
struct trad_frame_cache *cache =
|
||||
amd64obsd_trapframe_cache (this_frame, this_cache);
|
||||
|
||||
return trad_frame_get_register (cache, this_frame, regnum);
|
||||
}
|
||||
|
||||
static int
|
||||
amd64obsd_trapframe_sniffer (const struct frame_unwind *self,
|
||||
struct frame_info *this_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 = get_frame_register_unsigned (this_frame, AMD64_CS_REGNUM);
|
||||
if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
|
||||
return 0;
|
||||
|
||||
find_pc_partial_function (get_frame_pc (this_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);
|
||||
}
|
||||
575
gdb/annotate.c
575
gdb/annotate.c
@@ -1,575 +0,0 @@
|
||||
/* Annotation routines for GDB.
|
||||
Copyright (C) 1986, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1998, 1999,
|
||||
2000, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "annotate.h"
|
||||
#include "value.h"
|
||||
#include "target.h"
|
||||
#include "gdbtypes.h"
|
||||
#include "breakpoint.h"
|
||||
#include "observer.h"
|
||||
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
|
||||
extern void _initialize_annotate (void);
|
||||
|
||||
static void print_value_flags (struct type *);
|
||||
|
||||
static void breakpoint_changed (int);
|
||||
|
||||
|
||||
void (*deprecated_annotate_signalled_hook) (void);
|
||||
void (*deprecated_annotate_signal_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 (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032starting\n"));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_stopped (void)
|
||||
{
|
||||
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 (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_new_thread (void)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
{
|
||||
printf_unfiltered (("\n\032\032new-thread\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
annotate_thread_changed (void)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
{
|
||||
printf_unfiltered (("\n\032\032thread-changed\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:%s\n"), filename, line, character,
|
||||
mid ? "middle" : "beg", paddress (pc));
|
||||
}
|
||||
|
||||
void
|
||||
annotate_frame_begin (int level, CORE_ADDR pc)
|
||||
{
|
||||
if (annotation_level > 1)
|
||||
printf_filtered (("\n\032\032frame-begin %d %s\n"), level, paddress (pc));
|
||||
}
|
||||
|
||||
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 (int bpno)
|
||||
{
|
||||
breakpoints_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_annotate (void)
|
||||
{
|
||||
if (annotation_level == 2)
|
||||
{
|
||||
observer_attach_breakpoint_deleted (breakpoint_changed);
|
||||
observer_attach_breakpoint_modified (breakpoint_changed);
|
||||
}
|
||||
}
|
||||
103
gdb/annotate.h
103
gdb/annotate.h
@@ -1,103 +0,0 @@
|
||||
/* Annotation routines for GDB.
|
||||
Copyright (C) 1986, 1989, 1990, 1991, 1992, 1994, 1998, 1999, 2000, 2007,
|
||||
2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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);
|
||||
extern void annotate_new_thread (void);
|
||||
extern void annotate_thread_changed (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_signalled_hook) (void);
|
||||
extern void (*deprecated_annotate_signal_hook) (void);
|
||||
737
gdb/arch-utils.c
737
gdb/arch-utils.c
@@ -1,737 +0,0 @@
|
||||
/* Dynamic architecture support for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 "target-descriptions.h"
|
||||
#include "objfiles.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#include "floatformat.h"
|
||||
|
||||
|
||||
struct displaced_step_closure *
|
||||
simple_displaced_step_copy_insn (struct gdbarch *gdbarch,
|
||||
CORE_ADDR from, CORE_ADDR to,
|
||||
struct regcache *regs)
|
||||
{
|
||||
size_t len = gdbarch_max_insn_length (gdbarch);
|
||||
gdb_byte *buf = xmalloc (len);
|
||||
|
||||
read_memory (from, buf, len);
|
||||
write_memory (to, buf, len);
|
||||
|
||||
if (debug_displaced)
|
||||
{
|
||||
fprintf_unfiltered (gdb_stdlog, "displaced: copy 0x%s->0x%s: ",
|
||||
paddr_nz (from), paddr_nz (to));
|
||||
displaced_step_dump_bytes (gdb_stdlog, buf, len);
|
||||
}
|
||||
|
||||
return (struct displaced_step_closure *) buf;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
simple_displaced_step_free_closure (struct gdbarch *gdbarch,
|
||||
struct displaced_step_closure *closure)
|
||||
{
|
||||
xfree (closure);
|
||||
}
|
||||
|
||||
|
||||
CORE_ADDR
|
||||
displaced_step_at_entry_point (struct gdbarch *gdbarch)
|
||||
{
|
||||
CORE_ADDR addr;
|
||||
int bp_len;
|
||||
|
||||
addr = entry_point_address ();
|
||||
|
||||
/* Make certain that the address points at real code, and not a
|
||||
function descriptor. */
|
||||
addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr, ¤t_target);
|
||||
|
||||
/* Inferior calls also use the entry point as a breakpoint location.
|
||||
We don't want displaced stepping to interfere with those
|
||||
breakpoints, so leave space. */
|
||||
gdbarch_breakpoint_from_pc (gdbarch, &addr, &bp_len);
|
||||
addr += bp_len * 2;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
int
|
||||
legacy_register_sim_regno (struct gdbarch *gdbarch, int regnum)
|
||||
{
|
||||
/* Only makes sense to supply raw registers. */
|
||||
gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch));
|
||||
/* 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 (gdbarch_register_name (gdbarch, regnum) != NULL
|
||||
&& gdbarch_register_name (gdbarch, regnum)[0] != '\0')
|
||||
return regnum;
|
||||
else
|
||||
return LEGACY_SIM_REGNO_IGNORE;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
generic_skip_trampoline_code (struct frame_info *frame, 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;
|
||||
}
|
||||
|
||||
/* Helper functions for gdbarch_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);
|
||||
}
|
||||
|
||||
/* Misc helper functions for targets. */
|
||||
|
||||
CORE_ADDR
|
||||
core_addr_identity (struct gdbarch *gdbarch, 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 (struct gdbarch *gdbarch, 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 (struct gdbarch *gdbarch, int regnum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Legacy version of target_virtual_frame_pointer(). Assumes that
|
||||
there is an gdbarch_deprecated_fp_regnum and that it is the same, cooked or
|
||||
raw. */
|
||||
|
||||
void
|
||||
legacy_virtual_frame_pointer (struct gdbarch *gdbarch,
|
||||
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 (gdbarch_deprecated_fp_regnum (gdbarch) >= 0
|
||||
&& gdbarch_deprecated_fp_regnum (gdbarch)
|
||||
< gdbarch_num_regs (gdbarch))
|
||||
*frame_regnum = gdbarch_deprecated_fp_regnum (gdbarch);
|
||||
else if (gdbarch_sp_regnum (gdbarch) >= 0
|
||||
&& gdbarch_sp_regnum (gdbarch)
|
||||
< gdbarch_num_regs (gdbarch))
|
||||
*frame_regnum = gdbarch_sp_regnum (gdbarch);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
generic_convert_register_p (struct gdbarch *gdbarch, int regnum,
|
||||
struct type *type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
default_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
generic_instruction_nullified (struct gdbarch *gdbarch,
|
||||
struct regcache *regcache)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
default_remote_register_number (struct gdbarch *gdbarch,
|
||||
int regno)
|
||||
{
|
||||
return regno;
|
||||
}
|
||||
|
||||
|
||||
/* Functions to manipulate the endianness of the target. */
|
||||
|
||||
static int target_byte_order_user = BFD_ENDIAN_UNKNOWN;
|
||||
|
||||
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;
|
||||
|
||||
enum bfd_endian
|
||||
selected_byte_order (void)
|
||||
{
|
||||
if (target_byte_order_user != BFD_ENDIAN_UNKNOWN)
|
||||
return gdbarch_byte_order (current_gdbarch);
|
||||
else
|
||||
return BFD_ENDIAN_UNKNOWN;
|
||||
}
|
||||
|
||||
/* 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_user == BFD_ENDIAN_UNKNOWN)
|
||||
if (gdbarch_byte_order (current_gdbarch) == 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 (gdbarch_byte_order (current_gdbarch) == 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)
|
||||
{
|
||||
struct gdbarch_info info;
|
||||
|
||||
gdbarch_info_init (&info);
|
||||
|
||||
if (set_endian_string == endian_auto)
|
||||
{
|
||||
target_byte_order_user = BFD_ENDIAN_UNKNOWN;
|
||||
if (! gdbarch_update_p (info))
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("set_endian: architecture update failed"));
|
||||
}
|
||||
else if (set_endian_string == endian_little)
|
||||
{
|
||||
info.byte_order = BFD_ENDIAN_LITTLE;
|
||||
if (! gdbarch_update_p (info))
|
||||
printf_unfiltered (_("Little endian target not supported by GDB\n"));
|
||||
else
|
||||
target_byte_order_user = BFD_ENDIAN_LITTLE;
|
||||
}
|
||||
else if (set_endian_string == endian_big)
|
||||
{
|
||||
info.byte_order = BFD_ENDIAN_BIG;
|
||||
if (! gdbarch_update_p (info))
|
||||
printf_unfiltered (_("Big endian target not supported by GDB\n"));
|
||||
else
|
||||
target_byte_order_user = BFD_ENDIAN_BIG;
|
||||
}
|
||||
else
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("set_endian: bad value"));
|
||||
|
||||
show_endian (gdb_stdout, from_tty, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Given SELECTED, a currently selected BFD architecture, and
|
||||
FROM_TARGET, a BFD architecture reported by the target description,
|
||||
return what architecture to use. Either may be NULL; if both are
|
||||
specified, we use the more specific. If the two are obviously
|
||||
incompatible, warn the user. */
|
||||
|
||||
static const struct bfd_arch_info *
|
||||
choose_architecture_for_target (const struct bfd_arch_info *selected,
|
||||
const struct bfd_arch_info *from_target)
|
||||
{
|
||||
const struct bfd_arch_info *compat1, *compat2;
|
||||
|
||||
if (selected == NULL)
|
||||
return from_target;
|
||||
|
||||
if (from_target == NULL)
|
||||
return selected;
|
||||
|
||||
/* struct bfd_arch_info objects are singletons: that is, there's
|
||||
supposed to be exactly one instance for a given machine. So you
|
||||
can tell whether two are equivalent by comparing pointers. */
|
||||
if (from_target == selected)
|
||||
return selected;
|
||||
|
||||
/* BFD's 'A->compatible (A, B)' functions return zero if A and B are
|
||||
incompatible. But if they are compatible, it returns the 'more
|
||||
featureful' of the two arches. That is, if A can run code
|
||||
written for B, but B can't run code written for A, then it'll
|
||||
return A.
|
||||
|
||||
Some targets (e.g. MIPS as of 2006-12-04) don't fully
|
||||
implement this, instead always returning NULL or the first
|
||||
argument. We detect that case by checking both directions. */
|
||||
|
||||
compat1 = selected->compatible (selected, from_target);
|
||||
compat2 = from_target->compatible (from_target, selected);
|
||||
|
||||
if (compat1 == NULL && compat2 == NULL)
|
||||
{
|
||||
warning (_("Selected architecture %s is not compatible "
|
||||
"with reported target architecture %s"),
|
||||
selected->printable_name, from_target->printable_name);
|
||||
return selected;
|
||||
}
|
||||
|
||||
if (compat1 == NULL)
|
||||
return compat2;
|
||||
if (compat2 == NULL)
|
||||
return compat1;
|
||||
if (compat1 == compat2)
|
||||
return compat1;
|
||||
|
||||
/* If the two didn't match, but one of them was a default architecture,
|
||||
assume the more specific one is correct. This handles the case
|
||||
where an executable or target description just says "mips", but
|
||||
the other knows which MIPS variant. */
|
||||
if (compat1->the_default)
|
||||
return compat2;
|
||||
if (compat2->the_default)
|
||||
return compat1;
|
||||
|
||||
/* We have no idea which one is better. This is a bug, but not
|
||||
a critical problem; warn the user. */
|
||||
warning (_("Selected architecture %s is ambiguous with "
|
||||
"reported target architecture %s"),
|
||||
selected->printable_name, from_target->printable_name);
|
||||
return selected;
|
||||
}
|
||||
|
||||
/* Functions to manipulate the architecture of the target */
|
||||
|
||||
enum set_arch { set_arch_auto, set_arch_manual };
|
||||
|
||||
static const struct bfd_arch_info *target_architecture_user;
|
||||
|
||||
static const char *set_architecture_string;
|
||||
|
||||
const char *
|
||||
selected_architecture_name (void)
|
||||
{
|
||||
if (target_architecture_user == NULL)
|
||||
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 = gdbarch_bfd_arch_info (current_gdbarch)->printable_name;
|
||||
if (target_architecture_user == NULL)
|
||||
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)
|
||||
{
|
||||
struct gdbarch_info info;
|
||||
|
||||
gdbarch_info_init (&info);
|
||||
|
||||
if (strcmp (set_architecture_string, "auto") == 0)
|
||||
{
|
||||
target_architecture_user = NULL;
|
||||
if (!gdbarch_update_p (info))
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("could not select an architecture automatically"));
|
||||
}
|
||||
else
|
||||
{
|
||||
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_user = info.bfd_arch_info;
|
||||
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;
|
||||
|
||||
/* Check for the current file. */
|
||||
if (info.abfd == NULL)
|
||||
info.abfd = exec_bfd;
|
||||
if (info.abfd == NULL)
|
||||
info.abfd = core_bfd;
|
||||
|
||||
/* Check for the current target description. */
|
||||
if (info.target_desc == NULL)
|
||||
info.target_desc = target_current_description ();
|
||||
|
||||
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 == target_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_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_info info;
|
||||
struct gdbarch *gdbarch;
|
||||
|
||||
gdbarch_info_init (&info);
|
||||
info.abfd = abfd;
|
||||
info.target_desc = target_current_description ();
|
||||
gdbarch = gdbarch_find_by_info (info);
|
||||
|
||||
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
|
||||
|
||||
static int default_byte_order = BFD_ENDIAN_UNKNOWN;
|
||||
|
||||
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 (default_bfd_arch == 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"));
|
||||
default_bfd_arch = bfd_scan_arch (chosen);
|
||||
if (default_bfd_arch == NULL)
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("initialize_current_architecture: Arch not found"));
|
||||
}
|
||||
|
||||
info.bfd_arch_info = default_bfd_arch;
|
||||
|
||||
/* Take several guesses at a byte order. */
|
||||
if (default_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:
|
||||
default_byte_order = BFD_ENDIAN_BIG;
|
||||
break;
|
||||
case BFD_ENDIAN_LITTLE:
|
||||
default_byte_order = BFD_ENDIAN_LITTLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (default_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)
|
||||
default_byte_order = BFD_ENDIAN_LITTLE;
|
||||
}
|
||||
if (default_byte_order == BFD_ENDIAN_UNKNOWN)
|
||||
{
|
||||
/* Wire it to big-endian!!! */
|
||||
default_byte_order = BFD_ENDIAN_BIG;
|
||||
}
|
||||
|
||||
info.byte_order = default_byte_order;
|
||||
info.byte_order_for_code = info.byte_order;
|
||||
|
||||
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->byte_order_for_code = info->byte_order;
|
||||
info->osabi = GDB_OSABI_UNINITIALIZED;
|
||||
}
|
||||
|
||||
/* Similar to init, but this time fill in the blanks. Information is
|
||||
obtained from the global "set ..." options and explicitly
|
||||
initialized INFO fields. */
|
||||
|
||||
void
|
||||
gdbarch_info_fill (struct gdbarch_info *info)
|
||||
{
|
||||
/* "(gdb) set architecture ...". */
|
||||
if (info->bfd_arch_info == NULL
|
||||
&& target_architecture_user)
|
||||
info->bfd_arch_info = target_architecture_user;
|
||||
/* From the file. */
|
||||
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);
|
||||
/* From the target. */
|
||||
if (info->target_desc != NULL)
|
||||
info->bfd_arch_info = choose_architecture_for_target
|
||||
(info->bfd_arch_info, tdesc_architecture (info->target_desc));
|
||||
/* From the default. */
|
||||
if (info->bfd_arch_info == NULL)
|
||||
info->bfd_arch_info = default_bfd_arch;
|
||||
|
||||
/* "(gdb) set byte-order ...". */
|
||||
if (info->byte_order == BFD_ENDIAN_UNKNOWN
|
||||
&& target_byte_order_user != BFD_ENDIAN_UNKNOWN)
|
||||
info->byte_order = target_byte_order_user;
|
||||
/* 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 default. */
|
||||
if (info->byte_order == BFD_ENDIAN_UNKNOWN)
|
||||
info->byte_order = default_byte_order;
|
||||
info->byte_order_for_code = info->byte_order;
|
||||
|
||||
/* "(gdb) set osabi ...". Handled by gdbarch_lookup_osabi. */
|
||||
if (info->osabi == GDB_OSABI_UNINITIALIZED)
|
||||
info->osabi = gdbarch_lookup_osabi (info->abfd);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
142
gdb/arch-utils.h
142
gdb/arch-utils.h
@@ -1,142 +0,0 @@
|
||||
/* Dynamic architecture support for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 gdbarch_displaced_step_copy_insn for
|
||||
processors that don't need to modify the instruction before
|
||||
single-stepping the displaced copy.
|
||||
|
||||
Simply copy gdbarch_max_insn_length (ARCH) bytes from FROM to TO.
|
||||
The closure is an array of that many bytes containing the
|
||||
instruction's bytes, allocated with xmalloc. */
|
||||
extern struct displaced_step_closure *
|
||||
simple_displaced_step_copy_insn (struct gdbarch *gdbarch,
|
||||
CORE_ADDR from, CORE_ADDR to,
|
||||
struct regcache *regs);
|
||||
|
||||
/* Simple implementation of gdbarch_displaced_step_free_closure: Call
|
||||
xfree.
|
||||
This is appropriate for use with simple_displaced_step_copy_insn. */
|
||||
extern void
|
||||
simple_displaced_step_free_closure (struct gdbarch *gdbarch,
|
||||
struct displaced_step_closure *closure);
|
||||
|
||||
/* Possible value for gdbarch_displaced_step_location:
|
||||
Place displaced instructions at the program's entry point,
|
||||
leaving space for inferior function call return breakpoints. */
|
||||
extern CORE_ADDR displaced_step_at_entry_point (struct gdbarch *gdbarch);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Identity functions on a CORE_ADDR. Just return the "addr". */
|
||||
|
||||
extern CORE_ADDR core_addr_identity (struct gdbarch *gdbarch, 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 (struct gdbarch *gdbarch, 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 (struct gdbarch *gdbarch, int regnum);
|
||||
|
||||
/* Legacy version of target_virtual_frame_pointer(). Assumes that
|
||||
there is an gdbarch_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 (struct frame_info *frame,
|
||||
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);
|
||||
|
||||
/* By default, registers are not convertible. */
|
||||
extern int generic_convert_register_p (struct gdbarch *gdbarch, 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);
|
||||
|
||||
int default_remote_register_number (struct gdbarch *gdbarch,
|
||||
int regno);
|
||||
|
||||
/* 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 (struct gdbarch *gdbarch, 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);
|
||||
|
||||
/* Similar to init, but this time fill in the blanks. Information is
|
||||
obtained from the global "set ..." options and explicitly
|
||||
initialized INFO fields. */
|
||||
extern void gdbarch_info_fill (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,618 +0,0 @@
|
||||
/* GNU/Linux on ARM native support.
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
#include "gdb_string.h"
|
||||
#include "regcache.h"
|
||||
#include "target.h"
|
||||
#include "linux-nat.h"
|
||||
#include "target-descriptions.h"
|
||||
|
||||
#include "arm-tdep.h"
|
||||
#include "arm-linux-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"
|
||||
|
||||
/* Defines ps_err_e, struct ps_prochandle. */
|
||||
#include "gdb_proc_service.h"
|
||||
|
||||
#include "features/arm-with-iwmmxt.c"
|
||||
|
||||
#ifndef PTRACE_GET_THREAD_AREA
|
||||
#define PTRACE_GET_THREAD_AREA 22
|
||||
#endif
|
||||
|
||||
#ifndef PTRACE_GETWMMXREGS
|
||||
#define PTRACE_GETWMMXREGS 18
|
||||
#define PTRACE_SETWMMXREGS 19
|
||||
#endif
|
||||
|
||||
/* A flag for whether the WMMX registers are available. */
|
||||
static int arm_linux_has_wmmx_registers;
|
||||
|
||||
extern int arm_apcs_32;
|
||||
|
||||
/* 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)
|
||||
|
||||
/* Get the value of a particular register from the floating point
|
||||
state of the process and store it into regcache. */
|
||||
|
||||
static void
|
||||
fetch_fpregister (struct regcache *regcache, int regno)
|
||||
{
|
||||
int ret, tid;
|
||||
gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
|
||||
|
||||
/* 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 (regcache, ARM_FPS_REGNUM,
|
||||
fp + NWFPE_FPSR_OFFSET);
|
||||
|
||||
/* Fetch the floating point register. */
|
||||
if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
|
||||
supply_nwfpe_register (regcache, regno, fp);
|
||||
}
|
||||
|
||||
/* Get the whole floating point state of the process and store it
|
||||
into regcache. */
|
||||
|
||||
static void
|
||||
fetch_fpregs (struct regcache *regcache)
|
||||
{
|
||||
int ret, regno, tid;
|
||||
gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
|
||||
|
||||
/* 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 (regcache, ARM_FPS_REGNUM,
|
||||
fp + NWFPE_FPSR_OFFSET);
|
||||
|
||||
/* Fetch the floating point registers. */
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
supply_nwfpe_register (regcache, regno, fp);
|
||||
}
|
||||
|
||||
/* Save a particular register into the floating point state of the
|
||||
process using the contents from regcache. */
|
||||
|
||||
static void
|
||||
store_fpregister (const struct regcache *regcache, int regno)
|
||||
{
|
||||
int ret, tid;
|
||||
gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
|
||||
|
||||
/* 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 && regcache_valid_p (regcache, ARM_FPS_REGNUM))
|
||||
regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
|
||||
|
||||
/* Store the floating point register. */
|
||||
if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
|
||||
collect_nwfpe_register (regcache, 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 (const struct regcache *regcache)
|
||||
{
|
||||
int ret, regno, tid;
|
||||
gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
|
||||
|
||||
/* 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 (regcache_valid_p (regcache, ARM_FPS_REGNUM))
|
||||
regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
|
||||
|
||||
/* Store the floating point registers. */
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
if (regcache_valid_p (regcache, regno))
|
||||
collect_nwfpe_register (regcache, 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 (struct regcache *regcache, 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 (regcache, regno, (char *) ®s[regno]);
|
||||
|
||||
if (ARM_PS_REGNUM == regno)
|
||||
{
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
(char *) ®s[ARM_CPSR_REGNUM]);
|
||||
else
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
(char *) ®s[ARM_PC_REGNUM]);
|
||||
}
|
||||
|
||||
if (ARM_PC_REGNUM == regno)
|
||||
{
|
||||
regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
|
||||
(get_regcache_arch (regcache),
|
||||
regs[ARM_PC_REGNUM]);
|
||||
regcache_raw_supply (regcache, ARM_PC_REGNUM,
|
||||
(char *) ®s[ARM_PC_REGNUM]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch all general registers of the process and store into
|
||||
regcache. */
|
||||
|
||||
static void
|
||||
fetch_regs (struct regcache *regcache)
|
||||
{
|
||||
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 (regcache, regno, (char *) ®s[regno]);
|
||||
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
(char *) ®s[ARM_CPSR_REGNUM]);
|
||||
else
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
(char *) ®s[ARM_PC_REGNUM]);
|
||||
|
||||
regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
|
||||
(get_regcache_arch (regcache), regs[ARM_PC_REGNUM]);
|
||||
regcache_raw_supply (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 (const struct regcache *regcache, int regno)
|
||||
{
|
||||
int ret, tid;
|
||||
elf_gregset_t regs;
|
||||
|
||||
if (!regcache_valid_p (regcache, 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 (regcache, regno, (char *) ®s[regno]);
|
||||
else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
|
||||
regcache_raw_collect (regcache, regno,
|
||||
(char *) ®s[ARM_CPSR_REGNUM]);
|
||||
else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
|
||||
regcache_raw_collect (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 (const struct regcache *regcache)
|
||||
{
|
||||
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 (regcache_valid_p (regcache, regno))
|
||||
regcache_raw_collect (regcache, regno, (char *) ®s[regno]);
|
||||
}
|
||||
|
||||
if (arm_apcs_32 && regcache_valid_p (regcache, ARM_PS_REGNUM))
|
||||
regcache_raw_collect (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 all WMMX registers of the process and store into
|
||||
regcache. */
|
||||
|
||||
#define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4)
|
||||
|
||||
static void
|
||||
fetch_wmmx_regs (struct regcache *regcache)
|
||||
{
|
||||
char regbuf[IWMMXT_REGS_SIZE];
|
||||
int ret, regno, tid;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch WMMX registers."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (regno = 0; regno < 16; regno++)
|
||||
regcache_raw_supply (regcache, regno + ARM_WR0_REGNUM,
|
||||
®buf[regno * 8]);
|
||||
|
||||
for (regno = 0; regno < 2; regno++)
|
||||
regcache_raw_supply (regcache, regno + ARM_WCSSF_REGNUM,
|
||||
®buf[16 * 8 + regno * 4]);
|
||||
|
||||
for (regno = 0; regno < 4; regno++)
|
||||
regcache_raw_supply (regcache, regno + ARM_WCGR0_REGNUM,
|
||||
®buf[16 * 8 + 2 * 4 + regno * 4]);
|
||||
}
|
||||
|
||||
static void
|
||||
store_wmmx_regs (const struct regcache *regcache)
|
||||
{
|
||||
char regbuf[IWMMXT_REGS_SIZE];
|
||||
int ret, regno, tid;
|
||||
|
||||
/* Get the thread id for the ptrace call. */
|
||||
tid = GET_THREAD_ID (inferior_ptid);
|
||||
|
||||
ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to fetch WMMX registers."));
|
||||
return;
|
||||
}
|
||||
|
||||
for (regno = 0; regno < 16; regno++)
|
||||
if (regcache_valid_p (regcache, regno + ARM_WR0_REGNUM))
|
||||
regcache_raw_collect (regcache, regno + ARM_WR0_REGNUM,
|
||||
®buf[regno * 8]);
|
||||
|
||||
for (regno = 0; regno < 2; regno++)
|
||||
if (regcache_valid_p (regcache, regno + ARM_WCSSF_REGNUM))
|
||||
regcache_raw_collect (regcache, regno + ARM_WCSSF_REGNUM,
|
||||
®buf[16 * 8 + regno * 4]);
|
||||
|
||||
for (regno = 0; regno < 4; regno++)
|
||||
if (regcache_valid_p (regcache, regno + ARM_WCGR0_REGNUM))
|
||||
regcache_raw_collect (regcache, regno + ARM_WCGR0_REGNUM,
|
||||
®buf[16 * 8 + 2 * 4 + regno * 4]);
|
||||
|
||||
ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
warning (_("Unable to store WMMX 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 (struct regcache *regcache, int regno)
|
||||
{
|
||||
if (-1 == regno)
|
||||
{
|
||||
fetch_regs (regcache);
|
||||
fetch_fpregs (regcache);
|
||||
if (arm_linux_has_wmmx_registers)
|
||||
fetch_wmmx_regs (regcache);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
|
||||
fetch_register (regcache, regno);
|
||||
else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
|
||||
fetch_fpregister (regcache, regno);
|
||||
else if (arm_linux_has_wmmx_registers
|
||||
&& regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
|
||||
fetch_wmmx_regs (regcache);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (struct regcache *regcache, int regno)
|
||||
{
|
||||
if (-1 == regno)
|
||||
{
|
||||
store_regs (regcache);
|
||||
store_fpregs (regcache);
|
||||
if (arm_linux_has_wmmx_registers)
|
||||
store_wmmx_regs (regcache);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
|
||||
store_register (regcache, regno);
|
||||
else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
|
||||
store_fpregister (regcache, regno);
|
||||
else if (arm_linux_has_wmmx_registers
|
||||
&& regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
|
||||
store_wmmx_regs (regcache);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wrapper functions for the standard regset handling, used by
|
||||
thread debugging. */
|
||||
|
||||
void
|
||||
fill_gregset (const struct regcache *regcache,
|
||||
gdb_gregset_t *gregsetp, int regno)
|
||||
{
|
||||
arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
|
||||
}
|
||||
|
||||
void
|
||||
supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
|
||||
{
|
||||
arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
|
||||
}
|
||||
|
||||
void
|
||||
fill_fpregset (const struct regcache *regcache,
|
||||
gdb_fpregset_t *fpregsetp, int regno)
|
||||
{
|
||||
arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
|
||||
}
|
||||
|
||||
/* Fill GDB's register array with the floating-point register values
|
||||
in *fpregsetp. */
|
||||
|
||||
void
|
||||
supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
|
||||
{
|
||||
arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
|
||||
}
|
||||
|
||||
/* Fetch the thread-local storage pointer for libthread_db. */
|
||||
|
||||
ps_err_e
|
||||
ps_get_thread_area (const struct ps_prochandle *ph,
|
||||
lwpid_t lwpid, int idx, void **base)
|
||||
{
|
||||
if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
|
||||
return PS_ERR;
|
||||
|
||||
/* IDX is the bias from the thread pointer to the beginning of the
|
||||
thread descriptor. It has to be subtracted due to implementation
|
||||
quirks in libthread_db. */
|
||||
*base = (void *) ((char *)*base - idx);
|
||||
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static const struct target_desc *
|
||||
arm_linux_read_description (struct target_ops *ops)
|
||||
{
|
||||
int ret;
|
||||
char regbuf[IWMMXT_REGS_SIZE];
|
||||
|
||||
ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid),
|
||||
0, regbuf);
|
||||
if (ret < 0)
|
||||
arm_linux_has_wmmx_registers = 0;
|
||||
else
|
||||
arm_linux_has_wmmx_registers = 1;
|
||||
|
||||
if (arm_linux_has_wmmx_registers)
|
||||
return tdesc_arm_with_iwmmxt;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
t->to_read_description = arm_linux_read_description;
|
||||
|
||||
/* Register the target. */
|
||||
linux_nat_add_target (t);
|
||||
|
||||
/* Initialize the standard target descriptions. */
|
||||
initialize_tdesc_arm_with_iwmmxt ();
|
||||
}
|
||||
@@ -1,657 +0,0 @@
|
||||
/* GNU/Linux on ARM target support.
|
||||
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 "regset.h"
|
||||
#include "trad-frame.h"
|
||||
#include "tramp-frame.h"
|
||||
#include "breakpoint.h"
|
||||
|
||||
#include "arm-tdep.h"
|
||||
#include "arm-linux-tdep.h"
|
||||
#include "glibc-tdep.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
extern int arm_apcs_32;
|
||||
|
||||
/* 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
|
||||
|
||||
/*
|
||||
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, the syscall number is not in the SWI instruction
|
||||
(instead it is loaded into r7). We 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 *this_frame,
|
||||
struct trad_frame_cache *this_cache,
|
||||
CORE_ADDR func, int regs_offset)
|
||||
{
|
||||
CORE_ADDR sp = get_frame_register_unsigned (this_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));
|
||||
}
|
||||
|
||||
/* There are a couple of different possible stack layouts that
|
||||
we need to support.
|
||||
|
||||
Before version 2.6.18, the kernel used completely independent
|
||||
layouts for non-RT and RT signals. For non-RT signals the stack
|
||||
began directly with a struct sigcontext. For RT signals the stack
|
||||
began with two redundant pointers (to the siginfo and ucontext),
|
||||
and then the siginfo and ucontext.
|
||||
|
||||
As of version 2.6.18, the non-RT signal frame layout starts with
|
||||
a ucontext and the RT signal frame starts with a siginfo and then
|
||||
a ucontext. Also, the ucontext now has a designated save area
|
||||
for coprocessor registers.
|
||||
|
||||
For RT signals, it's easy to tell the difference: we look for
|
||||
pinfo, the pointer to the siginfo. If it has the expected
|
||||
value, we have an old layout. If it doesn't, we have the new
|
||||
layout.
|
||||
|
||||
For non-RT signals, it's a bit harder. We need something in one
|
||||
layout or the other with a recognizable offset and value. We can't
|
||||
use the return trampoline, because ARM usually uses SA_RESTORER,
|
||||
in which case the stack return trampoline is not filled in.
|
||||
We can't use the saved stack pointer, because sigaltstack might
|
||||
be in use. So for now we guess the new layout... */
|
||||
|
||||
/* There are three words (trap_no, error_code, oldmask) in
|
||||
struct sigcontext before r0. */
|
||||
#define ARM_SIGCONTEXT_R0 0xc
|
||||
|
||||
/* There are five words (uc_flags, uc_link, and three for uc_stack)
|
||||
in the ucontext_t before the sigcontext. */
|
||||
#define ARM_UCONTEXT_SIGCONTEXT 0x14
|
||||
|
||||
/* There are three elements in an rt_sigframe before the ucontext:
|
||||
pinfo, puc, and info. The first two are pointers and the third
|
||||
is a struct siginfo, with size 128 bytes. We could follow puc
|
||||
to the ucontext, but it's simpler to skip the whole thing. */
|
||||
#define ARM_OLD_RT_SIGFRAME_SIGINFO 0x8
|
||||
#define ARM_OLD_RT_SIGFRAME_UCONTEXT 0x88
|
||||
|
||||
#define ARM_NEW_RT_SIGFRAME_UCONTEXT 0x80
|
||||
|
||||
#define ARM_NEW_SIGFRAME_MAGIC 0x5ac3c35a
|
||||
|
||||
static void
|
||||
arm_linux_sigreturn_init (const struct tramp_frame *self,
|
||||
struct frame_info *this_frame,
|
||||
struct trad_frame_cache *this_cache,
|
||||
CORE_ADDR func)
|
||||
{
|
||||
CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
|
||||
ULONGEST uc_flags = read_memory_unsigned_integer (sp, 4);
|
||||
|
||||
if (uc_flags == ARM_NEW_SIGFRAME_MAGIC)
|
||||
arm_linux_sigtramp_cache (this_frame, this_cache, func,
|
||||
ARM_UCONTEXT_SIGCONTEXT
|
||||
+ ARM_SIGCONTEXT_R0);
|
||||
else
|
||||
arm_linux_sigtramp_cache (this_frame, this_cache, func,
|
||||
ARM_SIGCONTEXT_R0);
|
||||
}
|
||||
|
||||
static void
|
||||
arm_linux_rt_sigreturn_init (const struct tramp_frame *self,
|
||||
struct frame_info *this_frame,
|
||||
struct trad_frame_cache *this_cache,
|
||||
CORE_ADDR func)
|
||||
{
|
||||
CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
|
||||
ULONGEST pinfo = read_memory_unsigned_integer (sp, 4);
|
||||
|
||||
if (pinfo == sp + ARM_OLD_RT_SIGFRAME_SIGINFO)
|
||||
arm_linux_sigtramp_cache (this_frame, this_cache, func,
|
||||
ARM_OLD_RT_SIGFRAME_UCONTEXT
|
||||
+ ARM_UCONTEXT_SIGCONTEXT
|
||||
+ ARM_SIGCONTEXT_R0);
|
||||
else
|
||||
arm_linux_sigtramp_cache (this_frame, this_cache, func,
|
||||
ARM_NEW_RT_SIGFRAME_UCONTEXT
|
||||
+ ARM_UCONTEXT_SIGCONTEXT
|
||||
+ ARM_SIGCONTEXT_R0);
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/* Core file and register set support. */
|
||||
|
||||
#define ARM_LINUX_SIZEOF_GREGSET (18 * INT_REGISTER_SIZE)
|
||||
|
||||
void
|
||||
arm_linux_supply_gregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *gregs_buf, size_t len)
|
||||
{
|
||||
const gdb_byte *gregs = gregs_buf;
|
||||
int regno;
|
||||
CORE_ADDR reg_pc;
|
||||
gdb_byte pc_buf[INT_REGISTER_SIZE];
|
||||
|
||||
for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
|
||||
if (regnum == -1 || regnum == regno)
|
||||
regcache_raw_supply (regcache, regno,
|
||||
gregs + INT_REGISTER_SIZE * regno);
|
||||
|
||||
if (regnum == ARM_PS_REGNUM || regnum == -1)
|
||||
{
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
gregs + INT_REGISTER_SIZE * ARM_CPSR_REGNUM);
|
||||
else
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
|
||||
}
|
||||
|
||||
if (regnum == ARM_PC_REGNUM || regnum == -1)
|
||||
{
|
||||
reg_pc = extract_unsigned_integer (gregs
|
||||
+ INT_REGISTER_SIZE * ARM_PC_REGNUM,
|
||||
INT_REGISTER_SIZE);
|
||||
reg_pc = gdbarch_addr_bits_remove (get_regcache_arch (regcache), reg_pc);
|
||||
store_unsigned_integer (pc_buf, INT_REGISTER_SIZE, reg_pc);
|
||||
regcache_raw_supply (regcache, ARM_PC_REGNUM, pc_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
arm_linux_collect_gregset (const struct regset *regset,
|
||||
const struct regcache *regcache,
|
||||
int regnum, void *gregs_buf, size_t len)
|
||||
{
|
||||
gdb_byte *gregs = gregs_buf;
|
||||
int regno;
|
||||
|
||||
for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
|
||||
if (regnum == -1 || regnum == regno)
|
||||
regcache_raw_collect (regcache, regno,
|
||||
gregs + INT_REGISTER_SIZE * regno);
|
||||
|
||||
if (regnum == ARM_PS_REGNUM || regnum == -1)
|
||||
{
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_collect (regcache, ARM_PS_REGNUM,
|
||||
gregs + INT_REGISTER_SIZE * ARM_CPSR_REGNUM);
|
||||
else
|
||||
regcache_raw_collect (regcache, ARM_PS_REGNUM,
|
||||
gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
|
||||
}
|
||||
|
||||
if (regnum == ARM_PC_REGNUM || regnum == -1)
|
||||
regcache_raw_collect (regcache, ARM_PC_REGNUM,
|
||||
gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
|
||||
}
|
||||
|
||||
/* Support for register format used by the NWFPE FPA emulator. */
|
||||
|
||||
#define typeNone 0x00
|
||||
#define typeSingle 0x01
|
||||
#define typeDouble 0x02
|
||||
#define typeExtended 0x03
|
||||
|
||||
void
|
||||
supply_nwfpe_register (struct regcache *regcache, int regno,
|
||||
const gdb_byte *regs)
|
||||
{
|
||||
const gdb_byte *reg_data;
|
||||
gdb_byte reg_tag;
|
||||
gdb_byte buf[FP_REGISTER_SIZE];
|
||||
|
||||
reg_data = regs + (regno - ARM_F0_REGNUM) * FP_REGISTER_SIZE;
|
||||
reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET];
|
||||
memset (buf, 0, FP_REGISTER_SIZE);
|
||||
|
||||
switch (reg_tag)
|
||||
{
|
||||
case typeSingle:
|
||||
memcpy (buf, reg_data, 4);
|
||||
break;
|
||||
case typeDouble:
|
||||
memcpy (buf, reg_data + 4, 4);
|
||||
memcpy (buf + 4, reg_data, 4);
|
||||
break;
|
||||
case typeExtended:
|
||||
/* We want sign and exponent, then least significant bits,
|
||||
then most significant. NWFPE does sign, most, least. */
|
||||
memcpy (buf, reg_data, 4);
|
||||
memcpy (buf + 4, reg_data + 8, 4);
|
||||
memcpy (buf + 8, reg_data + 4, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
regcache_raw_supply (regcache, regno, buf);
|
||||
}
|
||||
|
||||
void
|
||||
collect_nwfpe_register (const struct regcache *regcache, int regno,
|
||||
gdb_byte *regs)
|
||||
{
|
||||
gdb_byte *reg_data;
|
||||
gdb_byte reg_tag;
|
||||
gdb_byte buf[FP_REGISTER_SIZE];
|
||||
|
||||
regcache_raw_collect (regcache, regno, buf);
|
||||
|
||||
/* NOTE drow/2006-06-07: This code uses the tag already in the
|
||||
register buffer. I've preserved that when moving the code
|
||||
from the native file to the target file. But this doesn't
|
||||
always make sense. */
|
||||
|
||||
reg_data = regs + (regno - ARM_F0_REGNUM) * FP_REGISTER_SIZE;
|
||||
reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET];
|
||||
|
||||
switch (reg_tag)
|
||||
{
|
||||
case typeSingle:
|
||||
memcpy (reg_data, buf, 4);
|
||||
break;
|
||||
case typeDouble:
|
||||
memcpy (reg_data, buf + 4, 4);
|
||||
memcpy (reg_data + 4, buf, 4);
|
||||
break;
|
||||
case typeExtended:
|
||||
memcpy (reg_data, buf, 4);
|
||||
memcpy (reg_data + 4, buf + 8, 4);
|
||||
memcpy (reg_data + 8, buf + 4, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
arm_linux_supply_nwfpe (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *regs_buf, size_t len)
|
||||
{
|
||||
const gdb_byte *regs = regs_buf;
|
||||
int regno;
|
||||
|
||||
if (regnum == ARM_FPS_REGNUM || regnum == -1)
|
||||
regcache_raw_supply (regcache, ARM_FPS_REGNUM,
|
||||
regs + NWFPE_FPSR_OFFSET);
|
||||
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
if (regnum == -1 || regnum == regno)
|
||||
supply_nwfpe_register (regcache, regno, regs);
|
||||
}
|
||||
|
||||
void
|
||||
arm_linux_collect_nwfpe (const struct regset *regset,
|
||||
const struct regcache *regcache,
|
||||
int regnum, void *regs_buf, size_t len)
|
||||
{
|
||||
gdb_byte *regs = regs_buf;
|
||||
int regno;
|
||||
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
if (regnum == -1 || regnum == regno)
|
||||
collect_nwfpe_register (regcache, regno, regs);
|
||||
|
||||
if (regnum == ARM_FPS_REGNUM || regnum == -1)
|
||||
regcache_raw_collect (regcache, ARM_FPS_REGNUM,
|
||||
regs + INT_REGISTER_SIZE * ARM_FPS_REGNUM);
|
||||
}
|
||||
|
||||
/* Return the appropriate register set for the core section identified
|
||||
by SECT_NAME and SECT_SIZE. */
|
||||
|
||||
static const struct regset *
|
||||
arm_linux_regset_from_core_section (struct gdbarch *gdbarch,
|
||||
const char *sect_name, size_t sect_size)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
if (strcmp (sect_name, ".reg") == 0
|
||||
&& sect_size == ARM_LINUX_SIZEOF_GREGSET)
|
||||
{
|
||||
if (tdep->gregset == NULL)
|
||||
tdep->gregset = regset_alloc (gdbarch, arm_linux_supply_gregset,
|
||||
arm_linux_collect_gregset);
|
||||
return tdep->gregset;
|
||||
}
|
||||
|
||||
if (strcmp (sect_name, ".reg2") == 0
|
||||
&& sect_size == ARM_LINUX_SIZEOF_NWFPE)
|
||||
{
|
||||
if (tdep->fpregset == NULL)
|
||||
tdep->fpregset = regset_alloc (gdbarch, arm_linux_supply_nwfpe,
|
||||
arm_linux_collect_nwfpe);
|
||||
return tdep->fpregset;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Insert a single step breakpoint at the next executed instruction. */
|
||||
|
||||
int
|
||||
arm_linux_software_single_step (struct frame_info *frame)
|
||||
{
|
||||
CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
|
||||
|
||||
/* The Linux kernel offers some user-mode helpers in a high page. We can
|
||||
not read this page (as of 2.6.23), and even if we could then we couldn't
|
||||
set breakpoints in it, and even if we could then the atomic operations
|
||||
would fail when interrupted. They are all called as functions and return
|
||||
to the address in LR, so step to there instead. */
|
||||
if (next_pc > 0xffff0000)
|
||||
next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
|
||||
|
||||
insert_single_step_breakpoint (next_pc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* Single stepping. */
|
||||
set_gdbarch_software_single_step (gdbarch, arm_linux_software_single_step);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Core file support. */
|
||||
set_gdbarch_regset_from_core_section (gdbarch,
|
||||
arm_linux_regset_from_core_section);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_arm_linux_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_LINUX,
|
||||
arm_linux_init_abi);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/* GNU/Linux on ARM target support, prototypes.
|
||||
|
||||
Copyright (C) 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
struct regset;
|
||||
struct regcache;
|
||||
|
||||
#define ARM_LINUX_SIZEOF_NWFPE (8 * FP_REGISTER_SIZE \
|
||||
+ 2 * INT_REGISTER_SIZE \
|
||||
+ 8 + INT_REGISTER_SIZE)
|
||||
|
||||
/* Support for register format used by the NWFPE FPA emulator. Each
|
||||
register takes three words, where either the first one, two, or
|
||||
three hold a single, double, or extended precision value (depending
|
||||
on the corresponding tag). The register set is eight registers,
|
||||
followed by the fpsr and fpcr, followed by eight tag bytes, and a
|
||||
final word flag which indicates whether NWFPE has been
|
||||
initialized. */
|
||||
|
||||
#define NWFPE_FPSR_OFFSET (8 * FP_REGISTER_SIZE)
|
||||
#define NWFPE_FPCR_OFFSET (NWFPE_FPSR_OFFSET + INT_REGISTER_SIZE)
|
||||
#define NWFPE_TAGS_OFFSET (NWFPE_FPCR_OFFSET + INT_REGISTER_SIZE)
|
||||
#define NWFPE_INITFLAG_OFFSET (NWFPE_TAGS_OFFSET + 8)
|
||||
|
||||
void arm_linux_supply_gregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *gregs_buf, size_t len);
|
||||
void arm_linux_collect_gregset (const struct regset *regset,
|
||||
const struct regcache *regcache,
|
||||
int regnum, void *gregs_buf, size_t len);
|
||||
|
||||
void supply_nwfpe_register (struct regcache *regcache, int regno,
|
||||
const gdb_byte *regs);
|
||||
void collect_nwfpe_register (const struct regcache *regcache, int regno,
|
||||
gdb_byte *regs);
|
||||
|
||||
void arm_linux_supply_nwfpe (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *regs_buf, size_t len);
|
||||
void arm_linux_collect_nwfpe (const struct regset *regset,
|
||||
const struct regcache *regcache,
|
||||
int regnum, void *regs_buf, size_t len);
|
||||
3526
gdb/arm-tdep.c
3526
gdb/arm-tdep.c
File diff suppressed because it is too large
Load Diff
190
gdb/arm-tdep.h
190
gdb/arm-tdep.h
@@ -1,190 +0,0 @@
|
||||
/* Common target dependent code for GDB on ARM systems.
|
||||
Copyright (C) 2002, 2003, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef ARM_TDEP_H
|
||||
#define ARM_TDEP_H
|
||||
|
||||
/* Forward declarations. */
|
||||
struct gdbarch;
|
||||
struct regset;
|
||||
|
||||
/* Register numbers of various important registers. */
|
||||
|
||||
enum gdb_regnum {
|
||||
ARM_A1_REGNUM = 0, /* first integer-like argument */
|
||||
ARM_A4_REGNUM = 3, /* last integer-like argument */
|
||||
ARM_AP_REGNUM = 11,
|
||||
ARM_IP_REGNUM = 12,
|
||||
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_CPSR_REGNUM = ARM_PS_REGNUM,
|
||||
ARM_WR0_REGNUM, /* WMMX data registers. */
|
||||
ARM_WR15_REGNUM = ARM_WR0_REGNUM + 15,
|
||||
ARM_WC0_REGNUM, /* WMMX control registers. */
|
||||
ARM_WCSSF_REGNUM = ARM_WC0_REGNUM + 2,
|
||||
ARM_WCASF_REGNUM = ARM_WC0_REGNUM + 3,
|
||||
ARM_WC7_REGNUM = ARM_WC0_REGNUM + 7,
|
||||
ARM_WCGR0_REGNUM, /* WMMX general purpose registers. */
|
||||
ARM_WCGR3_REGNUM = ARM_WCGR0_REGNUM + 3,
|
||||
ARM_WCGR7_REGNUM = ARM_WCGR0_REGNUM + 7,
|
||||
|
||||
ARM_NUM_REGS,
|
||||
|
||||
/* Other useful registers. */
|
||||
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
|
||||
|
||||
/* Number of machine registers. The only define actually required
|
||||
is gdbarch_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
|
||||
|
||||
#define CPSR_T 0x20
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
/* Convention for returning structures. */
|
||||
|
||||
enum struct_return
|
||||
{
|
||||
pcc_struct_return, /* Return "short" structures in memory. */
|
||||
reg_struct_return /* Return "short" structures in registers. */
|
||||
};
|
||||
|
||||
/* 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. */
|
||||
|
||||
int have_fpa_registers; /* Does the target report the FPA registers? */
|
||||
|
||||
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. */
|
||||
|
||||
/* Convention for returning structures. */
|
||||
enum struct_return struct_return;
|
||||
|
||||
/* Cached core file helpers. */
|
||||
struct regset *gregset, *fpregset;
|
||||
};
|
||||
|
||||
|
||||
CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR);
|
||||
CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR);
|
||||
int arm_software_single_step (struct frame_info *);
|
||||
|
||||
/* Functions exported from armbsd-tdep.h. */
|
||||
|
||||
/* Return the appropriate register set for the core section identified
|
||||
by SECT_NAME and SECT_SIZE. */
|
||||
|
||||
extern const struct regset *
|
||||
armbsd_regset_from_core_section (struct gdbarch *gdbarch,
|
||||
const char *sect_name, size_t sect_size);
|
||||
|
||||
#endif /* arm-tdep.h */
|
||||
@@ -1,126 +0,0 @@
|
||||
/* Target-dependent code for Windows CE running on ARM processors,
|
||||
for GDB.
|
||||
|
||||
Copyright (C) 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "osabi.h"
|
||||
#include "gdbcore.h"
|
||||
#include "target.h"
|
||||
#include "solib.h"
|
||||
#include "solib-target.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "arm-tdep.h"
|
||||
|
||||
static const char arm_wince_le_breakpoint[] = { 0x10, 0x00, 0x00, 0xe6 };
|
||||
static const char arm_wince_thumb_le_breakpoint[] = { 0xfe, 0xdf };
|
||||
|
||||
/* Description of the longjmp buffer. */
|
||||
#define ARM_WINCE_JB_ELEMENT_SIZE INT_REGISTER_SIZE
|
||||
#define ARM_WINCE_JB_PC 10
|
||||
|
||||
static CORE_ADDR
|
||||
arm_pe_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
|
||||
{
|
||||
ULONGEST indirect;
|
||||
struct minimal_symbol *indsym;
|
||||
char *symname;
|
||||
CORE_ADDR next_pc;
|
||||
|
||||
/* The format of an ARM DLL trampoline is:
|
||||
ldr ip, [pc]
|
||||
ldr pc, [ip]
|
||||
.dw __imp_<func> */
|
||||
|
||||
if (pc == 0
|
||||
|| read_memory_unsigned_integer (pc + 0, 4) != 0xe59fc000
|
||||
|| read_memory_unsigned_integer (pc + 4, 4) != 0xe59cf000)
|
||||
return 0;
|
||||
|
||||
indirect = read_memory_unsigned_integer (pc + 8, 4);
|
||||
if (indirect == 0)
|
||||
return 0;
|
||||
|
||||
indsym = lookup_minimal_symbol_by_pc (indirect);
|
||||
if (indsym == NULL)
|
||||
return 0;
|
||||
|
||||
symname = SYMBOL_LINKAGE_NAME (indsym);
|
||||
if (symname == NULL || strncmp (symname, "__imp_", 6) != 0)
|
||||
return 0;
|
||||
|
||||
next_pc = read_memory_unsigned_integer (indirect, 4);
|
||||
if (next_pc != 0)
|
||||
return next_pc;
|
||||
|
||||
/* Check with the default arm gdbarch_skip_trampoline. */
|
||||
return arm_skip_stub (frame, pc);
|
||||
}
|
||||
|
||||
static void
|
||||
arm_wince_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
tdep->arm_breakpoint = arm_wince_le_breakpoint;
|
||||
tdep->arm_breakpoint_size = sizeof (arm_wince_le_breakpoint);
|
||||
tdep->thumb_breakpoint = arm_wince_thumb_le_breakpoint;
|
||||
tdep->thumb_breakpoint_size = sizeof (arm_wince_thumb_le_breakpoint);
|
||||
tdep->struct_return = pcc_struct_return;
|
||||
|
||||
tdep->fp_model = ARM_FLOAT_SOFT_VFP;
|
||||
|
||||
tdep->jb_pc = ARM_WINCE_JB_PC;
|
||||
tdep->jb_elt_size = ARM_WINCE_JB_ELEMENT_SIZE;
|
||||
|
||||
/* On ARM WinCE char defaults to signed. */
|
||||
set_gdbarch_char_signed (gdbarch, 1);
|
||||
|
||||
/* Shared library handling. */
|
||||
set_solib_ops (gdbarch, &solib_target_so_ops);
|
||||
set_gdbarch_skip_trampoline_code (gdbarch, arm_pe_skip_trampoline_code);
|
||||
|
||||
/* Single stepping. */
|
||||
set_gdbarch_software_single_step (gdbarch, arm_software_single_step);
|
||||
}
|
||||
|
||||
static enum gdb_osabi
|
||||
arm_wince_osabi_sniffer (bfd *abfd)
|
||||
{
|
||||
const char *target_name = bfd_get_target (abfd);
|
||||
|
||||
if (strcmp (target_name, "pei-arm-wince-little") == 0)
|
||||
return GDB_OSABI_WINCE;
|
||||
|
||||
return GDB_OSABI_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||||
void _initialize_arm_wince_tdep (void);
|
||||
|
||||
void
|
||||
_initialize_arm_wince_tdep (void)
|
||||
{
|
||||
gdbarch_register_osabi_sniffer (bfd_arch_arm, bfd_target_coff_flavour,
|
||||
arm_wince_osabi_sniffer);
|
||||
|
||||
gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_WINCE,
|
||||
arm_wince_init_abi);
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/* Target-dependent code for ARM BSD's.
|
||||
|
||||
Copyright (C) 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "osabi.h"
|
||||
#include "regcache.h"
|
||||
#include "regset.h"
|
||||
|
||||
#include "gdb_assert.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "arm-tdep.h"
|
||||
|
||||
/* Core file support. */
|
||||
|
||||
/* Sizeof `struct reg' in <machine/reg.h>. */
|
||||
#define ARMBSD_SIZEOF_GREGS (17 * 4)
|
||||
|
||||
/* Sizeof `struct fpreg' in <machine/reg.h. */
|
||||
#define ARMBSD_SIZEOF_FPREGS ((1 + (8 * 3)) * 4)
|
||||
|
||||
int
|
||||
armbsd_fpreg_offset (int regnum)
|
||||
{
|
||||
if (regnum == ARM_FPS_REGNUM)
|
||||
return 0;
|
||||
|
||||
return 4 + (regnum - ARM_F0_REGNUM) * 12;
|
||||
}
|
||||
|
||||
/* Supply register REGNUM from the buffer specified by FPREGS and LEN
|
||||
in the floating-point register set REGSET to register cache
|
||||
REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
|
||||
|
||||
static void
|
||||
armbsd_supply_fpregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *fpregs, size_t len)
|
||||
{
|
||||
const gdb_byte *regs = fpregs;
|
||||
int i;
|
||||
|
||||
gdb_assert (len >= ARMBSD_SIZEOF_FPREGS);
|
||||
|
||||
for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++)
|
||||
{
|
||||
if (regnum == i || regnum == -1)
|
||||
regcache_raw_supply (regcache, i, regs + armbsd_fpreg_offset (i));
|
||||
}
|
||||
}
|
||||
|
||||
/* Supply register REGNUM from the buffer specified by GREGS and LEN
|
||||
in the general-purpose register set REGSET to register cache
|
||||
REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
|
||||
|
||||
static void
|
||||
armbsd_supply_gregset (const struct regset *regset,
|
||||
struct regcache *regcache,
|
||||
int regnum, const void *gregs, size_t len)
|
||||
{
|
||||
const gdb_byte *regs = gregs;
|
||||
int i;
|
||||
|
||||
gdb_assert (len >= ARMBSD_SIZEOF_GREGS);
|
||||
|
||||
for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++)
|
||||
{
|
||||
if (regnum == i || regnum == -1)
|
||||
regcache_raw_supply (regcache, i, regs + i * 4);
|
||||
}
|
||||
|
||||
if (regnum == ARM_PS_REGNUM || regnum == -1)
|
||||
regcache_raw_supply (regcache, i, regs + 16 * 4);
|
||||
|
||||
if (len >= ARMBSD_SIZEOF_GREGS + ARMBSD_SIZEOF_FPREGS)
|
||||
{
|
||||
regs += ARMBSD_SIZEOF_GREGS;
|
||||
len -= ARMBSD_SIZEOF_GREGS;
|
||||
armbsd_supply_fpregset (regset, regcache, regnum, regs, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* ARM register sets. */
|
||||
|
||||
static struct regset armbsd_gregset =
|
||||
{
|
||||
NULL,
|
||||
armbsd_supply_gregset
|
||||
};
|
||||
|
||||
static struct regset armbsd_fpregset =
|
||||
{
|
||||
NULL,
|
||||
armbsd_supply_fpregset
|
||||
};
|
||||
|
||||
/* Return the appropriate register set for the core section identified
|
||||
by SECT_NAME and SECT_SIZE. */
|
||||
|
||||
const struct regset *
|
||||
armbsd_regset_from_core_section (struct gdbarch *gdbarch,
|
||||
const char *sect_name, size_t sect_size)
|
||||
{
|
||||
if (strcmp (sect_name, ".reg") == 0 && sect_size >= ARMBSD_SIZEOF_GREGS)
|
||||
return &armbsd_gregset;
|
||||
|
||||
if (strcmp (sect_name, ".reg2") == 0 && sect_size >= ARMBSD_SIZEOF_FPREGS)
|
||||
return &armbsd_fpregset;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,502 +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, 2007,
|
||||
2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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
|
||||
arm_supply_gregset (struct regcache *regcache, struct reg *gregset)
|
||||
{
|
||||
int regno;
|
||||
CORE_ADDR r_pc;
|
||||
|
||||
/* Integer registers. */
|
||||
for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
|
||||
regcache_raw_supply (regcache, regno, (char *) &gregset->r[regno]);
|
||||
|
||||
regcache_raw_supply (regcache, ARM_SP_REGNUM,
|
||||
(char *) &gregset->r_sp);
|
||||
regcache_raw_supply (regcache, ARM_LR_REGNUM,
|
||||
(char *) &gregset->r_lr);
|
||||
/* This is ok: we're running native... */
|
||||
r_pc = gdbarch_addr_bits_remove (get_regcache_arch (regcache), gregset->r_pc);
|
||||
regcache_raw_supply (regcache, ARM_PC_REGNUM, (char *) &r_pc);
|
||||
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
(char *) &gregset->r_cpsr);
|
||||
else
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
(char *) &gregset->r_pc);
|
||||
}
|
||||
|
||||
static void
|
||||
arm_supply_fparegset (struct regcache *regcache, struct fpreg *fparegset)
|
||||
{
|
||||
int regno;
|
||||
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
regcache_raw_supply (regcache, regno,
|
||||
(char *) &fparegset->fpr[regno - ARM_F0_REGNUM]);
|
||||
|
||||
regcache_raw_supply (regcache, ARM_FPS_REGNUM,
|
||||
(char *) &fparegset->fpr_fpsr);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_register (struct regcache *regcache, 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 (regcache, ARM_SP_REGNUM,
|
||||
(char *) &inferior_registers.r_sp);
|
||||
break;
|
||||
|
||||
case ARM_LR_REGNUM:
|
||||
regcache_raw_supply (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 = gdbarch_addr_bits_remove
|
||||
(get_regcache_arch (regcache),
|
||||
inferior_registers.r_pc);
|
||||
regcache_raw_supply (regcache, ARM_PC_REGNUM,
|
||||
(char *) &inferior_registers.r_pc);
|
||||
break;
|
||||
|
||||
case ARM_PS_REGNUM:
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
(char *) &inferior_registers.r_cpsr);
|
||||
else
|
||||
regcache_raw_supply (regcache, ARM_PS_REGNUM,
|
||||
(char *) &inferior_registers.r_pc);
|
||||
break;
|
||||
|
||||
default:
|
||||
regcache_raw_supply (regcache, regno,
|
||||
(char *) &inferior_registers.r[regno]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_regs (struct regcache *regcache)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
arm_supply_gregset (regcache, &inferior_registers);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_fp_register (struct regcache *regcache, 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 (regcache, ARM_FPS_REGNUM,
|
||||
(char *) &inferior_fp_registers.fpr_fpsr);
|
||||
break;
|
||||
|
||||
default:
|
||||
regcache_raw_supply (regcache, regno,
|
||||
(char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_fp_regs (struct regcache *regcache)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
arm_supply_fparegset (regcache, &inferior_fp_registers);
|
||||
}
|
||||
|
||||
static void
|
||||
armnbsd_fetch_registers (struct regcache *regcache, int regno)
|
||||
{
|
||||
if (regno >= 0)
|
||||
{
|
||||
if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
|
||||
fetch_register (regcache, regno);
|
||||
else
|
||||
fetch_fp_register (regcache, regno);
|
||||
}
|
||||
else
|
||||
{
|
||||
fetch_regs (regcache);
|
||||
fetch_fp_regs (regcache);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
store_register (const struct regcache *regcache, int regno)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
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 (regcache, ARM_SP_REGNUM,
|
||||
(char *) &inferior_registers.r_sp);
|
||||
break;
|
||||
|
||||
case ARM_LR_REGNUM:
|
||||
regcache_raw_collect (regcache, ARM_LR_REGNUM,
|
||||
(char *) &inferior_registers.r_lr);
|
||||
break;
|
||||
|
||||
case ARM_PC_REGNUM:
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_collect (regcache, ARM_PC_REGNUM,
|
||||
(char *) &inferior_registers.r_pc);
|
||||
else
|
||||
{
|
||||
unsigned pc_val;
|
||||
|
||||
regcache_raw_collect (regcache, ARM_PC_REGNUM,
|
||||
(char *) &pc_val);
|
||||
|
||||
pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val);
|
||||
inferior_registers.r_pc ^= gdbarch_addr_bits_remove
|
||||
(gdbarch, inferior_registers.r_pc);
|
||||
inferior_registers.r_pc |= pc_val;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARM_PS_REGNUM:
|
||||
if (arm_apcs_32)
|
||||
regcache_raw_collect (regcache, ARM_PS_REGNUM,
|
||||
(char *) &inferior_registers.r_cpsr);
|
||||
else
|
||||
{
|
||||
unsigned psr_val;
|
||||
|
||||
regcache_raw_collect (regcache, ARM_PS_REGNUM,
|
||||
(char *) &psr_val);
|
||||
|
||||
psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val);
|
||||
inferior_registers.r_pc = gdbarch_addr_bits_remove
|
||||
(gdbarch, inferior_registers.r_pc);
|
||||
inferior_registers.r_pc |= psr_val;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
regcache_raw_collect (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 (const struct regcache *regcache)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
struct reg inferior_registers;
|
||||
int ret;
|
||||
int regno;
|
||||
|
||||
|
||||
for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
|
||||
regcache_raw_collect (regcache, regno,
|
||||
(char *) &inferior_registers.r[regno]);
|
||||
|
||||
regcache_raw_collect (regcache, ARM_SP_REGNUM,
|
||||
(char *) &inferior_registers.r_sp);
|
||||
regcache_raw_collect (regcache, ARM_LR_REGNUM,
|
||||
(char *) &inferior_registers.r_lr);
|
||||
|
||||
if (arm_apcs_32)
|
||||
{
|
||||
regcache_raw_collect (regcache, ARM_PC_REGNUM,
|
||||
(char *) &inferior_registers.r_pc);
|
||||
regcache_raw_collect (regcache, ARM_PS_REGNUM,
|
||||
(char *) &inferior_registers.r_cpsr);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned pc_val;
|
||||
unsigned psr_val;
|
||||
|
||||
regcache_raw_collect (regcache, ARM_PC_REGNUM,
|
||||
(char *) &pc_val);
|
||||
regcache_raw_collect (regcache, ARM_PS_REGNUM,
|
||||
(char *) &psr_val);
|
||||
|
||||
pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val);
|
||||
psr_val ^= gdbarch_addr_bits_remove (gdbarch, 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 (const struct regcache *regcache, 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 (regcache, ARM_FPS_REGNUM,
|
||||
(char *) &inferior_fp_registers.fpr_fpsr);
|
||||
break;
|
||||
|
||||
default:
|
||||
regcache_raw_collect (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 (const struct regcache *regcache)
|
||||
{
|
||||
struct fpreg inferior_fp_registers;
|
||||
int ret;
|
||||
int regno;
|
||||
|
||||
|
||||
for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
|
||||
regcache_raw_collect (regcache, regno,
|
||||
(char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
|
||||
|
||||
regcache_raw_collect (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 (struct regcache *regcache, int regno)
|
||||
{
|
||||
if (regno >= 0)
|
||||
{
|
||||
if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
|
||||
store_register (regcache, regno);
|
||||
else
|
||||
store_fp_register (regcache, regno);
|
||||
}
|
||||
else
|
||||
{
|
||||
store_regs (regcache);
|
||||
store_fp_regs (regcache);
|
||||
}
|
||||
}
|
||||
|
||||
struct md_core
|
||||
{
|
||||
struct reg intreg;
|
||||
struct fpreg freg;
|
||||
};
|
||||
|
||||
static void
|
||||
fetch_core_registers (struct regcache *regcache,
|
||||
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;
|
||||
|
||||
arm_supply_gregset (regcache, &core_reg->intreg);
|
||||
arm_supply_fparegset (regcache, &core_reg->freg);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_elfcore_registers (struct regcache *regcache,
|
||||
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));
|
||||
arm_supply_gregset (regcache, &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));
|
||||
arm_supply_fparegset (regcache, &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,120 +0,0 @@
|
||||
/* Target-dependent code for NetBSD/arm.
|
||||
|
||||
Copyright (C) 2002, 2003, 2004, 2006, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "osabi.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "arm-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;
|
||||
|
||||
/* Single stepping. */
|
||||
set_gdbarch_software_single_step (gdbarch, arm_software_single_step);
|
||||
}
|
||||
|
||||
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);
|
||||
if (tdep->fp_model == ARM_FLOAT_AUTO)
|
||||
tdep->fp_model = ARM_FLOAT_SOFT_VFP;
|
||||
|
||||
/* NetBSD ELF uses SVR4-style shared libraries. */
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
/* Target-dependent code for OpenBSD/arm.
|
||||
|
||||
Copyright (C) 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "osabi.h"
|
||||
#include "trad-frame.h"
|
||||
#include "tramp-frame.h"
|
||||
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include "obsd-tdep.h"
|
||||
#include "arm-tdep.h"
|
||||
#include "solib-svr4.h"
|
||||
|
||||
/* Signal trampolines. */
|
||||
|
||||
static void
|
||||
armobsd_sigframe_init (const struct tramp_frame *self,
|
||||
struct frame_info *this_frame,
|
||||
struct trad_frame_cache *cache,
|
||||
CORE_ADDR func)
|
||||
{
|
||||
CORE_ADDR sp, sigcontext_addr, addr;
|
||||
int regnum;
|
||||
|
||||
/* We find the appropriate instance of `struct sigcontext' at a
|
||||
fixed offset in the signal frame. */
|
||||
sp = get_frame_register_signed (this_frame, ARM_SP_REGNUM);
|
||||
sigcontext_addr = sp + 16;
|
||||
|
||||
/* PC. */
|
||||
trad_frame_set_reg_addr (cache, ARM_PC_REGNUM, sigcontext_addr + 76);
|
||||
|
||||
/* GPRs. */
|
||||
for (regnum = ARM_A1_REGNUM, addr = sigcontext_addr + 12;
|
||||
regnum <= ARM_LR_REGNUM; regnum++, addr += 4)
|
||||
trad_frame_set_reg_addr (cache, regnum, addr);
|
||||
|
||||
trad_frame_set_id (cache, frame_id_build (sp, func));
|
||||
}
|
||||
|
||||
static const struct tramp_frame armobsd_sigframe =
|
||||
{
|
||||
SIGTRAMP_FRAME,
|
||||
4,
|
||||
{
|
||||
{ 0xe28d0010, -1 }, /* add r0, sp, #16 */
|
||||
{ 0xef000067, -1 }, /* swi SYS_sigreturn */
|
||||
{ 0xef000001, -1 }, /* swi SYS_exit */
|
||||
{ 0xeafffffc, -1 }, /* b . - 8 */
|
||||
{ TRAMP_SENTINEL_INSN, -1 }
|
||||
},
|
||||
armobsd_sigframe_init
|
||||
};
|
||||
|
||||
|
||||
/* Override default thumb breakpoints. */
|
||||
static const char arm_obsd_thumb_le_breakpoint[] = {0xfe, 0xdf};
|
||||
static const char arm_obsd_thumb_be_breakpoint[] = {0xdf, 0xfe};
|
||||
|
||||
static void
|
||||
armobsd_init_abi (struct gdbarch_info info,
|
||||
struct gdbarch *gdbarch)
|
||||
{
|
||||
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||
|
||||
if (tdep->fp_model == ARM_FLOAT_AUTO)
|
||||
tdep->fp_model = ARM_FLOAT_SOFT_VFP;
|
||||
|
||||
tramp_frame_prepend_unwinder (gdbarch, &armobsd_sigframe);
|
||||
|
||||
/* OpenBSD/arm uses SVR4-style shared libraries. */
|
||||
set_solib_svr4_fetch_link_map_offsets
|
||||
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
|
||||
set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
|
||||
|
||||
tdep->jb_pc = 24;
|
||||
tdep->jb_elt_size = 4;
|
||||
|
||||
set_gdbarch_regset_from_core_section
|
||||
(gdbarch, armbsd_regset_from_core_section);
|
||||
|
||||
/* OpenBSD/arm uses -fpcc-struct-return by default. */
|
||||
tdep->struct_return = pcc_struct_return;
|
||||
|
||||
/* Single stepping. */
|
||||
set_gdbarch_software_single_step (gdbarch, arm_software_single_step);
|
||||
|
||||
/* Breakpoints. */
|
||||
switch (info.byte_order)
|
||||
{
|
||||
case BFD_ENDIAN_BIG:
|
||||
tdep->thumb_breakpoint = arm_obsd_thumb_be_breakpoint;
|
||||
tdep->thumb_breakpoint_size = sizeof (arm_obsd_thumb_be_breakpoint);
|
||||
break;
|
||||
|
||||
case BFD_ENDIAN_LITTLE:
|
||||
tdep->thumb_breakpoint = arm_obsd_thumb_le_breakpoint;
|
||||
tdep->thumb_breakpoint_size = sizeof (arm_obsd_thumb_le_breakpoint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static enum gdb_osabi
|
||||
armobsd_core_osabi_sniffer (bfd *abfd)
|
||||
{
|
||||
if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
|
||||
return GDB_OSABI_OPENBSD_ELF;
|
||||
|
||||
return GDB_OSABI_UNKNOWN;
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_armobsd_tdep (void)
|
||||
{
|
||||
/* BFD doesn't set a flavour for NetBSD style a.out core files. */
|
||||
gdbarch_register_osabi_sniffer (bfd_arch_arm, bfd_target_unknown_flavour,
|
||||
armobsd_core_osabi_sniffer);
|
||||
|
||||
gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_OPENBSD_ELF,
|
||||
armobsd_init_abi);
|
||||
}
|
||||
282
gdb/auxv.c
282
gdb/auxv.c
@@ -1,282 +0,0 @@
|
||||
/* Auxiliary vector support for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2004, 2005, 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 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
|
||||
default_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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct target_ops *t;
|
||||
for (t = ops; t != NULL; t = t->beneath)
|
||||
if (t->to_auxv_parse != NULL)
|
||||
return t->to_auxv_parse (t, readptr, endptr, typep, valp);
|
||||
|
||||
return default_auxv_parse (ops, readptr, endptr, typep, 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. */
|
||||
int
|
||||
target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
|
||||
{
|
||||
CORE_ADDR type, val;
|
||||
gdb_byte *data;
|
||||
LONGEST n = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL, &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;
|
||||
LONGEST len = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL,
|
||||
&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);
|
||||
TAG (AT_SUN_AUXFLAGS,
|
||||
_("AF_SUN_ flags passed from the kernel"), hex);
|
||||
}
|
||||
|
||||
fprintf_filtered (file, "%-4s %-20s %-30s ",
|
||||
plongest (type), name, description);
|
||||
switch (flavor)
|
||||
{
|
||||
case dec:
|
||||
fprintf_filtered (file, "%s\n", plongest (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;
|
||||
if (type == AT_NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
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."));
|
||||
}
|
||||
67
gdb/auxv.h
67
gdb/auxv.h
@@ -1,67 +0,0 @@
|
||||
/* Auxiliary vector support for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2004, 2005, 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 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
|
||||
1420
gdb/avr-tdep.c
1420
gdb/avr-tdep.c
File diff suppressed because it is too large
Load Diff
1807
gdb/ax-gdb.c
1807
gdb/ax-gdb.c
File diff suppressed because it is too large
Load Diff
101
gdb/ax-gdb.h
101
gdb/ax-gdb.h
@@ -1,101 +0,0 @@
|
||||
/* GDB-specific functions for operating on agent expressions
|
||||
Copyright (C) 1998, 1999, 2000, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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, 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 */
|
||||
546
gdb/ax-general.c
546
gdb/ax-general.c
@@ -1,546 +0,0 @@
|
||||
/* Functions for manipulating expressions designed to be executed on the agent
|
||||
Copyright (C) 1998, 1999, 2000, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* 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++)
|
||||
{
|
||||
LONGEST lim = 1 << (size - 1);
|
||||
|
||||
if (-lim <= l && l <= lim - 1)
|
||||
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;
|
||||
}
|
||||
290
gdb/ax.h
290
gdb/ax.h
@@ -1,290 +0,0 @@
|
||||
/* Definitions for expressions designed to be executed on the agent
|
||||
Copyright (C) 1998, 1999, 2000, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 */
|
||||
457
gdb/bcache.c
457
gdb/bcache.c
@@ -1,457 +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, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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. */
|
||||
const void *
|
||||
bcache (const void *addr, int length, struct bcache *bcache)
|
||||
{
|
||||
return bcache_full (addr, length, bcache, NULL);
|
||||
}
|
||||
|
||||
/* 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. If
|
||||
optional ADDED is not NULL, return 1 in case of new entry or 0 if
|
||||
returning an old entry. */
|
||||
|
||||
const void *
|
||||
bcache_full (const void *addr, int length, struct bcache *bcache, int *added)
|
||||
{
|
||||
unsigned long full_hash;
|
||||
unsigned short half_hash;
|
||||
int hash_index;
|
||||
struct bstring *s;
|
||||
|
||||
if (added)
|
||||
*added = 0;
|
||||
|
||||
/* Lazily initialize the obstack. This can save quite a bit of
|
||||
memory in some cases. */
|
||||
if (bcache->total_count == 0)
|
||||
{
|
||||
/* We could use obstack_specify_allocation here instead, but
|
||||
gdb_obstack.h specifies the allocation/deallocation
|
||||
functions. */
|
||||
obstack_init (&bcache->cache);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
if (added)
|
||||
*added = 1;
|
||||
|
||||
return &new->d.data;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocating and freeing bcaches. */
|
||||
|
||||
struct bcache *
|
||||
bcache_xmalloc (void)
|
||||
{
|
||||
/* Allocate the bcache pre-zeroed. */
|
||||
struct bcache *b = XCALLOC (1, struct bcache);
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Free all the storage associated with BCACHE. */
|
||||
void
|
||||
bcache_xfree (struct bcache *bcache)
|
||||
{
|
||||
if (bcache == NULL)
|
||||
return;
|
||||
/* Only free the obstack if we actually initialized it. */
|
||||
if (bcache->total_count > 0)
|
||||
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)
|
||||
{
|
||||
if (bcache->total_count == 0)
|
||||
return 0;
|
||||
return obstack_memory_used (&bcache->cache);
|
||||
}
|
||||
173
gdb/bcache.h
173
gdb/bcache.h
@@ -1,173 +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, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 const void *bcache (const void *addr, int length,
|
||||
struct bcache *bcache);
|
||||
|
||||
/* Like bcache, but if ADDED is not NULL, set *ADDED to true if the
|
||||
bytes were newly added to the cache, or to false if the bytes were
|
||||
found in the cache. */
|
||||
extern const void *bcache_full (const void *addr, int length,
|
||||
struct bcache *bcache, int *added);
|
||||
|
||||
/* 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 */
|
||||
130
gdb/bfd-target.c
130
gdb/bfd-target.c
@@ -1,130 +0,0 @@
|
||||
/* Very simple "bfd" target, for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2003, 2005, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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,37 +0,0 @@
|
||||
/* Very simple "bfd" target, for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2003, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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
|
||||
311
gdb/block.c
311
gdb/block.c
@@ -1,311 +0,0 @@
|
||||
/* Block-related functions for the GNU debugger, GDB.
|
||||
|
||||
Copyright (C) 2003, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "block.h"
|
||||
#include "symtab.h"
|
||||
#include "symfile.h"
|
||||
#include "gdb_obstack.h"
|
||||
#include "cp-support.h"
|
||||
#include "addrmap.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. The return value
|
||||
will not be an inlined function; the containing function will be
|
||||
returned instead. */
|
||||
|
||||
struct symbol *
|
||||
block_linkage_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. PBLOCK is a pointer to the block. If PBLOCK is NULL, we
|
||||
don't pass this information back to the caller. */
|
||||
|
||||
struct blockvector *
|
||||
blockvector_for_pc_sect (CORE_ADDR pc, struct obj_section *section,
|
||||
struct block **pblock, 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);
|
||||
|
||||
/* Then search that symtab for the smallest block that wins. */
|
||||
|
||||
/* If we have an addrmap mapping code addresses to blocks, then use
|
||||
that. */
|
||||
if (BLOCKVECTOR_MAP (bl))
|
||||
{
|
||||
b = addrmap_find (BLOCKVECTOR_MAP (bl), pc);
|
||||
if (b)
|
||||
{
|
||||
if (pblock)
|
||||
*pblock = b;
|
||||
return bl;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Otherwise, 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 (pblock)
|
||||
*pblock = b;
|
||||
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, struct block **pblock)
|
||||
{
|
||||
return blockvector_for_pc_sect (pc, find_pc_mapped_section (pc),
|
||||
pblock, 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 obj_section *section)
|
||||
{
|
||||
struct blockvector *bl;
|
||||
struct block *b;
|
||||
|
||||
bl = blockvector_for_pc_sect (pc, section, &b, NULL);
|
||||
if (bl)
|
||||
return b;
|
||||
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;
|
||||
|
||||
return bl;
|
||||
}
|
||||
167
gdb/block.h
167
gdb/block.h
@@ -1,167 +0,0 @@
|
||||
/* Code dealing with blocks for GDB.
|
||||
|
||||
Copyright (C) 2003, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef BLOCK_H
|
||||
#define BLOCK_H
|
||||
|
||||
/* Opaque declarations. */
|
||||
|
||||
struct symbol;
|
||||
struct symtab;
|
||||
struct block_namespace_info;
|
||||
struct using_direct;
|
||||
struct obstack;
|
||||
struct dictionary;
|
||||
struct addrmap;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
#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_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;
|
||||
/* An address map mapping addresses to blocks in this blockvector.
|
||||
This pointer is zero if the blocks' start and end addresses are
|
||||
enough. */
|
||||
struct addrmap *map;
|
||||
/* The blocks themselves. */
|
||||
struct block *block[1];
|
||||
};
|
||||
|
||||
#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks
|
||||
#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n]
|
||||
#define BLOCKVECTOR_MAP(blocklist) ((blocklist)->map)
|
||||
|
||||
/* Special block numbers */
|
||||
|
||||
enum { GLOBAL_BLOCK = 0, STATIC_BLOCK = 1, FIRST_LOCAL_BLOCK = 2 };
|
||||
|
||||
extern struct symbol *block_linkage_function (const struct block *);
|
||||
|
||||
extern int contained_in (const struct block *, const struct block *);
|
||||
|
||||
extern struct blockvector *blockvector_for_pc (CORE_ADDR, struct block **);
|
||||
|
||||
extern struct blockvector *blockvector_for_pc_sect (CORE_ADDR,
|
||||
struct obj_section *,
|
||||
struct block **,
|
||||
struct symtab *);
|
||||
|
||||
extern struct block *block_for_pc (CORE_ADDR);
|
||||
|
||||
extern struct block *block_for_pc_sect (CORE_ADDR, struct obj_section *);
|
||||
|
||||
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 */
|
||||
361
gdb/blockframe.c
361
gdb/blockframe.c
@@ -1,361 +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, 2007, 2008
|
||||
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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "symtab.h"
|
||||
#include "bfd.h"
|
||||
#include "objfiles.h"
|
||||
#include "frame.h"
|
||||
#include "gdbcore.h"
|
||||
#include "value.h"
|
||||
#include "target.h"
|
||||
#include "inferior.h"
|
||||
#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_linkage_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_linkage_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 obj_section *section)
|
||||
{
|
||||
struct block *b = block_for_pc_sect (pc, section);
|
||||
if (b == 0)
|
||||
return 0;
|
||||
return block_linkage_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 obj_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 obj_section *section;
|
||||
struct partial_symtab *pst;
|
||||
struct symbol *f;
|
||||
struct minimal_symbol *msymbol;
|
||||
struct partial_symbol *psb;
|
||||
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)
|
||||
section = find_pc_section (pc);
|
||||
|
||||
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 = SYMBOL_LINKAGE_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 = SYMBOL_LINKAGE_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. */
|
||||
|
||||
if (!section)
|
||||
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 = SYMBOL_LINKAGE_NAME (msymbol);
|
||||
cache_pc_function_section = section;
|
||||
|
||||
/* If the minimal symbol has a size, use it for the cache.
|
||||
Otherwise use the lesser of the next minimal symbol in the same
|
||||
section, or the end of the section, as the end of the
|
||||
function. */
|
||||
|
||||
if (MSYMBOL_SIZE (msymbol) != 0)
|
||||
cache_pc_function_high = cache_pc_function_low + MSYMBOL_SIZE (msymbol);
|
||||
else
|
||||
{
|
||||
/* 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; SYMBOL_LINKAGE_NAME (msymbol + i) != NULL; i++)
|
||||
{
|
||||
if (SYMBOL_VALUE_ADDRESS (msymbol + i) != SYMBOL_VALUE_ADDRESS (msymbol)
|
||||
&& SYMBOL_OBJ_SECTION (msymbol + i) == SYMBOL_OBJ_SECTION (msymbol))
|
||||
break;
|
||||
}
|
||||
|
||||
if (SYMBOL_LINKAGE_NAME (msymbol + i) != NULL
|
||||
&& SYMBOL_VALUE_ADDRESS (msymbol + i) < obj_section_endaddr (section))
|
||||
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 = obj_section_endaddr (section);
|
||||
}
|
||||
|
||||
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 = get_current_frame ();
|
||||
while (frame != NULL)
|
||||
{
|
||||
calling_pc = get_frame_address_in_block (frame);
|
||||
if (calling_pc >= start && calling_pc < end)
|
||||
return frame;
|
||||
|
||||
frame = get_prev_frame (frame);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
8657
gdb/breakpoint.c
8657
gdb/breakpoint.c
File diff suppressed because it is too large
Load Diff
885
gdb/breakpoint.h
885
gdb/breakpoint.h
@@ -1,885 +0,0 @@
|
||||
/* Data structures associated with breakpoints in GDB.
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
2002, 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#if !defined (BREAKPOINT_H)
|
||||
#define BREAKPOINT_H 1
|
||||
|
||||
#include "frame.h"
|
||||
#include "value.h"
|
||||
#include "vec.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 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,
|
||||
};
|
||||
|
||||
/* 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_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 */
|
||||
};
|
||||
|
||||
|
||||
/* Information used by targets to insert and remove breakpoints. */
|
||||
|
||||
struct bp_target_info
|
||||
{
|
||||
/* Address at which the breakpoint was placed. This is normally the
|
||||
same as ADDRESS from the bp_location, except when adjustment
|
||||
happens in gdbarch_breakpoint_from_pc. The most common form of
|
||||
adjustment is stripping an alternate ISA marker from the PC which
|
||||
is used to determine the type of breakpoint to insert. */
|
||||
CORE_ADDR placed_address;
|
||||
|
||||
/* If the breakpoint lives in memory and reading that memory would
|
||||
give back the breakpoint, instead of the original contents, then
|
||||
the original contents are cached here. Only SHADOW_LEN bytes of
|
||||
this buffer are valid, and only when the breakpoint is inserted. */
|
||||
gdb_byte shadow_contents[BREAKPOINT_MAX];
|
||||
|
||||
/* The length of the data cached in SHADOW_CONTENTS. */
|
||||
int shadow_len;
|
||||
|
||||
/* The size of the placed breakpoint, according to
|
||||
gdbarch_breakpoint_from_pc, when the breakpoint was inserted. This is
|
||||
generally the same as SHADOW_LEN, unless we did not need
|
||||
to read from the target to implement the memory breakpoint
|
||||
(e.g. if a remote stub handled the details). We may still
|
||||
need the size to remove the breakpoint safely. */
|
||||
int placed_size;
|
||||
};
|
||||
|
||||
/* 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 for
|
||||
the same parent breakpoint. */
|
||||
struct bp_location *next;
|
||||
|
||||
/* Pointer to the next breakpoint location, in a global
|
||||
list of all breakpoint locations. */
|
||||
struct bp_location *global_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;
|
||||
|
||||
/* Conditional. Break only if this expression's value is nonzero.
|
||||
Unlike string form of condition, which is associated with breakpoint,
|
||||
this is associated with location, since if breakpoint has several
|
||||
locations, the evaluation of expression can be different for
|
||||
different locations. */
|
||||
struct expression *cond;
|
||||
|
||||
/* This location's address is in an unloaded solib, and so this
|
||||
location should not be inserted. It will be automatically
|
||||
enabled when that solib is loaded. */
|
||||
char shlib_disabled;
|
||||
|
||||
/* Is this particular location enabled. */
|
||||
char enabled;
|
||||
|
||||
/* 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 hardware watchpoints, the size of data ad ADDRESS being watches. */
|
||||
int length;
|
||||
|
||||
/* Type of hardware watchpoint. */
|
||||
enum target_hw_bp_type watchpoint_type;
|
||||
|
||||
/* For any breakpoint type with an address, this is the section
|
||||
associated with the address. Used primarily for overlay debugging. */
|
||||
struct obj_section *section;
|
||||
|
||||
/* 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;
|
||||
|
||||
char *function_name;
|
||||
|
||||
/* Details of the placed breakpoint, when inserted. */
|
||||
struct bp_target_info target_info;
|
||||
|
||||
/* Similarly, for the breakpoint at an overlay's LMA, if necessary. */
|
||||
struct bp_target_info overlay_target_info;
|
||||
|
||||
/* In a non-stop mode, it's possible that we delete a breakpoint,
|
||||
but as we do that, some still running thread hits that breakpoint.
|
||||
For that reason, we need to keep locations belonging to deleted
|
||||
breakpoints for a bit, so that don't report unexpected SIGTRAP.
|
||||
We can't keep such locations forever, so we use a heuristic --
|
||||
after we process certain number of inferior events since
|
||||
breakpoint was deleted, we retire all locations of that breakpoint.
|
||||
This variable keeps a number of events still to go, when
|
||||
it becomes 0 this location is retired. */
|
||||
int events_till_retirement;
|
||||
};
|
||||
|
||||
/* 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 *);
|
||||
};
|
||||
|
||||
enum watchpoint_triggered
|
||||
{
|
||||
/* This watchpoint definitely did not trigger. */
|
||||
watch_triggered_no = 0,
|
||||
|
||||
/* Some hardware watchpoint triggered, and it might have been this
|
||||
one, but we do not know which it was. */
|
||||
watch_triggered_unknown,
|
||||
|
||||
/* This hardware watchpoint definitely did trigger. */
|
||||
watch_triggered_yes
|
||||
};
|
||||
|
||||
typedef struct bp_location *bp_location_p;
|
||||
DEF_VEC_P(bp_location_p);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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, or NULL
|
||||
when we do not know the value yet or the value was not
|
||||
readable. VAL is never lazy. */
|
||||
struct value *val;
|
||||
/* Nonzero if VAL is valid. If VAL_VALID is set but VAL is NULL,
|
||||
then an error occurred reading the value. */
|
||||
int val_valid;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* For hardware watchpoints, the triggered status according to the
|
||||
hardware. */
|
||||
enum watchpoint_triggered watchpoint_triggered;
|
||||
|
||||
/* 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. */
|
||||
ptid_t 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;
|
||||
|
||||
/* Is breakpoint's condition not yet parsed because we found
|
||||
no location initially so had no context to parse
|
||||
the condition in. */
|
||||
int condition_not_parsed;
|
||||
};
|
||||
|
||||
typedef struct breakpoint *breakpoint_p;
|
||||
DEF_VEC_P(breakpoint_p);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Frees any storage that is part of a bpstat.
|
||||
Does not walk the 'next' chain. */
|
||||
extern void bpstat_free (bpstat);
|
||||
|
||||
/* Clears a chain of bpstat, freeing storage
|
||||
of each. */
|
||||
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);
|
||||
|
||||
/* 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 step resume breakpoint, and keep checking. */
|
||||
BPSTAT_WHAT_STEP_RESUME,
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Put in *NUM 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.
|
||||
Return -1 if stopped at a breakpoint that has been deleted since
|
||||
we set it.
|
||||
Return 1 otherwise. */
|
||||
extern int bpstat_num (bpstat *, int *);
|
||||
|
||||
/* 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. */
|
||||
const struct bp_location *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 regular_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 struct breakpoint *set_momentary_breakpoint
|
||||
(struct symtab_and_line, struct frame_id, enum bptype);
|
||||
|
||||
extern struct breakpoint *set_momentary_breakpoint_at_pc
|
||||
(CORE_ADDR pc, enum bptype type);
|
||||
|
||||
extern void set_ignore_count (int, int, int);
|
||||
|
||||
extern void set_default_breakpoint (int, CORE_ADDR, struct symtab *, int);
|
||||
|
||||
extern void breakpoint_init_inferior (enum inf_context);
|
||||
|
||||
extern struct cleanup *make_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 void set_breakpoint (char *address, char *condition,
|
||||
int hardwareflag, int tempflag,
|
||||
int thread, int ignore_count,
|
||||
int pending);
|
||||
|
||||
extern void 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 set_longjmp_breakpoint (void);
|
||||
extern void delete_longjmp_breakpoint (int thread);
|
||||
|
||||
extern void enable_overlay_breakpoints (void);
|
||||
extern void disable_overlay_breakpoints (void);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* For script interpreters that need to define breakpoint commands
|
||||
after they've already read the commands into a struct command_line. */
|
||||
extern enum command_control_type commands_from_control_command
|
||||
(char *arg, struct command_line *cmd);
|
||||
|
||||
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 *);
|
||||
|
||||
/* Clear the "inserted" flag in all breakpoints. */
|
||||
extern void mark_breakpoints_out (void);
|
||||
|
||||
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 (void);
|
||||
|
||||
/* 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 *);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Manage a software single step breakpoint (or two). Insert may be called
|
||||
twice before remove is called. */
|
||||
extern void insert_single_step_breakpoint (CORE_ADDR);
|
||||
extern void remove_single_step_breakpoints (void);
|
||||
|
||||
/* Manage manual breakpoints, separate from the normal chain of
|
||||
breakpoints. These functions are used in murky target-specific
|
||||
ways. Please do not add more uses! */
|
||||
extern void *deprecated_insert_raw_breakpoint (CORE_ADDR);
|
||||
extern int deprecated_remove_raw_breakpoint (void *);
|
||||
|
||||
/* Check if any hardware watchpoints have triggered, according to the
|
||||
target. */
|
||||
int watchpoints_triggered (struct target_waitstatus *);
|
||||
|
||||
/* Update BUF, which is LEN bytes read from the target address MEMADDR,
|
||||
by replacing any memory breakpoints with their shadowed contents. */
|
||||
void breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr,
|
||||
LONGEST len);
|
||||
|
||||
extern int breakpoints_always_inserted_mode (void);
|
||||
|
||||
/* Called each time new event from target is processed.
|
||||
Retires previously deleted breakpoint locations that
|
||||
in our opinion won't ever trigger. */
|
||||
extern void breakpoint_retire_moribund (void);
|
||||
|
||||
#endif /* !defined (BREAKPOINT_H) */
|
||||
382
gdb/bsd-kvm.c
382
gdb/bsd-kvm.c
@@ -1,382 +0,0 @@
|
||||
/* BSD Kernel Data Access Library (libkvm) interface.
|
||||
|
||||
Copyright (C) 2004, 2005, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 "gdbthread.h"
|
||||
|
||||
#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;
|
||||
|
||||
/* This is the ptid we use while we're connected to kvm. The kvm
|
||||
target currently doesn't export any view of the running processes,
|
||||
so this represents the kernel task. */
|
||||
static ptid_t bsd_kvm_ptid;
|
||||
|
||||
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,
|
||||
write_files ? O_RDWR : 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);
|
||||
|
||||
add_thread_silent (bsd_kvm_ptid);
|
||||
inferior_ptid = bsd_kvm_ptid;
|
||||
|
||||
target_fetch_registers (get_current_regcache (), -1);
|
||||
|
||||
reinit_frame_cache ();
|
||||
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;
|
||||
}
|
||||
|
||||
inferior_ptid = null_ptid;
|
||||
delete_thread_silent (bsd_kvm_ptid);
|
||||
}
|
||||
|
||||
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 regcache *regcache, 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 (regcache, &pcb);
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_kvm_fetch_registers (struct regcache *regcache, int regnum)
|
||||
{
|
||||
struct nlist nl[2];
|
||||
|
||||
if (bsd_kvm_paddr)
|
||||
{
|
||||
bsd_kvm_fetch_pcb (regcache, 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 (regcache, (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 (regcache, 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 (regcache, 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 (get_current_regcache (), -1);
|
||||
|
||||
reinit_frame_cache ();
|
||||
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 (get_current_regcache (), -1);
|
||||
|
||||
reinit_frame_cache ();
|
||||
print_stack_frame (get_selected_frame (NULL), -1, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
bsd_kvm_thread_alive (ptid_t ptid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *
|
||||
bsd_kvm_pid_to_str (ptid_t ptid)
|
||||
{
|
||||
static char buf[64];
|
||||
xsnprintf (buf, sizeof buf, "<kvm>");
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* 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_thread_alive = bsd_kvm_thread_alive;
|
||||
bsd_kvm_ops.to_pid_to_str = bsd_kvm_pid_to_str;
|
||||
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);
|
||||
|
||||
/* Some notes on the ptid usage on this target.
|
||||
|
||||
The pid field represents the kvm inferior instance. Currently,
|
||||
we don't support multiple kvm inferiors, but we start at 1
|
||||
anyway. The lwp field is set to != 0, in case the core wants to
|
||||
refer to the whole kvm inferior with ptid(1,0,0).
|
||||
|
||||
If kvm is made to export running processes as gdb threads,
|
||||
the following form can be used:
|
||||
ptid (1, 1, 0) -> kvm inferior 1, in kernel
|
||||
ptid (1, 1, 1) -> kvm inferior 1, process 1
|
||||
ptid (1, 1, 2) -> kvm inferior 1, process 2
|
||||
ptid (1, 1, n) -> kvm inferior 1, process n
|
||||
*/
|
||||
bsd_kvm_ptid = ptid_build (1, 1, 0);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/* BSD Kernel Data Access Library (libkvm) interface.
|
||||
|
||||
Copyright (C) 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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,527 +0,0 @@
|
||||
/* BSD user-level threads support.
|
||||
|
||||
Copyright (C) 2005, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/* Cleanup due to deactivation. */
|
||||
|
||||
static void
|
||||
bsd_uthread_close (int quitting)
|
||||
{
|
||||
bsd_uthread_active = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
unpush_target (bsd_uthread_ops_hack);
|
||||
}
|
||||
|
||||
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 (struct regcache *regcache, int regnum)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
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 (regcache, 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 (regcache, regnum,
|
||||
addr + bsd_uthread_thread_ctx_offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bsd_uthread_store_registers (struct regcache *regcache, int regnum)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
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 (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 (regcache, 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);
|
||||
|
||||
/* If the process is no longer alive, there's no point in figuring
|
||||
out the thread ID. It will fail anyway. */
|
||||
if (status->kind == TARGET_WAITKIND_SIGNALLED
|
||||
|| status->kind == TARGET_WAITKIND_EXITED)
|
||||
return ptid;
|
||||
|
||||
/* 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_silent (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_close = bsd_uthread_close;
|
||||
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);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user