mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-19 06:23:36 +08:00
Add GPL copyright notices to uncopyrighted files.
Add copy of GPL.
This commit is contained in:
parent
53116e27b6
commit
ef368dac31
340
gprof/COPYING
Normal file
340
gprof/COPYING
Normal file
@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 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.
|
@ -1,3 +1,29 @@
|
||||
2000-07-24 Nick Clifton <nickc@cygnus.com>
|
||||
|
||||
* COPYING: New file: Describes GPL.
|
||||
|
||||
* basic_blocks.c: Add copyright notice.
|
||||
* basic_blocks.h: Add copyright notice.
|
||||
* call_graph.c: Add copyright notice.
|
||||
* call_graph.h: Add copyright notice.
|
||||
* cg_print.c: Add copyright notice.
|
||||
* cg_print.h: Add copyright notice.
|
||||
* corefile.c: Add copyright notice.
|
||||
* corefile.h: Add copyright notice.
|
||||
* gmon_io.c: Add copyright notice.
|
||||
* gmon_io.h: Add copyright notice.
|
||||
* gmon_out.h: Add copyright notice.
|
||||
* hist.c: Add copyright notice.
|
||||
* hist.h: Add copyright notice.
|
||||
* search_list.c: Add copyright notice.
|
||||
* search_list.h: Add copyright notice.
|
||||
* source.c: Add copyright notice.
|
||||
* source.h: Add copyright notice.
|
||||
* sym_ids.c: Add copyright notice.
|
||||
* sym_ids.h: Add copyright notice.
|
||||
* symtab.c: Add copyright notice.
|
||||
* symtab.h: Add copyright notice.
|
||||
|
||||
2000-07-05 Kenneth Block <krblock@computer.org>
|
||||
|
||||
* gprof/gprof.c: Add optional style to demangle switch
|
||||
|
@ -1,8 +1,26 @@
|
||||
/*
|
||||
* Basic-block level related code: reading/writing of basic-block info
|
||||
* to/from gmon.out; computing and formatting of basic-block related
|
||||
* statistics.
|
||||
*/
|
||||
/* basic_blocks.c - Basic-block level related code: reading/writing
|
||||
of basic-block info to/from gmon.out; computing and formatting of
|
||||
basic-block related statistics.
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "basic_blocks.h"
|
||||
@ -14,26 +32,19 @@
|
||||
#include "source.h"
|
||||
#include "sym_ids.h"
|
||||
|
||||
|
||||
/*
|
||||
* Default option values:
|
||||
*/
|
||||
/* Default option values: */
|
||||
bool bb_annotate_all_lines = FALSE;
|
||||
unsigned long bb_min_calls = 1;
|
||||
int bb_table_length = 10;
|
||||
|
||||
/*
|
||||
* Variables used to compute annotated source listing stats:
|
||||
*/
|
||||
/* Variables used to compute annotated source listing stats: */
|
||||
static long num_executable_lines;
|
||||
static long num_lines_executed;
|
||||
|
||||
|
||||
/*
|
||||
* Helper for sorting. Compares two symbols and returns result
|
||||
* such that sorting will be increasing according to filename, line
|
||||
* number, and address (in that order).
|
||||
*/
|
||||
/* Helper for sorting. Compares two symbols and returns result
|
||||
such that sorting will be increasing according to filename, line
|
||||
number, and address (in that order). */
|
||||
|
||||
static int
|
||||
DEFUN (cmp_bb, (lp, rp), const void *lp AND const void *rp)
|
||||
@ -45,36 +56,25 @@ DEFUN (cmp_bb, (lp, rp), const void *lp AND const void *rp)
|
||||
if (left->file && right->file)
|
||||
{
|
||||
r = strcmp (left->file->name, right->file->name);
|
||||
|
||||
if (r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
return r;
|
||||
|
||||
if (left->line_num != right->line_num)
|
||||
{
|
||||
return left->line_num - right->line_num;
|
||||
}
|
||||
return left->line_num - right->line_num;
|
||||
}
|
||||
|
||||
if (left->addr < right->addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
else if (left->addr > right->addr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper for sorting. Order basic blocks in decreasing number of
|
||||
* calls, ties are broken in increasing order of line numbers.
|
||||
*/
|
||||
/* Helper for sorting. Order basic blocks in decreasing number of
|
||||
calls, ties are broken in increasing order of line numbers. */
|
||||
static int
|
||||
DEFUN (cmp_ncalls, (lp, rp), const void *lp AND const void *rp)
|
||||
{
|
||||
@ -82,13 +82,9 @@ DEFUN (cmp_ncalls, (lp, rp), const void *lp AND const void *rp)
|
||||
const Sym *right = *(const Sym **) rp;
|
||||
|
||||
if (!left)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
else if (!right)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
|
||||
if (left->ncalls < right->ncalls)
|
||||
return 1;
|
||||
@ -98,10 +94,7 @@ DEFUN (cmp_ncalls, (lp, rp), const void *lp AND const void *rp)
|
||||
return left->line_num - right->line_num;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Skip over variable length string.
|
||||
*/
|
||||
/* Skip over variable length string. */
|
||||
static void
|
||||
DEFUN (fskip_string, (fp), FILE * fp)
|
||||
{
|
||||
@ -110,17 +103,13 @@ DEFUN (fskip_string, (fp), FILE * fp)
|
||||
while ((ch = fgetc (fp)) != EOF)
|
||||
{
|
||||
if (ch == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a basic-block record from file IFP. FILENAME is the name
|
||||
of file IFP and is provided for formatting error-messages only. */
|
||||
|
||||
/*
|
||||
* Read a basic-block record from file IFP. FILENAME is the name
|
||||
* of file IFP and is provided for formatting error-messages only.
|
||||
*/
|
||||
void
|
||||
DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
{
|
||||
@ -136,20 +125,18 @@ DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
}
|
||||
|
||||
nblocks = bfd_get_32 (core_bfd, (bfd_byte *) & nblocks);
|
||||
|
||||
if (gmon_file_version == 0)
|
||||
{
|
||||
fskip_string (ifp);
|
||||
}
|
||||
fskip_string (ifp);
|
||||
|
||||
for (b = 0; b < nblocks; ++b)
|
||||
{
|
||||
if (gmon_file_version == 0)
|
||||
{
|
||||
int line_num;
|
||||
/*
|
||||
* Version 0 had lots of extra stuff that we don't
|
||||
* care about anymore.
|
||||
*/
|
||||
|
||||
/* Version 0 had lots of extra stuff that we don't
|
||||
care about anymore. */
|
||||
if ((fread (&ncalls, sizeof (ncalls), 1, ifp) != 1)
|
||||
|| (fread (&addr, sizeof (addr), 1, ifp) != 1)
|
||||
|| (fskip_string (ifp), FALSE)
|
||||
@ -170,15 +157,11 @@ DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Basic-block execution counts are meaningful only if we're
|
||||
* profiling at the line-by-line level:
|
||||
*/
|
||||
/* Basic-block execution counts are meaningful only if we're
|
||||
profiling at the line-by-line level: */
|
||||
if (line_granularity)
|
||||
{
|
||||
|
||||
/* convert from target to host endianness: */
|
||||
|
||||
/* Convert from target to host endianness: */
|
||||
addr = get_vma (core_bfd, (bfd_byte *) & addr);
|
||||
ncalls = bfd_get_32 (core_bfd, (bfd_byte *) &ncalls);
|
||||
|
||||
@ -212,7 +195,7 @@ DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
{
|
||||
user_warned = TRUE;
|
||||
fprintf (stderr,
|
||||
_("%s: warning: ignoring basic-block exec counts (use -l or --line)\n"),
|
||||
_("%s: warning: ignoring basic-block exec counts (use -l or --line)\n"),
|
||||
whoami);
|
||||
}
|
||||
}
|
||||
@ -220,12 +203,9 @@ DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write all basic-blocks with non-zero counts to file OFP. FILENAME
|
||||
* is the name of OFP and is provided for producing error-messages
|
||||
* only.
|
||||
*/
|
||||
/* Write all basic-blocks with non-zero counts to file OFP. FILENAME
|
||||
is the name of OFP and is provided for producing error-messages
|
||||
only. */
|
||||
void
|
||||
DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
{
|
||||
@ -236,8 +216,7 @@ DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
Sym *sym;
|
||||
int i;
|
||||
|
||||
/* count how many non-zero blocks with have: */
|
||||
|
||||
/* Count how many non-zero blocks with have: */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
for (i = 0; i < NBBS && sym->bb_addr[i]; i++)
|
||||
@ -245,7 +224,7 @@ DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
nblocks += i;
|
||||
}
|
||||
|
||||
/* write header: */
|
||||
/* Write header: */
|
||||
bfd_put_32 (core_bfd, nblocks, (bfd_byte *) & nblocks);
|
||||
if (fwrite (&tag, sizeof (tag), 1, ofp) != 1
|
||||
|| fwrite (&nblocks, sizeof (nblocks), 1, ofp) != 1)
|
||||
@ -254,7 +233,7 @@ DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
done (1);
|
||||
}
|
||||
|
||||
/* write counts: */
|
||||
/* Write counts: */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
for (i = 0; i < NBBS && sym->bb_addr[i]; i++)
|
||||
@ -272,13 +251,11 @@ DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
/* Output basic-block statistics in a format that is easily parseable.
|
||||
Current the format is:
|
||||
|
||||
<filename>:<line-number>: (<function-name>:<bb-addr): <ncalls> */
|
||||
|
||||
/*
|
||||
* Output basic-block statistics in a format that is easily parseable.
|
||||
* Current the format is:
|
||||
*
|
||||
* <filename>:<line-number>: (<function-name>:<bb-addr): <ncalls>
|
||||
*/
|
||||
void
|
||||
DEFUN_VOID (print_exec_counts)
|
||||
{
|
||||
@ -286,25 +263,19 @@ DEFUN_VOID (print_exec_counts)
|
||||
int i, j, len;
|
||||
|
||||
if (first_output)
|
||||
{
|
||||
first_output = FALSE;
|
||||
}
|
||||
first_output = FALSE;
|
||||
else
|
||||
{
|
||||
printf ("\f\n");
|
||||
}
|
||||
|
||||
/* sort basic-blocks according to function name and line number: */
|
||||
printf ("\f\n");
|
||||
|
||||
/* Sort basic-blocks according to function name and line number: */
|
||||
sorted_bbs = (Sym **) xmalloc (symtab.len * sizeof (sorted_bbs[0]));
|
||||
len = 0;
|
||||
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
/*
|
||||
* Accept symbol if it's in the INCL_EXEC table
|
||||
* or there is no INCL_EXEC table
|
||||
* and it does not appear in the EXCL_EXEC table.
|
||||
*/
|
||||
/* Accept symbol if it's in the INCL_EXEC table
|
||||
or there is no INCL_EXEC table
|
||||
and it does not appear in the EXCL_EXEC table. */
|
||||
if (sym_lookup (&syms[INCL_EXEC], sym->addr)
|
||||
|| (syms[INCL_EXEC].len == 0
|
||||
&& !sym_lookup (&syms[EXCL_EXEC], sym->addr)))
|
||||
@ -312,9 +283,10 @@ DEFUN_VOID (print_exec_counts)
|
||||
sorted_bbs[len++] = sym;
|
||||
}
|
||||
}
|
||||
|
||||
qsort (sorted_bbs, len, sizeof (sorted_bbs[0]), cmp_bb);
|
||||
|
||||
/* output basic-blocks: */
|
||||
/* Output basic-blocks: */
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
@ -325,6 +297,7 @@ DEFUN_VOID (print_exec_counts)
|
||||
sym->file ? sym->file->name : _("<unknown>"), sym->line_num,
|
||||
sym->name, (unsigned long) sym->addr, sym->ncalls);
|
||||
}
|
||||
|
||||
for (j = 0; j < NBBS && sym->bb_addr[j]; j ++)
|
||||
{
|
||||
if (sym->bb_calls[j] > 0 || ! ignore_zeros)
|
||||
@ -340,17 +313,15 @@ DEFUN_VOID (print_exec_counts)
|
||||
free (sorted_bbs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper for bb_annotated_source: format annotation containing
|
||||
* number of line executions. Depends on being called on each
|
||||
* line of a file in sequential order.
|
||||
*
|
||||
* Global variable bb_annotate_all_lines enables execution count
|
||||
* compression (counts are supressed if identical to the last one)
|
||||
* and prints counts on all executed lines. Otherwise, print
|
||||
* all basic-block execution counts exactly once on the line
|
||||
* that starts the basic-block.
|
||||
*/
|
||||
/* Helper for bb_annotated_source: format annotation containing
|
||||
number of line executions. Depends on being called on each
|
||||
line of a file in sequential order.
|
||||
|
||||
Global variable bb_annotate_all_lines enables execution count
|
||||
compression (counts are supressed if identical to the last one)
|
||||
and prints counts on all executed lines. Otherwise, print
|
||||
all basic-block execution counts exactly once on the line
|
||||
that starts the basic-block. */
|
||||
|
||||
static void
|
||||
DEFUN (annotate_with_count, (buf, width, line_num, arg),
|
||||
@ -363,10 +334,10 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg),
|
||||
unsigned long last_print = (unsigned long) -1;
|
||||
|
||||
b = NULL;
|
||||
|
||||
if (line_num <= sf->num_lines)
|
||||
{
|
||||
b = sf->line[line_num - 1];
|
||||
}
|
||||
b = sf->line[line_num - 1];
|
||||
|
||||
if (!b)
|
||||
{
|
||||
for (i = 0; i < width; i++)
|
||||
@ -390,13 +361,11 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg),
|
||||
ncalls_set = 0;
|
||||
|
||||
/* If this is a function entry point, label the line no matter what.
|
||||
* Otherwise, we're in the middle of a function, so check to see
|
||||
* if the first basic-block address is larger than the starting
|
||||
* address of the line. If so, then this line begins with a
|
||||
* a portion of the previous basic-block, so print that prior
|
||||
* execution count (if bb_annotate_all_lines is set).
|
||||
*/
|
||||
|
||||
Otherwise, we're in the middle of a function, so check to see
|
||||
if the first basic-block address is larger than the starting
|
||||
address of the line. If so, then this line begins with a
|
||||
a portion of the previous basic-block, so print that prior
|
||||
execution count (if bb_annotate_all_lines is set). */
|
||||
if (b->is_func)
|
||||
{
|
||||
sprintf (p, "%lu", b->ncalls);
|
||||
@ -417,9 +386,8 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg),
|
||||
}
|
||||
|
||||
/* Loop through all of this line's basic-blocks. For each one,
|
||||
* update last_count, then compress sequential identical counts
|
||||
* (if bb_annotate_all_lines) and print the execution count.
|
||||
*/
|
||||
update last_count, then compress sequential identical counts
|
||||
(if bb_annotate_all_lines) and print the execution count. */
|
||||
|
||||
for (i = 0; i < NBBS && b->bb_addr[i]; i++)
|
||||
{
|
||||
@ -432,9 +400,7 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg),
|
||||
ncalls += last_count;
|
||||
|
||||
if (bb_annotate_all_lines && last_count == last_print)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
if (p > tmpbuf)
|
||||
*p++ = ',';
|
||||
@ -445,11 +411,10 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg),
|
||||
}
|
||||
|
||||
/* We're done. If nothing has been printed on this line,
|
||||
* print the last execution count (bb_annotate_all_lines),
|
||||
* which could be from either a previous line (if there were
|
||||
* no BBs on this line), or from this line (if all our BB
|
||||
* counts were compressed out because they were identical).
|
||||
*/
|
||||
print the last execution count (bb_annotate_all_lines),
|
||||
which could be from either a previous line (if there were
|
||||
no BBs on this line), or from this line (if all our BB
|
||||
counts were compressed out because they were identical). */
|
||||
|
||||
if (bb_annotate_all_lines && p == tmpbuf)
|
||||
{
|
||||
@ -497,11 +462,10 @@ DEFUN (annotate_with_count, (buf, width, line_num, arg),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Annotate the files named in SOURCE_FILES with basic-block statistics
|
||||
* (execution counts). After each source files, a few statistics
|
||||
* regarding that source file are printed.
|
||||
*/
|
||||
/* Annotate the files named in SOURCE_FILES with basic-block statistics
|
||||
(execution counts). After each source files, a few statistics
|
||||
regarding that source file are printed. */
|
||||
|
||||
void
|
||||
DEFUN_VOID (print_annotated_source)
|
||||
{
|
||||
@ -510,18 +474,14 @@ DEFUN_VOID (print_annotated_source)
|
||||
int i, table_len;
|
||||
FILE *ofp;
|
||||
|
||||
/*
|
||||
* Find maximum line number for each source file that user is
|
||||
* interested in:
|
||||
*/
|
||||
/* Find maximum line number for each source file that user is
|
||||
interested in: */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
/*
|
||||
* Accept symbol if it's file is known, its line number is
|
||||
* bigger than anything we have seen for that file so far and
|
||||
* if it's in the INCL_ANNO table or there is no INCL_ANNO
|
||||
* table and it does not appear in the EXCL_ANNO table.
|
||||
*/
|
||||
/* Accept symbol if it's file is known, its line number is
|
||||
bigger than anything we have seen for that file so far and
|
||||
if it's in the INCL_ANNO table or there is no INCL_ANNO
|
||||
table and it does not appear in the EXCL_ANNO table. */
|
||||
if (sym->file && sym->line_num > sym->file->num_lines
|
||||
&& (sym_lookup (&syms[INCL_ANNO], sym->addr)
|
||||
|| (syms[INCL_ANNO].len == 0
|
||||
@ -531,8 +491,7 @@ DEFUN_VOID (print_annotated_source)
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate line descriptors: */
|
||||
|
||||
/* Allocate line descriptors: */
|
||||
for (sf = first_src_file; sf; sf = sf->next)
|
||||
{
|
||||
if (sf->num_lines > 0)
|
||||
@ -542,8 +501,7 @@ DEFUN_VOID (print_annotated_source)
|
||||
}
|
||||
}
|
||||
|
||||
/* count executions per line: */
|
||||
|
||||
/* Count executions per line: */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
if (sym->file && sym->file->num_lines
|
||||
@ -553,19 +511,20 @@ DEFUN_VOID (print_annotated_source)
|
||||
{
|
||||
sym->file->ncalls += sym->ncalls;
|
||||
line_stats = sym->file->line[sym->line_num - 1];
|
||||
|
||||
if (!line_stats)
|
||||
{
|
||||
/* common case has at most one basic-block per source line: */
|
||||
/* Common case has at most one basic-block per source line: */
|
||||
sym->file->line[sym->line_num - 1] = sym;
|
||||
}
|
||||
else if (!line_stats->addr)
|
||||
{
|
||||
/* sym is the 3rd .. nth basic block for this line: */
|
||||
/* sym is the 3rd .. nth basic block for this line: */
|
||||
line_stats->ncalls += sym->ncalls;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* sym is the second basic block for this line */
|
||||
/* sym is the second basic block for this line. */
|
||||
new_line = (Sym *) xmalloc (sizeof (*new_line));
|
||||
*new_line = *line_stats;
|
||||
new_line->addr = 0;
|
||||
@ -575,41 +534,37 @@ DEFUN_VOID (print_annotated_source)
|
||||
}
|
||||
}
|
||||
|
||||
/* plod over source files, annotating them: */
|
||||
|
||||
/* Plod over source files, annotating them: */
|
||||
for (sf = first_src_file; sf; sf = sf->next)
|
||||
{
|
||||
if (!sf->num_lines || (ignore_zeros && sf->ncalls == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
num_executable_lines = num_lines_executed = 0;
|
||||
|
||||
ofp = annotate_source (sf, 16, annotate_with_count, sf);
|
||||
if (!ofp)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
if (bb_table_length > 0)
|
||||
{
|
||||
fprintf (ofp, _("\n\nTop %d Lines:\n\n Line Count\n\n"),
|
||||
bb_table_length);
|
||||
|
||||
/* abuse line arrays---it's not needed anymore: */
|
||||
/* Abuse line arrays---it's not needed anymore: */
|
||||
qsort (sf->line, sf->num_lines, sizeof (sf->line[0]), cmp_ncalls);
|
||||
table_len = bb_table_length;
|
||||
|
||||
if (table_len > sf->num_lines)
|
||||
{
|
||||
table_len = sf->num_lines;
|
||||
}
|
||||
table_len = sf->num_lines;
|
||||
|
||||
for (i = 0; i < table_len; ++i)
|
||||
{
|
||||
sym = sf->line[i];
|
||||
|
||||
if (!sym || sym->ncalls == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf (ofp, "%9d %10lu\n", sym->line_num, sym->ncalls);
|
||||
}
|
||||
}
|
||||
@ -631,9 +586,8 @@ DEFUN_VOID (print_annotated_source)
|
||||
num_executable_lines
|
||||
? (double) sf->ncalls / (double) num_executable_lines
|
||||
: 0.0);
|
||||
|
||||
if (ofp != stdout)
|
||||
{
|
||||
fclose (ofp);
|
||||
}
|
||||
fclose (ofp);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,22 @@
|
||||
/* basic_blocks.h
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef basic_blocks_h
|
||||
#define basic_blocks_h
|
||||
|
||||
@ -6,18 +25,14 @@
|
||||
#include "source.h"
|
||||
#include "symtab.h"
|
||||
|
||||
/*
|
||||
* Options:
|
||||
*/
|
||||
extern bool bb_annotate_all_lines; /* force annotation of all lines? */
|
||||
extern int bb_table_length; /* length of most-used bb table */
|
||||
extern unsigned long bb_min_calls; /* minimum execution count */
|
||||
|
||||
extern void bb_read_rec PARAMS ((FILE * ifp, const char *filename));
|
||||
extern void bb_write_blocks PARAMS ((FILE * ofp, const char *filename));
|
||||
extern void bb_create_syms PARAMS ((void));
|
||||
|
||||
extern void print_annotated_source PARAMS ((void));
|
||||
extern void print_exec_counts PARAMS ((void));
|
||||
/* Options: */
|
||||
extern bool bb_annotate_all_lines; /* Force annotation of all lines? */
|
||||
extern int bb_table_length; /* Length of most-used bb table. */
|
||||
extern unsigned long bb_min_calls; /* Minimum execution count. */
|
||||
|
||||
extern void bb_read_rec PARAMS ((FILE *, const char *));
|
||||
extern void bb_write_blocks PARAMS ((FILE *, const char *));
|
||||
extern void bb_create_syms PARAMS ((void));
|
||||
extern void print_annotated_source PARAMS ((void));
|
||||
extern void print_exec_counts PARAMS ((void));
|
||||
#endif /* basic_blocks_h */
|
||||
|
@ -1,3 +1,24 @@
|
||||
/* call_graph.c - Create call graphs.
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include "cg_arcs.h"
|
||||
#include "call_graph.h"
|
||||
#include "corefile.h"
|
||||
@ -28,17 +49,14 @@ DEFUN (cg_tally, (from_pc, self_pc, count),
|
||||
|
||||
For normal profiling, is_func will be set on all symbols, so this
|
||||
code will do nothing. */
|
||||
|
||||
while (child >= symtab.base && ! child->is_func)
|
||||
--child;
|
||||
|
||||
if (child < symtab.base)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Keep arc if it is on INCL_ARCS table or if the INCL_ARCS table
|
||||
* is empty and it is not in the EXCL_ARCS table.
|
||||
*/
|
||||
/* Keep arc if it is on INCL_ARCS table or if the INCL_ARCS table
|
||||
is empty and it is not in the EXCL_ARCS table. */
|
||||
if (sym_id_arc_is_present (&syms[INCL_ARCS], parent, child)
|
||||
|| (syms[INCL_ARCS].len == 0
|
||||
&& !sym_id_arc_is_present (&syms[EXCL_ARCS], parent, child)))
|
||||
@ -51,13 +69,11 @@ DEFUN (cg_tally, (from_pc, self_pc, count),
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a record from file IFP describing an arc in the function
|
||||
call-graph and the count of how many times the arc has been
|
||||
traversed. FILENAME is the name of file IFP and is provided
|
||||
for formatting error-messages only. */
|
||||
|
||||
/*
|
||||
* Read a record from file IFP describing an arc in the function
|
||||
* call-graph and the count of how many times the arc has been
|
||||
* traversed. FILENAME is the name of file IFP and is provided
|
||||
* for formatting error-messages only.
|
||||
*/
|
||||
void
|
||||
DEFUN (cg_read_rec, (ifp, filename), FILE * ifp AND CONST char *filename)
|
||||
{
|
||||
@ -71,22 +87,21 @@ DEFUN (cg_read_rec, (ifp, filename), FILE * ifp AND CONST char *filename)
|
||||
whoami, filename);
|
||||
done (1);
|
||||
}
|
||||
|
||||
from_pc = get_vma (core_bfd, (bfd_byte *) arc.from_pc);
|
||||
self_pc = get_vma (core_bfd, (bfd_byte *) arc.self_pc);
|
||||
count = bfd_get_32 (core_bfd, (bfd_byte *) arc.count);
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf ("[cg_read_rec] frompc 0x%lx selfpc 0x%lx count %lu\n",
|
||||
(unsigned long) from_pc, (unsigned long) self_pc, count));
|
||||
/* add this arc: */
|
||||
/* Add this arc: */
|
||||
cg_tally (from_pc, self_pc, count);
|
||||
}
|
||||
|
||||
/* Write all the arcs in the call-graph to file OFP. FILENAME is
|
||||
the name of OFP and is provided for formatting error-messages
|
||||
only. */
|
||||
|
||||
/*
|
||||
* Write all the arcs in the call-graph to file OFP. FILENAME is
|
||||
* the name of OFP and is provided for formatting error-messages
|
||||
* only.
|
||||
*/
|
||||
void
|
||||
DEFUN (cg_write_arcs, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
{
|
||||
|
@ -1,3 +1,23 @@
|
||||
/* call_graph.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef call_graph_h
|
||||
#define call_graph_h
|
||||
|
||||
@ -5,9 +25,8 @@
|
||||
#include "gprof.h"
|
||||
#include "symtab.h"
|
||||
|
||||
extern void cg_tally PARAMS ((bfd_vma from_pc, bfd_vma self_pc,
|
||||
unsigned long count));
|
||||
extern void cg_read_rec PARAMS ((FILE * ifp, const char *filename));
|
||||
extern void cg_write_arcs PARAMS ((FILE * ofp, const char *filename));
|
||||
extern void cg_tally PARAMS ((bfd_vma, bfd_vma, unsigned long));
|
||||
extern void cg_read_rec PARAMS ((FILE *, const char *));
|
||||
extern void cg_write_arcs PARAMS ((FILE *, const char *));
|
||||
|
||||
#endif /* call_graph_h */
|
||||
|
411
gprof/cg_print.c
411
gprof/cg_print.c
@ -1,12 +1,31 @@
|
||||
/* cg_print.c - Print routines for displaying call graphs.
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include "libiberty.h"
|
||||
#include "cg_arcs.h"
|
||||
#include "cg_print.h"
|
||||
#include "hist.h"
|
||||
#include "utils.h"
|
||||
|
||||
/*
|
||||
* Return value of comparison functions used to sort tables:
|
||||
*/
|
||||
/* Return value of comparison functions used to sort tables. */
|
||||
#define LESSTHAN -1
|
||||
#define EQUALTO 0
|
||||
#define GREATERTHAN 1
|
||||
@ -14,7 +33,7 @@
|
||||
static void order_and_dump_functions_by_arcs PARAMS ((Arc **, unsigned long,
|
||||
int, Arc **,
|
||||
unsigned long *));
|
||||
/* declarations of automatically generated functions to output blurbs: */
|
||||
/* Declarations of automatically generated functions to output blurbs. */
|
||||
extern void bsd_callg_blurb PARAMS ((FILE * fp));
|
||||
extern void fsf_callg_blurb PARAMS ((FILE * fp));
|
||||
|
||||
@ -25,39 +44,32 @@ static void
|
||||
DEFUN_VOID (print_header)
|
||||
{
|
||||
if (first_output)
|
||||
{
|
||||
first_output = FALSE;
|
||||
}
|
||||
first_output = FALSE;
|
||||
else
|
||||
{
|
||||
printf ("\f\n");
|
||||
}
|
||||
printf ("\f\n");
|
||||
|
||||
if (!bsd_style_output)
|
||||
{
|
||||
if (print_descriptions)
|
||||
{
|
||||
printf (_("\t\t Call graph (explanation follows)\n\n"));
|
||||
}
|
||||
printf (_("\t\t Call graph (explanation follows)\n\n"));
|
||||
else
|
||||
{
|
||||
printf (_("\t\t\tCall graph\n\n"));
|
||||
}
|
||||
printf (_("\t\t\tCall graph\n\n"));
|
||||
}
|
||||
|
||||
printf (_("\ngranularity: each sample hit covers %ld byte(s)"),
|
||||
(long) hist_scale * sizeof (UNIT));
|
||||
|
||||
if (print_time > 0.0)
|
||||
{
|
||||
printf (_(" for %.2f%% of %.2f seconds\n\n"),
|
||||
100.0 / print_time, print_time / hz);
|
||||
}
|
||||
printf (_(" for %.2f%% of %.2f seconds\n\n"),
|
||||
100.0 / print_time, print_time / hz);
|
||||
else
|
||||
{
|
||||
printf (_(" no time propagated\n\n"));
|
||||
/*
|
||||
* This doesn't hurt, since all the numerators will be 0.0:
|
||||
*/
|
||||
|
||||
/* This doesn't hurt, since all the numerators will be 0.0. */
|
||||
print_time = 1.0;
|
||||
}
|
||||
|
||||
if (bsd_style_output)
|
||||
{
|
||||
printf ("%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s %-8.8s\n",
|
||||
@ -75,10 +87,8 @@ DEFUN_VOID (print_header)
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a cycle header. */
|
||||
|
||||
/*
|
||||
* Print a cycle header.
|
||||
*/
|
||||
static void
|
||||
DEFUN (print_cycle, (cyc), Sym * cyc)
|
||||
{
|
||||
@ -90,22 +100,18 @@ DEFUN (print_cycle, (cyc), Sym * cyc)
|
||||
: "%-6.6s %5.1f %7.2f %7.2f %7lu", buf,
|
||||
100 * (cyc->cg.prop.self + cyc->cg.prop.child) / print_time,
|
||||
cyc->cg.prop.self / hz, cyc->cg.prop.child / hz, cyc->ncalls);
|
||||
|
||||
if (cyc->cg.self_calls != 0)
|
||||
{
|
||||
printf ("+%-7lu", cyc->cg.self_calls);
|
||||
}
|
||||
printf ("+%-7lu", cyc->cg.self_calls);
|
||||
else
|
||||
{
|
||||
printf (" %7.7s", "");
|
||||
}
|
||||
printf (" %7.7s", "");
|
||||
|
||||
printf (_(" <cycle %d as a whole> [%d]\n"), cyc->cg.cyc.num, cyc->cg.index);
|
||||
}
|
||||
|
||||
/* Compare LEFT and RIGHT membmer. Major comparison key is
|
||||
CG.PROP.SELF+CG.PROP.CHILD, secondary key is NCALLS+CG.SELF_CALLS. */
|
||||
|
||||
/*
|
||||
* Compare LEFT and RIGHT membmer. Major comparison key is
|
||||
* CG.PROP.SELF+CG.PROP.CHILD, secondary key is NCALLS+CG.SELF_CALLS.
|
||||
*/
|
||||
static int
|
||||
DEFUN (cmp_member, (left, right), Sym * left AND Sym * right)
|
||||
{
|
||||
@ -115,64 +121,56 @@ DEFUN (cmp_member, (left, right), Sym * left AND Sym * right)
|
||||
unsigned long right_calls = right->ncalls + right->cg.self_calls;
|
||||
|
||||
if (left_time > right_time)
|
||||
{
|
||||
return GREATERTHAN;
|
||||
}
|
||||
return GREATERTHAN;
|
||||
|
||||
if (left_time < right_time)
|
||||
{
|
||||
return LESSTHAN;
|
||||
}
|
||||
return LESSTHAN;
|
||||
|
||||
if (left_calls > right_calls)
|
||||
{
|
||||
return GREATERTHAN;
|
||||
}
|
||||
return GREATERTHAN;
|
||||
|
||||
if (left_calls < right_calls)
|
||||
{
|
||||
return LESSTHAN;
|
||||
}
|
||||
return LESSTHAN;
|
||||
|
||||
return EQUALTO;
|
||||
}
|
||||
|
||||
/* Sort members of a cycle. */
|
||||
|
||||
/*
|
||||
* Sort members of a cycle.
|
||||
*/
|
||||
static void
|
||||
DEFUN (sort_members, (cyc), Sym * cyc)
|
||||
{
|
||||
Sym *todo, *doing, *prev;
|
||||
/*
|
||||
* Detach cycle members from cyclehead, and insertion sort them
|
||||
* back on.
|
||||
*/
|
||||
|
||||
/* Detach cycle members from cyclehead,
|
||||
and insertion sort them back on. */
|
||||
todo = cyc->cg.cyc.next;
|
||||
cyc->cg.cyc.next = 0;
|
||||
|
||||
for (doing = todo; doing && doing->cg.cyc.next; doing = todo)
|
||||
{
|
||||
todo = doing->cg.cyc.next;
|
||||
|
||||
for (prev = cyc; prev->cg.cyc.next; prev = prev->cg.cyc.next)
|
||||
{
|
||||
if (cmp_member (doing, prev->cg.cyc.next) == GREATERTHAN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
doing->cg.cyc.next = prev->cg.cyc.next;
|
||||
prev->cg.cyc.next = doing;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the members of a cycle. */
|
||||
|
||||
/*
|
||||
* Print the members of a cycle.
|
||||
*/
|
||||
static void
|
||||
DEFUN (print_members, (cyc), Sym * cyc)
|
||||
{
|
||||
Sym *member;
|
||||
|
||||
sort_members (cyc);
|
||||
|
||||
for (member = cyc->cg.cyc.next; member; member = member->cg.cyc.next)
|
||||
{
|
||||
printf (bsd_style_output
|
||||
@ -180,30 +178,26 @@ DEFUN (print_members, (cyc), Sym * cyc)
|
||||
: "%6.6s %5.5s %7.2f %7.2f %7lu",
|
||||
"", "", member->cg.prop.self / hz, member->cg.prop.child / hz,
|
||||
member->ncalls);
|
||||
|
||||
if (member->cg.self_calls != 0)
|
||||
{
|
||||
printf ("+%-7lu", member->cg.self_calls);
|
||||
}
|
||||
printf ("+%-7lu", member->cg.self_calls);
|
||||
else
|
||||
{
|
||||
printf (" %7.7s", "");
|
||||
}
|
||||
printf (" %7.7s", "");
|
||||
|
||||
printf (" ");
|
||||
print_name (member);
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare two arcs to/from the same child/parent.
|
||||
- if one arc is a self arc, it's least.
|
||||
- if one arc is within a cycle, it's less than.
|
||||
- if both arcs are within a cycle, compare arc counts.
|
||||
- if neither arc is within a cycle, compare with
|
||||
time + child_time as major key
|
||||
arc count as minor key. */
|
||||
|
||||
/*
|
||||
* Compare two arcs to/from the same child/parent.
|
||||
* - if one arc is a self arc, it's least.
|
||||
* - if one arc is within a cycle, it's less than.
|
||||
* - if both arcs are within a cycle, compare arc counts.
|
||||
* - if neither arc is within a cycle, compare with
|
||||
* time + child_time as major key
|
||||
* arc count as minor key
|
||||
*/
|
||||
static int
|
||||
DEFUN (cmp_arc, (left, right), Arc * left AND Arc * right)
|
||||
{
|
||||
@ -228,69 +222,62 @@ DEFUN (cmp_arc, (left, right), Arc * left AND Arc * right)
|
||||
right->count, right_child->ncalls);
|
||||
printf ("\n");
|
||||
);
|
||||
|
||||
if (left_parent == left_child)
|
||||
{
|
||||
return LESSTHAN; /* left is a self call */
|
||||
}
|
||||
return LESSTHAN; /* Left is a self call. */
|
||||
|
||||
if (right_parent == right_child)
|
||||
{
|
||||
return GREATERTHAN; /* right is a self call */
|
||||
}
|
||||
return GREATERTHAN; /* Right is a self call. */
|
||||
|
||||
if (left_parent->cg.cyc.num != 0 && left_child->cg.cyc.num != 0
|
||||
&& left_parent->cg.cyc.num == left_child->cg.cyc.num)
|
||||
{
|
||||
/* left is a call within a cycle */
|
||||
/* Left is a call within a cycle. */
|
||||
if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0
|
||||
&& right_parent->cg.cyc.num == right_child->cg.cyc.num)
|
||||
{
|
||||
/* right is a call within the cycle, too */
|
||||
/* Right is a call within the cycle, too. */
|
||||
if (left->count < right->count)
|
||||
{
|
||||
return LESSTHAN;
|
||||
}
|
||||
return LESSTHAN;
|
||||
|
||||
if (left->count > right->count)
|
||||
{
|
||||
return GREATERTHAN;
|
||||
}
|
||||
return GREATERTHAN;
|
||||
|
||||
return EQUALTO;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* right isn't a call within the cycle */
|
||||
/* Right isn't a call within the cycle. */
|
||||
return LESSTHAN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* left isn't a call within a cycle */
|
||||
/* Left isn't a call within a cycle. */
|
||||
if (right_parent->cg.cyc.num != 0 && right_child->cg.cyc.num != 0
|
||||
&& right_parent->cg.cyc.num == right_child->cg.cyc.num)
|
||||
{
|
||||
/* right is a call within a cycle */
|
||||
/* Right is a call within a cycle. */
|
||||
return GREATERTHAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* neither is a call within a cycle */
|
||||
/* Neither is a call within a cycle. */
|
||||
left_time = left->time + left->child_time;
|
||||
right_time = right->time + right->child_time;
|
||||
|
||||
if (left_time < right_time)
|
||||
{
|
||||
return LESSTHAN;
|
||||
}
|
||||
return LESSTHAN;
|
||||
|
||||
if (left_time > right_time)
|
||||
{
|
||||
return GREATERTHAN;
|
||||
}
|
||||
return GREATERTHAN;
|
||||
|
||||
if (left->count < right->count)
|
||||
{
|
||||
return LESSTHAN;
|
||||
}
|
||||
return LESSTHAN;
|
||||
|
||||
if (left->count > right->count)
|
||||
{
|
||||
return GREATERTHAN;
|
||||
}
|
||||
return GREATERTHAN;
|
||||
|
||||
return EQUALTO;
|
||||
}
|
||||
}
|
||||
@ -302,32 +289,30 @@ DEFUN (sort_parents, (child), Sym * child)
|
||||
{
|
||||
Arc *arc, *detached, sorted, *prev;
|
||||
|
||||
/*
|
||||
* Unlink parents from child, then insertion sort back on to
|
||||
* sorted's parents.
|
||||
* *arc the arc you have detached and are inserting.
|
||||
* *detached the rest of the arcs to be sorted.
|
||||
* sorted arc list onto which you insertion sort.
|
||||
* *prev arc before the arc you are comparing.
|
||||
*/
|
||||
/* Unlink parents from child, then insertion sort back on to
|
||||
sorted's parents.
|
||||
*arc the arc you have detached and are inserting.
|
||||
*detached the rest of the arcs to be sorted.
|
||||
sorted arc list onto which you insertion sort.
|
||||
*prev arc before the arc you are comparing. */
|
||||
sorted.next_parent = 0;
|
||||
|
||||
for (arc = child->cg.parents; arc; arc = detached)
|
||||
{
|
||||
detached = arc->next_parent;
|
||||
|
||||
/* consider *arc as disconnected; insert it into sorted: */
|
||||
/* Consider *arc as disconnected; insert it into sorted. */
|
||||
for (prev = &sorted; prev->next_parent; prev = prev->next_parent)
|
||||
{
|
||||
if (cmp_arc (arc, prev->next_parent) != GREATERTHAN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
arc->next_parent = prev->next_parent;
|
||||
prev->next_parent = arc;
|
||||
}
|
||||
|
||||
/* reattach sorted arcs to child: */
|
||||
/* Reattach sorted arcs to child. */
|
||||
child->cg.parents = sorted.next_parent;
|
||||
}
|
||||
|
||||
@ -340,13 +325,10 @@ DEFUN (print_parents, (child), Sym * child)
|
||||
Sym *cycle_head;
|
||||
|
||||
if (child->cg.cyc.head != 0)
|
||||
{
|
||||
cycle_head = child->cg.cyc.head;
|
||||
}
|
||||
cycle_head = child->cg.cyc.head;
|
||||
else
|
||||
{
|
||||
cycle_head = child;
|
||||
}
|
||||
cycle_head = child;
|
||||
|
||||
if (!child->cg.parents)
|
||||
{
|
||||
printf (bsd_style_output
|
||||
@ -355,14 +337,16 @@ DEFUN (print_parents, (child), Sym * child)
|
||||
"", "", "", "", "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
sort_parents (child);
|
||||
|
||||
for (arc = child->cg.parents; arc; arc = arc->next_parent)
|
||||
{
|
||||
parent = arc->parent;
|
||||
if (child == parent || (child->cg.cyc.num != 0
|
||||
&& parent->cg.cyc.num == child->cg.cyc.num))
|
||||
{
|
||||
/* selfcall or call among siblings: */
|
||||
/* Selfcall or call among siblings. */
|
||||
printf (bsd_style_output
|
||||
? "%6.6s %5.5s %7.7s %11.11s %7lu %7.7s "
|
||||
: "%6.6s %5.5s %7.7s %7.7s %7lu %7.7s ",
|
||||
@ -373,7 +357,7 @@ DEFUN (print_parents, (child), Sym * child)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* regular parent of child: */
|
||||
/* Regular parent of child. */
|
||||
printf (bsd_style_output
|
||||
? "%6.6s %5.5s %7.2f %11.2f %7lu/%-7lu "
|
||||
: "%6.6s %5.5s %7.2f %7.2f %7lu/%-7lu ",
|
||||
@ -391,32 +375,31 @@ static void
|
||||
DEFUN (sort_children, (parent), Sym * parent)
|
||||
{
|
||||
Arc *arc, *detached, sorted, *prev;
|
||||
/*
|
||||
* Unlink children from parent, then insertion sort back on to
|
||||
* sorted's children.
|
||||
* *arc the arc you have detached and are inserting.
|
||||
* *detached the rest of the arcs to be sorted.
|
||||
* sorted arc list onto which you insertion sort.
|
||||
* *prev arc before the arc you are comparing.
|
||||
*/
|
||||
|
||||
/* Unlink children from parent, then insertion sort back on to
|
||||
sorted's children.
|
||||
*arc the arc you have detached and are inserting.
|
||||
*detached the rest of the arcs to be sorted.
|
||||
sorted arc list onto which you insertion sort.
|
||||
*prev arc before the arc you are comparing. */
|
||||
sorted.next_child = 0;
|
||||
|
||||
for (arc = parent->cg.children; arc; arc = detached)
|
||||
{
|
||||
detached = arc->next_child;
|
||||
|
||||
/* consider *arc as disconnected; insert it into sorted: */
|
||||
/* Consider *arc as disconnected; insert it into sorted. */
|
||||
for (prev = &sorted; prev->next_child; prev = prev->next_child)
|
||||
{
|
||||
if (cmp_arc (arc, prev->next_child) != LESSTHAN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
arc->next_child = prev->next_child;
|
||||
prev->next_child = arc;
|
||||
}
|
||||
|
||||
/* reattach sorted children to parent: */
|
||||
/* Reattach sorted children to parent. */
|
||||
parent->cg.children = sorted.next_child;
|
||||
}
|
||||
|
||||
@ -429,13 +412,14 @@ DEFUN (print_children, (parent), Sym * parent)
|
||||
|
||||
sort_children (parent);
|
||||
arc = parent->cg.children;
|
||||
|
||||
for (arc = parent->cg.children; arc; arc = arc->next_child)
|
||||
{
|
||||
child = arc->child;
|
||||
if (child == parent || (child->cg.cyc.num != 0
|
||||
&& child->cg.cyc.num == parent->cg.cyc.num))
|
||||
{
|
||||
/* self call or call to sibling: */
|
||||
/* Self call or call to sibling. */
|
||||
printf (bsd_style_output
|
||||
? "%6.6s %5.5s %7.7s %11.11s %7lu %7.7s "
|
||||
: "%6.6s %5.5s %7.7s %7.7s %7lu %7.7s ",
|
||||
@ -445,7 +429,7 @@ DEFUN (print_children, (parent), Sym * parent)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* regular child of parent: */
|
||||
/* Regular child of parent. */
|
||||
printf (bsd_style_output
|
||||
? "%6.6s %5.5s %7.2f %11.2f %7lu/%-7lu "
|
||||
: "%6.6s %5.5s %7.2f %7.2f %7lu/%-7lu ",
|
||||
@ -470,30 +454,28 @@ DEFUN (print_line, (np), Sym * np)
|
||||
: "%-6.6s %5.1f %7.2f %7.2f", buf,
|
||||
100 * (np->cg.prop.self + np->cg.prop.child) / print_time,
|
||||
np->cg.prop.self / hz, np->cg.prop.child / hz);
|
||||
|
||||
if ((np->ncalls + np->cg.self_calls) != 0)
|
||||
{
|
||||
printf (" %7lu", np->ncalls);
|
||||
|
||||
if (np->cg.self_calls != 0)
|
||||
{
|
||||
printf ("+%-7lu ", np->cg.self_calls);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" %7.7s ", "");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" %7.7s %7.7s ", "", "");
|
||||
}
|
||||
|
||||
print_name (np);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print dynamic call graph.
|
||||
*/
|
||||
/* Print dynamic call graph. */
|
||||
|
||||
void
|
||||
DEFUN (cg_print, (timesortsym), Sym ** timesortsym)
|
||||
{
|
||||
@ -501,26 +483,24 @@ DEFUN (cg_print, (timesortsym), Sym ** timesortsym)
|
||||
Sym *parent;
|
||||
|
||||
if (print_descriptions && bsd_style_output)
|
||||
{
|
||||
bsd_callg_blurb (stdout);
|
||||
}
|
||||
bsd_callg_blurb (stdout);
|
||||
|
||||
print_header ();
|
||||
|
||||
for (index = 0; index < symtab.len + num_cycles; ++index)
|
||||
{
|
||||
parent = timesortsym[index];
|
||||
|
||||
if ((ignore_zeros && parent->ncalls == 0
|
||||
&& parent->cg.self_calls == 0 && parent->cg.prop.self == 0
|
||||
&& parent->cg.prop.child == 0)
|
||||
|| !parent->cg.print_flag
|
||||
|| (line_granularity && ! parent->is_func))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
if (!parent->name && parent->cg.cyc.num != 0)
|
||||
{
|
||||
/* cycle header: */
|
||||
/* Cycle header. */
|
||||
print_cycle (parent);
|
||||
print_members (parent);
|
||||
}
|
||||
@ -530,17 +510,20 @@ DEFUN (cg_print, (timesortsym), Sym ** timesortsym)
|
||||
print_line (parent);
|
||||
print_children (parent);
|
||||
}
|
||||
|
||||
if (bsd_style_output)
|
||||
printf ("\n");
|
||||
|
||||
printf ("-----------------------------------------------\n");
|
||||
|
||||
if (bsd_style_output)
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
free (timesortsym);
|
||||
|
||||
if (print_descriptions && !bsd_style_output)
|
||||
{
|
||||
fsf_callg_blurb (stdout);
|
||||
}
|
||||
fsf_callg_blurb (stdout);
|
||||
}
|
||||
|
||||
|
||||
@ -563,44 +546,44 @@ DEFUN_VOID (cg_print_index)
|
||||
Sym **name_sorted_syms, *sym;
|
||||
const char *filename;
|
||||
char buf[20];
|
||||
int column_width = (output_width - 1) / 3; /* don't write in last col! */
|
||||
/*
|
||||
* Now, sort regular function name alphabetically to create an
|
||||
* index:
|
||||
*/
|
||||
int column_width = (output_width - 1) / 3; /* Don't write in last col! */
|
||||
|
||||
/* Now, sort regular function name
|
||||
alphabetically to create an index. */
|
||||
name_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *));
|
||||
|
||||
for (index = 0, nnames = 0; index < symtab.len; index++)
|
||||
{
|
||||
if (ignore_zeros && symtab.base[index].ncalls == 0
|
||||
&& symtab.base[index].hist.time == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
name_sorted_syms[nnames++] = &symtab.base[index];
|
||||
}
|
||||
|
||||
qsort (name_sorted_syms, nnames, sizeof (Sym *), cmp_name);
|
||||
|
||||
for (index = 1, todo = nnames; index <= num_cycles; index++)
|
||||
{
|
||||
name_sorted_syms[todo++] = &cycle_header[index];
|
||||
}
|
||||
name_sorted_syms[todo++] = &cycle_header[index];
|
||||
|
||||
printf ("\f\n");
|
||||
printf (_("Index by function name\n\n"));
|
||||
index = (todo + 2) / 3;
|
||||
|
||||
for (i = 0; i < index; i++)
|
||||
{
|
||||
col = 0;
|
||||
starting_col = 0;
|
||||
|
||||
for (j = i; j < todo; j += index)
|
||||
{
|
||||
sym = name_sorted_syms[j];
|
||||
|
||||
if (sym->cg.print_flag)
|
||||
{
|
||||
sprintf (buf, "[%d]", sym->cg.index);
|
||||
}
|
||||
sprintf (buf, "[%d]", sym->cg.index);
|
||||
else
|
||||
{
|
||||
sprintf (buf, "(%d)", sym->cg.index);
|
||||
}
|
||||
sprintf (buf, "(%d)", sym->cg.index);
|
||||
|
||||
if (j < nnames)
|
||||
{
|
||||
if (bsd_style_output)
|
||||
@ -610,27 +593,27 @@ DEFUN_VOID (cg_print_index)
|
||||
else
|
||||
{
|
||||
col += strlen (buf);
|
||||
|
||||
for (; col < starting_col + 5; ++col)
|
||||
{
|
||||
putchar (' ');
|
||||
}
|
||||
putchar (' ');
|
||||
|
||||
printf (" %s ", buf);
|
||||
col += print_name_only (sym);
|
||||
|
||||
if (!line_granularity && sym->is_static && sym->file)
|
||||
{
|
||||
filename = sym->file->name;
|
||||
|
||||
if (!print_path)
|
||||
{
|
||||
filename = strrchr (filename, '/');
|
||||
|
||||
if (filename)
|
||||
{
|
||||
++filename;
|
||||
}
|
||||
++filename;
|
||||
else
|
||||
{
|
||||
filename = sym->file->name;
|
||||
}
|
||||
filename = sym->file->name;
|
||||
}
|
||||
|
||||
printf (" (%s)", filename);
|
||||
col += strlen (filename) + 3;
|
||||
}
|
||||
@ -655,15 +638,19 @@ DEFUN_VOID (cg_print_index)
|
||||
col += strlen (buf);
|
||||
}
|
||||
}
|
||||
|
||||
starting_col += column_width;
|
||||
}
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
free (name_sorted_syms);
|
||||
}
|
||||
|
||||
/* Compare two arcs based on their usage counts. We want to sort
|
||||
in descending order. */
|
||||
/* Compare two arcs based on their usage counts.
|
||||
We want to sort in descending order. */
|
||||
|
||||
static int
|
||||
DEFUN (cmp_arc_count, (left, right), const PTR left AND const PTR right)
|
||||
{
|
||||
@ -678,8 +665,9 @@ DEFUN (cmp_arc_count, (left, right), const PTR left AND const PTR right)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare two funtions based on their usage counts. We want to sort
|
||||
in descending order. */
|
||||
/* Compare two funtions based on their usage counts.
|
||||
We want to sort in descending order. */
|
||||
|
||||
static int
|
||||
DEFUN (cmp_fun_nuses, (left, right), const PTR left AND const PTR right)
|
||||
{
|
||||
@ -873,8 +861,8 @@ DEFUN_VOID (cg_print_function_ordering)
|
||||
An interesting variation would be to quit when we found
|
||||
multi-call site functions which account for some percentage
|
||||
of the arcs. */
|
||||
|
||||
arc = sym->cg.children;
|
||||
|
||||
while (arc)
|
||||
{
|
||||
if (arc->parent != arc->child)
|
||||
@ -884,6 +872,7 @@ DEFUN_VOID (cg_print_function_ordering)
|
||||
}
|
||||
|
||||
arc = sym->cg.parents;
|
||||
|
||||
while (arc)
|
||||
{
|
||||
if (arc->parent != arc->child)
|
||||
@ -895,13 +884,13 @@ DEFUN_VOID (cg_print_function_ordering)
|
||||
/* Keep track of how many symbols we're going to place. */
|
||||
scratch_index = index;
|
||||
|
||||
/* A lie, but it makes identifying these functions easier
|
||||
later. */
|
||||
/* A lie, but it makes identifying
|
||||
these functions easier later. */
|
||||
sym->has_been_placed = 1;
|
||||
}
|
||||
|
||||
/* Now walk through the temporary arcs and copy those we care about
|
||||
into the high arcs array. */
|
||||
/* Now walk through the temporary arcs and copy
|
||||
those we care about into the high arcs array. */
|
||||
for (index = 0; index < scratch_arc_count; index++)
|
||||
{
|
||||
Arc *arc = scratch_arcs[index];
|
||||
@ -920,22 +909,22 @@ DEFUN_VOID (cg_print_function_ordering)
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the multi-site high usage functions which are not going
|
||||
to be ordered by the main ordering algorithm. */
|
||||
/* Dump the multi-site high usage functions which are not
|
||||
going to be ordered by the main ordering algorithm. */
|
||||
for (index = 0; index < scratch_index; index++)
|
||||
{
|
||||
if (scratch_syms[index]->has_been_placed)
|
||||
printf ("%s\n", scratch_syms[index]->name);
|
||||
}
|
||||
|
||||
/* Now we can order the multi-site high use functions based on the
|
||||
arcs between them. */
|
||||
/* Now we can order the multi-site high use
|
||||
functions based on the arcs between them. */
|
||||
qsort (high_arcs, high_arc_count, sizeof (Arc *), cmp_arc_count);
|
||||
order_and_dump_functions_by_arcs (high_arcs, high_arc_count, 1,
|
||||
unplaced_arcs, &unplaced_arc_count);
|
||||
|
||||
/* Order and dump the high use functions left, these typically
|
||||
have only a few call sites. */
|
||||
/* Order and dump the high use functions left,
|
||||
these typically have only a few call sites. */
|
||||
order_and_dump_functions_by_arcs (arcs, numarcs, 0,
|
||||
unplaced_arcs, &unplaced_arc_count);
|
||||
|
||||
@ -1003,6 +992,7 @@ order_and_dump_functions_by_arcs (arcs, numarcs, all,
|
||||
total_arcs = 0;
|
||||
|
||||
tmp_arcs = 0;
|
||||
|
||||
for (index = 0; index < numarcs; index++)
|
||||
{
|
||||
Sym *sym1, *sym2;
|
||||
@ -1062,7 +1052,7 @@ order_and_dump_functions_by_arcs (arcs, numarcs, all,
|
||||
|
||||
/* Choose the closest. */
|
||||
child = next_count < prev_count ? next : prev;
|
||||
}
|
||||
}
|
||||
else if (! child->next && !child->prev)
|
||||
{
|
||||
int next_count = 0;
|
||||
@ -1145,14 +1135,14 @@ order_and_dump_functions_by_arcs (arcs, numarcs, all,
|
||||
on where we've got space in the child. */
|
||||
if (child->prev)
|
||||
{
|
||||
/* parent-prev and child-next */
|
||||
/* parent-prev and child-next. */
|
||||
parent->prev = child;
|
||||
child->next = parent;
|
||||
arcs[index]->has_been_placed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* parent-next and child-prev */
|
||||
/* parent-next and child-prev. */
|
||||
parent->next = child;
|
||||
child->prev = parent;
|
||||
arcs[index]->has_been_placed = 1;
|
||||
@ -1191,8 +1181,8 @@ order_and_dump_functions_by_arcs (arcs, numarcs, all,
|
||||
}
|
||||
}
|
||||
|
||||
/* If we want to place all the arcs, then output those which weren't
|
||||
placed by the main algorithm. */
|
||||
/* If we want to place all the arcs, then output
|
||||
those which weren't placed by the main algorithm. */
|
||||
if (all)
|
||||
for (index = 0; index < numarcs; index++)
|
||||
{
|
||||
@ -1212,7 +1202,8 @@ order_and_dump_functions_by_arcs (arcs, numarcs, all,
|
||||
on profiling information. This uses the function placement
|
||||
code for the bulk of its work. */
|
||||
|
||||
struct function_map {
|
||||
struct function_map
|
||||
{
|
||||
char *function_name;
|
||||
char *file_name;
|
||||
};
|
||||
@ -1253,8 +1244,8 @@ DEFUN_VOID (cg_print_file_ordering)
|
||||
{
|
||||
unsigned int index2;
|
||||
|
||||
/* Don't bother searching if this symbol is the
|
||||
same as the previous one. */
|
||||
/* Don't bother searching if this symbol
|
||||
is the same as the previous one. */
|
||||
if (last && !strcmp (last, symbol_map[index].file_name))
|
||||
continue;
|
||||
|
||||
@ -1267,8 +1258,8 @@ DEFUN_VOID (cg_print_file_ordering)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we didn't find it in the symbol table, then it must be a .o
|
||||
with no text symbols. Output it last. */
|
||||
/* If we didn't find it in the symbol table, then it must
|
||||
be a .o with no text symbols. Output it last. */
|
||||
if (index2 == symtab.len)
|
||||
printf ("%s\n", symbol_map[index].file_name);
|
||||
last = symbol_map[index].file_name;
|
||||
|
@ -1,14 +1,34 @@
|
||||
/* cg_print.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef cg_print_h
|
||||
#define cg_print_h
|
||||
|
||||
#include "gprof.h"
|
||||
#include "symtab.h"
|
||||
|
||||
extern double print_time; /* total of time being printed */
|
||||
extern double print_time; /* Total of time being printed. */
|
||||
|
||||
extern void cg_print PARAMS ((Sym ** cg));
|
||||
extern void cg_print_index PARAMS ((void));
|
||||
extern void cg_print_file_ordering PARAMS ((void));
|
||||
extern void cg_print_function_ordering PARAMS ((void));
|
||||
extern void cg_print PARAMS ((Sym **));
|
||||
extern void cg_print_index PARAMS ((void));
|
||||
extern void cg_print_file_ordering PARAMS ((void));
|
||||
extern void cg_print_function_ordering PARAMS ((void));
|
||||
|
||||
#endif /* cg_print_h */
|
||||
|
301
gprof/corefile.c
301
gprof/corefile.c
@ -1,3 +1,24 @@
|
||||
/* corefile.c
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include "libiberty.h"
|
||||
#include "gprof.h"
|
||||
#include "corefile.h"
|
||||
@ -13,7 +34,8 @@ int min_insn_size;
|
||||
int offset_to_code;
|
||||
|
||||
/* For mapping symbols to specific .o files during file ordering. */
|
||||
struct function_map {
|
||||
struct function_map
|
||||
{
|
||||
char *function_name;
|
||||
char *file_name;
|
||||
};
|
||||
@ -21,9 +43,9 @@ struct function_map {
|
||||
struct function_map *symbol_map;
|
||||
unsigned int symbol_map_count;
|
||||
|
||||
extern void i386_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
|
||||
extern void i386_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
|
||||
extern void alpha_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
|
||||
extern void vax_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
|
||||
extern void vax_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
|
||||
extern void tahoe_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
|
||||
extern void sparc_find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
|
||||
|
||||
@ -112,6 +134,7 @@ DEFUN (read_function_mappings, (filename), const char *filename)
|
||||
symbol_map_count = count;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DEFUN (core_init, (a_out_name), const char *a_out_name)
|
||||
{
|
||||
@ -129,7 +152,7 @@ DEFUN (core_init, (a_out_name), const char *a_out_name)
|
||||
done (1);
|
||||
}
|
||||
|
||||
/* get core's text section: */
|
||||
/* Get core's text section. */
|
||||
core_text_sect = bfd_get_section_by_name (core_bfd, ".text");
|
||||
if (!core_text_sect)
|
||||
{
|
||||
@ -142,9 +165,9 @@ DEFUN (core_init, (a_out_name), const char *a_out_name)
|
||||
}
|
||||
}
|
||||
|
||||
/* read core's symbol table: */
|
||||
/* Read core's symbol table. */
|
||||
|
||||
/* this will probably give us more than we need, but that's ok: */
|
||||
/* This will probably give us more than we need, but that's ok. */
|
||||
core_num_syms = bfd_get_symtab_upper_bound (core_bfd);
|
||||
if (core_num_syms < 0)
|
||||
{
|
||||
@ -155,6 +178,7 @@ DEFUN (core_init, (a_out_name), const char *a_out_name)
|
||||
|
||||
core_syms = (asymbol **) xmalloc (core_num_syms);
|
||||
core_num_syms = bfd_canonicalize_symtab (core_bfd, core_syms);
|
||||
|
||||
if (core_num_syms < 0)
|
||||
{
|
||||
fprintf (stderr, "%s: %s: %s\n", whoami, a_out_name,
|
||||
@ -184,10 +208,8 @@ DEFUN (core_init, (a_out_name), const char *a_out_name)
|
||||
read_function_mappings (function_mapping_file);
|
||||
}
|
||||
|
||||
/* Read in the text space of an a.out file. */
|
||||
|
||||
/*
|
||||
* Read in the text space of an a.out file
|
||||
*/
|
||||
void
|
||||
DEFUN (core_get_text_space, (core_bfd), bfd * core_bfd)
|
||||
{
|
||||
@ -199,6 +221,7 @@ DEFUN (core_get_text_space, (core_bfd), bfd * core_bfd)
|
||||
whoami, (unsigned long) core_text_sect->_raw_size);
|
||||
done (1);
|
||||
}
|
||||
|
||||
if (!bfd_get_section_contents (core_bfd, core_text_sect, core_text_space,
|
||||
0, core_text_sect->_raw_size))
|
||||
{
|
||||
@ -206,10 +229,9 @@ DEFUN (core_get_text_space, (core_bfd), bfd * core_bfd)
|
||||
free (core_text_space);
|
||||
core_text_space = 0;
|
||||
}
|
||||
|
||||
if (!core_text_space)
|
||||
{
|
||||
fprintf (stderr, _("%s: can't do -c\n"), whoami);
|
||||
}
|
||||
fprintf (stderr, _("%s: can't do -c\n"), whoami);
|
||||
}
|
||||
|
||||
|
||||
@ -248,12 +270,11 @@ DEFUN (find_call, (parent, p_lowpc, p_highpc),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return class of symbol SYM. The returned class can be any of:
|
||||
* 0 -> symbol is not interesting to us
|
||||
* 'T' -> symbol is a global name
|
||||
* 't' -> symbol is a local (static) name
|
||||
*/
|
||||
/* Return class of symbol SYM. The returned class can be any of:
|
||||
0 -> symbol is not interesting to us
|
||||
'T' -> symbol is a global name
|
||||
't' -> symbol is a local (static) name. */
|
||||
|
||||
static int
|
||||
DEFUN (core_sym_class, (sym), asymbol * sym)
|
||||
{
|
||||
@ -263,14 +284,10 @@ DEFUN (core_sym_class, (sym), asymbol * sym)
|
||||
int i;
|
||||
|
||||
if (sym->section == NULL || (sym->flags & BSF_DEBUGGING) != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Must be a text symbol, and static text symbols don't qualify if
|
||||
* ignore_static_funcs set.
|
||||
*/
|
||||
/* Must be a text symbol, and static text symbols
|
||||
don't qualify if ignore_static_funcs set. */
|
||||
if (ignore_static_funcs && (sym->flags & BSF_LOCAL))
|
||||
{
|
||||
DBG (AOUTDEBUG, printf ("[core_sym_class] %s: not a function\n",
|
||||
@ -282,81 +299,65 @@ DEFUN (core_sym_class, (sym), asymbol * sym)
|
||||
i = syminfo.type;
|
||||
|
||||
if (i == 'T')
|
||||
{
|
||||
return i; /* it's a global symbol */
|
||||
}
|
||||
return i; /* It's a global symbol. */
|
||||
|
||||
if (i == 'W')
|
||||
{
|
||||
/* Treat weak symbols as text symbols. FIXME: a weak symbol may
|
||||
also be a data symbol. */
|
||||
return 'T';
|
||||
}
|
||||
/* Treat weak symbols as text symbols. FIXME: a weak symbol may
|
||||
also be a data symbol. */
|
||||
return 'T';
|
||||
|
||||
if (i != 't')
|
||||
{
|
||||
/* not a static text symbol */
|
||||
/* Not a static text symbol. */
|
||||
DBG (AOUTDEBUG, printf ("[core_sym_class] %s is of class %c\n",
|
||||
sym->name, i));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do some more filtering on static function-names: */
|
||||
|
||||
/* Do some more filtering on static function-names. */
|
||||
if (ignore_static_funcs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Can't zero-length name or funny characters in name, where
|
||||
* `funny' includes: `.' (.o file names) and `$' (Pascal labels).
|
||||
*/
|
||||
return 0;
|
||||
|
||||
/* Can't zero-length name or funny characters in name, where
|
||||
`funny' includes: `.' (.o file names) and `$' (Pascal labels). */
|
||||
if (!sym->name || sym->name[0] == '\0')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
for (name = sym->name; *name; ++name)
|
||||
{
|
||||
if (*name == '.' || *name == '$')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* On systems where the C compiler adds an underscore to all
|
||||
* names, static names without underscores seem usually to be
|
||||
* labels in hand written assembler in the library. We don't want
|
||||
* these names. This is certainly necessary on a Sparc running
|
||||
* SunOS 4.1 (try profiling a program that does a lot of
|
||||
* division). I don't know whether it has harmful side effects on
|
||||
* other systems. Perhaps it should be made configurable.
|
||||
*/
|
||||
|
||||
/* On systems where the C compiler adds an underscore to all
|
||||
names, static names without underscores seem usually to be
|
||||
labels in hand written assembler in the library. We don't want
|
||||
these names. This is certainly necessary on a Sparc running
|
||||
SunOS 4.1 (try profiling a program that does a lot of
|
||||
division). I don't know whether it has harmful side effects on
|
||||
other systems. Perhaps it should be made configurable. */
|
||||
sym_prefix = bfd_get_symbol_leading_char (core_bfd);
|
||||
|
||||
if ((sym_prefix && sym_prefix != sym->name[0])
|
||||
/*
|
||||
* GCC may add special symbols to help gdb figure out the file
|
||||
* language. We want to ignore these, since sometimes they mask
|
||||
* the real function. (dj@ctron)
|
||||
*/
|
||||
/* GCC may add special symbols to help gdb figure out the file
|
||||
language. We want to ignore these, since sometimes they mask
|
||||
the real function. (dj@ctron) */
|
||||
|| !strncmp (sym->name, "__gnu_compiled", 14)
|
||||
|| !strncmp (sym->name, "___gnu_compiled", 15))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the object file supports marking of function symbols, then we can
|
||||
zap anything that doesn't have BSF_FUNCTION set. */
|
||||
/* If the object file supports marking of function symbols, then
|
||||
we can zap anything that doesn't have BSF_FUNCTION set. */
|
||||
if (ignore_non_functions && (sym->flags & BSF_FUNCTION) == 0)
|
||||
return 0;
|
||||
|
||||
return 't'; /* it's a static text symbol */
|
||||
return 't'; /* It's a static text symbol. */
|
||||
}
|
||||
|
||||
/* Get whatever source info we can get regarding address ADDR. */
|
||||
|
||||
/*
|
||||
* Get whatever source info we can get regarding address ADDR:
|
||||
*/
|
||||
static bool
|
||||
DEFUN (get_src_info, (addr, filename, name, line_num),
|
||||
bfd_vma addr AND const char **filename AND const char **name
|
||||
@ -386,11 +387,9 @@ DEFUN (get_src_info, (addr, filename, name, line_num),
|
||||
}
|
||||
}
|
||||
|
||||
/* Read in symbol table from core.
|
||||
One symbol per function is entered. */
|
||||
|
||||
/*
|
||||
* Read in symbol table from core. One symbol per function is
|
||||
* entered.
|
||||
*/
|
||||
void
|
||||
core_create_function_syms (core_bfd)
|
||||
bfd *core_bfd ATTRIBUTE_UNUSED;
|
||||
@ -400,14 +399,13 @@ core_create_function_syms (core_bfd)
|
||||
long i, found, skip;
|
||||
unsigned int j;
|
||||
|
||||
/* pass 1 - determine upper bound on number of function names: */
|
||||
/* Pass 1 - determine upper bound on number of function names. */
|
||||
symtab.len = 0;
|
||||
|
||||
for (i = 0; i < core_num_syms; ++i)
|
||||
{
|
||||
if (!core_sym_class (core_syms[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
/* This should be replaced with a binary search or hashed
|
||||
search. Gross.
|
||||
@ -424,6 +422,7 @@ core_create_function_syms (core_bfd)
|
||||
skip = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!skip)
|
||||
++symtab.len;
|
||||
}
|
||||
@ -434,15 +433,16 @@ core_create_function_syms (core_bfd)
|
||||
done (1);
|
||||
}
|
||||
|
||||
/* the "+ 2" is for the sentinels: */
|
||||
/* The "+ 2" is for the sentinels. */
|
||||
symtab.base = (Sym *) xmalloc ((symtab.len + 2) * sizeof (Sym));
|
||||
|
||||
/* pass 2 - create symbols: */
|
||||
|
||||
/* Pass 2 - create symbols. */
|
||||
symtab.limit = symtab.base;
|
||||
|
||||
for (i = 0; i < core_num_syms; ++i)
|
||||
{
|
||||
class = core_sym_class (core_syms[i]);
|
||||
|
||||
if (!class)
|
||||
{
|
||||
DBG (AOUTDEBUG,
|
||||
@ -451,11 +451,12 @@ core_create_function_syms (core_bfd)
|
||||
core_syms[i]->name));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This should be replaced with a binary search or hashed
|
||||
search. Gross. */
|
||||
|
||||
skip = 0;
|
||||
found = 0;
|
||||
|
||||
for (j = 0; j < symbol_map_count; j++)
|
||||
if (!strcmp (core_syms[i]->name, symbol_map[j].function_name))
|
||||
{
|
||||
@ -472,9 +473,9 @@ core_create_function_syms (core_bfd)
|
||||
|
||||
sym_init (symtab.limit);
|
||||
|
||||
/* symbol offsets are always section-relative: */
|
||||
|
||||
/* Symbol offsets are always section-relative. */
|
||||
symtab.limit->addr = core_syms[i]->value + core_syms[i]->section->vma;
|
||||
|
||||
if (symbol_map_count
|
||||
&& !strcmp (core_syms[i]->name, symbol_map[found].function_name))
|
||||
{
|
||||
@ -487,8 +488,7 @@ core_create_function_syms (core_bfd)
|
||||
symtab.limit->mapped = 0;
|
||||
}
|
||||
|
||||
/* Lookup filename and line number, if we can */
|
||||
|
||||
/* Lookup filename and line number, if we can. */
|
||||
{
|
||||
const char *filename, *func_name;
|
||||
|
||||
@ -500,22 +500,18 @@ core_create_function_syms (core_bfd)
|
||||
/* FIXME: Checking __osf__ here does not work with a cross
|
||||
gprof. */
|
||||
#ifdef __osf__
|
||||
/*
|
||||
* Suppress symbols that are not function names. This is
|
||||
* useful to suppress code-labels and aliases.
|
||||
*
|
||||
* This is known to be useful under DEC's OSF/1. Under SunOS 4.x,
|
||||
* labels do not appear in the symbol table info, so this isn't
|
||||
* necessary.
|
||||
*/
|
||||
/* Suppress symbols that are not function names. This is
|
||||
useful to suppress code-labels and aliases.
|
||||
|
||||
This is known to be useful under DEC's OSF/1. Under SunOS 4.x,
|
||||
labels do not appear in the symbol table info, so this isn't
|
||||
necessary. */
|
||||
|
||||
if (strcmp (symtab.limit->name, func_name) != 0)
|
||||
{
|
||||
/*
|
||||
* The symbol's address maps to a different name, so
|
||||
* it can't be a function-entry point. This happens
|
||||
* for labels, for example.
|
||||
*/
|
||||
/* The symbol's address maps to a different name, so
|
||||
it can't be a function-entry point. This happens
|
||||
for labels, for example. */
|
||||
DBG (AOUTDEBUG,
|
||||
printf ("[core_create_function_syms: rej %s (maps to %s)\n",
|
||||
symtab.limit->name, func_name));
|
||||
@ -527,23 +523,18 @@ core_create_function_syms (core_bfd)
|
||||
|
||||
symtab.limit->is_func = TRUE;
|
||||
symtab.limit->is_bb_head = TRUE;
|
||||
|
||||
if (class == 't')
|
||||
{
|
||||
symtab.limit->is_static = TRUE;
|
||||
}
|
||||
symtab.limit->is_static = TRUE;
|
||||
|
||||
min_vma = MIN (symtab.limit->addr, min_vma);
|
||||
max_vma = MAX (symtab.limit->addr, max_vma);
|
||||
|
||||
/*
|
||||
* If we see "main" without an initial '_', we assume names
|
||||
* are *not* prefixed by '_'.
|
||||
*/
|
||||
/* If we see "main" without an initial '_', we assume names
|
||||
are *not* prefixed by '_'. */
|
||||
if (symtab.limit->name[0] == 'm' && discard_underscores
|
||||
&& strcmp (symtab.limit->name, "main") == 0)
|
||||
{
|
||||
discard_underscores = 0;
|
||||
}
|
||||
discard_underscores = 0;
|
||||
|
||||
DBG (AOUTDEBUG, printf ("[core_create_function_syms] %ld %s 0x%lx\n",
|
||||
(long) (symtab.limit - symtab.base),
|
||||
@ -552,8 +543,7 @@ core_create_function_syms (core_bfd)
|
||||
++symtab.limit;
|
||||
}
|
||||
|
||||
/* create sentinels: */
|
||||
|
||||
/* Create sentinels. */
|
||||
sym_init (symtab.limit);
|
||||
symtab.limit->name = "<locore>";
|
||||
symtab.limit->addr = 0;
|
||||
@ -570,11 +560,9 @@ core_create_function_syms (core_bfd)
|
||||
symtab_finalize (&symtab);
|
||||
}
|
||||
|
||||
/* Read in symbol table from core.
|
||||
One symbol per line of source code is entered. */
|
||||
|
||||
/*
|
||||
* Read in symbol table from core. One symbol per line of source code
|
||||
* is entered.
|
||||
*/
|
||||
void
|
||||
DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
|
||||
{
|
||||
@ -586,43 +574,40 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
|
||||
const char *filename;
|
||||
int prev_line_num;
|
||||
Sym_Table ltab;
|
||||
/*
|
||||
* Create symbols for functions as usual. This is necessary in
|
||||
* cases where parts of a program were not compiled with -g. For
|
||||
* those parts we still want to get info at the function level:
|
||||
*/
|
||||
|
||||
/* Create symbols for functions as usual. This is necessary in
|
||||
cases where parts of a program were not compiled with -g. For
|
||||
those parts we still want to get info at the function level. */
|
||||
core_create_function_syms (core_bfd);
|
||||
|
||||
/* pass 1 - counter number of symbols: */
|
||||
/* Pass 1 - counter number of symbols. */
|
||||
|
||||
/*
|
||||
* To find all line information, walk through all possible
|
||||
* text-space addresses (one by one!) and get the debugging
|
||||
* info for each address. When the debugging info changes,
|
||||
* it is time to create a new symbol.
|
||||
*
|
||||
* Of course, this is rather slow and it would be better if
|
||||
* bfd would provide an iterator for enumerating all line infos
|
||||
*/
|
||||
/* To find all line information, walk through all possible
|
||||
text-space addresses (one by one!) and get the debugging
|
||||
info for each address. When the debugging info changes,
|
||||
it is time to create a new symbol.
|
||||
|
||||
Of course, this is rather slow and it would be better if
|
||||
bfd would provide an iterator for enumerating all line infos. */
|
||||
prev_name_len = PATH_MAX;
|
||||
prev_filename_len = PATH_MAX;
|
||||
prev_name = xmalloc (prev_name_len);
|
||||
prev_filename = xmalloc (prev_filename_len);
|
||||
ltab.len = 0;
|
||||
prev_line_num = 0;
|
||||
|
||||
for (offset = 0; offset < core_text_sect->_raw_size; offset += min_insn_size)
|
||||
{
|
||||
int len;
|
||||
|
||||
vma = core_text_sect->vma + offset;
|
||||
|
||||
if (!get_src_info (vma, &filename, &dummy.name, &dummy.line_num)
|
||||
|| (prev_line_num == dummy.line_num
|
||||
&& prev_name != NULL
|
||||
&& strcmp (prev_name, dummy.name) == 0
|
||||
&& strcmp (prev_filename, filename) == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
++ltab.len;
|
||||
prev_line_num = dummy.line_num;
|
||||
@ -634,15 +619,17 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
|
||||
free (prev_name);
|
||||
prev_name = xmalloc (prev_name_len);
|
||||
}
|
||||
|
||||
strcpy (prev_name, dummy.name);
|
||||
|
||||
len = strlen (filename);
|
||||
|
||||
if (len >= prev_filename_len)
|
||||
{
|
||||
prev_filename_len = len + 1024;
|
||||
free (prev_filename);
|
||||
prev_filename = xmalloc (prev_filename_len);
|
||||
}
|
||||
|
||||
strcpy (prev_filename, filename);
|
||||
|
||||
min_vma = MIN (vma, min_vma);
|
||||
@ -652,12 +639,12 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
|
||||
free (prev_name);
|
||||
free (prev_filename);
|
||||
|
||||
/* make room for function symbols, too: */
|
||||
/* Make room for function symbols, too. */
|
||||
ltab.len += symtab.len;
|
||||
ltab.base = (Sym *) xmalloc (ltab.len * sizeof (Sym));
|
||||
ltab.limit = ltab.base;
|
||||
|
||||
/* pass 2 - create symbols: */
|
||||
/* Pass 2 - create symbols. */
|
||||
|
||||
/* We now set is_static as we go along, rather than by running
|
||||
through the symbol table at the end.
|
||||
@ -675,31 +662,28 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
|
||||
Perhaps symtab_finalize should be modified to make this
|
||||
distinction as well, but the current fix works and the code is a
|
||||
lot cleaner now. */
|
||||
|
||||
prev = 0;
|
||||
|
||||
for (offset = 0; offset < core_text_sect->_raw_size; offset += min_insn_size)
|
||||
{
|
||||
sym_init (ltab.limit);
|
||||
|
||||
if (!get_src_info (core_text_sect->vma + offset, &filename,
|
||||
<ab.limit->name, <ab.limit->line_num)
|
||||
|| (prev && prev->line_num == ltab.limit->line_num
|
||||
&& strcmp (prev->name, ltab.limit->name) == 0
|
||||
&& strcmp (prev->file->name, filename) == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
/* make name pointer a malloc'ed string: */
|
||||
/* Make name pointer a malloc'ed string. */
|
||||
ltab.limit->name = xstrdup (ltab.limit->name);
|
||||
ltab.limit->file = source_file_lookup_path (filename);
|
||||
|
||||
ltab.limit->addr = core_text_sect->vma + offset;
|
||||
|
||||
/* Set is_static based on the enclosing function, using either:
|
||||
* 1) the previous symbol, if it's from the same function, or
|
||||
* 2) a symtab lookup
|
||||
*/
|
||||
|
||||
1) the previous symbol, if it's from the same function, or
|
||||
2) a symtab lookup. */
|
||||
if (prev && ltab.limit->file == prev->file &&
|
||||
strcmp (ltab.limit->name, prev->name) == 0)
|
||||
{
|
||||
@ -713,15 +697,11 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
|
||||
|
||||
prev = ltab.limit;
|
||||
|
||||
/*
|
||||
* If we see "main" without an initial '_', we assume names
|
||||
* are *not* prefixed by '_'.
|
||||
*/
|
||||
/* If we see "main" without an initial '_', we assume names
|
||||
are *not* prefixed by '_'. */
|
||||
if (ltab.limit->name[0] == 'm' && discard_underscores
|
||||
&& strcmp (ltab.limit->name, "main") == 0)
|
||||
{
|
||||
discard_underscores = 0;
|
||||
}
|
||||
discard_underscores = 0;
|
||||
|
||||
DBG (AOUTDEBUG, printf ("[core_create_line_syms] %lu %s 0x%lx\n",
|
||||
(unsigned long) (ltab.limit - ltab.base),
|
||||
@ -730,22 +710,19 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
|
||||
++ltab.limit;
|
||||
}
|
||||
|
||||
/* update sentinels: */
|
||||
|
||||
/* Update sentinels. */
|
||||
sentinel = sym_lookup (&symtab, 0);
|
||||
|
||||
if (strcmp (sentinel->name, "<locore>") == 0
|
||||
&& min_vma <= sentinel->end_addr)
|
||||
{
|
||||
sentinel->end_addr = min_vma - 1;
|
||||
}
|
||||
sentinel->end_addr = min_vma - 1;
|
||||
|
||||
sentinel = sym_lookup (&symtab, ~0);
|
||||
|
||||
if (strcmp (sentinel->name, "<hicore>") == 0 && max_vma >= sentinel->addr)
|
||||
{
|
||||
sentinel->addr = max_vma + 1;
|
||||
}
|
||||
sentinel->addr = max_vma + 1;
|
||||
|
||||
/* copy in function symbols: */
|
||||
/* Copy in function symbols. */
|
||||
memcpy (ltab.limit, symtab.base, symtab.len * sizeof (Sym));
|
||||
ltab.limit += symtab.len;
|
||||
|
||||
@ -757,10 +734,8 @@ DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
|
||||
done (1);
|
||||
}
|
||||
|
||||
/* finalize ltab and make it symbol table: */
|
||||
|
||||
/* Finalize ltab and make it symbol table. */
|
||||
symtab_finalize (<ab);
|
||||
free (symtab.base);
|
||||
symtab = ltab;
|
||||
|
||||
}
|
||||
|
@ -1,21 +1,40 @@
|
||||
/* corefile.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef corefile_h
|
||||
#define corefile_h
|
||||
|
||||
#include "bfd.h"
|
||||
|
||||
extern bfd *core_bfd; /* bfd for core-file */
|
||||
extern int core_num_syms; /* # of entries in symbol-table */
|
||||
extern asymbol **core_syms; /* symbol table in a.out */
|
||||
extern asection *core_text_sect; /* core text section */
|
||||
extern PTR core_text_space; /* text space of a.out in core */
|
||||
extern bfd *core_bfd; /* BFD for core-file. */
|
||||
extern int core_num_syms; /* # of entries in symbol-table. */
|
||||
extern asymbol **core_syms; /* Symbol table in a.out. */
|
||||
extern asection *core_text_sect;/* Core text section. */
|
||||
extern PTR core_text_space; /* Text space of a.out in core. */
|
||||
extern int min_insn_size; /* Size of smallest instruction, in bytes. */
|
||||
extern int offset_to_code; /* Offset (in bytes) of code from entry
|
||||
address of routine. */
|
||||
|
||||
extern int min_insn_size; /* size of smallest instruction, in bytes */
|
||||
extern int offset_to_code; /* offset (in bytes) of code from entry
|
||||
address of routine */
|
||||
|
||||
extern void core_init PARAMS ((const char *a_out_name));
|
||||
extern void core_get_text_space PARAMS ((bfd * core_bfd));
|
||||
extern void core_create_function_syms PARAMS ((bfd * core_bfd));
|
||||
extern void core_create_line_syms PARAMS ((bfd * core_bfd));
|
||||
extern void core_init PARAMS ((const char *));
|
||||
extern void core_get_text_space PARAMS ((bfd *));
|
||||
extern void core_create_function_syms PARAMS ((bfd *));
|
||||
extern void core_create_line_syms PARAMS ((bfd *));
|
||||
|
||||
#endif /* corefile_h */
|
||||
|
123
gprof/gmon_io.c
123
gprof/gmon_io.c
@ -1,6 +1,24 @@
|
||||
/*
|
||||
* Input and output from/to gmon.out files.
|
||||
*/
|
||||
/* gmon_io.c - Input and output from/to gmon.out files.
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include "cg_arcs.h"
|
||||
#include "basic_blocks.h"
|
||||
#include "bfd.h"
|
||||
@ -8,18 +26,17 @@
|
||||
#include "call_graph.h"
|
||||
#include "gmon_io.h"
|
||||
#include "gmon_out.h"
|
||||
#include "gmon.h" /* fetch header for old format */
|
||||
#include "gmon.h" /* Fetch header for old format. */
|
||||
#include "gprof.h"
|
||||
#include "hertz.h"
|
||||
#include "hist.h"
|
||||
#include "libiberty.h"
|
||||
|
||||
int gmon_input = 0;
|
||||
int gmon_file_version = 0; /* 0 == old (non-versioned) file format */
|
||||
int gmon_file_version = 0; /* 0 == old (non-versioned) file format. */
|
||||
|
||||
/* This probably ought to be in libbfd. */
|
||||
|
||||
/*
|
||||
* This probably ought to be in libbfd.
|
||||
*/
|
||||
bfd_vma
|
||||
DEFUN (get_vma, (abfd, addr), bfd * abfd AND bfd_byte * addr)
|
||||
{
|
||||
@ -37,9 +54,8 @@ DEFUN (get_vma, (abfd, addr), bfd * abfd AND bfd_byte * addr)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This probably ought to be in libbfd.
|
||||
*/
|
||||
/* This probably ought to be in libbfd. */
|
||||
|
||||
void
|
||||
DEFUN (put_vma, (abfd, val, addr), bfd * abfd AND bfd_vma val AND bfd_byte * addr)
|
||||
{
|
||||
@ -67,8 +83,7 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
unsigned char tag;
|
||||
int nhist = 0, narcs = 0, nbbs = 0;
|
||||
|
||||
/* open gmon.out file: */
|
||||
|
||||
/* Open gmon.out file. */
|
||||
if (strcmp (filename, "-") == 0)
|
||||
{
|
||||
ifp = stdin;
|
||||
@ -79,12 +94,14 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
else
|
||||
{
|
||||
ifp = fopen (filename, FOPEN_RB);
|
||||
|
||||
if (!ifp)
|
||||
{
|
||||
perror (filename);
|
||||
done (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1)
|
||||
{
|
||||
fprintf (stderr, _("%s: file too short to be a gmon file\n"),
|
||||
@ -102,9 +119,9 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
done (1);
|
||||
}
|
||||
|
||||
/* right magic, so it's probably really a new gmon.out file */
|
||||
|
||||
/* Right magic, so it's probably really a new gmon.out file. */
|
||||
gmon_file_version = bfd_get_32 (core_bfd, (bfd_byte *) ghdr.version);
|
||||
|
||||
if (gmon_file_version != GMON_VERSION && gmon_file_version != 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
@ -113,7 +130,7 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
done (1);
|
||||
}
|
||||
|
||||
/* read in all the records: */
|
||||
/* Read in all the records. */
|
||||
while (fread (&tag, sizeof (tag), 1, ifp) == 1)
|
||||
{
|
||||
switch (tag)
|
||||
@ -163,22 +180,19 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
UNIT raw_bin_count;
|
||||
struct hdr tmp;
|
||||
|
||||
/*
|
||||
* Information from a gmon.out file is in two parts: an array of
|
||||
* sampling hits within pc ranges, and the arcs.
|
||||
*/
|
||||
/* Information from a gmon.out file is in two parts: an array of
|
||||
sampling hits within pc ranges, and the arcs. */
|
||||
gmon_input = INPUT_HISTOGRAM | INPUT_CALL_GRAPH;
|
||||
|
||||
/*
|
||||
* This fseek() ought to work even on stdin as long as it's
|
||||
* not an interactive device (heck, is there anybody who would
|
||||
* want to type in a gmon.out at the terminal?).
|
||||
*/
|
||||
/* This fseek() ought to work even on stdin as long as it's
|
||||
not an interactive device (heck, is there anybody who would
|
||||
want to type in a gmon.out at the terminal?). */
|
||||
if (fseek (ifp, 0, SEEK_SET) < 0)
|
||||
{
|
||||
perror (filename);
|
||||
done (1);
|
||||
}
|
||||
|
||||
if (fread (&raw, 1, sizeof (struct raw_phdr), ifp)
|
||||
!= sizeof (struct raw_phdr))
|
||||
{
|
||||
@ -186,6 +200,7 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
filename);
|
||||
done (1);
|
||||
}
|
||||
|
||||
tmp.low_pc = get_vma (core_bfd, (bfd_byte *) &raw.low_pc[0]);
|
||||
tmp.high_pc = get_vma (core_bfd, (bfd_byte *) &raw.high_pc[0]);
|
||||
tmp.ncnt = bfd_get_32 (core_bfd, (bfd_byte *) &raw.ncnt[0]);
|
||||
@ -196,8 +211,8 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
int profrate;
|
||||
|
||||
/* 4.4BSD format header. */
|
||||
|
||||
profrate = bfd_get_32 (core_bfd, (bfd_byte *) &raw.profrate[0]);
|
||||
|
||||
if (!s_highpc)
|
||||
hz = profrate;
|
||||
else if (hz != profrate)
|
||||
@ -212,7 +227,7 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* old style BSD format. */
|
||||
/* Old style BSD format. */
|
||||
if (file_format == FF_BSD44)
|
||||
{
|
||||
fprintf (stderr, _("%s: file `%s' has bad magic cookie\n"),
|
||||
@ -236,6 +251,7 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
filename);
|
||||
done (1);
|
||||
}
|
||||
|
||||
h = tmp;
|
||||
s_lowpc = (bfd_vma) h.low_pc;
|
||||
s_highpc = (bfd_vma) h.high_pc;
|
||||
@ -243,6 +259,7 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
highpc = (bfd_vma) h.high_pc / sizeof (UNIT);
|
||||
samp_bytes = h.ncnt - header_size;
|
||||
hist_num_bins = samp_bytes / sizeof (UNIT);
|
||||
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
|
||||
(unsigned long) h.low_pc, (unsigned long) h.high_pc,
|
||||
@ -264,14 +281,13 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
}
|
||||
|
||||
if (hist_num_bins)
|
||||
{
|
||||
++nhist;
|
||||
}
|
||||
++nhist;
|
||||
|
||||
if (!hist_sample)
|
||||
{
|
||||
hist_sample =
|
||||
(int *) xmalloc (hist_num_bins * sizeof (hist_sample[0]));
|
||||
|
||||
memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0]));
|
||||
}
|
||||
|
||||
@ -284,34 +300,35 @@ DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
whoami, --i, hist_num_bins);
|
||||
done (1);
|
||||
}
|
||||
|
||||
hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* The rest of the file consists of a bunch of <from,self,count>
|
||||
* tuples:
|
||||
*/
|
||||
/* The rest of the file consists of a bunch of
|
||||
<from,self,count> tuples. */
|
||||
while (fread (&raw_arc, sizeof (raw_arc), 1, ifp) == 1)
|
||||
{
|
||||
++narcs;
|
||||
from_pc = get_vma (core_bfd, (bfd_byte *) raw_arc.from_pc);
|
||||
self_pc = get_vma (core_bfd, (bfd_byte *) raw_arc.self_pc);
|
||||
count = bfd_get_32 (core_bfd, (bfd_byte *) raw_arc.count);
|
||||
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %lu\n",
|
||||
(unsigned long) from_pc, (unsigned long) self_pc, count));
|
||||
/* add this arc: */
|
||||
|
||||
/* Add this arc. */
|
||||
cg_tally (from_pc, self_pc, count);
|
||||
}
|
||||
|
||||
fclose (ifp);
|
||||
|
||||
if (hz == HZ_WRONG)
|
||||
{
|
||||
/*
|
||||
* How many ticks per second? If we can't tell, report
|
||||
* time in ticks.
|
||||
*/
|
||||
/* How many ticks per second? If we can't tell, report
|
||||
time in ticks. */
|
||||
hz = hertz ();
|
||||
|
||||
if (hz == HZ_WRONG)
|
||||
{
|
||||
hz = 1;
|
||||
@ -356,33 +373,28 @@ DEFUN (gmon_out_write, (filename), const char *filename)
|
||||
|
||||
if (file_format == FF_AUTO || file_format == FF_MAGIC)
|
||||
{
|
||||
/* write gmon header: */
|
||||
/* Write gmon header. */
|
||||
|
||||
memcpy (&ghdr.cookie[0], GMON_MAGIC, 4);
|
||||
bfd_put_32 (core_bfd, GMON_VERSION, (bfd_byte *) ghdr.version);
|
||||
|
||||
if (fwrite (&ghdr, sizeof (ghdr), 1, ofp) != 1)
|
||||
{
|
||||
perror (filename);
|
||||
done (1);
|
||||
}
|
||||
|
||||
/* write execution time histogram if we have one: */
|
||||
/* Write execution time histogram if we have one. */
|
||||
if (gmon_input & INPUT_HISTOGRAM)
|
||||
{
|
||||
hist_write_hist (ofp, filename);
|
||||
}
|
||||
hist_write_hist (ofp, filename);
|
||||
|
||||
/* write call graph arcs if we have any: */
|
||||
/* Write call graph arcs if we have any. */
|
||||
if (gmon_input & INPUT_CALL_GRAPH)
|
||||
{
|
||||
cg_write_arcs (ofp, filename);
|
||||
}
|
||||
cg_write_arcs (ofp, filename);
|
||||
|
||||
/* write basic-block info if we have it: */
|
||||
/* Write basic-block info if we have it. */
|
||||
if (gmon_input & INPUT_BB_COUNTS)
|
||||
{
|
||||
bb_write_blocks (ofp, filename);
|
||||
}
|
||||
bb_write_blocks (ofp, filename);
|
||||
}
|
||||
else if (file_format == FF_BSD || file_format == FF_BSD44)
|
||||
{
|
||||
@ -423,8 +435,7 @@ DEFUN (gmon_out_write, (filename), const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
/* dump the samples: */
|
||||
|
||||
/* Dump the samples. */
|
||||
for (i = 0; i < hist_num_bins; ++i)
|
||||
{
|
||||
bfd_put_16 (core_bfd, hist_sample[i], (bfd_byte *) & raw_bin_count[0]);
|
||||
@ -435,8 +446,7 @@ DEFUN (gmon_out_write, (filename), const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
/* dump the normalized raw arc information: */
|
||||
|
||||
/* Dump the normalized raw arc information. */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
for (arc = sym->cg.children; arc; arc = arc->next_child)
|
||||
@ -457,6 +467,7 @@ DEFUN (gmon_out_write, (filename), const char *filename)
|
||||
(unsigned long) arc->child->addr, arc->count));
|
||||
}
|
||||
}
|
||||
|
||||
fclose (ofp);
|
||||
}
|
||||
else
|
||||
|
@ -1,3 +1,23 @@
|
||||
/* gmon_io.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef gmon_io_h
|
||||
#define gmon_io_h
|
||||
|
||||
@ -22,17 +42,16 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define INPUT_HISTOGRAM (1<<0)
|
||||
#define INPUT_CALL_GRAPH (1<<1)
|
||||
#define INPUT_BB_COUNTS (1<<2)
|
||||
#define INPUT_HISTOGRAM (1 << 0)
|
||||
#define INPUT_CALL_GRAPH (1 << 1)
|
||||
#define INPUT_BB_COUNTS (1 << 2)
|
||||
|
||||
extern int gmon_input; /* what input did we see? */
|
||||
extern int gmon_file_version; /* file version are we dealing with */
|
||||
extern int gmon_input; /* What input did we see? */
|
||||
extern int gmon_file_version; /* File version are we dealing with. */
|
||||
|
||||
extern bfd_vma get_vma PARAMS ((bfd * abfd, bfd_byte * addr));
|
||||
extern void put_vma PARAMS ((bfd * abfd, bfd_vma val, bfd_byte * addr));
|
||||
|
||||
extern void gmon_out_read PARAMS ((const char *filename));
|
||||
extern void gmon_out_write PARAMS ((const char *filename));
|
||||
extern bfd_vma get_vma PARAMS ((bfd *, bfd_byte *));
|
||||
extern void put_vma PARAMS ((bfd *, bfd_vma, bfd_byte *));
|
||||
extern void gmon_out_read PARAMS ((const char *));
|
||||
extern void gmon_out_write PARAMS ((const char *));
|
||||
|
||||
#endif /* gmon_io_h */
|
||||
|
@ -1,22 +1,38 @@
|
||||
/*
|
||||
* This file specifies the format of gmon.out files. It should have
|
||||
* as few external dependencies as possible as it is going to be
|
||||
* included in many different programs. That is, minimize the
|
||||
* number of #include's.
|
||||
*
|
||||
* A gmon.out file consists of a header (defined by gmon_hdr) followed
|
||||
* by a sequence of records. Each record starts with a one-byte tag
|
||||
* identifying the type of records, followed by records specific data.
|
||||
*/
|
||||
/* gmon_out.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* This file specifies the format of gmon.out files. It should have
|
||||
as few external dependencies as possible as it is going to be
|
||||
included in many different programs. That is, minimize the
|
||||
number of #include's.
|
||||
|
||||
A gmon.out file consists of a header (defined by gmon_hdr) followed
|
||||
by a sequence of records. Each record starts with a one-byte tag
|
||||
identifying the type of records, followed by records specific data. */
|
||||
#ifndef gmon_out_h
|
||||
#define gmon_out_h
|
||||
|
||||
#define GMON_MAGIC "gmon" /* magic cookie */
|
||||
#define GMON_VERSION 1 /* version number */
|
||||
|
||||
/*
|
||||
* Raw header as it appears on file (without padding):
|
||||
*/
|
||||
/* Raw header as it appears on file (without padding). */
|
||||
struct gmon_hdr
|
||||
{
|
||||
char cookie[4];
|
||||
@ -24,7 +40,7 @@ struct gmon_hdr
|
||||
char spare[3 * 4];
|
||||
};
|
||||
|
||||
/* types of records in this file: */
|
||||
/* Types of records in this file. */
|
||||
typedef enum
|
||||
{
|
||||
GMON_TAG_TIME_HIST = 0, GMON_TAG_CG_ARC = 1, GMON_TAG_BB_COUNT = 2
|
||||
@ -33,19 +49,19 @@ GMON_Record_Tag;
|
||||
|
||||
struct gmon_hist_hdr
|
||||
{
|
||||
char low_pc[sizeof (char*)]; /* base pc address of sample buffer */
|
||||
char high_pc[sizeof (char*)]; /* max pc address of sampled buffer */
|
||||
char hist_size[4]; /* size of sample buffer */
|
||||
char prof_rate[4]; /* profiling clock rate */
|
||||
char dimen[15]; /* phys. dim., usually "seconds" */
|
||||
char dimen_abbrev; /* usually 's' for "seconds" */
|
||||
char low_pc[sizeof (char*)]; /* Base pc address of sample buffer. */
|
||||
char high_pc[sizeof (char*)]; /* Max pc address of sampled buffer. */
|
||||
char hist_size[4]; /* Size of sample buffer. */
|
||||
char prof_rate[4]; /* Profiling clock rate. */
|
||||
char dimen[15]; /* Phys. dim., usually "seconds". */
|
||||
char dimen_abbrev; /* Usually 's' for "seconds". */
|
||||
};
|
||||
|
||||
struct gmon_cg_arc_record
|
||||
{
|
||||
char from_pc[sizeof (char*)]; /* address within caller's body */
|
||||
char self_pc[sizeof (char*)]; /* address within callee's body */
|
||||
char count[4]; /* number of arc traversals */
|
||||
char from_pc[sizeof (char*)]; /* Address within caller's body. */
|
||||
char self_pc[sizeof (char*)]; /* Address within callee's body. */
|
||||
char count[4]; /* Number of arc traversals. */
|
||||
};
|
||||
|
||||
#endif /* gmon_out_h */
|
||||
|
354
gprof/hist.c
354
gprof/hist.c
@ -1,6 +1,24 @@
|
||||
/*
|
||||
* Histogram related operations.
|
||||
*/
|
||||
/* hist.c - Histogram related operations.
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "libiberty.h"
|
||||
#include "gprof.h"
|
||||
@ -16,25 +34,24 @@
|
||||
|
||||
static void scale_and_align_entries PARAMS ((void));
|
||||
|
||||
/* declarations of automatically generated functions to output blurbs: */
|
||||
/* Declarations of automatically generated functions to output blurbs. */
|
||||
extern void flat_blurb PARAMS ((FILE * fp));
|
||||
|
||||
bfd_vma s_lowpc; /* lowest address in .text */
|
||||
bfd_vma s_highpc = 0; /* highest address in .text */
|
||||
bfd_vma lowpc, highpc; /* same, but expressed in UNITs */
|
||||
int hist_num_bins = 0; /* number of histogram samples */
|
||||
int *hist_sample = 0; /* histogram samples (shorts in the file!) */
|
||||
bfd_vma s_lowpc; /* Lowest address in .text. */
|
||||
bfd_vma s_highpc = 0; /* Highest address in .text. */
|
||||
bfd_vma lowpc, highpc; /* Same, but expressed in UNITs. */
|
||||
int hist_num_bins = 0; /* Number of histogram samples. */
|
||||
int *hist_sample = 0; /* Histogram samples (shorts in the file!). */
|
||||
double hist_scale;
|
||||
char hist_dimension[sizeof (((struct gmon_hist_hdr *) 0)->dimen) + 1] =
|
||||
"seconds";
|
||||
char hist_dimension_abbrev = 's';
|
||||
|
||||
static double accum_time; /* accumulated time so far for print_line() */
|
||||
static double total_time; /* total time for all routines */
|
||||
/*
|
||||
* Table of SI prefixes for powers of 10 (used to automatically
|
||||
* scale some of the values in the flat profile).
|
||||
*/
|
||||
static double accum_time; /* Accumulated time so far for print_line(). */
|
||||
static double total_time; /* Total time for all routines. */
|
||||
|
||||
/* Table of SI prefixes for powers of 10 (used to automatically
|
||||
scale some of the values in the flat profile). */
|
||||
const struct
|
||||
{
|
||||
char prefix;
|
||||
@ -88,10 +105,10 @@ SItab[] =
|
||||
, /* ato */
|
||||
};
|
||||
|
||||
/*
|
||||
* Read the histogram from file IFP. FILENAME is the name of IFP and
|
||||
* is provided for formatting error messages only.
|
||||
*/
|
||||
|
||||
/* Read the histogram from file IFP. FILENAME is the name of IFP and
|
||||
is provided for formatting error messages only. */
|
||||
|
||||
void
|
||||
DEFUN (hist_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
{
|
||||
@ -117,9 +134,7 @@ DEFUN (hist_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
|
||||
if (!s_highpc)
|
||||
{
|
||||
|
||||
/* this is the first histogram record: */
|
||||
|
||||
/* This is the first histogram record. */
|
||||
s_lowpc = n_lowpc;
|
||||
s_highpc = n_highpc;
|
||||
lowpc = (bfd_vma) n_lowpc / sizeof (UNIT);
|
||||
@ -165,10 +180,9 @@ DEFUN (hist_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write execution histogram to file OFP. FILENAME is the name
|
||||
* of OFP and is provided for formatting error-messages only.
|
||||
*/
|
||||
/* Write execution histogram to file OFP. FILENAME is the name
|
||||
of OFP and is provided for formatting error-messages only. */
|
||||
|
||||
void
|
||||
DEFUN (hist_write_hist, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
{
|
||||
@ -177,7 +191,7 @@ DEFUN (hist_write_hist, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
UNIT count;
|
||||
int i;
|
||||
|
||||
/* write header: */
|
||||
/* Write header. */
|
||||
|
||||
tag = GMON_TAG_TIME_HIST;
|
||||
put_vma (core_bfd, s_lowpc, (bfd_byte *) hdr.low_pc);
|
||||
@ -197,6 +211,7 @@ DEFUN (hist_write_hist, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
for (i = 0; i < hist_num_bins; ++i)
|
||||
{
|
||||
bfd_put_16 (core_bfd, hist_sample[i], (bfd_byte *) & count[0]);
|
||||
|
||||
if (fwrite (&count[0], sizeof (count), 1, ofp) != 1)
|
||||
{
|
||||
perror (filename);
|
||||
@ -206,14 +221,13 @@ DEFUN (hist_write_hist, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Calculate scaled entry point addresses (to save time in
|
||||
* hist_assign_samples), and, on architectures that have procedure
|
||||
* entry masks at the start of a function, possibly push the scaled
|
||||
* entry points over the procedure entry mask, if it turns out that
|
||||
* the entry point is in one bin and the code for a routine is in the
|
||||
* next bin.
|
||||
*/
|
||||
/* Calculate scaled entry point addresses (to save time in
|
||||
hist_assign_samples), and, on architectures that have procedure
|
||||
entry masks at the start of a function, possibly push the scaled
|
||||
entry points over the procedure entry mask, if it turns out that
|
||||
the entry point is in one bin and the code for a routine is in the
|
||||
next bin. */
|
||||
|
||||
static void
|
||||
scale_and_align_entries ()
|
||||
{
|
||||
@ -239,44 +253,43 @@ scale_and_align_entries ()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Assign samples to the symbol to which they belong.
|
||||
*
|
||||
* Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
|
||||
* which may overlap one more symbol address ranges. If a symbol
|
||||
* overlaps with the bin's address range by O percent, then O percent
|
||||
* of the bin's count is credited to that symbol.
|
||||
*
|
||||
* There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
|
||||
* with respect to the symbol's address range [SYM_LOW_PC,
|
||||
* SYM_HIGH_PC) as shown in the following diagram. OVERLAP computes
|
||||
* the distance (in UNITs) between the arrows, the fraction of the
|
||||
* sample that is to be credited to the symbol which starts at
|
||||
* SYM_LOW_PC.
|
||||
*
|
||||
* sym_low_pc sym_high_pc
|
||||
* | |
|
||||
* v v
|
||||
*
|
||||
* +-----------------------------------------------+
|
||||
* | |
|
||||
* | ->| |<- ->| |<- ->| |<- |
|
||||
* | | | | | |
|
||||
* +---------+ +---------+ +---------+
|
||||
*
|
||||
* ^ ^ ^ ^ ^ ^
|
||||
* | | | | | |
|
||||
* bin_low_pc bin_high_pc bin_low_pc bin_high_pc bin_low_pc bin_high_pc
|
||||
*
|
||||
* For the VAX we assert that samples will never fall in the first two
|
||||
* bytes of any routine, since that is the entry mask, thus we call
|
||||
* scale_and_align_entries() to adjust the entry points if the entry
|
||||
* mask falls in one bin but the code for the routine doesn't start
|
||||
* until the next bin. In conjunction with the alignment of routine
|
||||
* addresses, this should allow us to have only one sample for every
|
||||
* four bytes of text space and never have any overlap (the two end
|
||||
* cases, above).
|
||||
*/
|
||||
/* Assign samples to the symbol to which they belong.
|
||||
|
||||
Histogram bin I covers some address range [BIN_LOWPC,BIN_HIGH_PC)
|
||||
which may overlap one more symbol address ranges. If a symbol
|
||||
overlaps with the bin's address range by O percent, then O percent
|
||||
of the bin's count is credited to that symbol.
|
||||
|
||||
There are three cases as to where BIN_LOW_PC and BIN_HIGH_PC can be
|
||||
with respect to the symbol's address range [SYM_LOW_PC,
|
||||
SYM_HIGH_PC) as shown in the following diagram. OVERLAP computes
|
||||
the distance (in UNITs) between the arrows, the fraction of the
|
||||
sample that is to be credited to the symbol which starts at
|
||||
SYM_LOW_PC.
|
||||
|
||||
sym_low_pc sym_high_pc
|
||||
| |
|
||||
v v
|
||||
|
||||
+-----------------------------------------------+
|
||||
| |
|
||||
| ->| |<- ->| |<- ->| |<- |
|
||||
| | | | | |
|
||||
+---------+ +---------+ +---------+
|
||||
|
||||
^ ^ ^ ^ ^ ^
|
||||
| | | | | |
|
||||
bin_low_pc bin_high_pc bin_low_pc bin_high_pc bin_low_pc bin_high_pc
|
||||
|
||||
For the VAX we assert that samples will never fall in the first two
|
||||
bytes of any routine, since that is the entry mask, thus we call
|
||||
scale_and_align_entries() to adjust the entry points if the entry
|
||||
mask falls in one bin but the code for the routine doesn't start
|
||||
until the next bin. In conjunction with the alignment of routine
|
||||
addresses, this should allow us to have only one sample for every
|
||||
four bytes of text space and never have any overlap (the two end
|
||||
cases, above). */
|
||||
|
||||
void
|
||||
DEFUN_VOID (hist_assign_samples)
|
||||
{
|
||||
@ -287,23 +300,22 @@ DEFUN_VOID (hist_assign_samples)
|
||||
unsigned int j;
|
||||
double time, credit;
|
||||
|
||||
/* read samples and assign to symbols: */
|
||||
/* Read samples and assign to symbols. */
|
||||
hist_scale = highpc - lowpc;
|
||||
hist_scale /= hist_num_bins;
|
||||
scale_and_align_entries ();
|
||||
|
||||
/* iterate over all sample bins: */
|
||||
|
||||
/* Iterate over all sample bins. */
|
||||
for (i = 0, j = 1; i < hist_num_bins; ++i)
|
||||
{
|
||||
bin_count = hist_sample[i];
|
||||
if (!bin_count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (! bin_count)
|
||||
continue;
|
||||
|
||||
bin_low_pc = lowpc + (bfd_vma) (hist_scale * i);
|
||||
bin_high_pc = lowpc + (bfd_vma) (hist_scale * (i + 1));
|
||||
time = bin_count;
|
||||
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf (
|
||||
"[assign_samples] bin_low_pc=0x%lx, bin_high_pc=0x%lx, bin_count=%d\n",
|
||||
@ -312,28 +324,22 @@ DEFUN_VOID (hist_assign_samples)
|
||||
bin_count));
|
||||
total_time += time;
|
||||
|
||||
/* credit all symbols that are covered by bin I: */
|
||||
|
||||
/* Credit all symbols that are covered by bin I. */
|
||||
for (j = j - 1; j < symtab.len; ++j)
|
||||
{
|
||||
sym_low_pc = symtab.base[j].hist.scaled_addr;
|
||||
sym_high_pc = symtab.base[j + 1].hist.scaled_addr;
|
||||
/*
|
||||
* If high end of bin is below entry address, go for next
|
||||
* bin:
|
||||
*/
|
||||
|
||||
/* If high end of bin is below entry address,
|
||||
go for next bin. */
|
||||
if (bin_high_pc < sym_low_pc)
|
||||
{
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If low end of bin is above high end of symbol, go for
|
||||
* next symbol.
|
||||
*/
|
||||
break;
|
||||
|
||||
/* If low end of bin is above high end of symbol,
|
||||
go for next symbol. */
|
||||
if (bin_low_pc >= sym_high_pc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
overlap =
|
||||
MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc);
|
||||
if (overlap > 0)
|
||||
@ -345,13 +351,13 @@ DEFUN_VOID (hist_assign_samples)
|
||||
(unsigned long) (sizeof (UNIT) * sym_high_pc),
|
||||
symtab.base[j].name, overlap * time / hist_scale,
|
||||
(long) overlap));
|
||||
|
||||
addr = symtab.base[j].addr;
|
||||
credit = overlap * time / hist_scale;
|
||||
/*
|
||||
* Credit symbol if it appears in INCL_FLAT or that
|
||||
* table is empty and it does not appear it in
|
||||
* EXCL_FLAT.
|
||||
*/
|
||||
|
||||
/* Credit symbol if it appears in INCL_FLAT or that
|
||||
table is empty and it does not appear it in
|
||||
EXCL_FLAT. */
|
||||
if (sym_lookup (&syms[INCL_FLAT], addr)
|
||||
|| (syms[INCL_FLAT].len == 0
|
||||
&& !sym_lookup (&syms[EXCL_FLAT], addr)))
|
||||
@ -365,14 +371,14 @@ DEFUN_VOID (hist_assign_samples)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n",
|
||||
total_time));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print header for flag histogram profile:
|
||||
*/
|
||||
/* Print header for flag histogram profile. */
|
||||
|
||||
static void
|
||||
DEFUN (print_header, (prefix), const char prefix)
|
||||
{
|
||||
@ -398,7 +404,8 @@ DEFUN (print_header, (prefix), const char prefix)
|
||||
if (total_time <= 0.0)
|
||||
{
|
||||
printf (_(" no time accumulated\n\n"));
|
||||
/* this doesn't hurt since all the numerators will be zero: */
|
||||
|
||||
/* This doesn't hurt since all the numerators will be zero. */
|
||||
total_time = 1.0;
|
||||
}
|
||||
|
||||
@ -414,50 +421,39 @@ static void
|
||||
DEFUN (print_line, (sym, scale), Sym * sym AND double scale)
|
||||
{
|
||||
if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
accum_time += sym->hist.time;
|
||||
|
||||
if (bsd_style_output)
|
||||
{
|
||||
printf ("%5.1f %10.2f %8.2f",
|
||||
total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
|
||||
accum_time / hz, sym->hist.time / hz);
|
||||
}
|
||||
printf ("%5.1f %10.2f %8.2f",
|
||||
total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
|
||||
accum_time / hz, sym->hist.time / hz);
|
||||
else
|
||||
{
|
||||
printf ("%6.2f %9.2f %8.2f",
|
||||
total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
|
||||
accum_time / hz, sym->hist.time / hz);
|
||||
}
|
||||
printf ("%6.2f %9.2f %8.2f",
|
||||
total_time > 0.0 ? 100 * sym->hist.time / total_time : 0.0,
|
||||
accum_time / hz, sym->hist.time / hz);
|
||||
|
||||
if (sym->ncalls != 0)
|
||||
{
|
||||
printf (" %8lu %8.2f %8.2f ",
|
||||
sym->ncalls, scale * sym->hist.time / hz / sym->ncalls,
|
||||
scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls);
|
||||
}
|
||||
printf (" %8lu %8.2f %8.2f ",
|
||||
sym->ncalls, scale * sym->hist.time / hz / sym->ncalls,
|
||||
scale * (sym->hist.time + sym->cg.child_time) / hz / sym->ncalls);
|
||||
else
|
||||
{
|
||||
printf (" %8.8s %8.8s %8.8s ", "", "", "");
|
||||
}
|
||||
printf (" %8.8s %8.8s %8.8s ", "", "", "");
|
||||
|
||||
if (bsd_style_output)
|
||||
{
|
||||
print_name (sym);
|
||||
}
|
||||
print_name (sym);
|
||||
else
|
||||
{
|
||||
print_name_only (sym);
|
||||
}
|
||||
print_name_only (sym);
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compare LP and RP. The primary comparison key is execution time,
|
||||
* the secondary is number of invocation, and the tertiary is the
|
||||
* lexicographic order of the function names.
|
||||
*/
|
||||
/* Compare LP and RP. The primary comparison key is execution time,
|
||||
the secondary is number of invocation, and the tertiary is the
|
||||
lexicographic order of the function names. */
|
||||
|
||||
static int
|
||||
DEFUN (cmp_time, (lp, rp), const PTR lp AND const PTR rp)
|
||||
{
|
||||
@ -466,31 +462,25 @@ DEFUN (cmp_time, (lp, rp), const PTR lp AND const PTR rp)
|
||||
double time_diff;
|
||||
|
||||
time_diff = right->hist.time - left->hist.time;
|
||||
|
||||
if (time_diff > 0.0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
if (time_diff < 0.0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
|
||||
if (right->ncalls > left->ncalls)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
if (right->ncalls < left->ncalls)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
|
||||
return strcmp (left->name, right->name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print the flat histogram profile.
|
||||
*/
|
||||
/* Print the flat histogram profile. */
|
||||
|
||||
void
|
||||
DEFUN_VOID (hist_print)
|
||||
{
|
||||
@ -501,15 +491,12 @@ DEFUN_VOID (hist_print)
|
||||
bfd_vma addr;
|
||||
|
||||
if (first_output)
|
||||
{
|
||||
first_output = FALSE;
|
||||
}
|
||||
first_output = FALSE;
|
||||
else
|
||||
{
|
||||
printf ("\f\n");
|
||||
}
|
||||
printf ("\f\n");
|
||||
|
||||
accum_time = 0.0;
|
||||
|
||||
if (bsd_style_output)
|
||||
{
|
||||
if (print_descriptions)
|
||||
@ -522,36 +509,36 @@ DEFUN_VOID (hist_print)
|
||||
{
|
||||
printf (_("Flat profile:\n"));
|
||||
}
|
||||
/*
|
||||
* Sort the symbol table by time (call-count and name as secondary
|
||||
* and tertiary keys):
|
||||
*/
|
||||
|
||||
/* Sort the symbol table by time (call-count and name as secondary
|
||||
and tertiary keys). */
|
||||
time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
|
||||
|
||||
for (index = 0; index < symtab.len; ++index)
|
||||
{
|
||||
time_sorted_syms[index] = &symtab.base[index];
|
||||
}
|
||||
time_sorted_syms[index] = &symtab.base[index];
|
||||
|
||||
qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
|
||||
|
||||
if (bsd_style_output)
|
||||
{
|
||||
log_scale = 5; /* milli-seconds is BSD-default */
|
||||
log_scale = 5; /* Milli-seconds is BSD-default. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Search for symbol with highest per-call execution time and
|
||||
* scale accordingly:
|
||||
*/
|
||||
/* Search for symbol with highest per-call
|
||||
execution time and scale accordingly. */
|
||||
log_scale = 0;
|
||||
top_dog = 0;
|
||||
top_time = 0.0;
|
||||
|
||||
for (index = 0; index < symtab.len; ++index)
|
||||
{
|
||||
sym = time_sorted_syms[index];
|
||||
|
||||
if (sym->ncalls != 0)
|
||||
{
|
||||
time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
|
||||
|
||||
if (time > top_time)
|
||||
{
|
||||
top_dog = sym;
|
||||
@ -559,9 +546,11 @@ DEFUN_VOID (hist_print)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (top_dog && top_dog->ncalls != 0 && top_time > 0.0)
|
||||
{
|
||||
top_time /= hz;
|
||||
|
||||
while (SItab[log_scale].scale * top_time < 1000.0
|
||||
&& ((size_t) log_scale
|
||||
< sizeof (SItab) / sizeof (SItab[0]) - 1))
|
||||
@ -571,30 +560,25 @@ DEFUN_VOID (hist_print)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, the dimension is always seconds. In the future, we
|
||||
* may also want to support other (pseudo-)dimensions (such as
|
||||
* I-cache misses etc.).
|
||||
*/
|
||||
/* For now, the dimension is always seconds. In the future, we
|
||||
may also want to support other (pseudo-)dimensions (such as
|
||||
I-cache misses etc.). */
|
||||
print_header (SItab[log_scale].prefix);
|
||||
|
||||
for (index = 0; index < symtab.len; ++index)
|
||||
{
|
||||
addr = time_sorted_syms[index]->addr;
|
||||
/*
|
||||
* Print symbol if its in INCL_FLAT table or that table
|
||||
* is empty and the symbol is not in EXCL_FLAT.
|
||||
*/
|
||||
|
||||
/* Print symbol if its in INCL_FLAT table or that table
|
||||
is empty and the symbol is not in EXCL_FLAT. */
|
||||
if (sym_lookup (&syms[INCL_FLAT], addr)
|
||||
|| (syms[INCL_FLAT].len == 0
|
||||
&& !sym_lookup (&syms[EXCL_FLAT], addr)))
|
||||
{
|
||||
print_line (time_sorted_syms[index], SItab[log_scale].scale);
|
||||
}
|
||||
print_line (time_sorted_syms[index], SItab[log_scale].scale);
|
||||
}
|
||||
|
||||
free (time_sorted_syms);
|
||||
|
||||
if (print_descriptions && !bsd_style_output)
|
||||
{
|
||||
flat_blurb (stdout);
|
||||
}
|
||||
flat_blurb (stdout);
|
||||
}
|
||||
|
45
gprof/hist.h
45
gprof/hist.h
@ -1,23 +1,42 @@
|
||||
/* hist.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef hist_h
|
||||
#define hist_h
|
||||
|
||||
#include "bfd.h"
|
||||
|
||||
extern bfd_vma s_lowpc; /* lowpc from the profile file */
|
||||
extern bfd_vma s_highpc; /* highpc from the profile file */
|
||||
extern bfd_vma lowpc, highpc; /* range profiled, in UNIT's */
|
||||
extern int hist_num_bins; /* number of histogram bins */
|
||||
extern int *hist_sample; /* code histogram */
|
||||
/*
|
||||
* Scale factor converting samples to pc values: each sample covers
|
||||
* HIST_SCALE bytes:
|
||||
*/
|
||||
extern bfd_vma s_lowpc; /* Lowpc from the profile file. */
|
||||
extern bfd_vma s_highpc; /* Highpc from the profile file. */
|
||||
extern bfd_vma lowpc, highpc; /* Range profiled, in UNIT's. */
|
||||
extern int hist_num_bins; /* Number of histogram bins. */
|
||||
extern int *hist_sample; /* Code histogram. */
|
||||
|
||||
/* Scale factor converting samples to pc values:
|
||||
each sample covers HIST_SCALE bytes. */
|
||||
extern double hist_scale;
|
||||
|
||||
|
||||
extern void hist_read_rec PARAMS ((FILE * ifp, const char *filename));
|
||||
extern void hist_write_hist PARAMS ((FILE * ofp, const char *filename));
|
||||
extern void hist_assign_samples PARAMS ((void));
|
||||
extern void hist_print PARAMS ((void));
|
||||
extern void hist_read_rec PARAMS ((FILE *, const char *));
|
||||
extern void hist_write_hist PARAMS ((FILE *, const char *));
|
||||
extern void hist_assign_samples PARAMS ((void));
|
||||
extern void hist_print PARAMS ((void));
|
||||
|
||||
#endif /* hist_h */
|
||||
|
@ -6,7 +6,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2000-06-18 16:58-0700\n"
|
||||
"POT-Creation-Date: 2000-07-24 13:55-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -33,27 +33,27 @@ msgstr ""
|
||||
msgid "[find_call] 0x%lx: bsr"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:134 call_graph.c:70 hist.c:105
|
||||
#: basic_blocks.c:123 call_graph.c:86 hist.c:122
|
||||
#, c-format
|
||||
msgid "%s: %s: unexpected end of file\n"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:215
|
||||
#: basic_blocks.c:198
|
||||
#, c-format
|
||||
msgid "%s: warning: ignoring basic-block exec counts (use -l or --line)\n"
|
||||
msgstr ""
|
||||
|
||||
#. FIXME: This only works if bfd_vma is unsigned long.
|
||||
#: basic_blocks.c:324 basic_blocks.c:333
|
||||
#: basic_blocks.c:296 basic_blocks.c:306
|
||||
#, c-format
|
||||
msgid "%s:%d: (%s:0x%lx) %lu executions\n"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:325 basic_blocks.c:334
|
||||
#: basic_blocks.c:297 basic_blocks.c:307
|
||||
msgid "<unknown>"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:596
|
||||
#: basic_blocks.c:551
|
||||
#, c-format
|
||||
msgid ""
|
||||
"\n"
|
||||
@ -64,262 +64,262 @@ msgid ""
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:620
|
||||
#: basic_blocks.c:575
|
||||
msgid ""
|
||||
"\n"
|
||||
"Execution Summary:\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:621
|
||||
#: basic_blocks.c:576
|
||||
#, c-format
|
||||
msgid "%9ld Executable lines in this file\n"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:623
|
||||
#: basic_blocks.c:578
|
||||
#, c-format
|
||||
msgid "%9ld Lines executed\n"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:624
|
||||
#: basic_blocks.c:579
|
||||
#, c-format
|
||||
msgid "%9.2f Percent of the file executed\n"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:628
|
||||
#: basic_blocks.c:583
|
||||
#, c-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"%9lu Total number of line executions\n"
|
||||
msgstr ""
|
||||
|
||||
#: basic_blocks.c:630
|
||||
#: basic_blocks.c:585
|
||||
#, c-format
|
||||
msgid "%9.2f Average executions per line\n"
|
||||
msgstr ""
|
||||
|
||||
#: call_graph.c:48
|
||||
#: call_graph.c:66
|
||||
#, c-format
|
||||
msgid "[cg_tally] arc from %s to %s traversed %lu times\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:39
|
||||
#: cg_print.c:54
|
||||
msgid ""
|
||||
"\t\t Call graph (explanation follows)\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:43
|
||||
#: cg_print.c:56
|
||||
msgid ""
|
||||
"\t\t\tCall graph\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:46 hist.c:385
|
||||
#: cg_print.c:59 hist.c:391
|
||||
#, c-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"granularity: each sample hit covers %ld byte(s)"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:50
|
||||
#: cg_print.c:63
|
||||
msgid ""
|
||||
" for %.2f%% of %.2f seconds\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:55
|
||||
#: cg_print.c:67
|
||||
msgid ""
|
||||
" no time propagated\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:64 cg_print.c:67 cg_print.c:69
|
||||
#: cg_print.c:76 cg_print.c:79 cg_print.c:81
|
||||
msgid "called"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:64 cg_print.c:69
|
||||
#: cg_print.c:76 cg_print.c:81
|
||||
msgid "total"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:64
|
||||
#: cg_print.c:76
|
||||
msgid "parents"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:66 cg_print.c:67
|
||||
#: cg_print.c:78 cg_print.c:79
|
||||
msgid "index"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:66
|
||||
#: cg_print.c:78
|
||||
msgid "%time"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:66 cg_print.c:67
|
||||
#: cg_print.c:78 cg_print.c:79
|
||||
msgid "self"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:66
|
||||
#: cg_print.c:78
|
||||
msgid "descendents"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:67 hist.c:409
|
||||
#: cg_print.c:79 hist.c:416
|
||||
msgid "name"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:69
|
||||
#: cg_print.c:81
|
||||
msgid "children"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:74
|
||||
#: cg_print.c:86
|
||||
msgid "index %% time self children called name\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:101
|
||||
#: cg_print.c:109
|
||||
#, c-format
|
||||
msgid " <cycle %d as a whole> [%d]\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:353
|
||||
#: cg_print.c:335
|
||||
#, c-format
|
||||
msgid "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s <spontaneous>\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:354
|
||||
#: cg_print.c:336
|
||||
#, c-format
|
||||
msgid "%6.6s %5.5s %7.7s %7.7s %7.7s %7.7s <spontaneous>\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:587
|
||||
#: cg_print.c:570
|
||||
msgid ""
|
||||
"Index by function name\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: cg_print.c:644 cg_print.c:653
|
||||
#: cg_print.c:627 cg_print.c:636
|
||||
#, c-format
|
||||
msgid "<cycle %d>"
|
||||
msgstr ""
|
||||
|
||||
#: corefile.c:39
|
||||
#: corefile.c:61
|
||||
#, c-format
|
||||
msgid "%s: could not open %s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: corefile.c:53 corefile.c:87
|
||||
#: corefile.c:75 corefile.c:109
|
||||
#, c-format
|
||||
msgid "%s: unable to parse mapping file %s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: corefile.c:128
|
||||
#: corefile.c:151
|
||||
#, c-format
|
||||
msgid "%s: %s: not in a.out format\n"
|
||||
msgstr ""
|
||||
|
||||
#: corefile.c:139
|
||||
#: corefile.c:162
|
||||
#, c-format
|
||||
msgid "%s: can't find .text section in %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: corefile.c:198
|
||||
#: corefile.c:220
|
||||
#, c-format
|
||||
msgid "%s: ran out room for %lu bytes of text space\n"
|
||||
msgstr ""
|
||||
|
||||
#: corefile.c:211
|
||||
#: corefile.c:234
|
||||
#, c-format
|
||||
msgid "%s: can't do -c\n"
|
||||
msgstr ""
|
||||
|
||||
#: corefile.c:243
|
||||
#: corefile.c:265
|
||||
#, c-format
|
||||
msgid "%s: -c not supported on architecture %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: corefile.c:433
|
||||
#: corefile.c:432
|
||||
#, c-format
|
||||
msgid "%s: file `%s' has no symbols\n"
|
||||
msgstr ""
|
||||
|
||||
#: corefile.c:755
|
||||
#: corefile.c:732
|
||||
#, c-format
|
||||
msgid "%s: somebody miscounted: ltab.len=%d instead of %ld\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:33 gmon_io.c:55
|
||||
#: gmon_io.c:50 gmon_io.c:71
|
||||
#, c-format
|
||||
msgid "%s: bfd_vma has unexpected size of %ld bytes\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:90 gmon_io.c:185
|
||||
#: gmon_io.c:107 gmon_io.c:199
|
||||
#, c-format
|
||||
msgid "%s: file too short to be a gmon file\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:100 gmon_io.c:218
|
||||
#: gmon_io.c:117 gmon_io.c:233
|
||||
#, c-format
|
||||
msgid "%s: file `%s' has bad magic cookie\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:111
|
||||
#: gmon_io.c:128
|
||||
#, c-format
|
||||
msgid "%s: file `%s' has unsupported version %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:141
|
||||
#: gmon_io.c:158
|
||||
#, c-format
|
||||
msgid "%s: %s: found bad tag %d (file corrupted?)\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:206
|
||||
#: gmon_io.c:221
|
||||
#, c-format
|
||||
msgid "%s: profiling rate incompatible with first gmon file\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:235
|
||||
#: gmon_io.c:250
|
||||
#, c-format
|
||||
msgid "%s: incompatible with first gmon file\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:261
|
||||
#: gmon_io.c:278
|
||||
#, c-format
|
||||
msgid "%s: file '%s' does not appear to be in gmon.out format\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:283
|
||||
#: gmon_io.c:299
|
||||
#, c-format
|
||||
msgid "%s: unexpected EOF after reading %d/%d bins\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:318
|
||||
#: gmon_io.c:335
|
||||
msgid "time is in ticks, not seconds\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:324 gmon_io.c:464
|
||||
#: gmon_io.c:341 gmon_io.c:475
|
||||
#, c-format
|
||||
msgid "%s: don't know how to deal with file format %d\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:331
|
||||
#: gmon_io.c:348
|
||||
#, c-format
|
||||
msgid "File `%s' (version %d) contains:\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:333
|
||||
#: gmon_io.c:350
|
||||
#, c-format
|
||||
msgid "\t%d histogram record%s\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:335
|
||||
#: gmon_io.c:352
|
||||
#, c-format
|
||||
msgid "\t%d call-graph record%s\n"
|
||||
msgstr ""
|
||||
|
||||
#: gmon_io.c:337
|
||||
#: gmon_io.c:354
|
||||
#, c-format
|
||||
msgid "\t%d basic-block count record%s\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:144
|
||||
#: gprof.c:145
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage: %s [-[abcDhilLsTvwxyz]] [-[ACeEfFJnNOpPqQZ][name]] [-I dirs]\n"
|
||||
@ -333,117 +333,122 @@ msgid ""
|
||||
"\t[--no-static] [--print-path] [--separate-files]\n"
|
||||
"\t[--static-call-graph] [--sum] [--table-length=len] [--traditional]\n"
|
||||
"\t[--version] [--width=n] [--ignore-non-functions]\n"
|
||||
"\t[--demangle] [--no-demangle]\n"
|
||||
"\t[--demangle[=STYLE]] [--no-demangle]\n"
|
||||
"\t[image-file] [profile-file...]\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:160
|
||||
#: gprof.c:161
|
||||
#, c-format
|
||||
msgid "Report bugs to %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:229
|
||||
#: gprof.c:230
|
||||
#, c-format
|
||||
msgid "%s: debugging not supported; -d ignored\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:309
|
||||
#: gprof.c:310
|
||||
#, c-format
|
||||
msgid "%s: unknown file format %s\n"
|
||||
msgstr ""
|
||||
|
||||
#. This output is intended to follow the GNU standards document.
|
||||
#: gprof.c:393
|
||||
#: gprof.c:394
|
||||
#, c-format
|
||||
msgid "GNU gprof %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:394
|
||||
#: gprof.c:395
|
||||
msgid ""
|
||||
"Based on BSD gprof, copyright 1983 Regents of the University of California.\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:395
|
||||
#: gprof.c:396
|
||||
msgid ""
|
||||
"This program is free software. This program has absolutely no warranty.\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:441
|
||||
#: gprof.c:437
|
||||
#, c-format
|
||||
msgid "%s: unknown demangling style `%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:457
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: Only one of --function-ordering and --file-ordering may be specified.\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:541
|
||||
#: gprof.c:557
|
||||
#, c-format
|
||||
msgid "%s: sorry, file format `prof' is not yet supported\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:602
|
||||
#: gprof.c:618
|
||||
#, c-format
|
||||
msgid "%s: gmon.out file is missing histogram\n"
|
||||
msgstr ""
|
||||
|
||||
#: gprof.c:609
|
||||
#: gprof.c:625
|
||||
#, c-format
|
||||
msgid "%s: gmon.out file is missing call-graph data\n"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:143
|
||||
#: hist.c:158
|
||||
#, c-format
|
||||
msgid "%s: `%s' is incompatible with first gmon file\n"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:159
|
||||
#: hist.c:174
|
||||
#, c-format
|
||||
msgid "%s: %s: unexpected EOF after reading %d of %d samples\n"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:381
|
||||
#: hist.c:387
|
||||
#, c-format
|
||||
msgid "%c%c/call"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:389
|
||||
#: hist.c:395
|
||||
msgid ""
|
||||
" for %.2f%% of %.2f %s\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:395
|
||||
#: hist.c:401
|
||||
#, c-format
|
||||
msgid ""
|
||||
"\n"
|
||||
"Each sample counts as %g %s.\n"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:400
|
||||
#: hist.c:406
|
||||
msgid ""
|
||||
" no time accumulated\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:406
|
||||
#: hist.c:413
|
||||
msgid "cumulative"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:406
|
||||
#: hist.c:413
|
||||
msgid "self "
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:406
|
||||
#: hist.c:413
|
||||
msgid "total "
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:408
|
||||
#: hist.c:415
|
||||
msgid "time"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:408
|
||||
#: hist.c:415
|
||||
msgid "calls"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:517
|
||||
#: hist.c:504
|
||||
msgid ""
|
||||
"\n"
|
||||
"\n"
|
||||
@ -451,16 +456,16 @@ msgid ""
|
||||
"flat profile:\n"
|
||||
msgstr ""
|
||||
|
||||
#: hist.c:523
|
||||
#: hist.c:510
|
||||
msgid "Flat profile:\n"
|
||||
msgstr ""
|
||||
|
||||
#: source.c:155
|
||||
#: source.c:163
|
||||
#, c-format
|
||||
msgid "%s: could not locate `%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: source.c:242
|
||||
#: source.c:238
|
||||
#, c-format
|
||||
msgid "*** File %s:\n"
|
||||
msgstr ""
|
||||
|
@ -1,3 +1,24 @@
|
||||
/* search-list.c
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include "libiberty.h"
|
||||
#include "gprof.h"
|
||||
#include "search_list.h"
|
||||
@ -16,28 +37,24 @@ DEFUN (search_list_append, (list, paths),
|
||||
{
|
||||
beg = colon + 1;
|
||||
colon = strchr (beg, PATH_SEP_CHAR);
|
||||
|
||||
if (colon)
|
||||
{
|
||||
len = colon - beg;
|
||||
}
|
||||
len = colon - beg;
|
||||
else
|
||||
{
|
||||
len = strlen (beg);
|
||||
}
|
||||
len = strlen (beg);
|
||||
|
||||
new_el = (Search_List_Elem *) xmalloc (sizeof (*new_el) + len);
|
||||
memcpy (new_el->path, beg, len);
|
||||
new_el->path[len] = '\0';
|
||||
|
||||
/* append new path at end of list: */
|
||||
/* Append new path at end of list. */
|
||||
new_el->next = 0;
|
||||
|
||||
if (list->tail)
|
||||
{
|
||||
list->tail->next = new_el;
|
||||
}
|
||||
list->tail->next = new_el;
|
||||
else
|
||||
{
|
||||
list->head = new_el;
|
||||
}
|
||||
list->head = new_el;
|
||||
|
||||
list->tail = new_el;
|
||||
}
|
||||
while (colon);
|
||||
|
@ -1,3 +1,23 @@
|
||||
/* search-list.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef search_list_h
|
||||
#define search_list_h
|
||||
|
||||
@ -23,6 +43,6 @@ typedef struct
|
||||
}
|
||||
Search_List;
|
||||
|
||||
extern void search_list_append PARAMS ((Search_List * list, const char *paths));
|
||||
extern void search_list_append PARAMS ((Search_List *, const char *));
|
||||
|
||||
#endif /* search_list_h */
|
||||
|
153
gprof/source.c
153
gprof/source.c
@ -1,21 +1,36 @@
|
||||
/*
|
||||
* Keeps track of source files.
|
||||
*/
|
||||
/* source.c - Keep track of source files.
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include "gprof.h"
|
||||
#include "libiberty.h"
|
||||
#include "filenames.h"
|
||||
#include "search_list.h"
|
||||
#include "source.h"
|
||||
|
||||
#define EXT_ANNO "-ann" /* postfix of annotated files */
|
||||
#define EXT_ANNO "-ann" /* Postfix of annotated files. */
|
||||
|
||||
/*
|
||||
* Default option values:
|
||||
*/
|
||||
/* Default option values. */
|
||||
bool create_annotation_files = FALSE;
|
||||
|
||||
Search_List src_search_list =
|
||||
{0, 0};
|
||||
Search_List src_search_list = {0, 0};
|
||||
Source_File *first_src_file = 0;
|
||||
|
||||
|
||||
@ -27,20 +42,21 @@ DEFUN (source_file_lookup_path, (path), const char *path)
|
||||
for (sf = first_src_file; sf; sf = sf->next)
|
||||
{
|
||||
if (FILENAME_CMP (path, sf->name) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sf)
|
||||
{
|
||||
/* create a new source file descriptor: */
|
||||
|
||||
/* Create a new source file descriptor. */
|
||||
sf = (Source_File *) xmalloc (sizeof (*sf));
|
||||
|
||||
memset (sf, 0, sizeof (*sf));
|
||||
|
||||
sf->name = xstrdup (path);
|
||||
sf->next = first_src_file;
|
||||
first_src_file = sf;
|
||||
}
|
||||
|
||||
return sf;
|
||||
}
|
||||
|
||||
@ -50,28 +66,24 @@ DEFUN (source_file_lookup_name, (filename), const char *filename)
|
||||
{
|
||||
const char *fname;
|
||||
Source_File *sf;
|
||||
/*
|
||||
* The user cannot know exactly how a filename will be stored in
|
||||
* the debugging info (e.g., ../include/foo.h
|
||||
* vs. /usr/include/foo.h). So we simply compare the filename
|
||||
* component of a path only:
|
||||
*/
|
||||
|
||||
/* The user cannot know exactly how a filename will be stored in
|
||||
the debugging info (e.g., ../include/foo.h
|
||||
vs. /usr/include/foo.h). So we simply compare the filename
|
||||
component of a path only. */
|
||||
for (sf = first_src_file; sf; sf = sf->next)
|
||||
{
|
||||
fname = strrchr (sf->name, '/');
|
||||
|
||||
if (fname)
|
||||
{
|
||||
++fname;
|
||||
}
|
||||
++fname;
|
||||
else
|
||||
{
|
||||
fname = sf->name;
|
||||
}
|
||||
fname = sf->name;
|
||||
|
||||
if (FILENAME_CMP (filename, fname) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return sf;
|
||||
}
|
||||
|
||||
@ -91,25 +103,23 @@ DEFUN (annotate_source, (sf, max_width, annote, arg),
|
||||
FILE *ifp, *ofp;
|
||||
Search_List_Elem *sle = src_search_list.head;
|
||||
|
||||
/*
|
||||
* Open input file. If open fails, walk along search-list until
|
||||
* open succeeds or reaching end of list:
|
||||
*/
|
||||
/* Open input file. If open fails, walk along search-list until
|
||||
open succeeds or reaching end of list. */
|
||||
strcpy (fname, sf->name);
|
||||
|
||||
if (IS_ABSOLUTE_PATH (sf->name))
|
||||
{
|
||||
sle = 0; /* don't use search list for absolute paths */
|
||||
}
|
||||
sle = 0; /* Don't use search list for absolute paths. */
|
||||
|
||||
name_only = 0;
|
||||
while (TRUE)
|
||||
{
|
||||
DBG (SRCDEBUG, printf ("[annotate_source]: looking for %s, trying %s\n",
|
||||
sf->name, fname));
|
||||
|
||||
ifp = fopen (fname, FOPEN_RB);
|
||||
if (ifp)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
if (!sle && !name_only)
|
||||
{
|
||||
name_only = strrchr (sf->name, '/');
|
||||
@ -124,11 +134,12 @@ DEFUN (annotate_source, (sf, max_width, annote, arg),
|
||||
#endif
|
||||
if (name_only)
|
||||
{
|
||||
/* try search-list again, but this time with name only: */
|
||||
/* Try search-list again, but this time with name only. */
|
||||
++name_only;
|
||||
sle = src_search_list.head;
|
||||
}
|
||||
}
|
||||
|
||||
if (sle)
|
||||
{
|
||||
strcpy (fname, sle->path);
|
||||
@ -138,38 +149,34 @@ DEFUN (annotate_source, (sf, max_width, annote, arg),
|
||||
strcat (fname, ".");
|
||||
#endif
|
||||
strcat (fname, "/");
|
||||
|
||||
if (name_only)
|
||||
{
|
||||
strcat (fname, name_only);
|
||||
}
|
||||
strcat (fname, name_only);
|
||||
else
|
||||
{
|
||||
strcat (fname, sf->name);
|
||||
}
|
||||
strcat (fname, sf->name);
|
||||
|
||||
sle = sle->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
fprintf (stderr, _("%s: could not locate `%s'\n"),
|
||||
whoami, sf->name);
|
||||
}
|
||||
fprintf (stderr, _("%s: could not locate `%s'\n"),
|
||||
whoami, sf->name);
|
||||
else
|
||||
{
|
||||
perror (sf->name);
|
||||
}
|
||||
perror (sf->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ofp = stdout;
|
||||
|
||||
if (create_annotation_files)
|
||||
{
|
||||
/* try to create annotated source file: */
|
||||
/* Try to create annotated source file. */
|
||||
const char *filename;
|
||||
|
||||
/* create annotation files in the current working directory: */
|
||||
/* Create annotation files in the current working directory. */
|
||||
filename = strrchr (sf->name, '/');
|
||||
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
|
||||
{
|
||||
@ -181,13 +188,9 @@ DEFUN (annotate_source, (sf, max_width, annote, arg),
|
||||
}
|
||||
#endif
|
||||
if (filename)
|
||||
{
|
||||
++filename;
|
||||
}
|
||||
++filename;
|
||||
else
|
||||
{
|
||||
filename = sf->name;
|
||||
}
|
||||
filename = sf->name;
|
||||
|
||||
strcpy (fname, filename);
|
||||
strcat (fname, EXT_ANNO);
|
||||
@ -210,6 +213,7 @@ DEFUN (annotate_source, (sf, max_width, annote, arg),
|
||||
}
|
||||
#endif
|
||||
ofp = fopen (fname, "w");
|
||||
|
||||
if (!ofp)
|
||||
{
|
||||
perror (fname);
|
||||
@ -217,34 +221,27 @@ DEFUN (annotate_source, (sf, max_width, annote, arg),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print file names if output goes to stdout and there are
|
||||
* more than one source file:
|
||||
*/
|
||||
/* Print file names if output goes to stdout
|
||||
and there are more than one source file. */
|
||||
if (ofp == stdout)
|
||||
{
|
||||
if (first_file)
|
||||
{
|
||||
first_file = FALSE;
|
||||
}
|
||||
first_file = FALSE;
|
||||
else
|
||||
{
|
||||
fputc ('\n', ofp);
|
||||
}
|
||||
fputc ('\n', ofp);
|
||||
|
||||
if (first_output)
|
||||
{
|
||||
first_output = FALSE;
|
||||
}
|
||||
first_output = FALSE;
|
||||
else
|
||||
{
|
||||
fprintf (ofp, "\f\n");
|
||||
}
|
||||
fprintf (ofp, "\f\n");
|
||||
|
||||
fprintf (ofp, _("*** File %s:\n"), sf->name);
|
||||
}
|
||||
|
||||
annotation = xmalloc (max_width + 1);
|
||||
line_num = 1;
|
||||
new_line = TRUE;
|
||||
|
||||
while ((nread = fread (buf, 1, sizeof (buf), ifp)) > 0)
|
||||
{
|
||||
for (i = 0; i < nread; ++i)
|
||||
@ -256,10 +253,12 @@ DEFUN (annotate_source, (sf, max_width, annote, arg),
|
||||
++line_num;
|
||||
new_line = FALSE;
|
||||
}
|
||||
|
||||
new_line = (buf[i] == '\n');
|
||||
fputc (buf[i], ofp);
|
||||
}
|
||||
}
|
||||
|
||||
free (annotation);
|
||||
return ofp;
|
||||
}
|
||||
|
@ -1,3 +1,23 @@
|
||||
/* source.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef source_h
|
||||
#define source_h
|
||||
|
||||
@ -8,48 +28,37 @@
|
||||
typedef struct source_file
|
||||
{
|
||||
struct source_file *next;
|
||||
const char *name; /* name of source file */
|
||||
unsigned long ncalls; /* # of "calls" to this file */
|
||||
int num_lines; /* # of lines in file */
|
||||
int nalloced; /* number of lines allocated */
|
||||
void **line; /* usage-dependent per-line data */
|
||||
const char *name; /* Name of source file. */
|
||||
unsigned long ncalls; /* # of "calls" to this file. */
|
||||
int num_lines; /* # of lines in file. */
|
||||
int nalloced; /* Number of lines allocated. */
|
||||
void **line; /* Usage-dependent per-line data. */
|
||||
}
|
||||
Source_File;
|
||||
|
||||
/*
|
||||
* Options:
|
||||
*/
|
||||
extern bool create_annotation_files; /* create annotated output files? */
|
||||
/* Options. */
|
||||
extern bool create_annotation_files; /* Create annotated output files? */
|
||||
|
||||
/*
|
||||
* List of directories to search for source files:
|
||||
*/
|
||||
/* List of directories to search for source files. */
|
||||
extern Search_List src_search_list;
|
||||
|
||||
/*
|
||||
* Chain of source-file descriptors:
|
||||
*/
|
||||
/* Chain of source-file descriptors. */
|
||||
extern Source_File *first_src_file;
|
||||
|
||||
/*
|
||||
* Returns pointer to source file descriptor for PATH/FILENAME.
|
||||
*/
|
||||
extern Source_File *source_file_lookup_path PARAMS ((const char *path));
|
||||
extern Source_File *source_file_lookup_name PARAMS ((const char *filename));
|
||||
/* Returns pointer to source file descriptor for PATH/FILENAME. */
|
||||
extern Source_File *source_file_lookup_path PARAMS ((const char *));
|
||||
extern Source_File *source_file_lookup_name PARAMS ((const char *));
|
||||
|
||||
/*
|
||||
* Read source file SF output annotated source. The annotation is at
|
||||
* MAX_WIDTH characters wide and for each source-line an annotation is
|
||||
* obtained by invoking function ANNOTE. ARG is an argument passed to
|
||||
* ANNOTE that is left uninterpreted by annotate_source().
|
||||
*
|
||||
* Returns a pointer to the output file (which maybe stdout) such
|
||||
* that summary statistics can be printed. If the returned file
|
||||
* is not stdout, it should be closed when done with it.
|
||||
*/
|
||||
/* Read source file SF output annotated source. The annotation is at
|
||||
MAX_WIDTH characters wide and for each source-line an annotation is
|
||||
obtained by invoking function ANNOTE. ARG is an argument passed to
|
||||
ANNOTE that is left uninterpreted by annotate_source().
|
||||
|
||||
Returns a pointer to the output file (which maybe stdout) such
|
||||
that summary statistics can be printed. If the returned file
|
||||
is not stdout, it should be closed when done with it. */
|
||||
extern FILE *annotate_source PARAMS ((Source_File * sf, int max_width,
|
||||
void (*annote) (char *b, int w, int l,
|
||||
void *arg),
|
||||
void *arg));
|
||||
|
||||
#endif /* source_h */
|
||||
|
218
gprof/sym_ids.c
218
gprof/sym_ids.c
@ -1,3 +1,24 @@
|
||||
/* sym_ids.c
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "libiberty.h"
|
||||
@ -7,14 +28,15 @@
|
||||
struct sym_id
|
||||
{
|
||||
struct sym_id *next;
|
||||
char *spec; /* parsing modifies this */
|
||||
char *spec; /* Parsing modifies this. */
|
||||
Table_Id which_table;
|
||||
bool has_right;
|
||||
|
||||
struct match
|
||||
{
|
||||
int prev_index; /* index of prev match */
|
||||
Sym *prev_match; /* previous match */
|
||||
Sym *first_match; /* chain of all matches */
|
||||
int prev_index; /* Index of prev match. */
|
||||
Sym *prev_match; /* Previous match. */
|
||||
Sym *first_match; /* Chain of all matches. */
|
||||
Sym sym;
|
||||
}
|
||||
left, right;
|
||||
@ -35,13 +57,11 @@ const char *table_name[] =
|
||||
};
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
* This is the table in which we keep all the syms that match
|
||||
* the right half of an arc id. It is NOT sorted according
|
||||
* to the addresses, because it is accessed only through
|
||||
* the left half's CHILDREN pointers (so it's crucial not
|
||||
* to reorder this table once pointers into it exist).
|
||||
*/
|
||||
/* This is the table in which we keep all the syms that match
|
||||
the right half of an arc id. It is NOT sorted according
|
||||
to the addresses, because it is accessed only through
|
||||
the left half's CHILDREN pointers (so it's crucial not
|
||||
to reorder this table once pointers into it exist). */
|
||||
static Sym_Table right_ids;
|
||||
|
||||
static Source_File non_existent_file =
|
||||
@ -69,17 +89,16 @@ DEFUN (sym_id_add, (spec, which_table),
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A spec has the syntax FILENAME:(FUNCNAME|LINENUM). As a convenience
|
||||
* to the user, a spec without a colon is interpreted as:
|
||||
*
|
||||
* (i) a FILENAME if it contains a dot
|
||||
* (ii) a FUNCNAME if it starts with a non-digit character
|
||||
* (iii) a LINENUM if it starts with a digit
|
||||
*
|
||||
* A FUNCNAME containing a dot can be specified by :FUNCNAME, a
|
||||
* FILENAME not containing a dot can be specified by FILENAME:.
|
||||
*/
|
||||
/* A spec has the syntax FILENAME:(FUNCNAME|LINENUM). As a convenience
|
||||
to the user, a spec without a colon is interpreted as:
|
||||
|
||||
(i) a FILENAME if it contains a dot
|
||||
(ii) a FUNCNAME if it starts with a non-digit character
|
||||
(iii) a LINENUM if it starts with a digit
|
||||
|
||||
A FUNCNAME containing a dot can be specified by :FUNCNAME, a
|
||||
FILENAME not containing a dot can be specified by FILENAME. */
|
||||
|
||||
static void
|
||||
DEFUN (parse_spec, (spec, sym), char *spec AND Sym * sym)
|
||||
{
|
||||
@ -87,40 +106,38 @@ DEFUN (parse_spec, (spec, sym), char *spec AND Sym * sym)
|
||||
|
||||
sym_init (sym);
|
||||
colon = strrchr (spec, ':');
|
||||
|
||||
if (colon)
|
||||
{
|
||||
*colon = '\0';
|
||||
|
||||
if (colon > spec)
|
||||
{
|
||||
sym->file = source_file_lookup_name (spec);
|
||||
|
||||
if (!sym->file)
|
||||
{
|
||||
sym->file = &non_existent_file;
|
||||
}
|
||||
sym->file = &non_existent_file;
|
||||
}
|
||||
|
||||
spec = colon + 1;
|
||||
|
||||
if (strlen (spec))
|
||||
{
|
||||
if (isdigit ((unsigned char) spec[0]))
|
||||
{
|
||||
sym->line_num = atoi (spec);
|
||||
}
|
||||
sym->line_num = atoi (spec);
|
||||
else
|
||||
{
|
||||
sym->name = spec;
|
||||
}
|
||||
sym->name = spec;
|
||||
}
|
||||
}
|
||||
else if (strlen (spec))
|
||||
{
|
||||
/* no colon: spec is a filename if it contains a dot: */
|
||||
/* No colon: spec is a filename if it contains a dot. */
|
||||
if (strchr (spec, '.'))
|
||||
{
|
||||
sym->file = source_file_lookup_name (spec);
|
||||
|
||||
if (!sym->file)
|
||||
{
|
||||
sym->file = &non_existent_file;
|
||||
}
|
||||
sym->file = &non_existent_file;
|
||||
}
|
||||
else if (isdigit ((unsigned char) *spec))
|
||||
{
|
||||
@ -134,10 +151,9 @@ DEFUN (parse_spec, (spec, sym), char *spec AND Sym * sym)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A symbol id has the syntax SPEC[/SPEC], where SPEC is is defined
|
||||
* by parse_spec().
|
||||
*/
|
||||
/* A symbol id has the syntax SPEC[/SPEC], where SPEC is is defined
|
||||
by parse_spec(). */
|
||||
|
||||
static void
|
||||
DEFUN (parse_id, (id), struct sym_id *id)
|
||||
{
|
||||
@ -158,44 +174,35 @@ DEFUN (parse_id, (id), struct sym_id *id)
|
||||
if (debug_level & IDDEBUG)
|
||||
{
|
||||
printf ("%s:", id->left.sym.file ? id->left.sym.file->name : "*");
|
||||
|
||||
if (id->left.sym.name)
|
||||
{
|
||||
printf ("%s", id->left.sym.name);
|
||||
}
|
||||
printf ("%s", id->left.sym.name);
|
||||
else if (id->left.sym.line_num)
|
||||
{
|
||||
printf ("%d", id->left.sym.line_num);
|
||||
}
|
||||
printf ("%d", id->left.sym.line_num);
|
||||
else
|
||||
{
|
||||
printf ("*");
|
||||
}
|
||||
printf ("*");
|
||||
|
||||
if (id->has_right)
|
||||
{
|
||||
printf ("/%s:",
|
||||
id->right.sym.file ? id->right.sym.file->name : "*");
|
||||
|
||||
if (id->right.sym.name)
|
||||
{
|
||||
printf ("%s", id->right.sym.name);
|
||||
}
|
||||
printf ("%s", id->right.sym.name);
|
||||
else if (id->right.sym.line_num)
|
||||
{
|
||||
printf ("%d", id->right.sym.line_num);
|
||||
}
|
||||
printf ("%d", id->right.sym.line_num);
|
||||
else
|
||||
{
|
||||
printf ("*");
|
||||
}
|
||||
printf ("*");
|
||||
}
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return TRUE iff PATTERN matches SYM.
|
||||
*/
|
||||
/* Return TRUE iff PATTERN matches SYM. */
|
||||
|
||||
static bool
|
||||
DEFUN (match, (pattern, sym), Sym * pattern AND Sym * sym)
|
||||
{
|
||||
@ -214,37 +221,36 @@ DEFUN (extend_match, (m, sym, tab, second_pass),
|
||||
{
|
||||
if (m->prev_match != sym - 1)
|
||||
{
|
||||
/* discontinuity: add new match to table: */
|
||||
/* Discontinuity: add new match to table. */
|
||||
if (second_pass)
|
||||
{
|
||||
tab->base[tab->len] = *sym;
|
||||
m->prev_index = tab->len;
|
||||
|
||||
/* link match into match's chain: */
|
||||
/* Link match into match's chain. */
|
||||
tab->base[tab->len].next = m->first_match;
|
||||
m->first_match = &tab->base[tab->len];
|
||||
}
|
||||
|
||||
++tab->len;
|
||||
}
|
||||
|
||||
/* extend match to include this symbol: */
|
||||
/* Extend match to include this symbol. */
|
||||
if (second_pass)
|
||||
{
|
||||
tab->base[m->prev_index].end_addr = sym->end_addr;
|
||||
}
|
||||
tab->base[m->prev_index].end_addr = sym->end_addr;
|
||||
|
||||
m->prev_match = sym;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Go through sym_id list produced by option processing and fill
|
||||
* in the various symbol tables indicating what symbols should
|
||||
* be displayed or suppressed for the various kinds of outputs.
|
||||
*
|
||||
* This can potentially produce huge tables and in particulars
|
||||
* tons of arcs, but this happens only if the user makes silly
|
||||
* requests---you get what you ask for!
|
||||
*/
|
||||
/* Go through sym_id list produced by option processing and fill
|
||||
in the various symbol tables indicating what symbols should
|
||||
be displayed or suppressed for the various kinds of outputs.
|
||||
|
||||
This can potentially produce huge tables and in particulars
|
||||
tons of arcs, but this happens only if the user makes silly
|
||||
requests---you get what you ask for! */
|
||||
|
||||
void
|
||||
DEFUN_VOID (sym_id_parse)
|
||||
{
|
||||
@ -252,33 +258,24 @@ DEFUN_VOID (sym_id_parse)
|
||||
struct sym_id *id;
|
||||
Sym_Table *tab;
|
||||
|
||||
/*
|
||||
* Convert symbol ids into Syms, so we can deal with them more easily:
|
||||
*/
|
||||
/* Convert symbol ids into Syms, so we can deal with them more easily. */
|
||||
for (id = id_list; id; id = id->next)
|
||||
{
|
||||
parse_id (id);
|
||||
}
|
||||
|
||||
/* first determine size of each table: */
|
||||
parse_id (id);
|
||||
|
||||
/* First determine size of each table. */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
for (id = id_list; id; id = id->next)
|
||||
{
|
||||
if (match (&id->left.sym, sym))
|
||||
{
|
||||
extend_match (&id->left, sym, &syms[id->which_table], FALSE);
|
||||
}
|
||||
extend_match (&id->left, sym, &syms[id->which_table], FALSE);
|
||||
|
||||
if (id->has_right && match (&id->right.sym, sym))
|
||||
{
|
||||
extend_match (&id->right, sym, &right_ids, FALSE);
|
||||
}
|
||||
extend_match (&id->right, sym, &right_ids, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* create tables of appropriate size and reset lengths: */
|
||||
|
||||
/* Create tables of appropriate size and reset lengths. */
|
||||
for (tab = syms; tab < &syms[NUM_TABLES]; ++tab)
|
||||
{
|
||||
if (tab->len)
|
||||
@ -288,6 +285,7 @@ DEFUN_VOID (sym_id_parse)
|
||||
tab->len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (right_ids.len)
|
||||
{
|
||||
right_ids.base = (Sym *) xmalloc (right_ids.len * sizeof (Sym));
|
||||
@ -295,25 +293,20 @@ DEFUN_VOID (sym_id_parse)
|
||||
right_ids.len = 0;
|
||||
}
|
||||
|
||||
/* make a second pass through symtab, creating syms as necessary: */
|
||||
|
||||
/* Make a second pass through symtab, creating syms as necessary. */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
for (id = id_list; id; id = id->next)
|
||||
{
|
||||
if (match (&id->left.sym, sym))
|
||||
{
|
||||
extend_match (&id->left, sym, &syms[id->which_table], TRUE);
|
||||
}
|
||||
extend_match (&id->left, sym, &syms[id->which_table], TRUE);
|
||||
|
||||
if (id->has_right && match (&id->right.sym, sym))
|
||||
{
|
||||
extend_match (&id->right, sym, &right_ids, TRUE);
|
||||
}
|
||||
extend_match (&id->right, sym, &right_ids, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* go through ids creating arcs as needed: */
|
||||
|
||||
/* Go through ids creating arcs as needed. */
|
||||
for (id = id_list; id; id = id->next)
|
||||
{
|
||||
if (id->has_right)
|
||||
@ -334,14 +327,14 @@ DEFUN_VOID (sym_id_parse)
|
||||
(unsigned long) right->addr,
|
||||
(unsigned long) right->end_addr,
|
||||
table_name[id->which_table]));
|
||||
|
||||
arc_add (left, right, (unsigned long) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* finally, we can sort the tables and we're done: */
|
||||
|
||||
/* Finally, we can sort the tables and we're done. */
|
||||
for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab)
|
||||
{
|
||||
DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n",
|
||||
@ -351,14 +344,12 @@ DEFUN_VOID (sym_id_parse)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Symbol tables storing the FROM symbols of arcs do not necessarily
|
||||
* have distinct address ranges. For example, somebody might request
|
||||
* -k /_mcount to suppress any arcs into _mcount, while at the same
|
||||
* time requesting -k a/b. Fortunately, those symbol tables don't get
|
||||
* very big (the user has to type them!), so a linear search is probably
|
||||
* tolerable.
|
||||
*/
|
||||
/* Symbol tables storing the FROM symbols of arcs do not necessarily
|
||||
have distinct address ranges. For example, somebody might request
|
||||
-k /_mcount to suppress any arcs into _mcount, while at the same
|
||||
time requesting -k a/b. Fortunately, those symbol tables don't get
|
||||
very big (the user has to type them!), so a linear search is probably
|
||||
tolerable. */
|
||||
bool
|
||||
DEFUN (sym_id_arc_is_present, (symtab, from, to),
|
||||
Sym_Table * symtab AND Sym * from AND Sym * to)
|
||||
@ -369,9 +360,8 @@ DEFUN (sym_id_arc_is_present, (symtab, from, to),
|
||||
{
|
||||
if (from->addr >= sym->addr && from->addr <= sym->end_addr
|
||||
&& arc_lookup (sym, to))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1,3 +1,23 @@
|
||||
/* sym_ids.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef sym_ids_h
|
||||
#define sym_ids_h
|
||||
|
||||
@ -17,9 +37,8 @@ Table_Id;
|
||||
|
||||
extern Sym_Table syms[NUM_TABLES];
|
||||
|
||||
extern void sym_id_add PARAMS ((const char *spec, Table_Id which_table));
|
||||
extern void sym_id_parse PARAMS ((void));
|
||||
extern bool sym_id_arc_is_present PARAMS ((Sym_Table * symtab,
|
||||
Sym * from, Sym * to));
|
||||
extern void sym_id_add PARAMS ((const char *, Table_Id));
|
||||
extern void sym_id_parse PARAMS ((void));
|
||||
extern bool sym_id_arc_is_present PARAMS ((Sym_Table *, Sym *, Sym *));
|
||||
|
||||
#endif /* sym_ids_h */
|
||||
|
164
gprof/symtab.c
164
gprof/symtab.c
@ -1,3 +1,24 @@
|
||||
/* symtab.c
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include "gprof.h"
|
||||
#include "cg_arcs.h"
|
||||
#include "corefile.h"
|
||||
@ -6,17 +27,15 @@
|
||||
Sym_Table symtab;
|
||||
|
||||
|
||||
/*
|
||||
* Initialize a symbol (so it's empty).
|
||||
*/
|
||||
/* Initialize a symbol (so it's empty). */
|
||||
|
||||
void
|
||||
DEFUN (sym_init, (sym), Sym * sym)
|
||||
{
|
||||
memset (sym, 0, sizeof (*sym));
|
||||
/*
|
||||
* It is not safe to assume that a binary zero corresponds to
|
||||
* a floating-point 0.0, so initialize floats explicitly:
|
||||
*/
|
||||
|
||||
/* It is not safe to assume that a binary zero corresponds
|
||||
to a floating-point 0.0, so initialize floats explicitly. */
|
||||
sym->hist.time = 0.0;
|
||||
sym->cg.child_time = 0.0;
|
||||
sym->cg.prop.fract = 0.0;
|
||||
@ -25,16 +44,15 @@ DEFUN (sym_init, (sym), Sym * sym)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compare the function entry-point of two symbols and return <0, =0,
|
||||
* or >0 depending on whether the left value is smaller than, equal
|
||||
* to, or greater than the right value. If two symbols are equal
|
||||
* but one has is_func set and the other doesn't, we make the
|
||||
* non-function symbol one "bigger" so that the function symbol will
|
||||
* survive duplicate removal. Finally, if both symbols have the
|
||||
* same is_func value, we discriminate against is_static such that
|
||||
* the global symbol survives.
|
||||
*/
|
||||
/* Compare the function entry-point of two symbols and return <0, =0,
|
||||
or >0 depending on whether the left value is smaller than, equal
|
||||
to, or greater than the right value. If two symbols are equal
|
||||
but one has is_func set and the other doesn't, we make the
|
||||
non-function symbol one "bigger" so that the function symbol will
|
||||
survive duplicate removal. Finally, if both symbols have the
|
||||
same is_func value, we discriminate against is_static such that
|
||||
the global symbol survives. */
|
||||
|
||||
static int
|
||||
DEFUN (cmp_addr, (lp, rp), const PTR lp AND const PTR rp)
|
||||
{
|
||||
@ -42,18 +60,12 @@ DEFUN (cmp_addr, (lp, rp), const PTR lp AND const PTR rp)
|
||||
Sym *right = (Sym *) rp;
|
||||
|
||||
if (left->addr > right->addr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
else if (left->addr < right->addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
|
||||
if (left->is_func != right->is_func)
|
||||
{
|
||||
return right->is_func - left->is_func;
|
||||
}
|
||||
return right->is_func - left->is_func;
|
||||
|
||||
return left->is_static - right->is_static;
|
||||
}
|
||||
@ -66,33 +78,26 @@ DEFUN (symtab_finalize, (tab), Sym_Table * tab)
|
||||
bfd_vma prev_addr;
|
||||
|
||||
if (!tab->len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
/*
|
||||
* Sort symbol table in order of increasing function addresses:
|
||||
*/
|
||||
/* Sort symbol table in order of increasing function addresses. */
|
||||
qsort (tab->base, tab->len, sizeof (Sym), cmp_addr);
|
||||
|
||||
/*
|
||||
* Remove duplicate entries to speed-up later processing and
|
||||
* set end_addr if its not set yet:
|
||||
*/
|
||||
/* Remove duplicate entries to speed-up later processing and
|
||||
set end_addr if its not set yet. */
|
||||
prev_addr = tab->base[0].addr + 1;
|
||||
|
||||
for (src = dst = tab->base; src < tab->limit; ++src)
|
||||
{
|
||||
if (src->addr == prev_addr)
|
||||
{
|
||||
/*
|
||||
* If same address, favor global symbol over static one,
|
||||
* then function over line number. If both symbols are
|
||||
* either static or global and either function or line, check
|
||||
* whether one has name beginning with underscore while
|
||||
* the other doesn't. In such cases, keep sym without
|
||||
* underscore. This takes cares of compiler generated
|
||||
* symbols (such as __gnu_compiled, __c89_used, etc.).
|
||||
*/
|
||||
/* If same address, favor global symbol over static one,
|
||||
then function over line number. If both symbols are
|
||||
either static or global and either function or line, check
|
||||
whether one has name beginning with underscore while
|
||||
the other doesn't. In such cases, keep sym without
|
||||
underscore. This takes cares of compiler generated
|
||||
symbols (such as __gnu_compiled, __c89_used, etc.). */
|
||||
if ((!src->is_static && dst[-1].is_static)
|
||||
|| ((src->is_static == dst[-1].is_static)
|
||||
&& ((src->is_func && !dst[-1].is_func)
|
||||
@ -109,6 +114,7 @@ DEFUN (symtab_finalize, (tab), Sym_Table * tab)
|
||||
dst[-1].name, dst[-1].is_static ? 't' : 'T',
|
||||
dst[-1].is_func ? 'F' : 'f');
|
||||
printf (" (addr=%lx)\n", (unsigned long) src->addr));
|
||||
|
||||
dst[-1] = *src;
|
||||
}
|
||||
else
|
||||
@ -125,11 +131,9 @@ DEFUN (symtab_finalize, (tab), Sym_Table * tab)
|
||||
else
|
||||
{
|
||||
if (dst > tab->base && dst[-1].end_addr == 0)
|
||||
{
|
||||
dst[-1].end_addr = src->addr - 1;
|
||||
}
|
||||
dst[-1].end_addr = src->addr - 1;
|
||||
|
||||
/* retain sym only if it has a non-empty address range: */
|
||||
/* Retain sym only if it has a non-empty address range. */
|
||||
if (!src->end_addr || src->addr <= src->end_addr)
|
||||
{
|
||||
*dst = *src;
|
||||
@ -138,10 +142,9 @@ DEFUN (symtab_finalize, (tab), Sym_Table * tab)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tab->len > 0 && dst[-1].end_addr == 0)
|
||||
{
|
||||
dst[-1].end_addr = core_text_sect->vma + core_text_sect->_raw_size - 1;
|
||||
}
|
||||
dst[-1].end_addr = core_text_sect->vma + core_text_sect->_raw_size - 1;
|
||||
|
||||
DBG (AOUTDEBUG | IDDEBUG,
|
||||
printf ("[symtab_finalize]: removed %d duplicate entries\n",
|
||||
@ -154,11 +157,11 @@ DEFUN (symtab_finalize, (tab), Sym_Table * tab)
|
||||
unsigned int j;
|
||||
|
||||
for (j = 0; j < tab->len; ++j)
|
||||
{
|
||||
printf ("[symtab_finalize] 0x%lx-0x%lx\t%s\n",
|
||||
(long) tab->base[j].addr, (long) tab->base[j].end_addr,
|
||||
tab->base[j].name);
|
||||
}
|
||||
{
|
||||
printf ("[symtab_finalize] 0x%lx-0x%lx\t%s\n",
|
||||
(long) tab->base[j].addr, (long) tab->base[j].end_addr,
|
||||
tab->base[j].name);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -178,35 +181,32 @@ DEFUN (dbg_sym_lookup, (symtab, address), Sym_Table * symtab AND bfd_vma address
|
||||
for (low = 0, high = symtab->len - 1; low != high;)
|
||||
{
|
||||
mid = (high + low) >> 1;
|
||||
|
||||
fprintf (stderr, "[dbg_sym_lookup] low=0x%lx, mid=0x%lx, high=0x%lx\n",
|
||||
low, mid, high);
|
||||
fprintf (stderr, "[dbg_sym_lookup] sym[m]=0x%lx sym[m + 1]=0x%lx\n",
|
||||
(unsigned long) sym[mid].addr,
|
||||
(unsigned long) sym[mid + 1].addr);
|
||||
|
||||
if (sym[mid].addr <= address && sym[mid + 1].addr > address)
|
||||
{
|
||||
return &sym[mid];
|
||||
}
|
||||
return &sym[mid];
|
||||
|
||||
if (sym[mid].addr > address)
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
high = mid;
|
||||
else
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
low = mid + 1;
|
||||
}
|
||||
|
||||
fprintf (stderr, "[dbg_sym_lookup] binary search fails???\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
|
||||
/*
|
||||
* Look up an address in the symbol-table that is sorted by address.
|
||||
* If address does not hit any symbol, 0 is returned.
|
||||
*/
|
||||
/* Look up an address in the symbol-table that is sorted by address.
|
||||
If address does not hit any symbol, 0 is returned. */
|
||||
Sym *
|
||||
DEFUN (sym_lookup, (symtab, address), Sym_Table * symtab AND bfd_vma address)
|
||||
{
|
||||
@ -218,23 +218,20 @@ DEFUN (sym_lookup, (symtab, address), Sym_Table * symtab AND bfd_vma address)
|
||||
#endif /* DEBUG */
|
||||
|
||||
if (!symtab->len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
sym = symtab->base;
|
||||
for (low = 0, high = symtab->len - 1; low != high;)
|
||||
{
|
||||
DBG (LOOKUPDEBUG, ++probes);
|
||||
mid = (high + low) / 2;
|
||||
|
||||
if (sym[mid].addr <= address && sym[mid + 1].addr > address)
|
||||
{
|
||||
if (address > sym[mid].end_addr)
|
||||
{
|
||||
/*
|
||||
* Address falls into gap between sym[mid] and
|
||||
* sym[mid + 1]:
|
||||
*/
|
||||
/* Address falls into gap between
|
||||
sym[mid] and sym[mid + 1]. */
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@ -245,20 +242,18 @@ DEFUN (sym_lookup, (symtab, address), Sym_Table * symtab AND bfd_vma address)
|
||||
return &sym[mid];
|
||||
}
|
||||
}
|
||||
|
||||
if (sym[mid].addr > address)
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
high = mid;
|
||||
else
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
low = mid + 1;
|
||||
}
|
||||
|
||||
if (sym[mid + 1].addr <= address)
|
||||
{
|
||||
if (address > sym[mid + 1].end_addr)
|
||||
{
|
||||
/* address is beyond end of sym[mid + 1]: */
|
||||
/* Address is beyond end of sym[mid + 1]. */
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@ -268,5 +263,6 @@ DEFUN (sym_lookup, (symtab, address), Sym_Table * symtab AND bfd_vma address)
|
||||
return &sym[mid + 1];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
149
gprof/symtab.h
149
gprof/symtab.h
@ -1,111 +1,124 @@
|
||||
/* symtab.h
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef symtab_h
|
||||
#define symtab_h
|
||||
|
||||
#include "bfd.h"
|
||||
#include "gprof.h"
|
||||
|
||||
/*
|
||||
* For a profile to be intelligible to a human user, it is necessary
|
||||
* to map code-addresses into source-code information. Source-code
|
||||
* information can be any combination of: (i) function-name, (ii)
|
||||
* source file-name, and (iii) source line number.
|
||||
*
|
||||
* The symbol table is used to map addresses into source-code
|
||||
* information.
|
||||
*/
|
||||
/* For a profile to be intelligible to a human user, it is necessary
|
||||
to map code-addresses into source-code information. Source-code
|
||||
information can be any combination of: (i) function-name, (ii)
|
||||
source file-name, and (iii) source line number.
|
||||
|
||||
The symbol table is used to map addresses into source-code
|
||||
information. */
|
||||
|
||||
#include "source.h"
|
||||
|
||||
#define NBBS 10
|
||||
|
||||
/*
|
||||
* Symbol-entry. For each external in the specified file we gather
|
||||
* its address, the number of calls and compute its share of cpu time.
|
||||
*/
|
||||
/* Symbol-entry. For each external in the specified file we gather
|
||||
its address, the number of calls and compute its share of cpu time. */
|
||||
typedef struct sym
|
||||
{
|
||||
/*
|
||||
* Common information:
|
||||
*
|
||||
* In the symbol-table, fields ADDR and FUNC_NAME are guaranteed
|
||||
* to contain valid information. FILE may be 0, if unknown and
|
||||
* LINE_NUM maybe 0 if unknown.
|
||||
*/
|
||||
bfd_vma addr; /* address of entry point */
|
||||
bfd_vma end_addr; /* end-address */
|
||||
const char *name; /* name of function this sym is from */
|
||||
Source_File *file; /* source file symbol comes from */
|
||||
int line_num; /* source line number */
|
||||
unsigned int is_func:1, /* is this a function entry point? */
|
||||
is_static:1, /* is this a local (static) symbol? */
|
||||
is_bb_head:1, /* is this the head of a basic-blk? */
|
||||
mapped:1, /* this symbol was mapped to another name */
|
||||
has_been_placed:1; /* have we placed this symbol? */
|
||||
unsigned long ncalls; /* how many times executed */
|
||||
int nuses; /* how many times this symbol appears in
|
||||
a particular context */
|
||||
bfd_vma bb_addr[NBBS]; /* address of basic-block start */
|
||||
unsigned long bb_calls[NBBS]; /* how many times basic-block was called */
|
||||
struct sym *next; /* for building chains of syms */
|
||||
struct sym *prev; /* for building chains of syms */
|
||||
/* Common information:
|
||||
|
||||
In the symbol-table, fields ADDR and FUNC_NAME are guaranteed
|
||||
to contain valid information. FILE may be 0, if unknown and
|
||||
LINE_NUM maybe 0 if unknown. */
|
||||
|
||||
bfd_vma addr; /* Address of entry point. */
|
||||
bfd_vma end_addr; /* End-address. */
|
||||
const char *name; /* Name of function this sym is from. */
|
||||
Source_File *file; /* Source file symbol comes from. */
|
||||
int line_num; /* Source line number. */
|
||||
unsigned int /* Boolean fields: */
|
||||
is_func:1, /* Is this a function entry point? */
|
||||
is_static:1, /* Is this a local (static) symbol? */
|
||||
is_bb_head:1, /* Is this the head of a basic-blk? */
|
||||
mapped:1, /* This symbol was mapped to another name. */
|
||||
has_been_placed:1; /* Have we placed this symbol? */
|
||||
unsigned long ncalls; /* How many times executed */
|
||||
int nuses; /* How many times this symbol appears in
|
||||
a particular context. */
|
||||
bfd_vma bb_addr[NBBS]; /* Address of basic-block start. */
|
||||
unsigned long bb_calls[NBBS];/* How many times basic-block was called. */
|
||||
struct sym *next; /* For building chains of syms. */
|
||||
struct sym *prev; /* For building chains of syms. */
|
||||
|
||||
/* profile-specific information: */
|
||||
/* Profile specific information: */
|
||||
|
||||
/* histogram specific info: */
|
||||
/* Histogram specific information: */
|
||||
struct
|
||||
{
|
||||
double time; /* (weighted) ticks in this routine */
|
||||
bfd_vma scaled_addr; /* scaled entry point */
|
||||
double time; /* (Weighted) ticks in this routine. */
|
||||
bfd_vma scaled_addr; /* Scaled entry point. */
|
||||
}
|
||||
hist;
|
||||
|
||||
/* call-graph specific info: */
|
||||
/* Call-graph specific information: */
|
||||
struct
|
||||
{
|
||||
unsigned long self_calls; /* how many calls to self */
|
||||
double child_time; /* cumulative ticks in children */
|
||||
int index; /* index in the graph list */
|
||||
int top_order; /* graph call chain top-sort order */
|
||||
bool print_flag; /* should this be printed? */
|
||||
unsigned long self_calls; /* How many calls to self. */
|
||||
double child_time; /* Cumulative ticks in children. */
|
||||
int index; /* Index in the graph list. */
|
||||
int top_order; /* Graph call chain top-sort order. */
|
||||
bool print_flag; /* Should this be printed? */
|
||||
struct
|
||||
{
|
||||
double fract; /* what % of time propagates */
|
||||
double self; /* how much self time propagates */
|
||||
double child; /* how much child time propagates */
|
||||
double fract; /* What % of time propagates. */
|
||||
double self; /* How much self time propagates. */
|
||||
double child; /* How much child time propagates. */
|
||||
}
|
||||
prop;
|
||||
struct
|
||||
{
|
||||
int num; /* internal number of cycle on */
|
||||
struct sym *head; /* head of cycle */
|
||||
struct sym *next; /* next member of cycle */
|
||||
int num; /* Internal number of cycle on. */
|
||||
struct sym *head; /* Head of cycle. */
|
||||
struct sym *next; /* Next member of cycle. */
|
||||
}
|
||||
cyc;
|
||||
struct arc *parents; /* list of caller arcs */
|
||||
struct arc *children; /* list of callee arcs */
|
||||
struct arc *parents; /* List of caller arcs. */
|
||||
struct arc *children; /* List of callee arcs. */
|
||||
}
|
||||
cg;
|
||||
}
|
||||
Sym;
|
||||
|
||||
/*
|
||||
* Symbol-tables are always assumed to be sorted in increasing order
|
||||
* of addresses:
|
||||
*/
|
||||
/* Symbol-tables are always assumed to be sorted
|
||||
in increasing order of addresses. */
|
||||
typedef struct
|
||||
{
|
||||
unsigned int len; /* # of symbols in this table */
|
||||
Sym *base; /* first element in symbol table */
|
||||
Sym *limit; /* limit = base + len */
|
||||
unsigned int len; /* # of symbols in this table. */
|
||||
Sym *base; /* First element in symbol table. */
|
||||
Sym *limit; /* Limit = base + len. */
|
||||
}
|
||||
Sym_Table;
|
||||
|
||||
extern Sym_Table symtab; /* the symbol table */
|
||||
extern Sym_Table symtab; /* The symbol table. */
|
||||
|
||||
extern void sym_init PARAMS ((Sym * sym));
|
||||
extern void symtab_finalize PARAMS ((Sym_Table * symtab));
|
||||
extern Sym *sym_lookup PARAMS ((Sym_Table * symtab, bfd_vma address));
|
||||
|
||||
extern void find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
|
||||
extern void sym_init PARAMS ((Sym *));
|
||||
extern void symtab_finalize PARAMS ((Sym_Table *));
|
||||
extern Sym *sym_lookup PARAMS ((Sym_Table *, bfd_vma));
|
||||
extern void find_call PARAMS ((Sym *, bfd_vma, bfd_vma));
|
||||
|
||||
#endif /* symtab_h */
|
||||
|
Loading…
Reference in New Issue
Block a user