mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-24 02:24:46 +08:00
ran "indent -gnu"; have not fixed block comment style
This commit is contained in:
parent
28860f46fa
commit
12516a373c
@ -1,5 +1,9 @@
|
||||
Tue Feb 7 17:24:12 1995 Ken Raeburn <raeburn@cujo.cygnus.com>
|
||||
|
||||
* All *.c and *.h files: Ran "indent -gnu". Cleaned up a couple
|
||||
of constructs GNU indent couldn't handle. Block comments not yet
|
||||
rewritten in GNU format.
|
||||
|
||||
* gprof.c (VERSION): Changed to 2.6, to get in sync for next
|
||||
binutils release.
|
||||
|
||||
|
205
gprof/alpha.c
205
gprof/alpha.c
@ -33,24 +33,32 @@
|
||||
#define Jxx_FUNC_RET 2
|
||||
#define Jxx_FUNC_JSR_COROUTINE 3
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
unsigned other : 26;
|
||||
unsigned op_code : 6;
|
||||
} a; /* any format */
|
||||
struct {
|
||||
signed disp : 21;
|
||||
unsigned ra : 5;
|
||||
unsigned op_code : 6;
|
||||
} b; /* branch format */
|
||||
struct {
|
||||
signed hint : 14;
|
||||
unsigned func : 2;
|
||||
unsigned rb : 5;
|
||||
unsigned ra : 5;
|
||||
unsigned op_code : 6;
|
||||
} j; /* jump format */
|
||||
} Instruction;
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned other:26;
|
||||
unsigned op_code:6;
|
||||
}
|
||||
a; /* any format */
|
||||
struct
|
||||
{
|
||||
signed disp:21;
|
||||
unsigned ra:5;
|
||||
unsigned op_code:6;
|
||||
}
|
||||
b; /* branch format */
|
||||
struct
|
||||
{
|
||||
signed hint:14;
|
||||
unsigned func:2;
|
||||
unsigned rb:5;
|
||||
unsigned ra:5;
|
||||
unsigned op_code:6;
|
||||
}
|
||||
j; /* jump format */
|
||||
}
|
||||
Instruction;
|
||||
|
||||
static Sym indirect_child;
|
||||
|
||||
@ -63,92 +71,99 @@ static Sym indirect_child;
|
||||
* potentially call integer division routines, for example.)
|
||||
*/
|
||||
void
|
||||
find_call(parent, p_lowpc, p_highpc)
|
||||
find_call (parent, p_lowpc, p_highpc)
|
||||
Sym *parent;
|
||||
bfd_vma p_lowpc;
|
||||
bfd_vma p_highpc;
|
||||
{
|
||||
static bfd_vma delta = 0;
|
||||
bfd_vma dest_pc;
|
||||
Instruction *pc;
|
||||
Sym *child;
|
||||
|
||||
if (!delta) {
|
||||
delta = (bfd_vma) core_text_space - core_text_sect->vma;
|
||||
static bfd_vma delta = 0;
|
||||
bfd_vma dest_pc;
|
||||
Instruction *pc;
|
||||
Sym *child;
|
||||
|
||||
sym_init(&indirect_child);
|
||||
indirect_child.name = "<indirect child>";
|
||||
indirect_child.cg.prop.fract = 1.0;
|
||||
indirect_child.cg.cyc.head = &indirect_child;
|
||||
} /* if */
|
||||
|
||||
if (!core_text_space) {
|
||||
return;
|
||||
} /* if */
|
||||
if (p_lowpc < s_lowpc) {
|
||||
p_lowpc = s_lowpc;
|
||||
} /* if */
|
||||
if (p_highpc > s_highpc) {
|
||||
p_highpc = s_highpc;
|
||||
} /* if */
|
||||
DBG(CALLDEBUG, printf("[find_call] %s: 0x%lx to 0x%lx\n",
|
||||
parent->name, p_lowpc, p_highpc));
|
||||
for (pc = (Instruction*)(p_lowpc + delta);
|
||||
pc < (Instruction*)(p_highpc + delta);
|
||||
++pc)
|
||||
if (!delta)
|
||||
{
|
||||
switch (pc->a.op_code) {
|
||||
case OP_Jxx:
|
||||
/*
|
||||
* There is no simple and reliable way to determine the
|
||||
* target of a jsr (the hint bits help, but there aren't
|
||||
* enough bits to get a satisfactory hit rate). Instead,
|
||||
* for any indirect jump we simply add an arc from PARENT
|
||||
* to INDIRECT_CHILD---that way the user it at least able
|
||||
* to see that there are other calls as well.
|
||||
*/
|
||||
if (pc->j.func == Jxx_FUNC_JSR
|
||||
|| pc->j.func == Jxx_FUNC_JSR_COROUTINE)
|
||||
delta = (bfd_vma) core_text_space - core_text_sect->vma;
|
||||
|
||||
sym_init (&indirect_child);
|
||||
indirect_child.name = "<indirect child>";
|
||||
indirect_child.cg.prop.fract = 1.0;
|
||||
indirect_child.cg.cyc.head = &indirect_child;
|
||||
} /* if */
|
||||
|
||||
if (!core_text_space)
|
||||
{
|
||||
return;
|
||||
} /* if */
|
||||
if (p_lowpc < s_lowpc)
|
||||
{
|
||||
p_lowpc = s_lowpc;
|
||||
} /* if */
|
||||
if (p_highpc > s_highpc)
|
||||
{
|
||||
p_highpc = s_highpc;
|
||||
} /* if */
|
||||
DBG (CALLDEBUG, printf ("[find_call] %s: 0x%lx to 0x%lx\n",
|
||||
parent->name, p_lowpc, p_highpc));
|
||||
for (pc = (Instruction *) (p_lowpc + delta);
|
||||
pc < (Instruction *) (p_highpc + delta);
|
||||
++pc)
|
||||
{
|
||||
switch (pc->a.op_code)
|
||||
{
|
||||
case OP_Jxx:
|
||||
/*
|
||||
* There is no simple and reliable way to determine the
|
||||
* target of a jsr (the hint bits help, but there aren't
|
||||
* enough bits to get a satisfactory hit rate). Instead,
|
||||
* for any indirect jump we simply add an arc from PARENT
|
||||
* to INDIRECT_CHILD---that way the user it at least able
|
||||
* to see that there are other calls as well.
|
||||
*/
|
||||
if (pc->j.func == Jxx_FUNC_JSR
|
||||
|| pc->j.func == Jxx_FUNC_JSR_COROUTINE)
|
||||
{
|
||||
DBG(CALLDEBUG,
|
||||
printf("[find_call] 0x%lx: jsr%s <indirect_child>\n",
|
||||
DBG (CALLDEBUG,
|
||||
printf ("[find_call] 0x%lx: jsr%s <indirect_child>\n",
|
||||
(bfd_vma) pc - delta,
|
||||
pc->j.func == Jxx_FUNC_JSR ? "" : "_coroutine"));
|
||||
arc_add(parent, &indirect_child, 0);
|
||||
} /* if */
|
||||
break;
|
||||
arc_add (parent, &indirect_child, 0);
|
||||
} /* if */
|
||||
break;
|
||||
|
||||
case OP_BSR:
|
||||
DBG(CALLDEBUG,
|
||||
printf("[find_call] 0x%lx: bsr", (bfd_vma) pc - delta));
|
||||
/*
|
||||
* Regular PC relative addressing. Check that this is the
|
||||
* address of a function. The linker sometimes redirects
|
||||
* the entry point by 8 bytes to skip loading the global
|
||||
* pointer, so we all for either address:
|
||||
*/
|
||||
dest_pc = ((bfd_vma) (pc + 1 + pc->b.disp)) - delta;
|
||||
if (dest_pc >= s_lowpc && dest_pc <= s_highpc) {
|
||||
child = sym_lookup(&symtab, dest_pc);
|
||||
DBG(CALLDEBUG,
|
||||
printf(" 0x%lx\t; name=%s, addr=0x%lx",
|
||||
case OP_BSR:
|
||||
DBG (CALLDEBUG,
|
||||
printf ("[find_call] 0x%lx: bsr", (bfd_vma) pc - delta));
|
||||
/*
|
||||
* Regular PC relative addressing. Check that this is the
|
||||
* address of a function. The linker sometimes redirects
|
||||
* the entry point by 8 bytes to skip loading the global
|
||||
* pointer, so we all for either address:
|
||||
*/
|
||||
dest_pc = ((bfd_vma) (pc + 1 + pc->b.disp)) - delta;
|
||||
if (dest_pc >= s_lowpc && dest_pc <= s_highpc)
|
||||
{
|
||||
child = sym_lookup (&symtab, dest_pc);
|
||||
DBG (CALLDEBUG,
|
||||
printf (" 0x%lx\t; name=%s, addr=0x%lx",
|
||||
dest_pc, child->name, child->addr));
|
||||
if (child->addr == dest_pc || child->addr == dest_pc - 8) {
|
||||
DBG(CALLDEBUG, printf("\n"));
|
||||
/* a hit: */
|
||||
arc_add(parent, child, 0);
|
||||
continue;
|
||||
} /* if */
|
||||
} /* if */
|
||||
/*
|
||||
* Something funny going on.
|
||||
*/
|
||||
DBG(CALLDEBUG, printf("\tbut it's a botch\n"));
|
||||
break;
|
||||
if (child->addr == dest_pc || child->addr == dest_pc - 8)
|
||||
{
|
||||
DBG (CALLDEBUG, printf ("\n"));
|
||||
/* a hit: */
|
||||
arc_add (parent, child, 0);
|
||||
continue;
|
||||
} /* if */
|
||||
} /* if */
|
||||
/*
|
||||
* Something funny going on.
|
||||
*/
|
||||
DBG (CALLDEBUG, printf ("\tbut it's a botch\n"));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
} /* switch */
|
||||
} /* for */
|
||||
} /* find_call */
|
||||
/*** end of alpha.c ***/
|
||||
default:
|
||||
break;
|
||||
} /* switch */
|
||||
} /* for */
|
||||
} /* find_call */
|
||||
/*** end of alpha.c ***/
|
||||
|
@ -16,7 +16,7 @@
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* @(#)alpha.h 1.4 (Berkeley) 6/1/90
|
||||
* @(#)alpha.h 1.4 (Berkeley) 6/1/90
|
||||
*/
|
||||
#ifndef alpha_h
|
||||
#define alpha_h
|
||||
|
@ -35,31 +35,39 @@ static long num_lines_executed;
|
||||
* number, and basic-block address (in that order).
|
||||
*/
|
||||
static int
|
||||
DEFUN(cmp_bb, (lp, rp), const void *lp AND const void *rp)
|
||||
DEFUN (cmp_bb, (lp, rp), const void *lp AND const void *rp)
|
||||
{
|
||||
int r;
|
||||
const Sym *left = *(const Sym**)lp;
|
||||
const Sym *right = *(const Sym**)rp;
|
||||
int r;
|
||||
const Sym *left = *(const Sym **) lp;
|
||||
const Sym *right = *(const Sym **) rp;
|
||||
|
||||
if (left->file && right->file) {
|
||||
r = strcmp(left->file->name, right->file->name);
|
||||
if (r) {
|
||||
return r;
|
||||
} /* if */
|
||||
if (left->file && right->file)
|
||||
{
|
||||
r = strcmp (left->file->name, right->file->name);
|
||||
if (r)
|
||||
{
|
||||
return r;
|
||||
} /* if */
|
||||
|
||||
if (left->line_num != right->line_num) {
|
||||
return left->line_num - right->line_num;
|
||||
} /* if */
|
||||
} /* if */
|
||||
if (left->line_num != right->line_num)
|
||||
{
|
||||
return left->line_num - right->line_num;
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
if (left->addr < right->addr) {
|
||||
return -1;
|
||||
} else if (left->addr > right->addr) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
} /* if */
|
||||
} /* cmp_bb */
|
||||
if (left->addr < right->addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (left->addr > right->addr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
} /* if */
|
||||
} /* cmp_bb */
|
||||
|
||||
|
||||
/*
|
||||
@ -67,39 +75,45 @@ DEFUN(cmp_bb, (lp, rp), const void *lp AND const void *rp)
|
||||
* calls, ties are broken in increasing order of line numbers.
|
||||
*/
|
||||
static int
|
||||
DEFUN(cmp_ncalls, (lp, rp), const void *lp AND const void *rp)
|
||||
DEFUN (cmp_ncalls, (lp, rp), const void *lp AND const void *rp)
|
||||
{
|
||||
const Sym *left = *(const Sym**)lp;
|
||||
const Sym *right = *(const Sym**)rp;
|
||||
const Sym *left = *(const Sym **) lp;
|
||||
const Sym *right = *(const Sym **) rp;
|
||||
|
||||
if (!left) {
|
||||
return 1;
|
||||
} else if (!right) {
|
||||
return -1;
|
||||
} /* if */
|
||||
if (!left)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (!right)
|
||||
{
|
||||
return -1;
|
||||
} /* if */
|
||||
|
||||
if (right->ncalls != left->ncalls) {
|
||||
return right->ncalls - left->ncalls;
|
||||
} /* if */
|
||||
if (right->ncalls != left->ncalls)
|
||||
{
|
||||
return right->ncalls - left->ncalls;
|
||||
} /* if */
|
||||
|
||||
return left->line_num - right->line_num;
|
||||
} /* cmp_ncalls */
|
||||
return left->line_num - right->line_num;
|
||||
} /* cmp_ncalls */
|
||||
|
||||
|
||||
/*
|
||||
* Skip over variable length string.
|
||||
*/
|
||||
static void
|
||||
DEFUN(fskip_string, (fp), FILE *fp)
|
||||
DEFUN (fskip_string, (fp), FILE * fp)
|
||||
{
|
||||
int ch;
|
||||
int ch;
|
||||
|
||||
while ((ch = fgetc(fp)) != EOF) {
|
||||
if (ch == '\0') {
|
||||
break;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* fskip_string */
|
||||
while ((ch = fgetc (fp)) != EOF)
|
||||
{
|
||||
if (ch == '\0')
|
||||
{
|
||||
break;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* fskip_string */
|
||||
|
||||
|
||||
/*
|
||||
@ -107,77 +121,87 @@ DEFUN(fskip_string, (fp), FILE *fp)
|
||||
* of file IFP and is provided for formatting error-messages only.
|
||||
*/
|
||||
void
|
||||
DEFUN(bb_read_rec, (ifp, filename), FILE *ifp AND const char *filename)
|
||||
DEFUN (bb_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
{
|
||||
int nblocks, b;
|
||||
bfd_vma addr;
|
||||
long ncalls;
|
||||
Sym *sym;
|
||||
int nblocks, b;
|
||||
bfd_vma addr;
|
||||
long ncalls;
|
||||
Sym *sym;
|
||||
|
||||
if (fread(&nblocks, sizeof(nblocks), 1, ifp) != 1) {
|
||||
fprintf(stderr, "%s: %s: unexpected end of file\n", whoami, filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (fread (&nblocks, sizeof (nblocks), 1, ifp) != 1)
|
||||
{
|
||||
fprintf (stderr, "%s: %s: unexpected end of file\n", whoami, filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
nblocks = bfd_get_32(core_bfd, (bfd_byte*) &nblocks);
|
||||
if (gmon_file_version == 0) {
|
||||
fskip_string(ifp);
|
||||
} /* if */
|
||||
nblocks = bfd_get_32 (core_bfd, (bfd_byte *) & nblocks);
|
||||
if (gmon_file_version == 0)
|
||||
{
|
||||
fskip_string (ifp);
|
||||
} /* if */
|
||||
|
||||
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.
|
||||
*/
|
||||
if ((fread(&ncalls, sizeof(ncalls), 1, ifp) != 1)
|
||||
|| (fread(&addr, sizeof(addr), 1, ifp) != 1)
|
||||
|| (fskip_string(ifp), FALSE)
|
||||
|| (fskip_string(ifp), FALSE)
|
||||
|| (fread(&line_num, sizeof(line_num), 1, ifp) != 1))
|
||||
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.
|
||||
*/
|
||||
if ((fread (&ncalls, sizeof (ncalls), 1, ifp) != 1)
|
||||
|| (fread (&addr, sizeof (addr), 1, ifp) != 1)
|
||||
|| (fskip_string (ifp), FALSE)
|
||||
|| (fskip_string (ifp), FALSE)
|
||||
|| (fread (&line_num, sizeof (line_num), 1, ifp) != 1))
|
||||
{
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
} else {
|
||||
if (fread(&addr, sizeof(addr), 1, ifp) != 1
|
||||
|| fread(&ncalls, sizeof(ncalls), 1, ifp) != 1)
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fread (&addr, sizeof (addr), 1, ifp) != 1
|
||||
|| fread (&ncalls, sizeof (ncalls), 1, ifp) != 1)
|
||||
{
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
} /* if */
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* Basic-block execution counts are meaningful only if we're
|
||||
* profiling at the line-by-line level:
|
||||
*/
|
||||
if (line_granularity) {
|
||||
/*
|
||||
* 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);
|
||||
addr = get_vma (core_bfd, (bfd_byte *) & addr);
|
||||
|
||||
sym = sym_lookup(&symtab, addr);
|
||||
sym->is_bb_head = TRUE;
|
||||
sym->ncalls += bfd_get_32(core_bfd, (bfd_byte*)&ncalls);
|
||||
sym = sym_lookup (&symtab, addr);
|
||||
sym->is_bb_head = TRUE;
|
||||
sym->ncalls += bfd_get_32 (core_bfd, (bfd_byte *) & ncalls);
|
||||
|
||||
DBG(BBDEBUG, printf("[bb_read_rec] 0x%lx->0x%lx (%s) cnt=%d\n",
|
||||
DBG (BBDEBUG, printf ("[bb_read_rec] 0x%lx->0x%lx (%s) cnt=%d\n",
|
||||
addr, sym->addr, sym->name, sym->ncalls));
|
||||
} else {
|
||||
static bool user_warned = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
static bool user_warned = FALSE;
|
||||
|
||||
if (!user_warned) {
|
||||
user_warned = TRUE;
|
||||
fprintf(stderr,
|
||||
"%s: warning: ignoring basic-block exec counts (use -l or --line)\n",
|
||||
whoami);
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* for */
|
||||
return;
|
||||
} /* bb_read_rec */
|
||||
if (!user_warned)
|
||||
{
|
||||
user_warned = TRUE;
|
||||
fprintf (stderr,
|
||||
"%s: warning: ignoring basic-block exec counts (use -l or --line)\n",
|
||||
whoami);
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* for */
|
||||
return;
|
||||
} /* bb_read_rec */
|
||||
|
||||
|
||||
/*
|
||||
@ -186,99 +210,108 @@ DEFUN(bb_read_rec, (ifp, filename), FILE *ifp AND const char *filename)
|
||||
* only.
|
||||
*/
|
||||
void
|
||||
DEFUN(bb_write_blocks, (ofp, filename), FILE *ofp AND const char *filename)
|
||||
DEFUN (bb_write_blocks, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
{
|
||||
const unsigned char tag = GMON_TAG_BB_COUNT;
|
||||
int nblocks = 0;
|
||||
bfd_vma addr;
|
||||
long ncalls;
|
||||
Sym *sym;
|
||||
const unsigned char tag = GMON_TAG_BB_COUNT;
|
||||
int nblocks = 0;
|
||||
bfd_vma addr;
|
||||
long ncalls;
|
||||
Sym *sym;
|
||||
|
||||
/* count how many non-zero blocks with have: */
|
||||
/* count how many non-zero blocks with have: */
|
||||
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym) {
|
||||
if (sym->ncalls > 0) {
|
||||
++nblocks;
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
/* 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)
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
|
||||
/* write counts: */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym) {
|
||||
if (sym->ncalls == 0) {
|
||||
continue;
|
||||
} /* if */
|
||||
|
||||
put_vma(core_bfd, sym->addr, (bfd_byte*) &addr);
|
||||
bfd_put_32(core_bfd, sym->ncalls, (bfd_byte*) &ncalls);
|
||||
|
||||
if (fwrite(&addr, sizeof(addr), 1, ofp) != 1
|
||||
|| fwrite(&ncalls, sizeof(ncalls), 1, ofp) != 1)
|
||||
if (sym->ncalls > 0)
|
||||
{
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* bb_write_blocks */
|
||||
++nblocks;
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
/* 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)
|
||||
{
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* write counts: */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
if (sym->ncalls == 0)
|
||||
{
|
||||
continue;
|
||||
} /* if */
|
||||
|
||||
put_vma (core_bfd, sym->addr, (bfd_byte *) & addr);
|
||||
bfd_put_32 (core_bfd, sym->ncalls, (bfd_byte *) & ncalls);
|
||||
|
||||
if (fwrite (&addr, sizeof (addr), 1, ofp) != 1
|
||||
|| fwrite (&ncalls, sizeof (ncalls), 1, ofp) != 1)
|
||||
{
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* bb_write_blocks */
|
||||
|
||||
|
||||
/*
|
||||
* Output basic-block statistics in a format that is easily parseable.
|
||||
* Current the format is:
|
||||
*
|
||||
* <filename>:<line-number>: (<function-name>:<bb-addr): <ncalls>
|
||||
* <filename>:<line-number>: (<function-name>:<bb-addr): <ncalls>
|
||||
*/
|
||||
void
|
||||
DEFUN_VOID(print_exec_counts)
|
||||
DEFUN_VOID (print_exec_counts)
|
||||
{
|
||||
Sym **sorted_bbs, *sym;
|
||||
int i, len;
|
||||
Sym **sorted_bbs, *sym;
|
||||
int i, len;
|
||||
|
||||
if (first_output) {
|
||||
first_output = FALSE;
|
||||
} else {
|
||||
printf("\f\n");
|
||||
} /* if */
|
||||
if (first_output)
|
||||
{
|
||||
first_output = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("\f\n");
|
||||
} /* if */
|
||||
|
||||
/* sort basic-blocks according to function name and line number: */
|
||||
/* 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 the start of a basic-block and it is
|
||||
* called at least bb_min_calls times and 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->is_bb_head && sym->ncalls >= bb_min_calls
|
||||
&& (sym_lookup(&syms[INCL_EXEC], sym->addr)
|
||||
|| (syms[INCL_EXEC].len == 0
|
||||
&& !sym_lookup(&syms[EXCL_EXEC], sym->addr))))
|
||||
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 the start of a basic-block and it is
|
||||
* called at least bb_min_calls times and 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->is_bb_head && sym->ncalls >= bb_min_calls
|
||||
&& (sym_lookup (&syms[INCL_EXEC], sym->addr)
|
||||
|| (syms[INCL_EXEC].len == 0
|
||||
&& !sym_lookup (&syms[EXCL_EXEC], sym->addr))))
|
||||
{
|
||||
sorted_bbs[len++] = sym;
|
||||
} /* if */
|
||||
} /* for */
|
||||
qsort(sorted_bbs, len, sizeof(sorted_bbs[0]), cmp_bb);
|
||||
sorted_bbs[len++] = sym;
|
||||
} /* if */
|
||||
} /* for */
|
||||
qsort (sorted_bbs, len, sizeof (sorted_bbs[0]), cmp_bb);
|
||||
|
||||
/* output basic-blocks: */
|
||||
/* output basic-blocks: */
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
sym = sorted_bbs[i];
|
||||
printf("%s:%d: (%s:0x%lx) %d executions\n",
|
||||
sym->file ? sym->file->name : "<unknown>", sym->line_num,
|
||||
sym->name, sym->addr, sym->ncalls);
|
||||
} /* for */
|
||||
free(sorted_bbs);
|
||||
} /* print_exec_counts */
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
sym = sorted_bbs[i];
|
||||
printf ("%s:%d: (%s:0x%lx) %d executions\n",
|
||||
sym->file ? sym->file->name : "<unknown>", sym->line_num,
|
||||
sym->name, sym->addr, sym->ncalls);
|
||||
} /* for */
|
||||
free (sorted_bbs);
|
||||
} /* print_exec_counts */
|
||||
|
||||
|
||||
/*
|
||||
@ -286,44 +319,56 @@ DEFUN_VOID(print_exec_counts)
|
||||
* number of line executions.
|
||||
*/
|
||||
static void
|
||||
DEFUN(annotate_with_count, (buf, width, line_num, arg),
|
||||
char *buf AND int width AND int line_num AND void *arg)
|
||||
DEFUN (annotate_with_count, (buf, width, line_num, arg),
|
||||
char *buf AND int width AND int line_num AND void *arg)
|
||||
{
|
||||
Source_File *sf = arg;
|
||||
Sym *b;
|
||||
long cnt;
|
||||
static long last_count;
|
||||
Source_File *sf = arg;
|
||||
Sym *b;
|
||||
long cnt;
|
||||
static long last_count;
|
||||
|
||||
if (line_num == 1) {
|
||||
last_count = -1;
|
||||
} /* if */
|
||||
if (line_num == 1)
|
||||
{
|
||||
last_count = -1;
|
||||
} /* if */
|
||||
|
||||
b = 0;
|
||||
if (line_num <= sf->num_lines) {
|
||||
b = sf->line[line_num - 1];
|
||||
} /* if */
|
||||
if (!b) {
|
||||
cnt = -1;
|
||||
} else {
|
||||
++num_executable_lines;
|
||||
cnt = b->ncalls;
|
||||
} /* if */
|
||||
if (cnt > 0) {
|
||||
++num_lines_executed;
|
||||
} /* if */
|
||||
if (cnt < 0 && bb_annotate_all_lines) {
|
||||
cnt = last_count;
|
||||
} /* if */
|
||||
b = 0;
|
||||
if (line_num <= sf->num_lines)
|
||||
{
|
||||
b = sf->line[line_num - 1];
|
||||
} /* if */
|
||||
if (!b)
|
||||
{
|
||||
cnt = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++num_executable_lines;
|
||||
cnt = b->ncalls;
|
||||
} /* if */
|
||||
if (cnt > 0)
|
||||
{
|
||||
++num_lines_executed;
|
||||
} /* if */
|
||||
if (cnt < 0 && bb_annotate_all_lines)
|
||||
{
|
||||
cnt = last_count;
|
||||
} /* if */
|
||||
|
||||
if (cnt < 0) {
|
||||
strcpy(buf, "\t\t");
|
||||
} else if (cnt < bb_min_calls) {
|
||||
strcpy(buf, " ##### -> ");
|
||||
} else {
|
||||
sprintf(buf, "%12ld -> ", cnt);
|
||||
} /* if */
|
||||
last_count = cnt;
|
||||
} /* annotate_with_count */
|
||||
if (cnt < 0)
|
||||
{
|
||||
strcpy (buf, "\t\t");
|
||||
}
|
||||
else if (cnt < bb_min_calls)
|
||||
{
|
||||
strcpy (buf, " ##### -> ");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (buf, "%12ld -> ", cnt);
|
||||
} /* if */
|
||||
last_count = cnt;
|
||||
} /* annotate_with_count */
|
||||
|
||||
|
||||
/*
|
||||
@ -332,121 +377,138 @@ DEFUN(annotate_with_count, (buf, width, line_num, arg),
|
||||
* regarding that source file are printed.
|
||||
*/
|
||||
void
|
||||
DEFUN_VOID(print_annotated_source)
|
||||
DEFUN_VOID (print_annotated_source)
|
||||
{
|
||||
Sym *sym, *line_stats, *new_line;
|
||||
Source_File *sf;
|
||||
int i, table_len;
|
||||
FILE *ofp;
|
||||
Sym *sym, *line_stats, *new_line;
|
||||
Source_File *sf;
|
||||
int i, table_len;
|
||||
FILE *ofp;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (sym->file && sym->line_num > sym->file->num_lines
|
||||
&& (sym_lookup(&syms[INCL_ANNO], sym->addr)
|
||||
|| (syms[INCL_ANNO].len == 0
|
||||
&& !sym_lookup(&syms[EXCL_ANNO], sym->addr))))
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (sym->file && sym->line_num > sym->file->num_lines
|
||||
&& (sym_lookup (&syms[INCL_ANNO], sym->addr)
|
||||
|| (syms[INCL_ANNO].len == 0
|
||||
&& !sym_lookup (&syms[EXCL_ANNO], sym->addr))))
|
||||
{
|
||||
sym->file->num_lines = sym->line_num;
|
||||
} /* if */
|
||||
} /* for */
|
||||
sym->file->num_lines = sym->line_num;
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
/* allocate line descriptors: */
|
||||
/* allocate line descriptors: */
|
||||
|
||||
for (sf = first_src_file; sf; sf = sf->next) {
|
||||
if (sf->num_lines > 0) {
|
||||
sf->line = (void*) xmalloc(sf->num_lines * sizeof(sf->line[0]));
|
||||
memset(sf->line, 0, sf->num_lines * sizeof(sf->line[0]));
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
/* count executions per line: */
|
||||
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym) {
|
||||
if (sym->is_bb_head && sym->file && sym->file->num_lines
|
||||
&& (sym_lookup(&syms[INCL_ANNO], sym->addr)
|
||||
|| (syms[INCL_ANNO].len == 0
|
||||
&& !sym_lookup(&syms[EXCL_ANNO], sym->addr))))
|
||||
for (sf = first_src_file; sf; sf = sf->next)
|
||||
{
|
||||
if (sf->num_lines > 0)
|
||||
{
|
||||
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: */
|
||||
sym->file->line[sym->line_num - 1] = sym;
|
||||
} else if (!line_stats->addr) {
|
||||
/* 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 */
|
||||
new_line = (Sym*) xmalloc(sizeof(*new_line));
|
||||
*new_line = *line_stats;
|
||||
new_line->addr = 0;
|
||||
new_line->ncalls += sym->ncalls;
|
||||
sym->file->line[sym->line_num - 1] = new_line;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* for */
|
||||
sf->line = (void *) xmalloc (sf->num_lines * sizeof (sf->line[0]));
|
||||
memset (sf->line, 0, sf->num_lines * sizeof (sf->line[0]));
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
/* plod over source files, annotating them: */
|
||||
/* count executions per line: */
|
||||
|
||||
for (sf = first_src_file; sf; sf = sf->next) {
|
||||
if (!sf->num_lines || (ignore_zeros && sf->ncalls == 0)) {
|
||||
continue;
|
||||
} /* if */
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
if (sym->is_bb_head && sym->file && sym->file->num_lines
|
||||
&& (sym_lookup (&syms[INCL_ANNO], sym->addr)
|
||||
|| (syms[INCL_ANNO].len == 0
|
||||
&& !sym_lookup (&syms[EXCL_ANNO], sym->addr))))
|
||||
{
|
||||
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: */
|
||||
sym->file->line[sym->line_num - 1] = sym;
|
||||
}
|
||||
else if (!line_stats->addr)
|
||||
{
|
||||
/* 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 */
|
||||
new_line = (Sym *) xmalloc (sizeof (*new_line));
|
||||
*new_line = *line_stats;
|
||||
new_line->addr = 0;
|
||||
new_line->ncalls += sym->ncalls;
|
||||
sym->file->line[sym->line_num - 1] = new_line;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
num_executable_lines = num_lines_executed = 0;
|
||||
ofp = annotate_source(sf, 16, annotate_with_count, sf);
|
||||
if (!ofp) {
|
||||
continue;
|
||||
} /* if */
|
||||
/* plod over source files, annotating them: */
|
||||
|
||||
if (bb_table_length > 0) {
|
||||
fprintf(ofp, "\n\nTop %d Lines:\n\n Line Count\n\n",
|
||||
bb_table_length);
|
||||
for (sf = first_src_file; sf; sf = sf->next)
|
||||
{
|
||||
if (!sf->num_lines || (ignore_zeros && sf->ncalls == 0))
|
||||
{
|
||||
continue;
|
||||
} /* if */
|
||||
|
||||
/* 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;
|
||||
} /* if */
|
||||
for (i = 0; i < table_len; ++i) {
|
||||
sym = sf->line[i];
|
||||
if (!sym || sym->ncalls <= 0) {
|
||||
break;
|
||||
} /* if */
|
||||
fprintf(ofp, "%9d %10d\n", sym->line_num, sym->ncalls);
|
||||
} /* for */
|
||||
} /* if */
|
||||
num_executable_lines = num_lines_executed = 0;
|
||||
ofp = annotate_source (sf, 16, annotate_with_count, sf);
|
||||
if (!ofp)
|
||||
{
|
||||
continue;
|
||||
} /* if */
|
||||
|
||||
free(sf->line);
|
||||
sf->line = 0;
|
||||
if (bb_table_length > 0)
|
||||
{
|
||||
fprintf (ofp, "\n\nTop %d Lines:\n\n Line Count\n\n",
|
||||
bb_table_length);
|
||||
|
||||
fprintf(ofp, "\nExecution Summary:\n\n");
|
||||
fprintf(ofp, "%9ld Executable lines in this file\n",
|
||||
num_executable_lines);
|
||||
fprintf(ofp, "%9ld Lines executed\n", num_lines_executed);
|
||||
fprintf(ofp, "%9.2f Percent of the file executed\n",
|
||||
num_executable_lines
|
||||
? 100.0 * num_lines_executed / (double) num_executable_lines
|
||||
: 100.0);
|
||||
fprintf(ofp, "\n%9d Total number of line executions\n", sf->ncalls);
|
||||
fprintf(ofp, "%9.2f Average executions per line\n",
|
||||
num_executable_lines
|
||||
? sf->ncalls / (double) num_executable_lines
|
||||
: 0.0);
|
||||
if (ofp != stdout) {
|
||||
fclose(ofp);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* print_annotated_source */
|
||||
/* 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;
|
||||
} /* if */
|
||||
for (i = 0; i < table_len; ++i)
|
||||
{
|
||||
sym = sf->line[i];
|
||||
if (!sym || sym->ncalls <= 0)
|
||||
{
|
||||
break;
|
||||
} /* if */
|
||||
fprintf (ofp, "%9d %10d\n", sym->line_num, sym->ncalls);
|
||||
} /* for */
|
||||
} /* if */
|
||||
|
||||
/*** end of basic_block.c ***/
|
||||
free (sf->line);
|
||||
sf->line = 0;
|
||||
|
||||
fprintf (ofp, "\nExecution Summary:\n\n");
|
||||
fprintf (ofp, "%9ld Executable lines in this file\n",
|
||||
num_executable_lines);
|
||||
fprintf (ofp, "%9ld Lines executed\n", num_lines_executed);
|
||||
fprintf (ofp, "%9.2f Percent of the file executed\n",
|
||||
num_executable_lines
|
||||
? 100.0 * num_lines_executed / (double) num_executable_lines
|
||||
: 100.0);
|
||||
fprintf (ofp, "\n%9d Total number of line executions\n", sf->ncalls);
|
||||
fprintf (ofp, "%9.2f Average executions per line\n",
|
||||
num_executable_lines
|
||||
? sf->ncalls / (double) num_executable_lines
|
||||
: 0.0);
|
||||
if (ofp != stdout)
|
||||
{
|
||||
fclose (ofp);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* print_annotated_source */
|
||||
|
||||
/*** end of basic_block.c ***/
|
||||
|
@ -10,14 +10,14 @@
|
||||
* Options:
|
||||
*/
|
||||
extern bool bb_annotate_all_lines; /* force annotation of all lines? */
|
||||
extern int bb_table_length; /* length of most-used bb table */
|
||||
extern int bb_min_calls; /* minimum execution count */
|
||||
extern int bb_table_length; /* length of most-used bb table */
|
||||
extern int 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 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));
|
||||
extern void print_annotated_source PARAMS ((void));
|
||||
extern void print_exec_counts PARAMS ((void));
|
||||
|
||||
#endif /* basic_blocks_h */
|
||||
|
@ -7,30 +7,30 @@
|
||||
#include "sym_ids.h"
|
||||
|
||||
extern void
|
||||
DEFUN(cg_tally, (from_pc, self_pc, count),
|
||||
bfd_vma from_pc AND bfd_vma self_pc AND int count)
|
||||
DEFUN (cg_tally, (from_pc, self_pc, count),
|
||||
bfd_vma from_pc AND bfd_vma self_pc AND int count)
|
||||
{
|
||||
Sym *parent;
|
||||
Sym *child;
|
||||
Sym *parent;
|
||||
Sym *child;
|
||||
|
||||
parent = sym_lookup(&symtab, from_pc);
|
||||
child = sym_lookup(&symtab, self_pc);
|
||||
parent = sym_lookup (&symtab, from_pc);
|
||||
child = sym_lookup (&symtab, self_pc);
|
||||
|
||||
/*
|
||||
* 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)))
|
||||
/*
|
||||
* 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)))
|
||||
{
|
||||
child->ncalls += count;
|
||||
DBG(TALLYDEBUG,
|
||||
printf("[cg_tally] arc from %s to %s traversed %d times\n",
|
||||
child->ncalls += count;
|
||||
DBG (TALLYDEBUG,
|
||||
printf ("[cg_tally] arc from %s to %s traversed %d times\n",
|
||||
parent->name, child->name, count));
|
||||
arc_add(parent, child, count);
|
||||
} /* if */
|
||||
} /* cg_tally */
|
||||
arc_add (parent, child, count);
|
||||
} /* if */
|
||||
} /* cg_tally */
|
||||
|
||||
|
||||
/*
|
||||
@ -40,26 +40,27 @@ DEFUN(cg_tally, (from_pc, self_pc, count),
|
||||
* for formatting error-messages only.
|
||||
*/
|
||||
void
|
||||
DEFUN(cg_read_rec, (ifp, filename), FILE *ifp AND CONST char *filename)
|
||||
DEFUN (cg_read_rec, (ifp, filename), FILE * ifp AND CONST char *filename)
|
||||
{
|
||||
bfd_vma from_pc, self_pc;
|
||||
struct gmon_cg_arc_record arc;
|
||||
int count;
|
||||
bfd_vma from_pc, self_pc;
|
||||
struct gmon_cg_arc_record arc;
|
||||
int count;
|
||||
|
||||
if (fread(&arc, sizeof(arc), 1, ifp) != 1) {
|
||||
fprintf(stderr, "%s: %s: unexpected end of file\n",
|
||||
whoami, filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
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 %d\n",
|
||||
if (fread (&arc, sizeof (arc), 1, ifp) != 1)
|
||||
{
|
||||
fprintf (stderr, "%s: %s: unexpected end of file\n",
|
||||
whoami, filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
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 %d\n",
|
||||
from_pc, self_pc, count));
|
||||
/* add this arc: */
|
||||
cg_tally(from_pc, self_pc, count);
|
||||
} /* cg_read_rec */
|
||||
/* add this arc: */
|
||||
cg_tally (from_pc, self_pc, count);
|
||||
} /* cg_read_rec */
|
||||
|
||||
|
||||
/*
|
||||
@ -68,29 +69,31 @@ DEFUN(cg_read_rec, (ifp, filename), FILE *ifp AND CONST char *filename)
|
||||
* only.
|
||||
*/
|
||||
void
|
||||
DEFUN(cg_write_arcs, (ofp, filename), FILE *ofp AND const char *filename)
|
||||
DEFUN (cg_write_arcs, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
{
|
||||
const unsigned char tag = GMON_TAG_CG_ARC;
|
||||
struct gmon_cg_arc_record raw_arc;
|
||||
Arc *arc;
|
||||
Sym *sym;
|
||||
const unsigned char tag = GMON_TAG_CG_ARC;
|
||||
struct gmon_cg_arc_record raw_arc;
|
||||
Arc *arc;
|
||||
Sym *sym;
|
||||
|
||||
for (sym = symtab.base; sym < symtab.limit; sym++) {
|
||||
for (arc = sym->cg.children; arc; arc = arc->next_child) {
|
||||
put_vma(core_bfd, arc->parent->addr, (bfd_byte*) raw_arc.from_pc);
|
||||
put_vma(core_bfd, arc->child->addr, (bfd_byte*) raw_arc.self_pc);
|
||||
bfd_put_32(core_bfd, arc->count, (bfd_byte*) raw_arc.count);
|
||||
if (fwrite(&tag, sizeof(tag), 1, ofp) != 1
|
||||
|| fwrite(&raw_arc, sizeof(raw_arc), 1, ofp) != 1)
|
||||
for (sym = symtab.base; sym < symtab.limit; sym++)
|
||||
{
|
||||
for (arc = sym->cg.children; arc; arc = arc->next_child)
|
||||
{
|
||||
put_vma (core_bfd, arc->parent->addr, (bfd_byte *) raw_arc.from_pc);
|
||||
put_vma (core_bfd, arc->child->addr, (bfd_byte *) raw_arc.self_pc);
|
||||
bfd_put_32 (core_bfd, arc->count, (bfd_byte *) raw_arc.count);
|
||||
if (fwrite (&tag, sizeof (tag), 1, ofp) != 1
|
||||
|| fwrite (&raw_arc, sizeof (raw_arc), 1, ofp) != 1)
|
||||
{
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
DBG(SAMPLEDEBUG,
|
||||
printf("[cg_write_arcs] frompc 0x%lx selfpc 0x%lx count %d\n",
|
||||
arc->parent->addr, arc->child->addr, arc->count));
|
||||
} /* for */
|
||||
} /* for */
|
||||
} /* cg_write_arcs */
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf ("[cg_write_arcs] frompc 0x%lx selfpc 0x%lx count %d\n",
|
||||
arc->parent->addr, arc->child->addr, arc->count));
|
||||
} /* for */
|
||||
} /* for */
|
||||
} /* cg_write_arcs */
|
||||
|
||||
/*** end of call_graph.c ***/
|
||||
/*** end of call_graph.c ***/
|
||||
|
@ -5,8 +5,8 @@
|
||||
#include "gprof.h"
|
||||
#include "symtab.h"
|
||||
|
||||
extern void cg_tally PARAMS((bfd_vma from_pc, bfd_vma self_pc, int 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 from_pc, bfd_vma self_pc, int count));
|
||||
extern void cg_read_rec PARAMS ((FILE * ifp, const char *filename));
|
||||
extern void cg_write_arcs PARAMS ((FILE * ofp, const char *filename));
|
||||
|
||||
#endif /* call_graph_h */
|
||||
|
953
gprof/cg_arcs.c
953
gprof/cg_arcs.c
File diff suppressed because it is too large
Load Diff
@ -11,21 +11,23 @@
|
||||
* of how many times this arc was traversed, and pointers to the next
|
||||
* parent of this child and the next child of this parent.
|
||||
*/
|
||||
typedef struct arc {
|
||||
Sym *parent; /* source vertice of arc */
|
||||
Sym *child; /* dest vertice of arc */
|
||||
int count; /* # of calls from parent to child */
|
||||
double time; /* time inherited along arc */
|
||||
double child_time; /* child-time inherited along arc */
|
||||
struct arc *next_parent; /* next parent of CHILD */
|
||||
struct arc *next_child; /* next child of PARENT */
|
||||
} Arc;
|
||||
typedef struct arc
|
||||
{
|
||||
Sym *parent; /* source vertice of arc */
|
||||
Sym *child; /* dest vertice of arc */
|
||||
int count; /* # of calls from parent to child */
|
||||
double time; /* time inherited along arc */
|
||||
double child_time; /* child-time inherited along arc */
|
||||
struct arc *next_parent; /* next parent of CHILD */
|
||||
struct arc *next_child; /* next child of PARENT */
|
||||
}
|
||||
Arc;
|
||||
|
||||
extern int num_cycles; /* number of cycles discovered */
|
||||
extern Sym *cycle_header; /* cycle headers */
|
||||
extern int num_cycles; /* number of cycles discovered */
|
||||
extern Sym *cycle_header; /* cycle headers */
|
||||
|
||||
extern void arc_add PARAMS((Sym *parent, Sym *child, int count));
|
||||
extern Arc *arc_lookup PARAMS((Sym *parent, Sym *child));
|
||||
extern Sym **cg_assemble PARAMS((void));
|
||||
extern void arc_add PARAMS ((Sym * parent, Sym * child, int count));
|
||||
extern Arc *arc_lookup PARAMS ((Sym * parent, Sym * child));
|
||||
extern Sym **cg_assemble PARAMS ((void));
|
||||
|
||||
#endif /* cg_arcs_h */
|
||||
|
355
gprof/cg_dfn.c
355
gprof/cg_dfn.c
@ -25,37 +25,40 @@
|
||||
|
||||
#define DFN_DEPTH 100
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
Sym *sym;
|
||||
int cycle_top;
|
||||
} DFN_Stack;
|
||||
}
|
||||
DFN_Stack;
|
||||
|
||||
DFN_Stack dfn_stack[DFN_DEPTH];
|
||||
int dfn_depth = 0;
|
||||
int dfn_counter = DFN_NAN;
|
||||
int dfn_depth = 0;
|
||||
int dfn_counter = DFN_NAN;
|
||||
|
||||
|
||||
/*
|
||||
* Is CHILD already numbered?
|
||||
*/
|
||||
static bool
|
||||
DEFUN(is_numbered, (child), Sym *child)
|
||||
DEFUN (is_numbered, (child), Sym * child)
|
||||
{
|
||||
return child->cg.top_order != DFN_NAN && child->cg.top_order != DFN_BUSY;
|
||||
} /* is_numbered */
|
||||
return child->cg.top_order != DFN_NAN && child->cg.top_order != DFN_BUSY;
|
||||
} /* is_numbered */
|
||||
|
||||
|
||||
/*
|
||||
* Is CHILD already busy?
|
||||
*/
|
||||
static bool
|
||||
DEFUN(is_busy, (child), Sym *child)
|
||||
DEFUN (is_busy, (child), Sym * child)
|
||||
{
|
||||
if (child->cg.top_order == DFN_NAN) {
|
||||
return FALSE;
|
||||
} /* if */
|
||||
return TRUE;
|
||||
} /* is_busy */
|
||||
if (child->cg.top_order == DFN_NAN)
|
||||
{
|
||||
return FALSE;
|
||||
} /* if */
|
||||
return TRUE;
|
||||
} /* is_busy */
|
||||
|
||||
|
||||
/*
|
||||
@ -65,92 +68,122 @@ DEFUN(is_busy, (child), Sym *child)
|
||||
* depth-first number).
|
||||
*/
|
||||
static void
|
||||
DEFUN(find_cycle, (child), Sym *child)
|
||||
DEFUN (find_cycle, (child), Sym * child)
|
||||
{
|
||||
Sym *head = 0;
|
||||
Sym *tail;
|
||||
int cycle_top;
|
||||
int index;
|
||||
Sym *head = 0;
|
||||
Sym *tail;
|
||||
int cycle_top;
|
||||
int index;
|
||||
|
||||
for (cycle_top = dfn_depth; cycle_top > 0; --cycle_top) {
|
||||
head = dfn_stack[cycle_top].sym;
|
||||
if (child == head) {
|
||||
break;
|
||||
} /* if */
|
||||
if (child->cg.cyc.head != child && child->cg.cyc.head == head) {
|
||||
break;
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (cycle_top <= 0) {
|
||||
fprintf(stderr, "[find_cycle] couldn't find head of cycle\n");
|
||||
done(1);
|
||||
} /* if */
|
||||
DBG(DFNDEBUG, printf("[find_cycle] dfn_depth %d cycle_top %d ",
|
||||
dfn_depth, cycle_top);
|
||||
if (head) {
|
||||
print_name(head);
|
||||
} else {
|
||||
printf("<unknown>");
|
||||
} /* if */
|
||||
printf("\n"));
|
||||
if (cycle_top == dfn_depth) {
|
||||
/*
|
||||
* This is previous function, e.g. this calls itself. Sort of
|
||||
* boring.
|
||||
*
|
||||
* Since we are taking out self-cycles elsewhere no need for
|
||||
* the special case, here.
|
||||
*/
|
||||
DBG(DFNDEBUG,
|
||||
printf("[find_cycle] "); print_name(child); printf("\n"));
|
||||
} else {
|
||||
/*
|
||||
* Glom intervening functions that aren't already glommed into
|
||||
* this cycle. Things have been glommed when their cyclehead
|
||||
* field points to the head of the cycle they are glommed
|
||||
* into.
|
||||
*/
|
||||
for (tail = head; tail->cg.cyc.next; tail = tail->cg.cyc.next) {
|
||||
/* void: chase down to tail of things already glommed */
|
||||
DBG(DFNDEBUG,
|
||||
printf("[find_cycle] tail "); print_name(tail); printf("\n"));
|
||||
} /* for */
|
||||
/*
|
||||
* If what we think is the top of the cycle has a cyclehead
|
||||
* field, then it's not really the head of the cycle, which is
|
||||
* really what we want.
|
||||
*/
|
||||
if (head->cg.cyc.head != head) {
|
||||
head = head->cg.cyc.head;
|
||||
DBG(DFNDEBUG, printf("[find_cycle] new cyclehead ");
|
||||
print_name(head); printf("\n"));
|
||||
} /* if */
|
||||
for (index = cycle_top + 1; index <= dfn_depth; ++index) {
|
||||
child = dfn_stack[index].sym;
|
||||
if (child->cg.cyc.head == child) {
|
||||
/*
|
||||
* Not yet glommed anywhere, glom it and fix any
|
||||
* children it has glommed.
|
||||
*/
|
||||
tail->cg.cyc.next = child;
|
||||
child->cg.cyc.head = head;
|
||||
DBG(DFNDEBUG, printf("[find_cycle] glomming ");
|
||||
print_name(child); printf(" onto "); print_name(head);
|
||||
printf("\n"));
|
||||
for (tail = child; tail->cg.cyc.next; tail = tail->cg.cyc.next)
|
||||
for (cycle_top = dfn_depth; cycle_top > 0; --cycle_top)
|
||||
{
|
||||
head = dfn_stack[cycle_top].sym;
|
||||
if (child == head)
|
||||
{
|
||||
break;
|
||||
} /* if */
|
||||
if (child->cg.cyc.head != child && child->cg.cyc.head == head)
|
||||
{
|
||||
break;
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (cycle_top <= 0)
|
||||
{
|
||||
fprintf (stderr, "[find_cycle] couldn't find head of cycle\n");
|
||||
done (1);
|
||||
} /* if */
|
||||
#ifdef DEBUG
|
||||
if (debug_level & DFNDEBUG)
|
||||
{
|
||||
printf ("[find_cycle] dfn_depth %d cycle_top %d ",
|
||||
dfn_depth, cycle_top);
|
||||
if (head)
|
||||
{
|
||||
print_name (head);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("<unknown>");
|
||||
} /* if */
|
||||
printf ("\n");
|
||||
}
|
||||
#endif
|
||||
if (cycle_top == dfn_depth)
|
||||
{
|
||||
/*
|
||||
* This is previous function, e.g. this calls itself. Sort of
|
||||
* boring.
|
||||
*
|
||||
* Since we are taking out self-cycles elsewhere no need for
|
||||
* the special case, here.
|
||||
*/
|
||||
DBG (DFNDEBUG,
|
||||
printf ("[find_cycle] ");
|
||||
print_name (child);
|
||||
printf ("\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Glom intervening functions that aren't already glommed into
|
||||
* this cycle. Things have been glommed when their cyclehead
|
||||
* field points to the head of the cycle they are glommed
|
||||
* into.
|
||||
*/
|
||||
for (tail = head; tail->cg.cyc.next; tail = tail->cg.cyc.next)
|
||||
{
|
||||
/* void: chase down to tail of things already glommed */
|
||||
DBG (DFNDEBUG,
|
||||
printf ("[find_cycle] tail ");
|
||||
print_name (tail);
|
||||
printf ("\n"));
|
||||
} /* for */
|
||||
/*
|
||||
* If what we think is the top of the cycle has a cyclehead
|
||||
* field, then it's not really the head of the cycle, which is
|
||||
* really what we want.
|
||||
*/
|
||||
if (head->cg.cyc.head != head)
|
||||
{
|
||||
head = head->cg.cyc.head;
|
||||
DBG (DFNDEBUG, printf ("[find_cycle] new cyclehead ");
|
||||
print_name (head);
|
||||
printf ("\n"));
|
||||
} /* if */
|
||||
for (index = cycle_top + 1; index <= dfn_depth; ++index)
|
||||
{
|
||||
child = dfn_stack[index].sym;
|
||||
if (child->cg.cyc.head == child)
|
||||
{
|
||||
/*
|
||||
* Not yet glommed anywhere, glom it and fix any
|
||||
* children it has glommed.
|
||||
*/
|
||||
tail->cg.cyc.next = child;
|
||||
child->cg.cyc.head = head;
|
||||
DBG (DFNDEBUG, printf ("[find_cycle] glomming ");
|
||||
print_name (child);
|
||||
printf (" onto ");
|
||||
print_name (head);
|
||||
printf ("\n"));
|
||||
for (tail = child; tail->cg.cyc.next; tail = tail->cg.cyc.next)
|
||||
{
|
||||
tail->cg.cyc.next->cg.cyc.head = head;
|
||||
DBG(DFNDEBUG, printf("[find_cycle] and its tail ");
|
||||
print_name(tail->cg.cyc.next); printf(" onto ");
|
||||
print_name(head); printf("\n"));
|
||||
} /* for */
|
||||
} else if (child->cg.cyc.head != head /* firewall */) {
|
||||
fprintf(stderr, "[find_cycle] glommed, but not to head\n");
|
||||
done(1);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* if */
|
||||
} /* find_cycle */
|
||||
tail->cg.cyc.next->cg.cyc.head = head;
|
||||
DBG (DFNDEBUG, printf ("[find_cycle] and its tail ");
|
||||
print_name (tail->cg.cyc.next);
|
||||
printf (" onto ");
|
||||
print_name (head);
|
||||
printf ("\n"));
|
||||
} /* for */
|
||||
}
|
||||
else if (child->cg.cyc.head != head /* firewall */ )
|
||||
{
|
||||
fprintf (stderr, "[find_cycle] glommed, but not to head\n");
|
||||
done (1);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* if */
|
||||
} /* find_cycle */
|
||||
|
||||
|
||||
/*
|
||||
@ -158,19 +191,21 @@ DEFUN(find_cycle, (child), Sym *child)
|
||||
* the stack and mark it busy.
|
||||
*/
|
||||
static void
|
||||
DEFUN(pre_visit, (parent), Sym *parent)
|
||||
DEFUN (pre_visit, (parent), Sym * parent)
|
||||
{
|
||||
++dfn_depth;
|
||||
if (dfn_depth >= DFN_DEPTH) {
|
||||
fprintf(stderr, "[pre_visit] dfn_stack overflow\n");
|
||||
done(1);
|
||||
} /* if */
|
||||
dfn_stack[dfn_depth].sym = parent;
|
||||
dfn_stack[dfn_depth].cycle_top = dfn_depth;
|
||||
parent->cg.top_order = DFN_BUSY;
|
||||
DBG(DFNDEBUG, printf("[pre_visit]\t\t%d:", dfn_depth); print_name(parent);
|
||||
printf("\n"));
|
||||
} /* pre_visit */
|
||||
++dfn_depth;
|
||||
if (dfn_depth >= DFN_DEPTH)
|
||||
{
|
||||
fprintf (stderr, "[pre_visit] dfn_stack overflow\n");
|
||||
done (1);
|
||||
} /* if */
|
||||
dfn_stack[dfn_depth].sym = parent;
|
||||
dfn_stack[dfn_depth].cycle_top = dfn_depth;
|
||||
parent->cg.top_order = DFN_BUSY;
|
||||
DBG (DFNDEBUG, printf ("[pre_visit]\t\t%d:", dfn_depth);
|
||||
print_name (parent);
|
||||
printf ("\n"));
|
||||
} /* pre_visit */
|
||||
|
||||
|
||||
/*
|
||||
@ -178,61 +213,71 @@ DEFUN(pre_visit, (parent), Sym *parent)
|
||||
* and number functions if PARENT is head of a cycle.
|
||||
*/
|
||||
static void
|
||||
DEFUN(post_visit, (parent), Sym *parent)
|
||||
DEFUN (post_visit, (parent), Sym * parent)
|
||||
{
|
||||
Sym *member;
|
||||
Sym *member;
|
||||
|
||||
DBG(DFNDEBUG, printf("[post_visit]\t%d: ", dfn_depth);
|
||||
print_name(parent); printf("\n"));
|
||||
/*
|
||||
* Number functions and things in their cycles unless the function
|
||||
* is itself part of a cycle:
|
||||
*/
|
||||
if (parent->cg.cyc.head == parent) {
|
||||
++dfn_counter;
|
||||
for (member = parent; member; member = member->cg.cyc.next) {
|
||||
member->cg.top_order = dfn_counter;
|
||||
DBG(DFNDEBUG, printf("[post_visit]\t\tmember ");
|
||||
print_name(member);
|
||||
printf("-> cg.top_order = %d\n", dfn_counter));
|
||||
} /* for */
|
||||
} else {
|
||||
DBG(DFNDEBUG, printf("[post_visit]\t\tis part of a cycle\n"));
|
||||
} /* if */
|
||||
--dfn_depth;
|
||||
} /* post_visit */
|
||||
DBG (DFNDEBUG, printf ("[post_visit]\t%d: ", dfn_depth);
|
||||
print_name (parent);
|
||||
printf ("\n"));
|
||||
/*
|
||||
* Number functions and things in their cycles unless the function
|
||||
* is itself part of a cycle:
|
||||
*/
|
||||
if (parent->cg.cyc.head == parent)
|
||||
{
|
||||
++dfn_counter;
|
||||
for (member = parent; member; member = member->cg.cyc.next)
|
||||
{
|
||||
member->cg.top_order = dfn_counter;
|
||||
DBG (DFNDEBUG, printf ("[post_visit]\t\tmember ");
|
||||
print_name (member);
|
||||
printf ("-> cg.top_order = %d\n", dfn_counter));
|
||||
} /* for */
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG (DFNDEBUG, printf ("[post_visit]\t\tis part of a cycle\n"));
|
||||
} /* if */
|
||||
--dfn_depth;
|
||||
} /* post_visit */
|
||||
|
||||
|
||||
/*
|
||||
* Given this PARENT, depth first number its children.
|
||||
*/
|
||||
void
|
||||
DEFUN(cg_dfn, (parent), Sym *parent)
|
||||
DEFUN (cg_dfn, (parent), Sym * parent)
|
||||
{
|
||||
Arc *arc;
|
||||
Arc *arc;
|
||||
|
||||
DBG(DFNDEBUG, printf("[dfn] dfn( "); print_name(parent); printf(")\n"));
|
||||
/*
|
||||
* If we're already numbered, no need to look any further:
|
||||
*/
|
||||
if (is_numbered(parent)) {
|
||||
return;
|
||||
} /* if */
|
||||
/*
|
||||
* If we're already busy, must be a cycle:
|
||||
*/
|
||||
if (is_busy(parent)) {
|
||||
find_cycle(parent);
|
||||
return;
|
||||
} /* if */
|
||||
pre_visit(parent);
|
||||
/*
|
||||
* Recursively visit children:
|
||||
*/
|
||||
for (arc = parent->cg.children; arc; arc = arc->next_child) {
|
||||
cg_dfn(arc->child);
|
||||
} /* for */
|
||||
post_visit(parent);
|
||||
} /* cg_dfn */
|
||||
DBG (DFNDEBUG, printf ("[dfn] dfn( ");
|
||||
print_name (parent);
|
||||
printf (")\n"));
|
||||
/*
|
||||
* If we're already numbered, no need to look any further:
|
||||
*/
|
||||
if (is_numbered (parent))
|
||||
{
|
||||
return;
|
||||
} /* if */
|
||||
/*
|
||||
* If we're already busy, must be a cycle:
|
||||
*/
|
||||
if (is_busy (parent))
|
||||
{
|
||||
find_cycle (parent);
|
||||
return;
|
||||
} /* if */
|
||||
pre_visit (parent);
|
||||
/*
|
||||
* Recursively visit children:
|
||||
*/
|
||||
for (arc = parent->cg.children; arc; arc = arc->next_child)
|
||||
{
|
||||
cg_dfn (arc->child);
|
||||
} /* for */
|
||||
post_visit (parent);
|
||||
} /* cg_dfn */
|
||||
|
||||
/*** end of cg_dfn.c ***/
|
||||
/*** end of cg_dfn.c ***/
|
||||
|
@ -12,6 +12,6 @@
|
||||
* Depth-first numbering of a call-graph.
|
||||
*/
|
||||
|
||||
extern void cg_dfn PARAMS((Sym *root));
|
||||
extern void cg_dfn PARAMS ((Sym * root));
|
||||
|
||||
#endif /* cg_dfn_h */
|
||||
|
1000
gprof/cg_print.c
1000
gprof/cg_print.c
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@
|
||||
#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 PARAMS ((Sym ** cg));
|
||||
extern void cg_print_index PARAMS ((void));
|
||||
|
||||
#endif /* cg_print_h */
|
||||
|
760
gprof/core.c
760
gprof/core.c
@ -11,191 +11,209 @@ PTR core_text_space;
|
||||
|
||||
|
||||
void
|
||||
DEFUN(core_init, (a_out_name), const char *a_out_name)
|
||||
DEFUN (core_init, (a_out_name), const char *a_out_name)
|
||||
{
|
||||
core_bfd = bfd_openr(a_out_name, 0);
|
||||
core_bfd = bfd_openr (a_out_name, 0);
|
||||
|
||||
if (!core_bfd) {
|
||||
perror(a_out_name);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (!core_bfd)
|
||||
{
|
||||
perror (a_out_name);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
if (!bfd_check_format(core_bfd, bfd_object)) {
|
||||
fprintf(stderr, "%s: %s: not in a.out format\n", whoami, a_out_name);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (!bfd_check_format (core_bfd, bfd_object))
|
||||
{
|
||||
fprintf (stderr, "%s: %s: not in a.out format\n", whoami, a_out_name);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* get core's text section: */
|
||||
core_text_sect = bfd_get_section_by_name(core_bfd, ".text");
|
||||
if (!core_text_sect) {
|
||||
core_text_sect = bfd_get_section_by_name(core_bfd, "$CODE$");
|
||||
if (!core_text_sect) {
|
||||
fprintf(stderr, "%s: can't find .text section in %s\n",
|
||||
whoami, a_out_name);
|
||||
done(1);
|
||||
} /* if */
|
||||
} /* if */
|
||||
/* get core's text section: */
|
||||
core_text_sect = bfd_get_section_by_name (core_bfd, ".text");
|
||||
if (!core_text_sect)
|
||||
{
|
||||
core_text_sect = bfd_get_section_by_name (core_bfd, "$CODE$");
|
||||
if (!core_text_sect)
|
||||
{
|
||||
fprintf (stderr, "%s: can't find .text section in %s\n",
|
||||
whoami, a_out_name);
|
||||
done (1);
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
/* read core's symbol table: */
|
||||
/* read core's symbol table: */
|
||||
|
||||
/* 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) {
|
||||
fprintf(stderr, "%s: %s: %s\n", whoami, a_out_name,
|
||||
bfd_errmsg(bfd_get_error()));
|
||||
done(1);
|
||||
} /* if */
|
||||
/* 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)
|
||||
{
|
||||
fprintf (stderr, "%s: %s: %s\n", whoami, a_out_name,
|
||||
bfd_errmsg (bfd_get_error ()));
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
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,
|
||||
bfd_errmsg(bfd_get_error()));
|
||||
done(1);
|
||||
} /* if */
|
||||
} /* core_init */
|
||||
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,
|
||||
bfd_errmsg (bfd_get_error ()));
|
||||
done (1);
|
||||
} /* if */
|
||||
} /* core_init */
|
||||
|
||||
|
||||
/*
|
||||
* Read in the text space of an a.out file
|
||||
*/
|
||||
void
|
||||
DEFUN(core_get_text_space, (core_bfd), bfd *core_bfd)
|
||||
DEFUN (core_get_text_space, (core_bfd), bfd * core_bfd)
|
||||
{
|
||||
core_text_space = (PTR) malloc(core_text_sect->_raw_size);
|
||||
core_text_space = (PTR) malloc (core_text_sect->_raw_size);
|
||||
|
||||
if (!core_text_space) {
|
||||
fprintf(stderr, "%s: ran out room for %ld bytes of text space\n",
|
||||
whoami, core_text_sect->_raw_size);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (!bfd_get_section_contents(core_bfd, core_text_sect, core_text_space,
|
||||
0, core_text_sect->_raw_size))
|
||||
if (!core_text_space)
|
||||
{
|
||||
bfd_perror("bfd_get_section_contents");
|
||||
free(core_text_space);
|
||||
core_text_space = 0;
|
||||
} /* if */
|
||||
if (!core_text_space) {
|
||||
fprintf(stderr, "%s: can't do -c\n", whoami);
|
||||
} /* if */
|
||||
} /* core_get_text_space */
|
||||
fprintf (stderr, "%s: ran out room for %ld bytes of text space\n",
|
||||
whoami, core_text_sect->_raw_size);
|
||||
done (1);
|
||||
} /* if */
|
||||
if (!bfd_get_section_contents (core_bfd, core_text_sect, core_text_space,
|
||||
0, core_text_sect->_raw_size))
|
||||
{
|
||||
bfd_perror ("bfd_get_section_contents");
|
||||
free (core_text_space);
|
||||
core_text_space = 0;
|
||||
} /* if */
|
||||
if (!core_text_space)
|
||||
{
|
||||
fprintf (stderr, "%s: can't do -c\n", whoami);
|
||||
} /* if */
|
||||
} /* core_get_text_space */
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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)
|
||||
DEFUN (core_sym_class, (sym), asymbol * sym)
|
||||
{
|
||||
symbol_info syminfo;
|
||||
const char *name;
|
||||
char sym_prefix;
|
||||
int i;
|
||||
symbol_info syminfo;
|
||||
const char *name;
|
||||
char sym_prefix;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Must be a text symbol, and static text symbols don't qualify if
|
||||
* ignore_static_funcs set.
|
||||
*/
|
||||
if (!sym->section) {
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
if (ignore_static_funcs && (sym->flags & BSF_LOCAL)) {
|
||||
DBG(AOUTDEBUG, printf("[core_sym_class] %s: not a function\n",
|
||||
sym->name));
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
bfd_get_symbol_info(core_bfd, sym, &syminfo);
|
||||
i = syminfo.type;
|
||||
|
||||
if (i == 'T') {
|
||||
return i; /* it's a global symbol */
|
||||
} /* if */
|
||||
|
||||
if (i != 't') {
|
||||
/* not a static text symbol */
|
||||
DBG(AOUTDEBUG, printf("[core_sym_class] %s is of class %c\n",
|
||||
sym->name, i));
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
/* do some more filtering on static function-names: */
|
||||
|
||||
if (ignore_static_funcs) {
|
||||
return 0;
|
||||
} /* if */
|
||||
/*
|
||||
* 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;
|
||||
} /* if */
|
||||
|
||||
for (name = sym->name; *name; ++name) {
|
||||
if (*name == '.' || *name == '$') {
|
||||
return 0;
|
||||
} /* if */
|
||||
} /* if */
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
|| !strncmp (sym->name, "__gnu_compiled", 14)
|
||||
|| !strncmp (sym->name, "___gnu_compiled", 15))
|
||||
/*
|
||||
* Must be a text symbol, and static text symbols don't qualify if
|
||||
* ignore_static_funcs set.
|
||||
*/
|
||||
if (!sym->section)
|
||||
{
|
||||
return 0;
|
||||
} /* if */
|
||||
return 't'; /* it's a static text symbol */
|
||||
} /* core_sym_class */
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
if (ignore_static_funcs && (sym->flags & BSF_LOCAL))
|
||||
{
|
||||
DBG (AOUTDEBUG, printf ("[core_sym_class] %s: not a function\n",
|
||||
sym->name));
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
bfd_get_symbol_info (core_bfd, sym, &syminfo);
|
||||
i = syminfo.type;
|
||||
|
||||
if (i == 'T')
|
||||
{
|
||||
return i; /* it's a global symbol */
|
||||
} /* if */
|
||||
|
||||
if (i != 't')
|
||||
{
|
||||
/* not a static text symbol */
|
||||
DBG (AOUTDEBUG, printf ("[core_sym_class] %s is of class %c\n",
|
||||
sym->name, i));
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
/* do some more filtering on static function-names: */
|
||||
|
||||
if (ignore_static_funcs)
|
||||
{
|
||||
return 0;
|
||||
} /* if */
|
||||
/*
|
||||
* 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;
|
||||
} /* if */
|
||||
|
||||
for (name = sym->name; *name; ++name)
|
||||
{
|
||||
if (*name == '.' || *name == '$')
|
||||
{
|
||||
return 0;
|
||||
} /* if */
|
||||
} /* if */
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
|| !strncmp (sym->name, "__gnu_compiled", 14)
|
||||
|| !strncmp (sym->name, "___gnu_compiled", 15))
|
||||
{
|
||||
return 0;
|
||||
} /* if */
|
||||
return 't'; /* it's a static text symbol */
|
||||
} /* core_sym_class */
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
AND int *line_num)
|
||||
DEFUN (get_src_info, (addr, filename, name, line_num),
|
||||
bfd_vma addr AND const char **filename AND const char **name
|
||||
AND int *line_num)
|
||||
{
|
||||
const char *fname = 0, *func_name = 0;
|
||||
int l = 0;
|
||||
const char *fname = 0, *func_name = 0;
|
||||
int l = 0;
|
||||
|
||||
if (bfd_find_nearest_line(core_bfd, core_text_sect, core_syms,
|
||||
addr - core_text_sect->vma,
|
||||
&fname, &func_name, &l)
|
||||
&& fname && func_name && l)
|
||||
if (bfd_find_nearest_line (core_bfd, core_text_sect, core_syms,
|
||||
addr - core_text_sect->vma,
|
||||
&fname, &func_name, &l)
|
||||
&& fname && func_name && l)
|
||||
{
|
||||
DBG(AOUTDEBUG, printf("[get_src_info] 0x%lx -> %s:%d (%s)\n",
|
||||
DBG (AOUTDEBUG, printf ("[get_src_info] 0x%lx -> %s:%d (%s)\n",
|
||||
addr, fname, l, func_name));
|
||||
*filename = fname;
|
||||
*name = func_name;
|
||||
*line_num = l;
|
||||
return TRUE;
|
||||
} else {
|
||||
DBG(AOUTDEBUG, printf("[get_src_info] no info for 0x%lx (%s:%d,%s)\n",
|
||||
*filename = fname;
|
||||
*name = func_name;
|
||||
*line_num = l;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG (AOUTDEBUG, printf ("[get_src_info] no info for 0x%lx (%s:%d,%s)\n",
|
||||
(long) addr, fname ? fname : "<unknown>", l,
|
||||
func_name ? func_name : "<unknown>"));
|
||||
return FALSE;
|
||||
} /* if */
|
||||
} /* get_src_info */
|
||||
return FALSE;
|
||||
} /* if */
|
||||
} /* get_src_info */
|
||||
|
||||
|
||||
/*
|
||||
@ -203,119 +221,126 @@ DEFUN(get_src_info, (addr, filename, name, line_num),
|
||||
* entered.
|
||||
*/
|
||||
void
|
||||
DEFUN(core_create_function_syms, (core_bfd), bfd *core_bfd)
|
||||
DEFUN (core_create_function_syms, (core_bfd), bfd * core_bfd)
|
||||
{
|
||||
bfd_vma min_vma = ~0, max_vma = 0;
|
||||
const char *filename, *func_name;
|
||||
int class;
|
||||
long i;
|
||||
bfd_vma min_vma = ~0, max_vma = 0;
|
||||
const char *filename, *func_name;
|
||||
int class;
|
||||
long i;
|
||||
|
||||
/* 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;
|
||||
} /* if */
|
||||
++symtab.len;
|
||||
} /* for */
|
||||
/* 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;
|
||||
} /* if */
|
||||
++symtab.len;
|
||||
} /* for */
|
||||
|
||||
if (symtab.len == 0) {
|
||||
fprintf(stderr, "%s: file `%s' has no symbols\n", whoami, a_out_name);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (symtab.len == 0)
|
||||
{
|
||||
fprintf (stderr, "%s: file `%s' has no symbols\n", whoami, a_out_name);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* the "+ 2" is for the sentinels: */
|
||||
symtab.base = (Sym*)xmalloc((symtab.len + 2) * sizeof(Sym));
|
||||
/* 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,
|
||||
printf("[core_create_function_syms] rejecting: 0x%lx %s\n",
|
||||
symtab.limit = symtab.base;
|
||||
for (i = 0; i < core_num_syms; ++i)
|
||||
{
|
||||
class = core_sym_class (core_syms[i]);
|
||||
if (!class)
|
||||
{
|
||||
DBG (AOUTDEBUG,
|
||||
printf ("[core_create_function_syms] rejecting: 0x%lx %s\n",
|
||||
core_syms[i]->value, core_syms[i]->name));
|
||||
continue;
|
||||
} /* if */
|
||||
continue;
|
||||
} /* if */
|
||||
|
||||
sym_init(symtab.limit);
|
||||
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;
|
||||
symtab.limit->name = core_syms[i]->name;
|
||||
symtab.limit->addr = core_syms[i]->value + core_syms[i]->section->vma;
|
||||
symtab.limit->name = core_syms[i]->name;
|
||||
|
||||
#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.
|
||||
*/
|
||||
if (get_src_info(symtab.limit->addr, &filename, &func_name,
|
||||
&symtab.limit->line_num))
|
||||
/*
|
||||
* 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 (get_src_info (symtab.limit->addr, &filename, &func_name,
|
||||
&symtab.limit->line_num))
|
||||
{
|
||||
symtab.limit->file = source_file_lookup_path(filename);
|
||||
symtab.limit->file = source_file_lookup_path (filename);
|
||||
|
||||
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.
|
||||
*/
|
||||
DBG(AOUTDEBUG,
|
||||
printf("[core_create_function_syms: rej %s (maps to %s)\n",
|
||||
symtab.limit->name, func_name));
|
||||
continue;
|
||||
} /* if */
|
||||
} /* if */
|
||||
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.
|
||||
*/
|
||||
DBG (AOUTDEBUG,
|
||||
printf ("[core_create_function_syms: rej %s (maps to %s)\n",
|
||||
symtab.limit->name, func_name));
|
||||
continue;
|
||||
} /* if */
|
||||
} /* if */
|
||||
#endif
|
||||
|
||||
symtab.limit->is_func = TRUE;
|
||||
symtab.limit->is_bb_head = TRUE;
|
||||
if (class == 't') {
|
||||
symtab.limit->is_static = TRUE;
|
||||
} /* if */
|
||||
|
||||
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 (symtab.limit->name[0] == 'm' && discard_underscores
|
||||
&& strcmp(symtab.limit->name, "main") == 0)
|
||||
symtab.limit->is_func = TRUE;
|
||||
symtab.limit->is_bb_head = TRUE;
|
||||
if (class == 't')
|
||||
{
|
||||
discard_underscores = 0;
|
||||
} /* if */
|
||||
symtab.limit->is_static = TRUE;
|
||||
} /* if */
|
||||
|
||||
DBG(AOUTDEBUG, printf("[core_create_function_syms] %ld %s 0x%lx\n",
|
||||
(long)(symtab.limit - symtab.base),
|
||||
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 (symtab.limit->name[0] == 'm' && discard_underscores
|
||||
&& strcmp (symtab.limit->name, "main") == 0)
|
||||
{
|
||||
discard_underscores = 0;
|
||||
} /* if */
|
||||
|
||||
DBG (AOUTDEBUG, printf ("[core_create_function_syms] %ld %s 0x%lx\n",
|
||||
(long) (symtab.limit - symtab.base),
|
||||
symtab.limit->name, symtab.limit->addr));
|
||||
++symtab.limit;
|
||||
} /* for */
|
||||
++symtab.limit;
|
||||
} /* for */
|
||||
|
||||
/* create sentinels: */
|
||||
/* create sentinels: */
|
||||
|
||||
sym_init(symtab.limit);
|
||||
symtab.limit->name = "<locore>";
|
||||
symtab.limit->addr = 0;
|
||||
symtab.limit->end_addr = min_vma - 1;
|
||||
++symtab.limit;
|
||||
sym_init (symtab.limit);
|
||||
symtab.limit->name = "<locore>";
|
||||
symtab.limit->addr = 0;
|
||||
symtab.limit->end_addr = min_vma - 1;
|
||||
++symtab.limit;
|
||||
|
||||
sym_init(symtab.limit);
|
||||
symtab.limit->name = "<hicore>";
|
||||
symtab.limit->addr = max_vma + 1;
|
||||
symtab.limit->end_addr = ~0;
|
||||
++symtab.limit;
|
||||
sym_init (symtab.limit);
|
||||
symtab.limit->name = "<hicore>";
|
||||
symtab.limit->addr = max_vma + 1;
|
||||
symtab.limit->end_addr = ~0;
|
||||
++symtab.limit;
|
||||
|
||||
symtab.len = symtab.limit - symtab.base;
|
||||
symtab_finalize(&symtab);
|
||||
} /* core_create_function_syms */
|
||||
symtab.len = symtab.limit - symtab.base;
|
||||
symtab_finalize (&symtab);
|
||||
} /* core_create_function_syms */
|
||||
|
||||
|
||||
/*
|
||||
@ -323,154 +348,163 @@ DEFUN(core_create_function_syms, (core_bfd), bfd *core_bfd)
|
||||
* is entered.
|
||||
*/
|
||||
void
|
||||
DEFUN(core_create_line_syms, (core_bfd), bfd *core_bfd)
|
||||
DEFUN (core_create_line_syms, (core_bfd), bfd * core_bfd)
|
||||
{
|
||||
char prev_name[PATH_MAX], prev_filename[PATH_MAX];
|
||||
bfd_vma vma, min_vma = ~0, max_vma = 0;
|
||||
bfd_vma offset, prev_offset, min_dist;
|
||||
Sym *prev, dummy, *sentinel, *sym;
|
||||
const char *filename;
|
||||
int prev_line_num, i;
|
||||
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:
|
||||
*/
|
||||
core_create_function_syms(core_bfd);
|
||||
char prev_name[PATH_MAX], prev_filename[PATH_MAX];
|
||||
bfd_vma vma, min_vma = ~0, max_vma = 0;
|
||||
bfd_vma offset, prev_offset, min_dist;
|
||||
Sym *prev, dummy, *sentinel, *sym;
|
||||
const char *filename;
|
||||
int prev_line_num, i;
|
||||
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:
|
||||
*/
|
||||
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, but for now, we try to speed up the second pass
|
||||
* by determining what the minimum code distance between two
|
||||
* lines is.
|
||||
*/
|
||||
prev_name[0] = '\0';
|
||||
ltab.len = 0;
|
||||
min_dist = core_text_sect->_raw_size;
|
||||
prev_offset = -min_dist;
|
||||
prev_filename[0] = '\0';
|
||||
prev_line_num = 0;
|
||||
for (offset = 0; offset < core_text_sect->_raw_size; ++offset) {
|
||||
vma = core_text_sect->vma + offset;
|
||||
if (!get_src_info(vma, &filename, &dummy.name, &dummy.line_num)
|
||||
|| (prev_line_num == dummy.line_num &&
|
||||
strcmp(prev_name, dummy.name) == 0
|
||||
&& strcmp(prev_filename, filename) == 0))
|
||||
/*
|
||||
* 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, but for now, we try to speed up the second pass
|
||||
* by determining what the minimum code distance between two
|
||||
* lines is.
|
||||
*/
|
||||
prev_name[0] = '\0';
|
||||
ltab.len = 0;
|
||||
min_dist = core_text_sect->_raw_size;
|
||||
prev_offset = -min_dist;
|
||||
prev_filename[0] = '\0';
|
||||
prev_line_num = 0;
|
||||
for (offset = 0; offset < core_text_sect->_raw_size; ++offset)
|
||||
{
|
||||
vma = core_text_sect->vma + offset;
|
||||
if (!get_src_info (vma, &filename, &dummy.name, &dummy.line_num)
|
||||
|| (prev_line_num == dummy.line_num &&
|
||||
strcmp (prev_name, dummy.name) == 0
|
||||
&& strcmp (prev_filename, filename) == 0))
|
||||
{
|
||||
continue;
|
||||
} /* if */
|
||||
continue;
|
||||
} /* if */
|
||||
|
||||
++ltab.len;
|
||||
prev_line_num = dummy.line_num;
|
||||
strcpy(prev_name, dummy.name);
|
||||
strcpy(prev_filename, filename);
|
||||
++ltab.len;
|
||||
prev_line_num = dummy.line_num;
|
||||
strcpy (prev_name, dummy.name);
|
||||
strcpy (prev_filename, filename);
|
||||
|
||||
if (offset - prev_offset < min_dist) {
|
||||
min_dist = offset - prev_offset;
|
||||
} /* if */
|
||||
prev_offset = offset;
|
||||
|
||||
min_vma = MIN(vma, min_vma);
|
||||
max_vma = MAX(vma, max_vma);
|
||||
} /* for */
|
||||
|
||||
DBG(AOUTDEBUG, printf("[core_create_line_syms] min_dist=%lx\n", min_dist));
|
||||
|
||||
/* 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: */
|
||||
|
||||
prev = 0;
|
||||
for (offset = 0; offset < core_text_sect->_raw_size; offset += min_dist) {
|
||||
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))
|
||||
if (offset - prev_offset < min_dist)
|
||||
{
|
||||
continue;
|
||||
} /* if */
|
||||
min_dist = offset - prev_offset;
|
||||
} /* if */
|
||||
prev_offset = offset;
|
||||
|
||||
/* make name pointer a malloc'ed string: */
|
||||
ltab.limit->name = strdup(ltab.limit->name);
|
||||
ltab.limit->file = source_file_lookup_path(filename);
|
||||
min_vma = MIN (vma, min_vma);
|
||||
max_vma = MAX (vma, max_vma);
|
||||
} /* for */
|
||||
|
||||
ltab.limit->addr = core_text_sect->vma + offset;
|
||||
prev = ltab.limit;
|
||||
DBG (AOUTDEBUG, printf ("[core_create_line_syms] min_dist=%lx\n", min_dist));
|
||||
|
||||
/*
|
||||
* 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)
|
||||
/* 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: */
|
||||
|
||||
prev = 0;
|
||||
for (offset = 0; offset < core_text_sect->_raw_size; offset += min_dist)
|
||||
{
|
||||
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))
|
||||
{
|
||||
discard_underscores = 0;
|
||||
} /* if */
|
||||
continue;
|
||||
} /* if */
|
||||
|
||||
DBG(AOUTDEBUG, printf("[core_create_line_syms] %d %s 0x%lx\n",
|
||||
/* make name pointer a malloc'ed string: */
|
||||
ltab.limit->name = strdup (ltab.limit->name);
|
||||
ltab.limit->file = source_file_lookup_path (filename);
|
||||
|
||||
ltab.limit->addr = core_text_sect->vma + offset;
|
||||
prev = ltab.limit;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
} /* if */
|
||||
|
||||
DBG (AOUTDEBUG, printf ("[core_create_line_syms] %d %s 0x%lx\n",
|
||||
ltab.len, ltab.limit->name,
|
||||
ltab.limit->addr));
|
||||
++ltab.limit;
|
||||
} /* for */
|
||||
++ltab.limit;
|
||||
} /* for */
|
||||
|
||||
/* update sentinels: */
|
||||
/* update sentinels: */
|
||||
|
||||
sentinel = sym_lookup(&symtab, 0);
|
||||
if (strcmp(sentinel->name, "<locore>") == 0
|
||||
&& min_vma <= sentinel->end_addr)
|
||||
sentinel = sym_lookup (&symtab, 0);
|
||||
if (strcmp (sentinel->name, "<locore>") == 0
|
||||
&& min_vma <= sentinel->end_addr)
|
||||
{
|
||||
sentinel->end_addr = min_vma - 1;
|
||||
} /* if */
|
||||
sentinel->end_addr = min_vma - 1;
|
||||
} /* if */
|
||||
|
||||
sentinel = sym_lookup(&symtab, ~0);
|
||||
if (strcmp(sentinel->name, "<hicore>") == 0 && max_vma >= sentinel->addr) {
|
||||
sentinel->addr = max_vma + 1;
|
||||
} /* if */
|
||||
sentinel = sym_lookup (&symtab, ~0);
|
||||
if (strcmp (sentinel->name, "<hicore>") == 0 && max_vma >= sentinel->addr)
|
||||
{
|
||||
sentinel->addr = max_vma + 1;
|
||||
} /* if */
|
||||
|
||||
/* copy in function symbols: */
|
||||
memcpy(ltab.limit, symtab.base, symtab.len * sizeof(Sym));
|
||||
ltab.limit += symtab.len;
|
||||
/* copy in function symbols: */
|
||||
memcpy (ltab.limit, symtab.base, symtab.len * sizeof (Sym));
|
||||
ltab.limit += symtab.len;
|
||||
|
||||
if (ltab.limit - ltab.base != ltab.len) {
|
||||
fprintf(stderr,
|
||||
"%s: somebody miscounted: ltab.len=%ld instead of %d\n",
|
||||
whoami, (long) (ltab.limit - ltab.base), ltab.len);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (ltab.limit - ltab.base != ltab.len)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"%s: somebody miscounted: ltab.len=%ld instead of %d\n",
|
||||
whoami, (long) (ltab.limit - ltab.base), ltab.len);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* finalize ltab and make it symbol table: */
|
||||
/* finalize ltab and make it symbol table: */
|
||||
|
||||
symtab_finalize(<ab);
|
||||
free(symtab.base);
|
||||
symtab = ltab;
|
||||
symtab_finalize (<ab);
|
||||
free (symtab.base);
|
||||
symtab = ltab;
|
||||
|
||||
/* now go through all core symbols and set is_static accordingly: */
|
||||
/* now go through all core symbols and set is_static accordingly: */
|
||||
|
||||
for (i = 0; i < core_num_syms; ++i) {
|
||||
if (core_sym_class(core_syms[i]) == 't') {
|
||||
sym = sym_lookup(&symtab, core_syms[i]->value
|
||||
+ core_syms[i]->section->vma);
|
||||
do {
|
||||
sym++->is_static = TRUE;
|
||||
} while (sym->file == sym[-1].file &&
|
||||
strcmp(sym->name, sym[-1].name) == 0);
|
||||
} /* if */
|
||||
} /* for */
|
||||
for (i = 0; i < core_num_syms; ++i)
|
||||
{
|
||||
if (core_sym_class (core_syms[i]) == 't')
|
||||
{
|
||||
sym = sym_lookup (&symtab, core_syms[i]->value
|
||||
+ core_syms[i]->section->vma);
|
||||
do
|
||||
{
|
||||
sym++->is_static = TRUE;
|
||||
}
|
||||
while (sym->file == sym[-1].file &&
|
||||
strcmp (sym->name, sym[-1].name) == 0);
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
} /* core_create_line_syms */
|
||||
} /* core_create_line_syms */
|
||||
|
||||
/*** end of core.c ***/
|
||||
/*** end of core.c ***/
|
||||
|
18
gprof/core.h
18
gprof/core.h
@ -3,15 +3,15 @@
|
||||
|
||||
#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 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 *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));
|
||||
|
||||
#endif /* core_h */
|
||||
|
@ -8,11 +8,11 @@
|
||||
*/
|
||||
|
||||
void
|
||||
DEFUN(find_call, (parent, p_lowpc, p_highpc),
|
||||
Sym *parent AND bfd_vma p_lowpc AND bfd_vma p_highpc)
|
||||
DEFUN (find_call, (parent, p_lowpc, p_highpc),
|
||||
Sym * parent AND bfd_vma p_lowpc AND bfd_vma p_highpc)
|
||||
{
|
||||
fprintf(stderr, "%s: -c supported on this machine architecture\n",
|
||||
whoami);
|
||||
} /* find_call */
|
||||
fprintf (stderr, "%s: -c supported on this machine architecture\n",
|
||||
whoami);
|
||||
} /* find_call */
|
||||
|
||||
/*** end of dummy.c ***/
|
||||
/*** end of dummy.c ***/
|
||||
|
@ -46,7 +46,10 @@
|
||||
#define OFFSET_TO_CODE 0
|
||||
#define UNITS_TO_CODE (OFFSET_TO_CODE / sizeof(UNIT))
|
||||
|
||||
enum opermodes { dummy };
|
||||
enum opermodes
|
||||
{
|
||||
dummy
|
||||
};
|
||||
typedef enum opermodes operandenum;
|
||||
|
||||
#endif /* dummy_h */
|
||||
|
39
gprof/gmon.h
39
gprof/gmon.h
@ -35,9 +35,10 @@
|
||||
#ifndef gmon_h
|
||||
#define gmon_h
|
||||
|
||||
struct raw_phdr {
|
||||
char low_pc[sizeof(bfd_vma)]; /* base pc address of sample buffer */
|
||||
char high_pc[sizeof(bfd_vma)]; /* max pc address of sampled buffer */
|
||||
struct raw_phdr
|
||||
{
|
||||
char low_pc[sizeof (bfd_vma)]; /* base pc address of sample buffer */
|
||||
char high_pc[sizeof (bfd_vma)]; /* max pc address of sampled buffer */
|
||||
char ncnt[4]; /* size of sample buffer (plus this header) */
|
||||
#ifdef __osf__
|
||||
/*
|
||||
@ -46,7 +47,7 @@ struct raw_phdr {
|
||||
*/
|
||||
char pad[4];
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Histogram counters are unsigned shorts:
|
||||
@ -65,17 +66,17 @@ struct raw_phdr {
|
||||
* Given MIN_SUBR_SEPARATION bytes of separation the value of
|
||||
* HASHFRACTION is calculated as:
|
||||
*
|
||||
* HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1);
|
||||
* HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1);
|
||||
*
|
||||
* For the VAX, the shortest two call sequence is:
|
||||
*
|
||||
* calls $0,(r0)
|
||||
* calls $0,(r0)
|
||||
* calls $0,(r0)
|
||||
* calls $0,(r0)
|
||||
*
|
||||
* which is separated by only three bytes, thus HASHFRACTION is
|
||||
* calculated as:
|
||||
*
|
||||
* HASHFRACTION = 3 / (2 * 2 - 1) = 1
|
||||
* HASHFRACTION = 3 / (2 * 2 - 1) = 1
|
||||
*
|
||||
* Note that the division above rounds down, thus if MIN_SUBR_FRACTION
|
||||
* is less than three, this algorithm will not work!
|
||||
@ -88,11 +89,12 @@ struct raw_phdr {
|
||||
#define ARCDENSITY 2
|
||||
#define MINARCS 50
|
||||
|
||||
struct tostruct {
|
||||
char *selfpc;
|
||||
int count;
|
||||
unsigned short link;
|
||||
};
|
||||
struct tostruct
|
||||
{
|
||||
char *selfpc;
|
||||
int count;
|
||||
unsigned short link;
|
||||
};
|
||||
|
||||
/*
|
||||
* A raw arc, with pointers to the calling site and the called site
|
||||
@ -100,11 +102,12 @@ struct tostruct {
|
||||
* as to get a packed representation (otherwise, different compilers
|
||||
* might introduce different padding):
|
||||
*/
|
||||
struct raw_arc {
|
||||
char from_pc[sizeof(bfd_vma)];
|
||||
char self_pc[sizeof(bfd_vma)];
|
||||
char count[sizeof(long)];
|
||||
};
|
||||
struct raw_arc
|
||||
{
|
||||
char from_pc[sizeof (bfd_vma)];
|
||||
char self_pc[sizeof (bfd_vma)];
|
||||
char count[sizeof (long)];
|
||||
};
|
||||
|
||||
/*
|
||||
* General rounding functions:
|
||||
|
620
gprof/gmon_io.c
620
gprof/gmon_io.c
@ -8,7 +8,7 @@
|
||||
#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"
|
||||
@ -21,334 +21,378 @@ int gmon_file_version = 0; /* 0 == old (non-versioned) file format */
|
||||
* This probably ought to be in libbfd.
|
||||
*/
|
||||
bfd_vma
|
||||
DEFUN(get_vma, (abfd, addr), bfd *abfd AND bfd_byte *addr)
|
||||
DEFUN (get_vma, (abfd, addr), bfd * abfd AND bfd_byte * addr)
|
||||
{
|
||||
switch (sizeof(bfd_vma)) {
|
||||
case 4: return bfd_get_32(abfd, addr);
|
||||
case 8: return bfd_get_64(abfd, addr);
|
||||
default:
|
||||
fprintf(stderr, "%s: bfd_vma has unexpected size of %ld bytes\n",
|
||||
whoami, (long) sizeof(bfd_vma));
|
||||
done(1);
|
||||
} /* switch */
|
||||
} /* get_vma */
|
||||
switch (sizeof (bfd_vma))
|
||||
{
|
||||
case 4:
|
||||
return bfd_get_32 (abfd, addr);
|
||||
case 8:
|
||||
return bfd_get_64 (abfd, addr);
|
||||
default:
|
||||
fprintf (stderr, "%s: bfd_vma has unexpected size of %ld bytes\n",
|
||||
whoami, (long) sizeof (bfd_vma));
|
||||
done (1);
|
||||
} /* switch */
|
||||
} /* get_vma */
|
||||
|
||||
|
||||
/*
|
||||
* This probably ought to be in libbfd.
|
||||
*/
|
||||
void
|
||||
DEFUN(put_vma, (abfd, val, addr), bfd *abfd AND bfd_vma val AND bfd_byte *addr)
|
||||
DEFUN (put_vma, (abfd, val, addr), bfd * abfd AND bfd_vma val AND bfd_byte * addr)
|
||||
{
|
||||
switch (sizeof(bfd_vma)) {
|
||||
case 4: bfd_put_32(abfd, val, addr); break;
|
||||
case 8: bfd_put_64(abfd, val, addr); break;
|
||||
default:
|
||||
fprintf(stderr, "%s: bfd_vma has unexpected size of %ld bytes\n",
|
||||
whoami, (long) sizeof(bfd_vma));
|
||||
done(1);
|
||||
} /* switch */
|
||||
} /* put_vma */
|
||||
switch (sizeof (bfd_vma))
|
||||
{
|
||||
case 4:
|
||||
bfd_put_32 (abfd, val, addr);
|
||||
break;
|
||||
case 8:
|
||||
bfd_put_64 (abfd, val, addr);
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "%s: bfd_vma has unexpected size of %ld bytes\n",
|
||||
whoami, (long) sizeof (bfd_vma));
|
||||
done (1);
|
||||
} /* switch */
|
||||
} /* put_vma */
|
||||
|
||||
|
||||
void
|
||||
DEFUN(gmon_out_read, (filename), const char *filename)
|
||||
DEFUN (gmon_out_read, (filename), const char *filename)
|
||||
{
|
||||
FILE *ifp;
|
||||
struct gmon_hdr ghdr;
|
||||
unsigned char tag;
|
||||
int nhist = 0, narcs = 0, nbbs = 0;
|
||||
FILE *ifp;
|
||||
struct gmon_hdr ghdr;
|
||||
unsigned char tag;
|
||||
int nhist = 0, narcs = 0, nbbs = 0;
|
||||
|
||||
/* open gmon.out file: */
|
||||
/* open gmon.out file: */
|
||||
|
||||
if (strcmp(filename, "-") == 0) {
|
||||
ifp = stdin;
|
||||
} else {
|
||||
ifp = fopen(filename, FOPEN_RB);
|
||||
if (!ifp) {
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
} /* if */
|
||||
if (fread(&ghdr, sizeof(struct gmon_hdr), 1, ifp) != 1) {
|
||||
fprintf(stderr, "%s: file too short to be a gmon file\n",
|
||||
filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
|
||||
if ((file_format == FF_MAGIC) ||
|
||||
(file_format == FF_AUTO && !strncmp(&ghdr.cookie[0], GMON_MAGIC, 4)))
|
||||
if (strcmp (filename, "-") == 0)
|
||||
{
|
||||
if (file_format == FF_MAGIC && strncmp(&ghdr.cookie[0], GMON_MAGIC, 4))
|
||||
ifp = stdin;
|
||||
}
|
||||
else
|
||||
{
|
||||
ifp = fopen (filename, FOPEN_RB);
|
||||
if (!ifp)
|
||||
{
|
||||
fprintf(stderr, "%s: file `%s' has bad magic cookie\n",
|
||||
whoami, filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
} /* if */
|
||||
if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1)
|
||||
{
|
||||
fprintf (stderr, "%s: file too short to be a gmon file\n",
|
||||
filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* 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,
|
||||
"%s: file `%s' has unsupported version %d\n",
|
||||
whoami, filename, gmon_file_version);
|
||||
done(1);
|
||||
} /* if */
|
||||
|
||||
/* read in all the records: */
|
||||
while (fread(&tag, sizeof(tag), 1, ifp) == 1) {
|
||||
switch (tag) {
|
||||
case GMON_TAG_TIME_HIST:
|
||||
++nhist;
|
||||
gmon_input |= INPUT_HISTOGRAM;
|
||||
hist_read_rec(ifp, filename);
|
||||
break;
|
||||
|
||||
case GMON_TAG_CG_ARC:
|
||||
++narcs;
|
||||
gmon_input |= INPUT_CALL_GRAPH;
|
||||
cg_read_rec(ifp, filename);
|
||||
break;
|
||||
|
||||
case GMON_TAG_BB_COUNT:
|
||||
++nbbs;
|
||||
gmon_input |= INPUT_BB_COUNTS;
|
||||
bb_read_rec(ifp, filename);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"%s: %s: found bad tag %d (file corrupted?)\n",
|
||||
whoami, filename, tag);
|
||||
done(1);
|
||||
} /* switch */
|
||||
} /* while */
|
||||
} else if (file_format == FF_AUTO || file_format == FF_BSD) {
|
||||
struct hdr {
|
||||
bfd_vma low_pc;
|
||||
bfd_vma high_pc;
|
||||
int ncnt;
|
||||
};
|
||||
int i, samp_bytes, count;
|
||||
bfd_vma from_pc, self_pc;
|
||||
struct raw_arc raw_arc;
|
||||
struct raw_phdr raw;
|
||||
static struct hdr h;
|
||||
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.
|
||||
*/
|
||||
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?).
|
||||
*/
|
||||
if (fseek(ifp, 0, SEEK_SET) < 0) {
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (fread(&raw, 1, sizeof(struct raw_phdr), ifp)
|
||||
!= sizeof(struct raw_phdr))
|
||||
if ((file_format == FF_MAGIC) ||
|
||||
(file_format == FF_AUTO && !strncmp (&ghdr.cookie[0], GMON_MAGIC, 4)))
|
||||
{
|
||||
if (file_format == FF_MAGIC && strncmp (&ghdr.cookie[0], GMON_MAGIC, 4))
|
||||
{
|
||||
fprintf(stderr, "%s: file too short to be a gmon file\n",
|
||||
filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
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]);
|
||||
if (s_highpc && (tmp.low_pc != h.low_pc ||
|
||||
tmp.high_pc != h.high_pc || tmp.ncnt != h.ncnt))
|
||||
fprintf (stderr, "%s: file `%s' has bad magic cookie\n",
|
||||
whoami, filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* 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, "%s: incompatible with first gmon file\n",
|
||||
filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
h = tmp;
|
||||
s_lowpc = (bfd_vma) h.low_pc;
|
||||
s_highpc = (bfd_vma) h.high_pc;
|
||||
lowpc = (bfd_vma) h.low_pc / sizeof(UNIT);
|
||||
highpc = (bfd_vma) h.high_pc / sizeof(UNIT);
|
||||
samp_bytes = h.ncnt - sizeof(struct raw_phdr);
|
||||
hist_num_bins = samp_bytes / sizeof (UNIT);
|
||||
DBG(SAMPLEDEBUG,
|
||||
printf("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
|
||||
fprintf (stderr,
|
||||
"%s: file `%s' has unsupported version %d\n",
|
||||
whoami, filename, gmon_file_version);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* read in all the records: */
|
||||
while (fread (&tag, sizeof (tag), 1, ifp) == 1)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case GMON_TAG_TIME_HIST:
|
||||
++nhist;
|
||||
gmon_input |= INPUT_HISTOGRAM;
|
||||
hist_read_rec (ifp, filename);
|
||||
break;
|
||||
|
||||
case GMON_TAG_CG_ARC:
|
||||
++narcs;
|
||||
gmon_input |= INPUT_CALL_GRAPH;
|
||||
cg_read_rec (ifp, filename);
|
||||
break;
|
||||
|
||||
case GMON_TAG_BB_COUNT:
|
||||
++nbbs;
|
||||
gmon_input |= INPUT_BB_COUNTS;
|
||||
bb_read_rec (ifp, filename);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stderr,
|
||||
"%s: %s: found bad tag %d (file corrupted?)\n",
|
||||
whoami, filename, tag);
|
||||
done (1);
|
||||
} /* switch */
|
||||
} /* while */
|
||||
}
|
||||
else if (file_format == FF_AUTO || file_format == FF_BSD)
|
||||
{
|
||||
struct hdr
|
||||
{
|
||||
bfd_vma low_pc;
|
||||
bfd_vma high_pc;
|
||||
int ncnt;
|
||||
};
|
||||
int i, samp_bytes, count;
|
||||
bfd_vma from_pc, self_pc;
|
||||
struct raw_arc raw_arc;
|
||||
struct raw_phdr raw;
|
||||
static struct hdr h;
|
||||
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.
|
||||
*/
|
||||
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?).
|
||||
*/
|
||||
if (fseek (ifp, 0, SEEK_SET) < 0)
|
||||
{
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
if (fread (&raw, 1, sizeof (struct raw_phdr), ifp)
|
||||
!= sizeof (struct raw_phdr))
|
||||
{
|
||||
fprintf (stderr, "%s: file too short to be a gmon file\n",
|
||||
filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
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]);
|
||||
if (s_highpc && (tmp.low_pc != h.low_pc ||
|
||||
tmp.high_pc != h.high_pc || tmp.ncnt != h.ncnt))
|
||||
{
|
||||
fprintf (stderr, "%s: incompatible with first gmon file\n",
|
||||
filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
h = tmp;
|
||||
s_lowpc = (bfd_vma) h.low_pc;
|
||||
s_highpc = (bfd_vma) h.high_pc;
|
||||
lowpc = (bfd_vma) h.low_pc / sizeof (UNIT);
|
||||
highpc = (bfd_vma) h.high_pc / sizeof (UNIT);
|
||||
samp_bytes = h.ncnt - sizeof (struct raw_phdr);
|
||||
hist_num_bins = samp_bytes / sizeof (UNIT);
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
|
||||
h.low_pc, h.high_pc, h.ncnt);
|
||||
printf("[gmon_out_read] s_lowpc 0x%lx s_highpc 0x%lx\n",
|
||||
printf ("[gmon_out_read] s_lowpc 0x%lx s_highpc 0x%lx\n",
|
||||
s_lowpc, s_highpc);
|
||||
printf("[gmon_out_read] lowpc 0x%lx highpc 0x%lx\n",
|
||||
printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx\n",
|
||||
lowpc, highpc);
|
||||
printf("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
|
||||
printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
|
||||
samp_bytes, hist_num_bins));
|
||||
|
||||
if (hist_num_bins) {
|
||||
++nhist;
|
||||
} /* if */
|
||||
if (hist_num_bins)
|
||||
{
|
||||
++nhist;
|
||||
} /* if */
|
||||
|
||||
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]));
|
||||
} /* if */
|
||||
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]));
|
||||
} /* if */
|
||||
|
||||
for (i = 0; i < hist_num_bins; ++i) {
|
||||
if (fread(raw_bin_count, sizeof(raw_bin_count), 1, ifp) != 1) {
|
||||
fprintf(stderr,
|
||||
"%s: unexpected EOF after reading %d/%d bins\n",
|
||||
whoami, --i, hist_num_bins);
|
||||
done(1);
|
||||
} /* if */
|
||||
hist_sample[i] += bfd_get_16(core_bfd, (bfd_byte*) raw_bin_count);
|
||||
} /* for */
|
||||
for (i = 0; i < hist_num_bins; ++i)
|
||||
{
|
||||
if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"%s: unexpected EOF after reading %d/%d bins\n",
|
||||
whoami, --i, hist_num_bins);
|
||||
done (1);
|
||||
} /* if */
|
||||
hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count);
|
||||
} /* for */
|
||||
|
||||
/*
|
||||
* 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 %d\n",
|
||||
from_pc, self_pc, count));
|
||||
/* add this arc: */
|
||||
cg_tally(from_pc, self_pc, count);
|
||||
} /* while */
|
||||
fclose(ifp);
|
||||
/*
|
||||
* 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 %d\n",
|
||||
from_pc, self_pc, count));
|
||||
/* add this arc: */
|
||||
cg_tally (from_pc, self_pc, count);
|
||||
} /* while */
|
||||
fclose (ifp);
|
||||
|
||||
if (hz == HZ_WRONG) {
|
||||
/*
|
||||
* How many ticks per second? If we can't tell, report
|
||||
* time in ticks.
|
||||
*/
|
||||
hz = hertz();
|
||||
if (hz == HZ_WRONG) {
|
||||
hz = 1;
|
||||
fprintf(stderr, "time is in ticks, not seconds\n");
|
||||
} /* if */
|
||||
} /* if */
|
||||
} else {
|
||||
fprintf(stderr, "%s: don't know how to deal with file format %d\n",
|
||||
whoami, file_format);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (hz == HZ_WRONG)
|
||||
{
|
||||
/*
|
||||
* How many ticks per second? If we can't tell, report
|
||||
* time in ticks.
|
||||
*/
|
||||
hz = hertz ();
|
||||
if (hz == HZ_WRONG)
|
||||
{
|
||||
hz = 1;
|
||||
fprintf (stderr, "time is in ticks, not seconds\n");
|
||||
} /* if */
|
||||
} /* if */
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s: don't know how to deal with file format %d\n",
|
||||
whoami, file_format);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
if (output_style & STYLE_GMON_INFO) {
|
||||
printf("File `%s' (version %d) contains:\n",
|
||||
filename, gmon_file_version);
|
||||
printf("\t%d histogram record%s\n",
|
||||
nhist, nhist == 1 ? "" : "s");
|
||||
printf("\t%d call-graph record%s\n",
|
||||
narcs, narcs == 1 ? "" : "s");
|
||||
printf("\t%d basic-block count record%s\n",
|
||||
nbbs, nbbs == 1 ? "" : "s");
|
||||
first_output = FALSE;
|
||||
} /* if */
|
||||
} /* gmon_out_read */
|
||||
if (output_style & STYLE_GMON_INFO)
|
||||
{
|
||||
printf ("File `%s' (version %d) contains:\n",
|
||||
filename, gmon_file_version);
|
||||
printf ("\t%d histogram record%s\n",
|
||||
nhist, nhist == 1 ? "" : "s");
|
||||
printf ("\t%d call-graph record%s\n",
|
||||
narcs, narcs == 1 ? "" : "s");
|
||||
printf ("\t%d basic-block count record%s\n",
|
||||
nbbs, nbbs == 1 ? "" : "s");
|
||||
first_output = FALSE;
|
||||
} /* if */
|
||||
} /* gmon_out_read */
|
||||
|
||||
|
||||
void
|
||||
DEFUN(gmon_out_write, (filename), const char *filename)
|
||||
DEFUN (gmon_out_write, (filename), const char *filename)
|
||||
{
|
||||
FILE *ofp;
|
||||
struct gmon_hdr ghdr;
|
||||
FILE *ofp;
|
||||
struct gmon_hdr ghdr;
|
||||
|
||||
ofp = fopen(filename, FOPEN_WB);
|
||||
if (!ofp) {
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
ofp = fopen (filename, FOPEN_WB);
|
||||
if (!ofp)
|
||||
{
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
if (file_format == FF_AUTO || file_format == FF_MAGIC) {
|
||||
/* write gmon header: */
|
||||
if (file_format == FF_AUTO || file_format == FF_MAGIC)
|
||||
{
|
||||
/* 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);
|
||||
} /* if */
|
||||
|
||||
/* write execution time histogram if we have one: */
|
||||
if (gmon_input & INPUT_HISTOGRAM) {
|
||||
hist_write_hist(ofp, filename);
|
||||
} /* if */
|
||||
|
||||
/* write call graph arcs if we have any: */
|
||||
if (gmon_input & INPUT_CALL_GRAPH) {
|
||||
cg_write_arcs(ofp, filename);
|
||||
} /* if */
|
||||
|
||||
/* write basic-block info if we have it: */
|
||||
if (gmon_input & INPUT_BB_COUNTS) {
|
||||
bb_write_blocks(ofp, filename);
|
||||
} /* if */
|
||||
} else if (file_format == FF_BSD) {
|
||||
struct raw_arc raw_arc;
|
||||
UNIT raw_bin_count;
|
||||
bfd_vma lpc, hpc;
|
||||
int i, ncnt;
|
||||
Arc *arc;
|
||||
Sym *sym;
|
||||
|
||||
put_vma(core_bfd, s_lowpc, (bfd_byte*) &lpc);
|
||||
put_vma(core_bfd, s_highpc, (bfd_byte*) &hpc);
|
||||
bfd_put_32(core_bfd,
|
||||
hist_num_bins * sizeof(UNIT) + sizeof(struct raw_phdr),
|
||||
(bfd_byte*) &ncnt);
|
||||
|
||||
/* write header: */
|
||||
if (fwrite(&lpc, sizeof(lpc), 1, ofp) != 1
|
||||
|| fwrite(&hpc, sizeof(hpc), 1, ofp) != 1
|
||||
|| fwrite(&ncnt, sizeof(ncnt), 1, ofp) != 1)
|
||||
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);
|
||||
} /* if */
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* dump the samples: */
|
||||
/* write execution time histogram if we have one: */
|
||||
if (gmon_input & INPUT_HISTOGRAM)
|
||||
{
|
||||
hist_write_hist (ofp, filename);
|
||||
} /* if */
|
||||
|
||||
for (i = 0; i < hist_num_bins; ++i) {
|
||||
bfd_put_16(core_bfd, hist_sample[i], (bfd_byte*)&raw_bin_count[0]);
|
||||
if (fwrite(&raw_bin_count[0], sizeof(raw_bin_count), 1, ofp) != 1)
|
||||
/* write call graph arcs if we have any: */
|
||||
if (gmon_input & INPUT_CALL_GRAPH)
|
||||
{
|
||||
cg_write_arcs (ofp, filename);
|
||||
} /* if */
|
||||
|
||||
/* write basic-block info if we have it: */
|
||||
if (gmon_input & INPUT_BB_COUNTS)
|
||||
{
|
||||
bb_write_blocks (ofp, filename);
|
||||
} /* if */
|
||||
}
|
||||
else if (file_format == FF_BSD)
|
||||
{
|
||||
struct raw_arc raw_arc;
|
||||
UNIT raw_bin_count;
|
||||
bfd_vma lpc, hpc;
|
||||
int i, ncnt;
|
||||
Arc *arc;
|
||||
Sym *sym;
|
||||
|
||||
put_vma (core_bfd, s_lowpc, (bfd_byte *) & lpc);
|
||||
put_vma (core_bfd, s_highpc, (bfd_byte *) & hpc);
|
||||
bfd_put_32 (core_bfd,
|
||||
hist_num_bins * sizeof (UNIT) + sizeof (struct raw_phdr),
|
||||
(bfd_byte *) & ncnt);
|
||||
|
||||
/* write header: */
|
||||
if (fwrite (&lpc, sizeof (lpc), 1, ofp) != 1
|
||||
|| fwrite (&hpc, sizeof (hpc), 1, ofp) != 1
|
||||
|| fwrite (&ncnt, sizeof (ncnt), 1, ofp) != 1)
|
||||
{
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* 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]);
|
||||
if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1)
|
||||
{
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
} /* for */
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
/* 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) {
|
||||
put_vma(core_bfd, arc->parent->addr,
|
||||
(bfd_byte*) raw_arc.from_pc);
|
||||
put_vma(core_bfd, arc->child->addr,
|
||||
(bfd_byte*) raw_arc.self_pc);
|
||||
bfd_put_32(core_bfd, arc->count, (bfd_byte*) raw_arc.count);
|
||||
if (fwrite(&raw_arc, sizeof(raw_arc), 1, ofp) != 1) {
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
DBG(SAMPLEDEBUG,
|
||||
printf("[dumpsum] frompc 0x%lx selfpc 0x%lx count %d\n",
|
||||
for (sym = symtab.base; sym < symtab.limit; ++sym)
|
||||
{
|
||||
for (arc = sym->cg.children; arc; arc = arc->next_child)
|
||||
{
|
||||
put_vma (core_bfd, arc->parent->addr,
|
||||
(bfd_byte *) raw_arc.from_pc);
|
||||
put_vma (core_bfd, arc->child->addr,
|
||||
(bfd_byte *) raw_arc.self_pc);
|
||||
bfd_put_32 (core_bfd, arc->count, (bfd_byte *) raw_arc.count);
|
||||
if (fwrite (&raw_arc, sizeof (raw_arc), 1, ofp) != 1)
|
||||
{
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %d\n",
|
||||
arc->parent->addr, arc->child->addr, arc->count));
|
||||
} /* for */
|
||||
} /* for */
|
||||
fclose(ofp);
|
||||
} else {
|
||||
fprintf(stderr, "%s: don't know how to deal with file format %d\n",
|
||||
whoami, file_format);
|
||||
done(1);
|
||||
} /* if */
|
||||
} /* gmon_out_write */
|
||||
} /* for */
|
||||
} /* for */
|
||||
fclose (ofp);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s: don't know how to deal with file format %d\n",
|
||||
whoami, file_format);
|
||||
done (1);
|
||||
} /* if */
|
||||
} /* gmon_out_write */
|
||||
|
||||
/*** gmon_out.c ***/
|
||||
/*** gmon_out.c ***/
|
||||
|
@ -8,13 +8,13 @@
|
||||
#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 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 void gmon_out_read PARAMS ((const char *filename));
|
||||
extern void gmon_out_write PARAMS ((const char *filename));
|
||||
|
||||
#endif /* gmon_io_h */
|
||||
|
@ -17,30 +17,35 @@
|
||||
/*
|
||||
* Raw header as it appears on file (without padding):
|
||||
*/
|
||||
struct gmon_hdr {
|
||||
char cookie[4];
|
||||
char version[4];
|
||||
char spare[3*4];
|
||||
};
|
||||
struct gmon_hdr
|
||||
{
|
||||
char cookie[4];
|
||||
char version[4];
|
||||
char spare[3 * 4];
|
||||
};
|
||||
|
||||
/* types of records in this file: */
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
GMON_TAG_TIME_HIST, GMON_TAG_CG_ARC, GMON_TAG_BB_COUNT
|
||||
} GMON_Record_Tag;
|
||||
}
|
||||
GMON_Record_Tag;
|
||||
|
||||
struct gmon_hist_hdr {
|
||||
char low_pc[sizeof(bfd_vma)]; /* base pc address of sample buffer */
|
||||
char high_pc[sizeof(bfd_vma)]; /* 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_hist_hdr
|
||||
{
|
||||
char low_pc[sizeof (bfd_vma)]; /* base pc address of sample buffer */
|
||||
char high_pc[sizeof (bfd_vma)]; /* 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(bfd_vma)]; /* address within caller's body */
|
||||
char self_pc[sizeof(bfd_vma)]; /* address within callee's body */
|
||||
char count[4]; /* number of arc traversals */
|
||||
};
|
||||
struct gmon_cg_arc_record
|
||||
{
|
||||
char from_pc[sizeof (bfd_vma)]; /* address within caller's body */
|
||||
char self_pc[sizeof (bfd_vma)]; /* address within callee's body */
|
||||
char count[4]; /* number of arc traversals */
|
||||
};
|
||||
|
||||
#endif /* gmon_out_h */
|
||||
|
790
gprof/gprof.c
790
gprof/gprof.c
@ -58,76 +58,77 @@ char copyright[] =
|
||||
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
|
||||
All rights reserved.\n";
|
||||
|
||||
static char *gmon_name = GMONNAME; /* profile filename */
|
||||
static char *gmon_name = GMONNAME; /* profile filename */
|
||||
|
||||
bfd *abfd;
|
||||
bfd *abfd;
|
||||
|
||||
/*
|
||||
* Functions that get excluded by default:
|
||||
*/
|
||||
static char *default_excluded_list[] = {
|
||||
"_gprof_mcount", "mcount", "_mcount", "__mcleanup",
|
||||
"<locore>", "<hicore>",
|
||||
0
|
||||
static char *default_excluded_list[] =
|
||||
{
|
||||
"_gprof_mcount", "mcount", "_mcount", "__mcleanup",
|
||||
"<locore>", "<hicore>",
|
||||
0
|
||||
};
|
||||
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"line", no_argument, 0, 'l'},
|
||||
{"no-static", no_argument, 0, 'a'},
|
||||
{"line", no_argument, 0, 'l'},
|
||||
{"no-static", no_argument, 0, 'a'},
|
||||
|
||||
/* output styles: */
|
||||
|
||||
{"annotated-source", optional_argument, 0, 'A'},
|
||||
{"no-annotated-source", optional_argument, 0, 'J'},
|
||||
{"flat-profile", optional_argument, 0, 'p'},
|
||||
{"no-flat-profile", optional_argument, 0, 'P'},
|
||||
{"graph", optional_argument, 0, 'q'},
|
||||
{"no-graph", optional_argument, 0, 'Q'},
|
||||
{"exec-counts", optional_argument, 0, 'C'},
|
||||
{"no-exec-counts", optional_argument, 0, 'Z'},
|
||||
{"file-info", no_argument, 0, 'i'},
|
||||
{"sum", no_argument, 0, 's'},
|
||||
{"annotated-source", optional_argument, 0, 'A'},
|
||||
{"no-annotated-source", optional_argument, 0, 'J'},
|
||||
{"flat-profile", optional_argument, 0, 'p'},
|
||||
{"no-flat-profile", optional_argument, 0, 'P'},
|
||||
{"graph", optional_argument, 0, 'q'},
|
||||
{"no-graph", optional_argument, 0, 'Q'},
|
||||
{"exec-counts", optional_argument, 0, 'C'},
|
||||
{"no-exec-counts", optional_argument, 0, 'Z'},
|
||||
{"file-info", no_argument, 0, 'i'},
|
||||
{"sum", no_argument, 0, 's'},
|
||||
|
||||
/* various options to affect output: */
|
||||
|
||||
{"all-lines", no_argument, 0, 'x'},
|
||||
{"directory-path", required_argument, 0, 'I'},
|
||||
{"display-unused-functions", no_argument, 0, 'z'},
|
||||
{"min-count", required_argument, 0, 'm'},
|
||||
{"print-path", no_argument, 0, 'L'},
|
||||
{"separate-files", no_argument, 0, 'y'},
|
||||
{"static-call-graph", no_argument, 0, 'c'},
|
||||
{"table-length", required_argument, 0, 't'},
|
||||
{"time", required_argument, 0, 'n'},
|
||||
{"no-time", required_argument, 0, 'N'},
|
||||
{"width", required_argument, 0, 'w'},
|
||||
{"all-lines", no_argument, 0, 'x'},
|
||||
{"directory-path", required_argument, 0, 'I'},
|
||||
{"display-unused-functions", no_argument, 0, 'z'},
|
||||
{"min-count", required_argument, 0, 'm'},
|
||||
{"print-path", no_argument, 0, 'L'},
|
||||
{"separate-files", no_argument, 0, 'y'},
|
||||
{"static-call-graph", no_argument, 0, 'c'},
|
||||
{"table-length", required_argument, 0, 't'},
|
||||
{"time", required_argument, 0, 'n'},
|
||||
{"no-time", required_argument, 0, 'N'},
|
||||
{"width", required_argument, 0, 'w'},
|
||||
/*
|
||||
* These are for backwards-compatibility only. Their functionality
|
||||
* is provided by the output style options already:
|
||||
*/
|
||||
{"", required_argument, 0, 'e'},
|
||||
{"", required_argument, 0, 'E'},
|
||||
{"", required_argument, 0, 'f'},
|
||||
{"", required_argument, 0, 'F'},
|
||||
{"", required_argument, 0, 'k'},
|
||||
{"", required_argument, 0, 'e'},
|
||||
{"", required_argument, 0, 'E'},
|
||||
{"", required_argument, 0, 'f'},
|
||||
{"", required_argument, 0, 'F'},
|
||||
{"", required_argument, 0, 'k'},
|
||||
|
||||
/* miscellaneous: */
|
||||
|
||||
{"brief", no_argument, 0, 'b'},
|
||||
{"debug", optional_argument, 0, 'd'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"file-format", required_argument, 0, 'O'},
|
||||
{"traditional", no_argument, 0, 'T'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{0, no_argument, 0, 0}
|
||||
{"brief", no_argument, 0, 'b'},
|
||||
{"debug", optional_argument, 0, 'd'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"file-format", required_argument, 0, 'O'},
|
||||
{"traditional", no_argument, 0, 'T'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{0, no_argument, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
DEFUN(usage, (stream, status), FILE *stream AND int status)
|
||||
DEFUN (usage, (stream, status), FILE * stream AND int status)
|
||||
{
|
||||
fprintf(stream, "\
|
||||
fprintf (stream, "\
|
||||
Usage: %s [-[abchilLsTvwxyz]] [-[ACeEfFJnNOpPqQZ][name]] [-I dirs]\n\
|
||||
[-d[num]] [-k from/to] [-m min-count] [-t table-length]\n\
|
||||
[--[no-]annotated-source[=name]] [--[no-]exec-counts[=name]]\n\
|
||||
@ -139,337 +140,448 @@ Usage: %s [-[abchilLsTvwxyz]] [-[ACeEfFJnNOpPqQZ][name]] [-I dirs]\n\
|
||||
[--static-call-graph] [--sum] [--table-length=len] [--traditional]\n\
|
||||
[--version] [--width=n]\n\
|
||||
[image-file] [profile-file...]\n",
|
||||
whoami);
|
||||
done(status);
|
||||
} /* usage */
|
||||
whoami);
|
||||
done (status);
|
||||
} /* usage */
|
||||
|
||||
|
||||
int
|
||||
DEFUN(main, (argc, argv), int argc AND char **argv)
|
||||
DEFUN (main, (argc, argv), int argc AND char **argv)
|
||||
{
|
||||
char **sp, *str;
|
||||
Sym **cg = 0;
|
||||
int ch, user_specified = 0;
|
||||
char **sp, *str;
|
||||
Sym **cg = 0;
|
||||
int ch, user_specified = 0;
|
||||
|
||||
whoami = argv[0];
|
||||
xmalloc_set_program_name(whoami);
|
||||
whoami = argv[0];
|
||||
xmalloc_set_program_name (whoami);
|
||||
|
||||
while ((ch = getopt_long(argc, argv,
|
||||
"aA::bBcCd::e:E:f:F:hiI:J::k:lLm:n::N::O:p::P::q::Q::st:Tvw:xyzZ::",
|
||||
long_options, 0))
|
||||
!= EOF)
|
||||
while ((ch = getopt_long (argc, argv,
|
||||
"aA::bBcCd::e:E:f:F:hiI:J::k:lLm:n::N::O:p::P::q::Q::st:Tvw:xyzZ::",
|
||||
long_options, 0))
|
||||
!= EOF)
|
||||
{
|
||||
switch (ch) {
|
||||
case 'a': ignore_static_funcs = TRUE; break;
|
||||
case 'A':
|
||||
if (optarg) {
|
||||
sym_id_add(optarg, INCL_ANNO);
|
||||
} /* if */
|
||||
output_style |= STYLE_ANNOTATED_SOURCE;
|
||||
user_specified |= STYLE_ANNOTATED_SOURCE;
|
||||
break;
|
||||
case 'b': print_descriptions = FALSE; break;
|
||||
case 'B':
|
||||
output_style |= STYLE_CALL_GRAPH;
|
||||
user_specified |= STYLE_CALL_GRAPH;
|
||||
break;
|
||||
case 'c': ignore_direct_calls = TRUE; break;
|
||||
case 'C':
|
||||
if (optarg) {
|
||||
sym_id_add(optarg, INCL_EXEC);
|
||||
} /* if */
|
||||
output_style |= STYLE_EXEC_COUNTS;
|
||||
user_specified |= STYLE_EXEC_COUNTS;
|
||||
break;
|
||||
case 'd':
|
||||
if (optarg) {
|
||||
debug_level |= atoi(optarg);
|
||||
debug_level |= ANYDEBUG;
|
||||
} else {
|
||||
debug_level = ~0;
|
||||
} /* if */
|
||||
DBG(ANYDEBUG, printf("[main] debug-level=0x%x\n", debug_level));
|
||||
switch (ch)
|
||||
{
|
||||
case 'a':
|
||||
ignore_static_funcs = TRUE;
|
||||
break;
|
||||
case 'A':
|
||||
if (optarg)
|
||||
{
|
||||
sym_id_add (optarg, INCL_ANNO);
|
||||
} /* if */
|
||||
output_style |= STYLE_ANNOTATED_SOURCE;
|
||||
user_specified |= STYLE_ANNOTATED_SOURCE;
|
||||
break;
|
||||
case 'b':
|
||||
print_descriptions = FALSE;
|
||||
break;
|
||||
case 'B':
|
||||
output_style |= STYLE_CALL_GRAPH;
|
||||
user_specified |= STYLE_CALL_GRAPH;
|
||||
break;
|
||||
case 'c':
|
||||
ignore_direct_calls = TRUE;
|
||||
break;
|
||||
case 'C':
|
||||
if (optarg)
|
||||
{
|
||||
sym_id_add (optarg, INCL_EXEC);
|
||||
} /* if */
|
||||
output_style |= STYLE_EXEC_COUNTS;
|
||||
user_specified |= STYLE_EXEC_COUNTS;
|
||||
break;
|
||||
case 'd':
|
||||
if (optarg)
|
||||
{
|
||||
debug_level |= atoi (optarg);
|
||||
debug_level |= ANYDEBUG;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_level = ~0;
|
||||
} /* if */
|
||||
DBG (ANYDEBUG, printf ("[main] debug-level=0x%x\n", debug_level));
|
||||
#ifndef DEBUG
|
||||
printf("%s: debugging not supported; -d ignored\n", whoami);
|
||||
#endif DEBUG
|
||||
break;
|
||||
case 'E': sym_id_add(optarg, EXCL_TIME);
|
||||
case 'e': sym_id_add(optarg, EXCL_GRAPH); break;
|
||||
case 'F': sym_id_add(optarg, INCL_TIME);
|
||||
case 'f': sym_id_add(optarg, INCL_GRAPH); break;
|
||||
case 'g': sym_id_add(optarg, EXCL_FLAT); break;
|
||||
case 'G': sym_id_add(optarg, INCL_FLAT); break;
|
||||
case 'h': usage(stdout, 0);
|
||||
case 'i':
|
||||
output_style |= STYLE_GMON_INFO;
|
||||
user_specified |= STYLE_GMON_INFO;
|
||||
break;
|
||||
case 'I': search_list_append(&src_search_list, optarg); break;
|
||||
case 'J':
|
||||
if (optarg) {
|
||||
sym_id_add(optarg, EXCL_ANNO);
|
||||
output_style |= STYLE_ANNOTATED_SOURCE;
|
||||
} else {
|
||||
output_style &= ~STYLE_ANNOTATED_SOURCE;
|
||||
} /* if */
|
||||
user_specified |= STYLE_ANNOTATED_SOURCE;
|
||||
break;
|
||||
case 'k': sym_id_add(optarg, EXCL_ARCS); break;
|
||||
case 'l': line_granularity = TRUE; break;
|
||||
case 'L': print_path = TRUE; break;
|
||||
case 'm': bb_min_calls = atoi(optarg); break;
|
||||
case 'n': sym_id_add(optarg, INCL_TIME); break;
|
||||
case 'N': sym_id_add(optarg, EXCL_TIME); break;
|
||||
case 'O':
|
||||
switch (optarg[0]) {
|
||||
case 'a': file_format = FF_AUTO; break;
|
||||
case 'm': file_format = FF_MAGIC; break;
|
||||
case 'b': file_format = FF_BSD; break;
|
||||
case 'p': file_format = FF_PROF; break;
|
||||
default:
|
||||
fprintf(stderr, "%s: unknown file format %s\n",
|
||||
optarg, whoami);
|
||||
done(1);
|
||||
} /* switch */
|
||||
break;
|
||||
case 'p':
|
||||
if (optarg) {
|
||||
sym_id_add(optarg, INCL_FLAT);
|
||||
} /* if */
|
||||
output_style |= STYLE_FLAT_PROFILE;
|
||||
user_specified |= STYLE_FLAT_PROFILE;
|
||||
break;
|
||||
case 'P':
|
||||
if (optarg) {
|
||||
sym_id_add(optarg, EXCL_FLAT);
|
||||
output_style |= STYLE_FLAT_PROFILE;
|
||||
} else {
|
||||
output_style &= ~STYLE_FLAT_PROFILE;
|
||||
} /* if */
|
||||
user_specified |= STYLE_FLAT_PROFILE;
|
||||
break;
|
||||
case 'q':
|
||||
if (optarg) {
|
||||
if (strchr(optarg, '/')) {
|
||||
sym_id_add(optarg, INCL_ARCS);
|
||||
} else {
|
||||
sym_id_add(optarg, INCL_GRAPH);
|
||||
} /* if */
|
||||
} /* if */
|
||||
output_style |= STYLE_CALL_GRAPH;
|
||||
user_specified |= STYLE_CALL_GRAPH;
|
||||
break;
|
||||
case 'Q':
|
||||
if (optarg) {
|
||||
if (strchr(optarg, '/')) {
|
||||
sym_id_add(optarg, EXCL_ARCS);
|
||||
} else {
|
||||
sym_id_add(optarg, EXCL_GRAPH);
|
||||
} /* if */
|
||||
output_style |= STYLE_CALL_GRAPH;
|
||||
} else {
|
||||
output_style &= ~STYLE_CALL_GRAPH;
|
||||
} /* if */
|
||||
user_specified |= STYLE_CALL_GRAPH;
|
||||
break;
|
||||
case 's':
|
||||
output_style |= STYLE_SUMMARY_FILE;
|
||||
user_specified |= STYLE_SUMMARY_FILE;
|
||||
break;
|
||||
case 't':
|
||||
bb_table_length = atoi(optarg);
|
||||
if (bb_table_length < 0) {
|
||||
bb_table_length = 0;
|
||||
} /* if */
|
||||
break;
|
||||
case 'T': bsd_style_output = TRUE; break;
|
||||
case 'v': printf ("%s version %s\n", whoami, VERSION); done(0);
|
||||
case 'w':
|
||||
output_width = atoi(optarg);
|
||||
if (output_width < 1) {
|
||||
output_width = 1;
|
||||
} /* if */
|
||||
break;
|
||||
case 'x': bb_annotate_all_lines = TRUE; break;
|
||||
case 'y': create_annotation_files = TRUE; break;
|
||||
case 'z': ignore_zeros = FALSE; break;
|
||||
case 'Z':
|
||||
if (optarg) {
|
||||
sym_id_add(optarg, EXCL_EXEC);
|
||||
output_style |= STYLE_EXEC_COUNTS;
|
||||
} else {
|
||||
output_style &= ~STYLE_EXEC_COUNTS;
|
||||
} /* if */
|
||||
user_specified |= STYLE_ANNOTATED_SOURCE;
|
||||
break;
|
||||
default: usage(stderr, 1);
|
||||
} /* switch */
|
||||
} /* while */
|
||||
printf ("%s: debugging not supported; -d ignored\n", whoami);
|
||||
#endif /* DEBUG */
|
||||
break;
|
||||
case 'E':
|
||||
sym_id_add (optarg, EXCL_TIME);
|
||||
case 'e':
|
||||
sym_id_add (optarg, EXCL_GRAPH);
|
||||
break;
|
||||
case 'F':
|
||||
sym_id_add (optarg, INCL_TIME);
|
||||
case 'f':
|
||||
sym_id_add (optarg, INCL_GRAPH);
|
||||
break;
|
||||
case 'g':
|
||||
sym_id_add (optarg, EXCL_FLAT);
|
||||
break;
|
||||
case 'G':
|
||||
sym_id_add (optarg, INCL_FLAT);
|
||||
break;
|
||||
case 'h':
|
||||
usage (stdout, 0);
|
||||
case 'i':
|
||||
output_style |= STYLE_GMON_INFO;
|
||||
user_specified |= STYLE_GMON_INFO;
|
||||
break;
|
||||
case 'I':
|
||||
search_list_append (&src_search_list, optarg);
|
||||
break;
|
||||
case 'J':
|
||||
if (optarg)
|
||||
{
|
||||
sym_id_add (optarg, EXCL_ANNO);
|
||||
output_style |= STYLE_ANNOTATED_SOURCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_style &= ~STYLE_ANNOTATED_SOURCE;
|
||||
} /* if */
|
||||
user_specified |= STYLE_ANNOTATED_SOURCE;
|
||||
break;
|
||||
case 'k':
|
||||
sym_id_add (optarg, EXCL_ARCS);
|
||||
break;
|
||||
case 'l':
|
||||
line_granularity = TRUE;
|
||||
break;
|
||||
case 'L':
|
||||
print_path = TRUE;
|
||||
break;
|
||||
case 'm':
|
||||
bb_min_calls = atoi (optarg);
|
||||
break;
|
||||
case 'n':
|
||||
sym_id_add (optarg, INCL_TIME);
|
||||
break;
|
||||
case 'N':
|
||||
sym_id_add (optarg, EXCL_TIME);
|
||||
break;
|
||||
case 'O':
|
||||
switch (optarg[0])
|
||||
{
|
||||
case 'a':
|
||||
file_format = FF_AUTO;
|
||||
break;
|
||||
case 'm':
|
||||
file_format = FF_MAGIC;
|
||||
break;
|
||||
case 'b':
|
||||
file_format = FF_BSD;
|
||||
break;
|
||||
case 'p':
|
||||
file_format = FF_PROF;
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "%s: unknown file format %s\n",
|
||||
optarg, whoami);
|
||||
done (1);
|
||||
} /* switch */
|
||||
break;
|
||||
case 'p':
|
||||
if (optarg)
|
||||
{
|
||||
sym_id_add (optarg, INCL_FLAT);
|
||||
} /* if */
|
||||
output_style |= STYLE_FLAT_PROFILE;
|
||||
user_specified |= STYLE_FLAT_PROFILE;
|
||||
break;
|
||||
case 'P':
|
||||
if (optarg)
|
||||
{
|
||||
sym_id_add (optarg, EXCL_FLAT);
|
||||
output_style |= STYLE_FLAT_PROFILE;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_style &= ~STYLE_FLAT_PROFILE;
|
||||
} /* if */
|
||||
user_specified |= STYLE_FLAT_PROFILE;
|
||||
break;
|
||||
case 'q':
|
||||
if (optarg)
|
||||
{
|
||||
if (strchr (optarg, '/'))
|
||||
{
|
||||
sym_id_add (optarg, INCL_ARCS);
|
||||
}
|
||||
else
|
||||
{
|
||||
sym_id_add (optarg, INCL_GRAPH);
|
||||
} /* if */
|
||||
} /* if */
|
||||
output_style |= STYLE_CALL_GRAPH;
|
||||
user_specified |= STYLE_CALL_GRAPH;
|
||||
break;
|
||||
case 'Q':
|
||||
if (optarg)
|
||||
{
|
||||
if (strchr (optarg, '/'))
|
||||
{
|
||||
sym_id_add (optarg, EXCL_ARCS);
|
||||
}
|
||||
else
|
||||
{
|
||||
sym_id_add (optarg, EXCL_GRAPH);
|
||||
} /* if */
|
||||
output_style |= STYLE_CALL_GRAPH;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_style &= ~STYLE_CALL_GRAPH;
|
||||
} /* if */
|
||||
user_specified |= STYLE_CALL_GRAPH;
|
||||
break;
|
||||
case 's':
|
||||
output_style |= STYLE_SUMMARY_FILE;
|
||||
user_specified |= STYLE_SUMMARY_FILE;
|
||||
break;
|
||||
case 't':
|
||||
bb_table_length = atoi (optarg);
|
||||
if (bb_table_length < 0)
|
||||
{
|
||||
bb_table_length = 0;
|
||||
} /* if */
|
||||
break;
|
||||
case 'T':
|
||||
bsd_style_output = TRUE;
|
||||
break;
|
||||
case 'v':
|
||||
printf ("%s version %s\n", whoami, VERSION);
|
||||
done (0);
|
||||
case 'w':
|
||||
output_width = atoi (optarg);
|
||||
if (output_width < 1)
|
||||
{
|
||||
output_width = 1;
|
||||
} /* if */
|
||||
break;
|
||||
case 'x':
|
||||
bb_annotate_all_lines = TRUE;
|
||||
break;
|
||||
case 'y':
|
||||
create_annotation_files = TRUE;
|
||||
break;
|
||||
case 'z':
|
||||
ignore_zeros = FALSE;
|
||||
break;
|
||||
case 'Z':
|
||||
if (optarg)
|
||||
{
|
||||
sym_id_add (optarg, EXCL_EXEC);
|
||||
output_style |= STYLE_EXEC_COUNTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_style &= ~STYLE_EXEC_COUNTS;
|
||||
} /* if */
|
||||
user_specified |= STYLE_ANNOTATED_SOURCE;
|
||||
break;
|
||||
default:
|
||||
usage (stderr, 1);
|
||||
} /* switch */
|
||||
} /* while */
|
||||
|
||||
/* append value of GPROF_PATH to source search list if set: */
|
||||
str = getenv("GPROF_PATH");
|
||||
if (str) {
|
||||
search_list_append(&src_search_list, str);
|
||||
} /* if */
|
||||
/* append value of GPROF_PATH to source search list if set: */
|
||||
str = getenv ("GPROF_PATH");
|
||||
if (str)
|
||||
{
|
||||
search_list_append (&src_search_list, str);
|
||||
} /* if */
|
||||
|
||||
if (optind < argc) {
|
||||
a_out_name = argv[optind++];
|
||||
} /* if */
|
||||
if (optind < argc) {
|
||||
gmon_name = argv[optind++];
|
||||
} /* if */
|
||||
if (optind < argc)
|
||||
{
|
||||
a_out_name = argv[optind++];
|
||||
} /* if */
|
||||
if (optind < argc)
|
||||
{
|
||||
gmon_name = argv[optind++];
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* Turn off default functions:
|
||||
*/
|
||||
for (sp = &default_excluded_list[0]; *sp; sp++) {
|
||||
sym_id_add(*sp, EXCL_TIME);
|
||||
sym_id_add(*sp, EXCL_GRAPH);
|
||||
/*
|
||||
* Turn off default functions:
|
||||
*/
|
||||
for (sp = &default_excluded_list[0]; *sp; sp++)
|
||||
{
|
||||
sym_id_add (*sp, EXCL_TIME);
|
||||
sym_id_add (*sp, EXCL_GRAPH);
|
||||
#ifdef __osf__
|
||||
sym_id_add(*sp, EXCL_FLAT);
|
||||
sym_id_add (*sp, EXCL_FLAT);
|
||||
#endif
|
||||
} /* for */
|
||||
} /* for */
|
||||
|
||||
/*
|
||||
* For line-by-line profiling, also want to keep those
|
||||
* functions off the flat profile:
|
||||
*/
|
||||
if (line_granularity) {
|
||||
for (sp = &default_excluded_list[0]; *sp; sp++) {
|
||||
sym_id_add(*sp, EXCL_FLAT);
|
||||
} /* for */
|
||||
} /* if */
|
||||
/*
|
||||
* For line-by-line profiling, also want to keep those
|
||||
* functions off the flat profile:
|
||||
*/
|
||||
if (line_granularity)
|
||||
{
|
||||
for (sp = &default_excluded_list[0]; *sp; sp++)
|
||||
{
|
||||
sym_id_add (*sp, EXCL_FLAT);
|
||||
} /* for */
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* Read symbol table from core file:
|
||||
*/
|
||||
core_init(a_out_name);
|
||||
/*
|
||||
* Read symbol table from core file:
|
||||
*/
|
||||
core_init (a_out_name);
|
||||
|
||||
/*
|
||||
* If we should ignore direct function calls, we need to load
|
||||
* to core's text-space:
|
||||
*/
|
||||
if (ignore_direct_calls) {
|
||||
core_get_text_space(core_bfd);
|
||||
} /* if */
|
||||
/*
|
||||
* If we should ignore direct function calls, we need to load
|
||||
* to core's text-space:
|
||||
*/
|
||||
if (ignore_direct_calls)
|
||||
{
|
||||
core_get_text_space (core_bfd);
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* Create symbols from core image:
|
||||
*/
|
||||
if (line_granularity) {
|
||||
core_create_line_syms(core_bfd);
|
||||
} else {
|
||||
core_create_function_syms(core_bfd);
|
||||
} /* if */
|
||||
/*
|
||||
* Create symbols from core image:
|
||||
*/
|
||||
if (line_granularity)
|
||||
{
|
||||
core_create_line_syms (core_bfd);
|
||||
}
|
||||
else
|
||||
{
|
||||
core_create_function_syms (core_bfd);
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* Translate sym specs into syms:
|
||||
*/
|
||||
sym_id_parse();
|
||||
/*
|
||||
* Translate sym specs into syms:
|
||||
*/
|
||||
sym_id_parse ();
|
||||
|
||||
if (file_format == FF_PROF) {
|
||||
if (file_format == FF_PROF)
|
||||
{
|
||||
#ifdef PROF_SUPPORT_IMPLEMENTED
|
||||
/*
|
||||
* Get information about mon.out file(s):
|
||||
*/
|
||||
do {
|
||||
mon_out_read(gmon_name);
|
||||
if (optind < argc) {
|
||||
gmon_name = argv[optind];
|
||||
} /* if */
|
||||
} while (optind++ < argc);
|
||||
/*
|
||||
* Get information about mon.out file(s):
|
||||
*/
|
||||
do
|
||||
{
|
||||
mon_out_read (gmon_name);
|
||||
if (optind < argc)
|
||||
{
|
||||
gmon_name = argv[optind];
|
||||
} /* if */
|
||||
}
|
||||
while (optind++ < argc);
|
||||
#else
|
||||
fprintf(stderr,
|
||||
"%s: sorry, file format `prof' is not yet supported\n",
|
||||
whoami);
|
||||
done(1);
|
||||
fprintf (stderr,
|
||||
"%s: sorry, file format `prof' is not yet supported\n",
|
||||
whoami);
|
||||
done (1);
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* Get information about gmon.out file(s):
|
||||
*/
|
||||
do {
|
||||
gmon_out_read(gmon_name);
|
||||
if (optind < argc) {
|
||||
gmon_name = argv[optind];
|
||||
} /* if */
|
||||
} while (optind++ < argc);
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* If user did not specify output style, try to guess something
|
||||
* reasonable:
|
||||
*/
|
||||
if (output_style == 0) {
|
||||
if (gmon_input & (INPUT_HISTOGRAM | INPUT_CALL_GRAPH)) {
|
||||
output_style = STYLE_FLAT_PROFILE | STYLE_CALL_GRAPH;
|
||||
} else {
|
||||
output_style = STYLE_EXEC_COUNTS;
|
||||
} /* if */
|
||||
output_style &= ~user_specified;
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* Dump a gmon.sum file if requested (before any other processing!):
|
||||
*/
|
||||
if (output_style & STYLE_SUMMARY_FILE) {
|
||||
gmon_out_write(GMONSUM);
|
||||
} /* if */
|
||||
|
||||
if (gmon_input & INPUT_HISTOGRAM) {
|
||||
hist_assign_samples();
|
||||
} /* if */
|
||||
|
||||
if (gmon_input & INPUT_CALL_GRAPH) {
|
||||
cg = cg_assemble();
|
||||
} /* if */
|
||||
|
||||
/* do some simple sanity checks: */
|
||||
|
||||
if ((output_style & STYLE_FLAT_PROFILE)
|
||||
&& !(gmon_input & INPUT_HISTOGRAM))
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: gmon.out file is missing histogram\n", whoami);
|
||||
done(1);
|
||||
} /* if */
|
||||
/*
|
||||
* Get information about gmon.out file(s):
|
||||
*/
|
||||
do
|
||||
{
|
||||
gmon_out_read (gmon_name);
|
||||
if (optind < argc)
|
||||
{
|
||||
gmon_name = argv[optind];
|
||||
} /* if */
|
||||
}
|
||||
while (optind++ < argc);
|
||||
} /* if */
|
||||
|
||||
if ((output_style & STYLE_CALL_GRAPH) && !(gmon_input & INPUT_CALL_GRAPH))
|
||||
/*
|
||||
* If user did not specify output style, try to guess something
|
||||
* reasonable:
|
||||
*/
|
||||
if (output_style == 0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"%s: gmon.out file is missing call-graph data\n", whoami);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (gmon_input & (INPUT_HISTOGRAM | INPUT_CALL_GRAPH))
|
||||
{
|
||||
output_style = STYLE_FLAT_PROFILE | STYLE_CALL_GRAPH;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_style = STYLE_EXEC_COUNTS;
|
||||
} /* if */
|
||||
output_style &= ~user_specified;
|
||||
} /* if */
|
||||
|
||||
/* output whatever user whishes to see: */
|
||||
/*
|
||||
* Dump a gmon.sum file if requested (before any other processing!):
|
||||
*/
|
||||
if (output_style & STYLE_SUMMARY_FILE)
|
||||
{
|
||||
gmon_out_write (GMONSUM);
|
||||
} /* if */
|
||||
|
||||
if (cg && (output_style & STYLE_CALL_GRAPH) && bsd_style_output) {
|
||||
cg_print(cg); /* print the dynamic profile */
|
||||
} /* if */
|
||||
if (gmon_input & INPUT_HISTOGRAM)
|
||||
{
|
||||
hist_assign_samples ();
|
||||
} /* if */
|
||||
|
||||
if (output_style & STYLE_FLAT_PROFILE) {
|
||||
hist_print(); /* print the flat profile */
|
||||
} /* if */
|
||||
if (gmon_input & INPUT_CALL_GRAPH)
|
||||
{
|
||||
cg = cg_assemble ();
|
||||
} /* if */
|
||||
|
||||
if (cg && (output_style & STYLE_CALL_GRAPH)) {
|
||||
if (!bsd_style_output) {
|
||||
cg_print(cg); /* print the dynamic profile */
|
||||
} /* if */
|
||||
cg_print_index();
|
||||
} /* if */
|
||||
/* do some simple sanity checks: */
|
||||
|
||||
if (output_style & STYLE_EXEC_COUNTS) {
|
||||
print_exec_counts();
|
||||
} /* if */
|
||||
if ((output_style & STYLE_FLAT_PROFILE)
|
||||
&& !(gmon_input & INPUT_HISTOGRAM))
|
||||
{
|
||||
fprintf (stderr, "%s: gmon.out file is missing histogram\n", whoami);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
if (output_style & STYLE_ANNOTATED_SOURCE) {
|
||||
print_annotated_source();
|
||||
} /* if */
|
||||
return 0;
|
||||
if ((output_style & STYLE_CALL_GRAPH) && !(gmon_input & INPUT_CALL_GRAPH))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"%s: gmon.out file is missing call-graph data\n", whoami);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
/* output whatever user whishes to see: */
|
||||
|
||||
if (cg && (output_style & STYLE_CALL_GRAPH) && bsd_style_output)
|
||||
{
|
||||
cg_print (cg); /* print the dynamic profile */
|
||||
} /* if */
|
||||
|
||||
if (output_style & STYLE_FLAT_PROFILE)
|
||||
{
|
||||
hist_print (); /* print the flat profile */
|
||||
} /* if */
|
||||
|
||||
if (cg && (output_style & STYLE_CALL_GRAPH))
|
||||
{
|
||||
if (!bsd_style_output)
|
||||
{
|
||||
cg_print (cg); /* print the dynamic profile */
|
||||
} /* if */
|
||||
cg_print_index ();
|
||||
} /* if */
|
||||
|
||||
if (output_style & STYLE_EXEC_COUNTS)
|
||||
{
|
||||
print_exec_counts ();
|
||||
} /* if */
|
||||
|
||||
if (output_style & STYLE_ANNOTATED_SOURCE)
|
||||
{
|
||||
print_annotated_source ();
|
||||
} /* if */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
done (status)
|
||||
int status;
|
||||
{
|
||||
exit(status);
|
||||
exit (status);
|
||||
}
|
||||
|
100
gprof/gprof.h
100
gprof/gprof.h
@ -16,7 +16,7 @@
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* @(#)gprof.h 5.9 (Berkeley) 6/1/90
|
||||
* @(#)gprof.h 5.9 (Berkeley) 6/1/90
|
||||
*/
|
||||
#ifndef gprof_h
|
||||
#define gprof_h
|
||||
@ -25,41 +25,41 @@
|
||||
#include "sysdep.h"
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
# define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/* AIX defines hz as a macro. */
|
||||
#undef hz
|
||||
|
||||
#ifdef MACHINE_H
|
||||
# include MACHINE_H
|
||||
#include MACHINE_H
|
||||
#else
|
||||
# if vax
|
||||
# include "vax.h"
|
||||
# endif
|
||||
# if sun
|
||||
# include "sun.h"
|
||||
# endif
|
||||
# if tahoe
|
||||
# include "tahoe.h"
|
||||
# endif
|
||||
#if vax
|
||||
#include "vax.h"
|
||||
#endif
|
||||
#if sun
|
||||
#include "sun.h"
|
||||
#endif
|
||||
#if tahoe
|
||||
#include "tahoe.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef FOPEN_RB
|
||||
# define FOPEN_RB "r"
|
||||
#define FOPEN_RB "r"
|
||||
#endif
|
||||
#ifndef FOPEN_WB
|
||||
# define FOPEN_WB "w"
|
||||
#define FOPEN_WB "w"
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 1024
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
|
||||
#define A_OUTNAME "a.out" /* default core filename */
|
||||
#define A_OUTNAME "a.out" /* default core filename */
|
||||
#define GMONNAME "gmon.out" /* default profile filename */
|
||||
#define GMONSUM "gmon.sum" /* profile summary filename */
|
||||
|
||||
@ -80,56 +80,58 @@
|
||||
#define STYLE_ANNOTATED_SOURCE (1<<4)
|
||||
#define STYLE_GMON_INFO (1<<5)
|
||||
|
||||
#define ANYDEBUG (1<<0) /* 1 */
|
||||
#define DFNDEBUG (1<<1) /* 2 */
|
||||
#define CYCLEDEBUG (1<<2) /* 4 */
|
||||
#define ARCDEBUG (1<<3) /* 8 */
|
||||
#define TALLYDEBUG (1<<4) /* 16 */
|
||||
#define TIMEDEBUG (1<<5) /* 32 */
|
||||
#define SAMPLEDEBUG (1<<6) /* 64 */
|
||||
#define AOUTDEBUG (1<<7) /* 128 */
|
||||
#define CALLDEBUG (1<<8) /* 256 */
|
||||
#define LOOKUPDEBUG (1<<9) /* 512 */
|
||||
#define PROPDEBUG (1<<10) /* 1024 */
|
||||
#define BBDEBUG (1<<11) /* 2048 */
|
||||
#define IDDEBUG (1<<12) /* 4096 */
|
||||
#define SRCDEBUG (1<<13) /* 8192 */
|
||||
#define ANYDEBUG (1<<0) /* 1 */
|
||||
#define DFNDEBUG (1<<1) /* 2 */
|
||||
#define CYCLEDEBUG (1<<2) /* 4 */
|
||||
#define ARCDEBUG (1<<3) /* 8 */
|
||||
#define TALLYDEBUG (1<<4) /* 16 */
|
||||
#define TIMEDEBUG (1<<5) /* 32 */
|
||||
#define SAMPLEDEBUG (1<<6) /* 64 */
|
||||
#define AOUTDEBUG (1<<7) /* 128 */
|
||||
#define CALLDEBUG (1<<8) /* 256 */
|
||||
#define LOOKUPDEBUG (1<<9) /* 512 */
|
||||
#define PROPDEBUG (1<<10) /* 1024 */
|
||||
#define BBDEBUG (1<<11) /* 2048 */
|
||||
#define IDDEBUG (1<<12) /* 4096 */
|
||||
#define SRCDEBUG (1<<13) /* 8192 */
|
||||
|
||||
#ifdef DEBUG
|
||||
# define DBG(l,s) if (debug_level & (l)) {s;}
|
||||
#define DBG(l,s) if (debug_level & (l)) {s;}
|
||||
#else
|
||||
# define DBG(l,s)
|
||||
#define DBG(l,s)
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
FF_AUTO = 0, FF_MAGIC, FF_BSD, FF_PROF
|
||||
} File_Format;
|
||||
}
|
||||
File_Format;
|
||||
|
||||
typedef int bool;
|
||||
typedef unsigned char UNIT[2]; /* unit of profiling */
|
||||
typedef unsigned char UNIT[2]; /* unit of profiling */
|
||||
|
||||
extern const char *whoami; /* command-name, for error messages */
|
||||
extern const char *a_out_name; /* core filename */
|
||||
extern long hz; /* ticks per second */
|
||||
extern const char *whoami; /* command-name, for error messages */
|
||||
extern const char *a_out_name; /* core filename */
|
||||
extern long hz; /* ticks per second */
|
||||
|
||||
/*
|
||||
* Command-line options:
|
||||
*/
|
||||
extern int debug_level; /* debug level */
|
||||
extern int debug_level; /* debug level */
|
||||
extern int output_style;
|
||||
extern int output_width; /* controls column width in index */
|
||||
extern bool bsd_style_output; /* as opposed to FSF style output */
|
||||
extern int output_width; /* controls column width in index */
|
||||
extern bool bsd_style_output; /* as opposed to FSF style output */
|
||||
extern bool discard_underscores; /* discard leading underscores? */
|
||||
extern bool ignore_direct_calls; /* don't count direct calls */
|
||||
extern bool ignore_static_funcs; /* suppress static functions */
|
||||
extern bool ignore_zeros; /* ignore unused symbols/files */
|
||||
extern bool line_granularity; /* function or line granularity? */
|
||||
extern bool print_descriptions; /* output profile description */
|
||||
extern bool print_path; /* print path or just filename? */
|
||||
extern File_Format file_format; /* requested file format */
|
||||
extern bool ignore_zeros; /* ignore unused symbols/files */
|
||||
extern bool line_granularity; /* function or line granularity? */
|
||||
extern bool print_descriptions; /* output profile description */
|
||||
extern bool print_path; /* print path or just filename? */
|
||||
extern File_Format file_format; /* requested file format */
|
||||
|
||||
extern bool first_output; /* no output so far? */
|
||||
extern bool first_output; /* no output so far? */
|
||||
|
||||
extern void done PARAMS((int status));
|
||||
extern void done PARAMS ((int status));
|
||||
|
||||
#endif /* gprof_h */
|
||||
|
@ -21,26 +21,27 @@
|
||||
|
||||
|
||||
#ifdef __MSDOS__
|
||||
# define HERTZ 18
|
||||
#define HERTZ 18
|
||||
#endif
|
||||
|
||||
int
|
||||
hertz()
|
||||
hertz ()
|
||||
{
|
||||
#ifdef HERTZ
|
||||
return HERTZ;
|
||||
return HERTZ;
|
||||
#else
|
||||
struct itimerval tim;
|
||||
struct itimerval tim;
|
||||
|
||||
tim.it_interval.tv_sec = 0;
|
||||
tim.it_interval.tv_usec = 1;
|
||||
tim.it_value.tv_sec = 0;
|
||||
tim.it_value.tv_usec = 0;
|
||||
setitimer(ITIMER_REAL, &tim, 0);
|
||||
setitimer(ITIMER_REAL, 0, &tim);
|
||||
if (tim.it_interval.tv_usec < 2) {
|
||||
return HZ_WRONG;
|
||||
} /* if */
|
||||
return 1000000 / tim.it_interval.tv_usec;
|
||||
tim.it_interval.tv_sec = 0;
|
||||
tim.it_interval.tv_usec = 1;
|
||||
tim.it_value.tv_sec = 0;
|
||||
tim.it_value.tv_usec = 0;
|
||||
setitimer (ITIMER_REAL, &tim, 0);
|
||||
setitimer (ITIMER_REAL, 0, &tim);
|
||||
if (tim.it_interval.tv_usec < 2)
|
||||
{
|
||||
return HZ_WRONG;
|
||||
} /* if */
|
||||
return 1000000 / tim.it_interval.tv_usec;
|
||||
#endif
|
||||
} /* hertz */
|
||||
} /* hertz */
|
||||
|
@ -3,12 +3,12 @@
|
||||
|
||||
#include "gprof.h"
|
||||
|
||||
#define HZ_WRONG 0 /* impossible clock frequency */
|
||||
#define HZ_WRONG 0 /* impossible clock frequency */
|
||||
|
||||
/*
|
||||
* Discover the tick frequency of the machine if something goes wrong,
|
||||
* we return HZ_WRONG, an impossible sampling frequency.
|
||||
*/
|
||||
extern int hertz PARAMS((void));
|
||||
extern int hertz PARAMS ((void));
|
||||
|
||||
#endif /* hertz_h */
|
||||
|
781
gprof/hist.c
781
gprof/hist.c
@ -13,7 +13,7 @@
|
||||
#include "utils.h"
|
||||
|
||||
/* declarations of automatically generated functions to output blurbs: */
|
||||
extern void flat_blurb PARAMS((FILE *fp));
|
||||
extern void flat_blurb PARAMS ((FILE * fp));
|
||||
|
||||
bfd_vma s_lowpc; /* lowest address in .text */
|
||||
bfd_vma s_highpc = 0; /* highest address in .text */
|
||||
@ -21,8 +21,8 @@ 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[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() */
|
||||
@ -31,21 +31,57 @@ 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 {
|
||||
const struct
|
||||
{
|
||||
char prefix;
|
||||
double scale;
|
||||
} SItab[] = {
|
||||
{'T', 1e-12}, /* tera */
|
||||
{'G', 1e-09}, /* giga */
|
||||
{'M', 1e-06}, /* mega */
|
||||
{'K', 1e-03}, /* kilo */
|
||||
{' ', 1e-00},
|
||||
{'m', 1e+03}, /* milli */
|
||||
{'u', 1e+06}, /* micro */
|
||||
{'n', 1e+09}, /* nano */
|
||||
{'p', 1e+12}, /* pico */
|
||||
{'f', 1e+15}, /* femto */
|
||||
{'a', 1e+18}, /* ato */
|
||||
}
|
||||
SItab[] =
|
||||
{
|
||||
{
|
||||
'T', 1e-12
|
||||
}
|
||||
, /* tera */
|
||||
{
|
||||
'G', 1e-09
|
||||
}
|
||||
, /* giga */
|
||||
{
|
||||
'M', 1e-06
|
||||
}
|
||||
, /* mega */
|
||||
{
|
||||
'K', 1e-03
|
||||
}
|
||||
, /* kilo */
|
||||
{
|
||||
' ', 1e-00
|
||||
}
|
||||
,
|
||||
{
|
||||
'm', 1e+03
|
||||
}
|
||||
, /* milli */
|
||||
{
|
||||
'u', 1e+06
|
||||
}
|
||||
, /* micro */
|
||||
{
|
||||
'n', 1e+09
|
||||
}
|
||||
, /* nano */
|
||||
{
|
||||
'p', 1e+12
|
||||
}
|
||||
, /* pico */
|
||||
{
|
||||
'f', 1e+15
|
||||
}
|
||||
, /* femto */
|
||||
{
|
||||
'a', 1e+18
|
||||
}
|
||||
, /* ato */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -53,70 +89,75 @@ const struct {
|
||||
* is provided for formatting error messages only.
|
||||
*/
|
||||
void
|
||||
DEFUN(hist_read_rec, (ifp, filename), FILE *ifp AND const char *filename)
|
||||
DEFUN (hist_read_rec, (ifp, filename), FILE * ifp AND const char *filename)
|
||||
{
|
||||
struct gmon_hist_hdr hdr;
|
||||
bfd_vma n_lowpc, n_highpc;
|
||||
int i, ncnt, profrate;
|
||||
UNIT count;
|
||||
struct gmon_hist_hdr hdr;
|
||||
bfd_vma n_lowpc, n_highpc;
|
||||
int i, ncnt, profrate;
|
||||
UNIT count;
|
||||
|
||||
if (fread(&hdr, sizeof(hdr), 1, ifp) != 1) {
|
||||
fprintf(stderr, "%s: %s: unexpected end of file\n",
|
||||
whoami, filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
if (fread (&hdr, sizeof (hdr), 1, ifp) != 1)
|
||||
{
|
||||
fprintf (stderr, "%s: %s: unexpected end of file\n",
|
||||
whoami, filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
n_lowpc = (bfd_vma) get_vma(core_bfd, (bfd_byte *) hdr.low_pc);
|
||||
n_highpc = (bfd_vma) get_vma(core_bfd, (bfd_byte *) hdr.high_pc);
|
||||
ncnt = bfd_get_32(core_bfd, (bfd_byte *) hdr.hist_size);
|
||||
profrate = bfd_get_32(core_bfd, (bfd_byte *) hdr.prof_rate);
|
||||
strncpy(hist_dimension, hdr.dimen, sizeof(hdr.dimen));
|
||||
hist_dimension[sizeof(hdr.dimen)] = '\0';
|
||||
hist_dimension_abbrev = hdr.dimen_abbrev;
|
||||
n_lowpc = (bfd_vma) get_vma (core_bfd, (bfd_byte *) hdr.low_pc);
|
||||
n_highpc = (bfd_vma) get_vma (core_bfd, (bfd_byte *) hdr.high_pc);
|
||||
ncnt = bfd_get_32 (core_bfd, (bfd_byte *) hdr.hist_size);
|
||||
profrate = bfd_get_32 (core_bfd, (bfd_byte *) hdr.prof_rate);
|
||||
strncpy (hist_dimension, hdr.dimen, sizeof (hdr.dimen));
|
||||
hist_dimension[sizeof (hdr.dimen)] = '\0';
|
||||
hist_dimension_abbrev = hdr.dimen_abbrev;
|
||||
|
||||
if (!s_highpc) {
|
||||
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);
|
||||
highpc = (bfd_vma) n_highpc / sizeof(UNIT);
|
||||
hist_num_bins = ncnt;
|
||||
hz = profrate;
|
||||
} /* if */
|
||||
s_lowpc = n_lowpc;
|
||||
s_highpc = n_highpc;
|
||||
lowpc = (bfd_vma) n_lowpc / sizeof (UNIT);
|
||||
highpc = (bfd_vma) n_highpc / sizeof (UNIT);
|
||||
hist_num_bins = ncnt;
|
||||
hz = profrate;
|
||||
} /* if */
|
||||
|
||||
DBG(SAMPLEDEBUG,
|
||||
printf("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %d\n",
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf ("[hist_read_rec] n_lowpc 0x%lx n_highpc 0x%lx ncnt %d\n",
|
||||
n_lowpc, n_highpc, ncnt);
|
||||
printf("[hist_read_rec] s_lowpc 0x%lx s_highpc 0x%lx nsamples %d\n",
|
||||
printf ("[hist_read_rec] s_lowpc 0x%lx s_highpc 0x%lx nsamples %d\n",
|
||||
s_lowpc, s_highpc, hist_num_bins);
|
||||
printf("[hist_read_rec] lowpc 0x%lx highpc 0x%lx\n",
|
||||
printf ("[hist_read_rec] lowpc 0x%lx highpc 0x%lx\n",
|
||||
lowpc, highpc));
|
||||
|
||||
if (n_lowpc != s_lowpc || n_highpc != s_highpc
|
||||
|| ncnt != hist_num_bins || hz != profrate)
|
||||
if (n_lowpc != s_lowpc || n_highpc != s_highpc
|
||||
|| ncnt != hist_num_bins || hz != profrate)
|
||||
{
|
||||
fprintf(stderr, "%s: `%s' is incompatible with first gmon file\n",
|
||||
whoami, filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
fprintf (stderr, "%s: `%s' is incompatible with first gmon file\n",
|
||||
whoami, filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
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]));
|
||||
} /* if */
|
||||
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]));
|
||||
} /* if */
|
||||
|
||||
for (i = 0; i < hist_num_bins; ++i) {
|
||||
if (fread(&count[0], sizeof(count), 1, ifp) != 1) {
|
||||
fprintf(stderr,
|
||||
"%s: %s: unexpected EOF after reading %d of %d samples\n",
|
||||
whoami, filename, i, hist_num_bins);
|
||||
done(1);
|
||||
} /* if */
|
||||
hist_sample[i] += bfd_get_16(core_bfd, (bfd_byte*) &count[0]);
|
||||
} /* for */
|
||||
} /* hist_read_rec */
|
||||
for (i = 0; i < hist_num_bins; ++i)
|
||||
{
|
||||
if (fread (&count[0], sizeof (count), 1, ifp) != 1)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"%s: %s: unexpected EOF after reading %d of %d samples\n",
|
||||
whoami, filename, i, hist_num_bins);
|
||||
done (1);
|
||||
} /* if */
|
||||
hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) & count[0]);
|
||||
} /* for */
|
||||
} /* hist_read_rec */
|
||||
|
||||
|
||||
/*
|
||||
@ -124,38 +165,40 @@ DEFUN(hist_read_rec, (ifp, filename), FILE *ifp AND const char *filename)
|
||||
* of OFP and is provided for formatting error-messages only.
|
||||
*/
|
||||
void
|
||||
DEFUN(hist_write_hist, (ofp, filename), FILE *ofp AND const char *filename)
|
||||
DEFUN (hist_write_hist, (ofp, filename), FILE * ofp AND const char *filename)
|
||||
{
|
||||
struct gmon_hist_hdr hdr;
|
||||
unsigned char tag;
|
||||
UNIT count;
|
||||
int i;
|
||||
|
||||
/* write header: */
|
||||
struct gmon_hist_hdr hdr;
|
||||
unsigned char tag;
|
||||
UNIT count;
|
||||
int i;
|
||||
|
||||
tag = GMON_TAG_TIME_HIST;
|
||||
put_vma(core_bfd, s_lowpc, (bfd_byte*) hdr.low_pc);
|
||||
put_vma(core_bfd, s_highpc, (bfd_byte*) hdr.high_pc);
|
||||
bfd_put_32(core_bfd, hist_num_bins, (bfd_byte*) hdr.hist_size);
|
||||
bfd_put_32(core_bfd, hz, (bfd_byte*) hdr.prof_rate);
|
||||
strncpy(hdr.dimen, hist_dimension, sizeof(hdr.dimen));
|
||||
hdr.dimen_abbrev = hist_dimension_abbrev;
|
||||
/* write header: */
|
||||
|
||||
if (fwrite(&tag, sizeof(tag), 1, ofp) != 1
|
||||
|| fwrite(&hdr, sizeof(hdr), 1, ofp) != 1)
|
||||
tag = GMON_TAG_TIME_HIST;
|
||||
put_vma (core_bfd, s_lowpc, (bfd_byte *) hdr.low_pc);
|
||||
put_vma (core_bfd, s_highpc, (bfd_byte *) hdr.high_pc);
|
||||
bfd_put_32 (core_bfd, hist_num_bins, (bfd_byte *) hdr.hist_size);
|
||||
bfd_put_32 (core_bfd, hz, (bfd_byte *) hdr.prof_rate);
|
||||
strncpy (hdr.dimen, hist_dimension, sizeof (hdr.dimen));
|
||||
hdr.dimen_abbrev = hist_dimension_abbrev;
|
||||
|
||||
if (fwrite (&tag, sizeof (tag), 1, ofp) != 1
|
||||
|| fwrite (&hdr, sizeof (hdr), 1, ofp) != 1)
|
||||
{
|
||||
perror(filename);
|
||||
done(1);
|
||||
} /* if */
|
||||
perror (filename);
|
||||
done (1);
|
||||
} /* if */
|
||||
|
||||
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);
|
||||
done(1);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* hist_write_hist */
|
||||
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);
|
||||
done (1);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* hist_write_hist */
|
||||
|
||||
|
||||
/*
|
||||
@ -167,28 +210,30 @@ DEFUN(hist_write_hist, (ofp, filename), FILE *ofp AND const char *filename)
|
||||
* next bin.
|
||||
*/
|
||||
static void
|
||||
DEFUN_VOID(scale_and_align_entries)
|
||||
DEFUN_VOID (scale_and_align_entries)
|
||||
{
|
||||
Sym *sym;
|
||||
Sym *sym;
|
||||
#if OFFSET_TO_CODE > 0
|
||||
bfd_vma bin_of_entry;
|
||||
bfd_vma bin_of_code;
|
||||
bfd_vma bin_of_entry;
|
||||
bfd_vma bin_of_code;
|
||||
#endif
|
||||
|
||||
for (sym = symtab.base; sym < symtab.limit; sym++) {
|
||||
sym->hist.scaled_addr = sym->addr / sizeof(UNIT);
|
||||
for (sym = symtab.base; sym < symtab.limit; sym++)
|
||||
{
|
||||
sym->hist.scaled_addr = sym->addr / sizeof (UNIT);
|
||||
#if OFFSET_TO_CODE > 0
|
||||
bin_of_entry = (sym->hist.scaled_addr - lowpc) / hist_scale;
|
||||
bin_of_code = (sym->hist.scaled_addr + UNITS_TO_CODE - lowpc) / hist_scale;
|
||||
if (bin_of_entry < bin_of_code) {
|
||||
DBG(SAMPLEDEBUG,
|
||||
printf("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
|
||||
sym->hist.scaled_addr, sym->aligned_addr + UNITS_TO_CODE));
|
||||
sym->aligned_addr += UNITS_TO_CODE;
|
||||
} /* if */
|
||||
bin_of_entry = (sym->hist.scaled_addr - lowpc) / hist_scale;
|
||||
bin_of_code = (sym->hist.scaled_addr + UNITS_TO_CODE - lowpc) / hist_scale;
|
||||
if (bin_of_entry < bin_of_code)
|
||||
{
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf ("[scale_and_align_entries] pushing 0x%lx to 0x%lx\n",
|
||||
sym->hist.scaled_addr, sym->aligned_addr + UNITS_TO_CODE));
|
||||
sym->aligned_addr += UNITS_TO_CODE;
|
||||
} /* if */
|
||||
#endif /* OFFSET_TO_CODE > 0 */
|
||||
} /* for */
|
||||
} /* scale_and_align_entries */
|
||||
} /* for */
|
||||
} /* scale_and_align_entries */
|
||||
|
||||
|
||||
/*
|
||||
@ -206,18 +251,18 @@ DEFUN_VOID(scale_and_align_entries)
|
||||
* sample that is to be credited to the symbol which starts at
|
||||
* SYM_LOW_PC.
|
||||
*
|
||||
* sym_low_pc sym_high_pc
|
||||
* | |
|
||||
* v v
|
||||
* 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
|
||||
@ -230,153 +275,176 @@ DEFUN_VOID(scale_and_align_entries)
|
||||
* cases, above).
|
||||
*/
|
||||
void
|
||||
DEFUN_VOID(hist_assign_samples)
|
||||
DEFUN_VOID (hist_assign_samples)
|
||||
{
|
||||
bfd_vma bin_low_pc, bin_high_pc;
|
||||
bfd_vma sym_low_pc, sym_high_pc;
|
||||
bfd_vma overlap, addr;
|
||||
int bin_count, i, j;
|
||||
double time, credit;
|
||||
bfd_vma bin_low_pc, bin_high_pc;
|
||||
bfd_vma sym_low_pc, sym_high_pc;
|
||||
bfd_vma overlap, addr;
|
||||
int bin_count, i, j;
|
||||
double time, credit;
|
||||
|
||||
/* read samples and assign to symbols: */
|
||||
hist_scale = highpc - lowpc;
|
||||
hist_scale /= hist_num_bins;
|
||||
scale_and_align_entries();
|
||||
/* 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_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",
|
||||
sizeof(UNIT) * bin_low_pc, sizeof(UNIT) * bin_high_pc,
|
||||
bin_count));
|
||||
total_time += time;
|
||||
for (i = 0, j = 1; i < hist_num_bins; ++i)
|
||||
{
|
||||
bin_count = hist_sample[i];
|
||||
if (!bin_count)
|
||||
{
|
||||
continue;
|
||||
} /* if */
|
||||
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",
|
||||
sizeof (UNIT) * bin_low_pc, sizeof (UNIT) * bin_high_pc,
|
||||
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 (bin_high_pc < sym_low_pc) {
|
||||
break;
|
||||
} /* if */
|
||||
/*
|
||||
* If low end of bin is above high end of symbol, go for
|
||||
* next symbol.
|
||||
*/
|
||||
if (bin_low_pc >= sym_high_pc) {
|
||||
continue;
|
||||
} /* if */
|
||||
overlap =
|
||||
MIN(bin_high_pc, sym_high_pc) - MAX(bin_low_pc, sym_low_pc);
|
||||
if (overlap > 0) {
|
||||
DBG(SAMPLEDEBUG,
|
||||
printf(
|
||||
"[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
|
||||
symtab.base[j].addr, sizeof(UNIT) * sym_high_pc,
|
||||
symtab.base[j].name, overlap * time / hist_scale,
|
||||
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.
|
||||
*/
|
||||
if (sym_lookup(&syms[INCL_FLAT], addr)
|
||||
|| (syms[INCL_FLAT].len == 0
|
||||
&& !sym_lookup(&syms[EXCL_FLAT], addr)))
|
||||
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 (bin_high_pc < sym_low_pc)
|
||||
{
|
||||
break;
|
||||
} /* if */
|
||||
/*
|
||||
* If low end of bin is above high end of symbol, go for
|
||||
* next symbol.
|
||||
*/
|
||||
if (bin_low_pc >= sym_high_pc)
|
||||
{
|
||||
continue;
|
||||
} /* if */
|
||||
overlap =
|
||||
MIN (bin_high_pc, sym_high_pc) - MAX (bin_low_pc, sym_low_pc);
|
||||
if (overlap > 0)
|
||||
{
|
||||
DBG (SAMPLEDEBUG,
|
||||
printf (
|
||||
"[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
|
||||
symtab.base[j].addr, sizeof (UNIT) * sym_high_pc,
|
||||
symtab.base[j].name, overlap * time / hist_scale,
|
||||
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.
|
||||
*/
|
||||
if (sym_lookup (&syms[INCL_FLAT], addr)
|
||||
|| (syms[INCL_FLAT].len == 0
|
||||
&& !sym_lookup (&syms[EXCL_FLAT], addr)))
|
||||
{
|
||||
symtab.base[j].hist.time += credit;
|
||||
} else {
|
||||
total_time -= credit;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* for */
|
||||
DBG(SAMPLEDEBUG, printf("[assign_samples] total_time %f\n",
|
||||
symtab.base[j].hist.time += credit;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_time -= credit;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* for */
|
||||
DBG (SAMPLEDEBUG, printf ("[assign_samples] total_time %f\n",
|
||||
total_time));
|
||||
} /* hist_assign_samples */
|
||||
} /* hist_assign_samples */
|
||||
|
||||
|
||||
/*
|
||||
* Print header for flag histogram profile:
|
||||
*/
|
||||
static void
|
||||
DEFUN(print_header, (prefix), const char prefix)
|
||||
DEFUN (print_header, (prefix), const char prefix)
|
||||
{
|
||||
char unit[64];
|
||||
char unit[64];
|
||||
|
||||
sprintf(unit, "%c%c/call", prefix, hist_dimension_abbrev);
|
||||
sprintf (unit, "%c%c/call", prefix, hist_dimension_abbrev);
|
||||
|
||||
if (bsd_style_output) {
|
||||
printf("\ngranularity: each sample hit covers %ld byte(s)",
|
||||
(long) hist_scale * sizeof(UNIT));
|
||||
if (total_time > 0.0) {
|
||||
printf(" for %.2f%% of %.2f %s\n\n",
|
||||
100.0/total_time, total_time/hz, hist_dimension);
|
||||
} /* if */
|
||||
} else {
|
||||
printf("\nEach sample counts as %g %s.\n", 1.0 / hz, hist_dimension);
|
||||
} /* if */
|
||||
if (bsd_style_output)
|
||||
{
|
||||
printf ("\ngranularity: each sample hit covers %ld byte(s)",
|
||||
(long) hist_scale * sizeof (UNIT));
|
||||
if (total_time > 0.0)
|
||||
{
|
||||
printf (" for %.2f%% of %.2f %s\n\n",
|
||||
100.0 / total_time, total_time / hz, hist_dimension);
|
||||
} /* if */
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("\nEach sample counts as %g %s.\n", 1.0 / hz, hist_dimension);
|
||||
} /* if */
|
||||
|
||||
if (total_time <= 0.0) {
|
||||
printf(" no time accumulated\n\n");
|
||||
/* this doesn't hurt since all the numerators will be zero: */
|
||||
total_time = 1.0;
|
||||
} /* if */
|
||||
if (total_time <= 0.0)
|
||||
{
|
||||
printf (" no time accumulated\n\n");
|
||||
/* this doesn't hurt since all the numerators will be zero: */
|
||||
total_time = 1.0;
|
||||
} /* if */
|
||||
|
||||
printf("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
|
||||
"% ", "cumulative", "self ", "", "self ", "total ", "");
|
||||
printf("%5.5s %9.9s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
|
||||
"time", hist_dimension, hist_dimension, "calls", unit, unit,
|
||||
"name");
|
||||
} /* print_header */
|
||||
printf ("%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
|
||||
"% ", "cumulative", "self ", "", "self ", "total ", "");
|
||||
printf ("%5.5s %9.9s %8.8s %8.8s %8.8s %8.8s %-8.8s\n",
|
||||
"time", hist_dimension, hist_dimension, "calls", unit, unit,
|
||||
"name");
|
||||
} /* print_header */
|
||||
|
||||
|
||||
static void
|
||||
DEFUN(print_line, (sym, scale), Sym *sym AND double scale)
|
||||
DEFUN (print_line, (sym, scale), Sym * sym AND double scale)
|
||||
{
|
||||
if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0) {
|
||||
return;
|
||||
} /* if */
|
||||
if (ignore_zeros && sym->ncalls == 0 && sym->hist.time == 0)
|
||||
{
|
||||
return;
|
||||
} /* if */
|
||||
|
||||
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);
|
||||
} 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);
|
||||
} /* if */
|
||||
if (sym->ncalls) {
|
||||
printf(" %8d %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 ", "", "", "");
|
||||
} /* if */
|
||||
if (bsd_style_output) {
|
||||
print_name(sym);
|
||||
} else {
|
||||
print_name_only(sym);
|
||||
} /* if */
|
||||
printf("\n");
|
||||
} /* print_line */
|
||||
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);
|
||||
}
|
||||
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);
|
||||
} /* if */
|
||||
if (sym->ncalls)
|
||||
{
|
||||
printf (" %8d %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 ", "", "", "");
|
||||
} /* if */
|
||||
if (bsd_style_output)
|
||||
{
|
||||
print_name (sym);
|
||||
}
|
||||
else
|
||||
{
|
||||
print_name_only (sym);
|
||||
} /* if */
|
||||
printf ("\n");
|
||||
} /* print_line */
|
||||
|
||||
|
||||
/*
|
||||
@ -385,123 +453,144 @@ DEFUN(print_line, (sym, scale), Sym *sym AND double scale)
|
||||
* lexicographic order of the function names.
|
||||
*/
|
||||
static int
|
||||
DEFUN(cmp_time, (lp, rp), const PTR lp AND const PTR rp)
|
||||
DEFUN (cmp_time, (lp, rp), const PTR lp AND const PTR rp)
|
||||
{
|
||||
const Sym *left = *(const Sym **)lp;
|
||||
const Sym *right = *(const Sym **)rp;
|
||||
double time_diff;
|
||||
long call_diff;
|
||||
const Sym *left = *(const Sym **) lp;
|
||||
const Sym *right = *(const Sym **) rp;
|
||||
double time_diff;
|
||||
long call_diff;
|
||||
|
||||
time_diff = right->hist.time - left->hist.time;
|
||||
if (time_diff > 0.0) {
|
||||
return 1;
|
||||
} /* if */
|
||||
if (time_diff < 0.0) {
|
||||
return -1;
|
||||
} /* if */
|
||||
time_diff = right->hist.time - left->hist.time;
|
||||
if (time_diff > 0.0)
|
||||
{
|
||||
return 1;
|
||||
} /* if */
|
||||
if (time_diff < 0.0)
|
||||
{
|
||||
return -1;
|
||||
} /* if */
|
||||
|
||||
call_diff = right->ncalls - left->ncalls;
|
||||
if (call_diff > 0) {
|
||||
return 1;
|
||||
} /* if */
|
||||
if (call_diff < 0) {
|
||||
return -1;
|
||||
} /* if */
|
||||
call_diff = right->ncalls - left->ncalls;
|
||||
if (call_diff > 0)
|
||||
{
|
||||
return 1;
|
||||
} /* if */
|
||||
if (call_diff < 0)
|
||||
{
|
||||
return -1;
|
||||
} /* if */
|
||||
|
||||
return strcmp(left->name, right->name);
|
||||
} /* cmp_time */
|
||||
return strcmp (left->name, right->name);
|
||||
} /* cmp_time */
|
||||
|
||||
|
||||
/*
|
||||
* Print the flat histogram profile.
|
||||
*/
|
||||
void
|
||||
DEFUN_VOID(hist_print)
|
||||
DEFUN_VOID (hist_print)
|
||||
{
|
||||
Sym **time_sorted_syms, *top_dog, *sym;
|
||||
int index, log_scale;
|
||||
double top_time, time;
|
||||
bfd_vma addr;
|
||||
Sym **time_sorted_syms, *top_dog, *sym;
|
||||
int index, log_scale;
|
||||
double top_time, time;
|
||||
bfd_vma addr;
|
||||
|
||||
if (first_output) {
|
||||
first_output = FALSE;
|
||||
} else {
|
||||
printf("\f\n");
|
||||
} /* if */
|
||||
if (first_output)
|
||||
{
|
||||
first_output = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("\f\n");
|
||||
} /* if */
|
||||
|
||||
accum_time = 0.0;
|
||||
if (bsd_style_output) {
|
||||
if (print_descriptions) {
|
||||
printf("\n\n\nflat profile:\n");
|
||||
flat_blurb(stdout);
|
||||
} /* if */
|
||||
} else {
|
||||
printf ("Flat profile:\n");
|
||||
} /* if */
|
||||
/*
|
||||
* 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];
|
||||
} /* for */
|
||||
qsort(time_sorted_syms, symtab.len, sizeof(Sym *), cmp_time);
|
||||
|
||||
if (bsd_style_output) {
|
||||
log_scale = 5; /* milli-seconds is BSD-default */
|
||||
} else {
|
||||
/*
|
||||
* 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) {
|
||||
time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
|
||||
if (time > top_time) {
|
||||
top_dog = sym;
|
||||
top_time = time;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (top_dog && top_dog->ncalls && top_time > 0.0) {
|
||||
top_time /= hz;
|
||||
while (SItab[log_scale].scale * top_time < 1000.0
|
||||
&& log_scale < sizeof(SItab)/sizeof(SItab[0]) - 1)
|
||||
{
|
||||
++log_scale;
|
||||
} /* while */
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (sym_lookup(&syms[INCL_FLAT], addr)
|
||||
|| (syms[INCL_FLAT].len == 0
|
||||
&& !sym_lookup(&syms[EXCL_FLAT], addr)))
|
||||
accum_time = 0.0;
|
||||
if (bsd_style_output)
|
||||
{
|
||||
if (print_descriptions)
|
||||
{
|
||||
print_line(time_sorted_syms[index], SItab[log_scale].scale);
|
||||
} /* if */
|
||||
} /* for */
|
||||
free(time_sorted_syms);
|
||||
printf ("\n\n\nflat profile:\n");
|
||||
flat_blurb (stdout);
|
||||
} /* if */
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Flat profile:\n");
|
||||
} /* if */
|
||||
/*
|
||||
* 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];
|
||||
} /* for */
|
||||
qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
|
||||
|
||||
if (print_descriptions && !bsd_style_output) {
|
||||
flat_blurb(stdout);
|
||||
} /* if */
|
||||
} /* hist_print */
|
||||
if (bsd_style_output)
|
||||
{
|
||||
log_scale = 5; /* milli-seconds is BSD-default */
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
time = (sym->hist.time + sym->cg.child_time) / sym->ncalls;
|
||||
if (time > top_time)
|
||||
{
|
||||
top_dog = sym;
|
||||
top_time = time;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (top_dog && top_dog->ncalls && top_time > 0.0)
|
||||
{
|
||||
top_time /= hz;
|
||||
while (SItab[log_scale].scale * top_time < 1000.0
|
||||
&& log_scale < sizeof (SItab) / sizeof (SItab[0]) - 1)
|
||||
{
|
||||
++log_scale;
|
||||
} /* while */
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
/*** end of hist.c ***/
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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);
|
||||
} /* if */
|
||||
} /* for */
|
||||
free (time_sorted_syms);
|
||||
|
||||
if (print_descriptions && !bsd_style_output)
|
||||
{
|
||||
flat_blurb (stdout);
|
||||
} /* if */
|
||||
} /* hist_print */
|
||||
|
||||
/*** end of hist.c ***/
|
||||
|
18
gprof/hist.h
18
gprof/hist.h
@ -3,11 +3,11 @@
|
||||
|
||||
#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 */
|
||||
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:
|
||||
@ -15,9 +15,9 @@ extern int *hist_sample; /* code histogram */
|
||||
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 * 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));
|
||||
|
||||
#endif /* hist_h */
|
||||
|
113
gprof/i386.c
113
gprof/i386.c
@ -24,80 +24,87 @@
|
||||
|
||||
|
||||
int
|
||||
DEFUN(iscall, (ip), unsigned char *ip)
|
||||
DEFUN (iscall, (ip), unsigned char *ip)
|
||||
{
|
||||
if (*ip == 0xeb || *ip == 0x9a)
|
||||
if (*ip == 0xeb || *ip == 0x9a)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
find_call(parent, p_lowpc, p_highpc)
|
||||
Sym *parent;
|
||||
bfd_vma p_lowpc;
|
||||
bfd_vma p_highpc;
|
||||
find_call (parent, p_lowpc, p_highpc)
|
||||
Sym *parent;
|
||||
bfd_vma p_lowpc;
|
||||
bfd_vma p_highpc;
|
||||
{
|
||||
unsigned char *instructp;
|
||||
long length;
|
||||
Sym *child;
|
||||
bfd_vma destpc;
|
||||
unsigned char *instructp;
|
||||
long length;
|
||||
Sym *child;
|
||||
bfd_vma destpc;
|
||||
|
||||
if (core_text_space == 0) {
|
||||
return;
|
||||
if (core_text_space == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (p_lowpc < s_lowpc) {
|
||||
p_lowpc = s_lowpc;
|
||||
if (p_lowpc < s_lowpc)
|
||||
{
|
||||
p_lowpc = s_lowpc;
|
||||
}
|
||||
if (p_highpc > s_highpc) {
|
||||
p_highpc = s_highpc;
|
||||
if (p_highpc > s_highpc)
|
||||
{
|
||||
p_highpc = s_highpc;
|
||||
}
|
||||
DBG(CALLDEBUG, printf("[findcall] %s: 0x%lx to 0x%lx\n",
|
||||
DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
|
||||
parent->name, p_lowpc, p_highpc));
|
||||
for ( instructp = (unsigned char*) core_text_space + p_lowpc ;
|
||||
instructp < (unsigned char*) core_text_space + p_highpc ;
|
||||
instructp += length) {
|
||||
length = 1;
|
||||
if (iscall (instructp)) {
|
||||
DBG(CALLDEBUG,
|
||||
printf("[findcall]\t0x%x:callf",
|
||||
instructp - (unsigned char*) core_text_space));
|
||||
for (instructp = (unsigned char *) core_text_space + p_lowpc;
|
||||
instructp < (unsigned char *) core_text_space + p_highpc;
|
||||
instructp += length)
|
||||
{
|
||||
length = 1;
|
||||
if (iscall (instructp))
|
||||
{
|
||||
DBG (CALLDEBUG,
|
||||
printf ("[findcall]\t0x%x:callf",
|
||||
instructp - (unsigned char *) core_text_space));
|
||||
length = 4;
|
||||
/*
|
||||
* regular pc relative addressing
|
||||
* check that this is the address of
|
||||
* a function.
|
||||
* regular pc relative addressing
|
||||
* check that this is the address of
|
||||
* a function.
|
||||
*/
|
||||
destpc = ((bfd_vma)instructp + 5 - (bfd_vma) core_text_space);
|
||||
if (destpc >= s_lowpc && destpc <= s_highpc) {
|
||||
child = sym_lookup(&symtab, destpc);
|
||||
DBG(CALLDEBUG,
|
||||
printf("[findcall]\tdestpc 0x%lx", destpc);
|
||||
printf(" child->name %s", child->name);
|
||||
printf(" child->addr 0x%lx\n", child->addr);
|
||||
destpc = ((bfd_vma) instructp + 5 - (bfd_vma) core_text_space);
|
||||
if (destpc >= s_lowpc && destpc <= s_highpc)
|
||||
{
|
||||
child = sym_lookup (&symtab, destpc);
|
||||
DBG (CALLDEBUG,
|
||||
printf ("[findcall]\tdestpc 0x%lx", destpc);
|
||||
printf (" child->name %s", child->name);
|
||||
printf (" child->addr 0x%lx\n", child->addr);
|
||||
);
|
||||
if (child->addr == destpc) {
|
||||
/*
|
||||
* a hit
|
||||
*/
|
||||
arc_add(parent, child, (long) 0);
|
||||
length += 4; /* constant lengths */
|
||||
continue;
|
||||
if (child->addr == destpc)
|
||||
{
|
||||
/*
|
||||
* a hit
|
||||
*/
|
||||
arc_add (parent, child, (long) 0);
|
||||
length += 4; /* constant lengths */
|
||||
continue;
|
||||
}
|
||||
goto botched;
|
||||
}
|
||||
goto botched;
|
||||
}
|
||||
/*
|
||||
* else:
|
||||
* it looked like a callf,
|
||||
* but it wasn't to anywhere.
|
||||
* else:
|
||||
* it looked like a callf,
|
||||
* but it wasn't to anywhere.
|
||||
*/
|
||||
botched:
|
||||
/*
|
||||
* something funny going on.
|
||||
* something funny going on.
|
||||
*/
|
||||
DBG(CALLDEBUG, printf("[findcall]\tbut it's a botch\n"));
|
||||
length = 1;
|
||||
continue;
|
||||
DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
|
||||
length = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* @(#)tahoe.h 1.4 (Berkeley) 6/1/90
|
||||
* @(#)tahoe.h 1.4 (Berkeley) 6/1/90
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -24,11 +24,11 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* opcode of the `callf' instruction
|
||||
* opcode of the `callf' instruction
|
||||
*/
|
||||
/*
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
*/
|
||||
#define OFFSET_TO_CODE 0
|
||||
#define UNITS_TO_CODE (OFFSET_TO_CODE / sizeof(UNIT))
|
||||
|
@ -5,9 +5,9 @@
|
||||
* It does nothing, but prevents findcall() from being unresolved.
|
||||
*/
|
||||
|
||||
findcall( parentp , p_lowpc , p_highpc )
|
||||
nltype *parentp;
|
||||
unsigned long p_lowpc;
|
||||
unsigned long p_highpc;
|
||||
findcall (parentp, p_lowpc, p_highpc)
|
||||
nltype *parentp;
|
||||
unsigned long p_lowpc;
|
||||
unsigned long p_highpc;
|
||||
{
|
||||
}
|
||||
|
@ -38,8 +38,8 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
*/
|
||||
#ifdef MACH
|
||||
#include <machine/mach_param.h>
|
||||
@ -48,5 +48,8 @@
|
||||
#define OFFSET_OF_CODE 0
|
||||
#define UNITS_TO_CODE (OFFSET_OF_CODE / sizeof(UNIT))
|
||||
|
||||
enum opermodes { dummy };
|
||||
typedef enum opermodes operandenum;
|
||||
enum opermodes
|
||||
{
|
||||
dummy
|
||||
};
|
||||
typedef enum opermodes operandenum;
|
||||
|
@ -4,35 +4,43 @@
|
||||
|
||||
|
||||
void
|
||||
DEFUN(search_list_append, (list, paths),
|
||||
Search_List *list AND const char *paths)
|
||||
DEFUN (search_list_append, (list, paths),
|
||||
Search_List * list AND const char *paths)
|
||||
{
|
||||
Search_List_Elem *new_el;
|
||||
const char *beg, *colon;
|
||||
int len;
|
||||
Search_List_Elem *new_el;
|
||||
const char *beg, *colon;
|
||||
int len;
|
||||
|
||||
colon = paths - 1;
|
||||
do {
|
||||
beg = colon + 1;
|
||||
colon = strchr(beg, ':');
|
||||
if (colon) {
|
||||
len = colon - beg;
|
||||
} else {
|
||||
len = strlen(beg);
|
||||
} /* if */
|
||||
new_el = (Search_List_Elem*) xmalloc(sizeof(*new_el) + len);
|
||||
memcpy(new_el->path, beg, len);
|
||||
new_el->path[len] = '\0';
|
||||
colon = paths - 1;
|
||||
do
|
||||
{
|
||||
beg = colon + 1;
|
||||
colon = strchr (beg, ':');
|
||||
if (colon)
|
||||
{
|
||||
len = colon - beg;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = strlen (beg);
|
||||
} /* if */
|
||||
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: */
|
||||
new_el->next = 0;
|
||||
if (list->tail) {
|
||||
list->tail->next = new_el;
|
||||
} else {
|
||||
list->head = new_el;
|
||||
} /* if */
|
||||
list->tail = new_el;
|
||||
} while (colon);
|
||||
} /* search_list_append */
|
||||
/* append new path at end of list: */
|
||||
new_el->next = 0;
|
||||
if (list->tail)
|
||||
{
|
||||
list->tail->next = new_el;
|
||||
}
|
||||
else
|
||||
{
|
||||
list->head = new_el;
|
||||
} /* if */
|
||||
list->tail = new_el;
|
||||
}
|
||||
while (colon);
|
||||
} /* search_list_append */
|
||||
|
||||
/*** end of search_list.c ***/
|
||||
/*** end of search_list.c ***/
|
||||
|
@ -1,16 +1,20 @@
|
||||
#ifndef search_list_h
|
||||
#define search_list_h
|
||||
|
||||
typedef struct search_list_elem {
|
||||
struct search_list_elem *next;
|
||||
char path[1];
|
||||
} Search_List_Elem;
|
||||
typedef struct search_list_elem
|
||||
{
|
||||
struct search_list_elem *next;
|
||||
char path[1];
|
||||
}
|
||||
Search_List_Elem;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
struct search_list_elem *head;
|
||||
struct search_list_elem *tail;
|
||||
} Search_List;
|
||||
}
|
||||
Search_List;
|
||||
|
||||
extern void search_list_append PARAMS((Search_List *list, const char *paths));
|
||||
extern void search_list_append PARAMS ((Search_List * list, const char *paths));
|
||||
|
||||
#endif /* search_list_h */
|
||||
|
341
gprof/source.c
341
gprof/source.c
@ -13,174 +13,213 @@
|
||||
*/
|
||||
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;
|
||||
|
||||
|
||||
Source_File*
|
||||
DEFUN(source_file_lookup_path, (path), const char *path)
|
||||
Source_File *
|
||||
DEFUN (source_file_lookup_path, (path), const char *path)
|
||||
{
|
||||
Source_File *sf;
|
||||
Source_File *sf;
|
||||
|
||||
for (sf = first_src_file; sf; sf = sf->next) {
|
||||
if (strcmp(path, sf->name) == 0) {
|
||||
break;
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (!sf) {
|
||||
/* create a new source file descriptor: */
|
||||
for (sf = first_src_file; sf; sf = sf->next)
|
||||
{
|
||||
if (strcmp (path, sf->name) == 0)
|
||||
{
|
||||
break;
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (!sf)
|
||||
{
|
||||
/* create a new source file descriptor: */
|
||||
|
||||
sf = (Source_File*) xmalloc(sizeof(*sf));
|
||||
memset(sf, 0, sizeof(*sf));
|
||||
sf->name = strdup(path);
|
||||
sf->next = first_src_file;
|
||||
first_src_file = sf;
|
||||
} /* if */
|
||||
return sf;
|
||||
} /* source_file_lookup_path */
|
||||
sf = (Source_File *) xmalloc (sizeof (*sf));
|
||||
memset (sf, 0, sizeof (*sf));
|
||||
sf->name = strdup (path);
|
||||
sf->next = first_src_file;
|
||||
first_src_file = sf;
|
||||
} /* if */
|
||||
return sf;
|
||||
} /* source_file_lookup_path */
|
||||
|
||||
|
||||
Source_File*
|
||||
DEFUN(source_file_lookup_name, (filename), const char *filename)
|
||||
Source_File *
|
||||
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:
|
||||
*/
|
||||
for (sf = first_src_file; sf; sf = sf->next) {
|
||||
fname = strrchr(sf->name, '/');
|
||||
if (fname) {
|
||||
++fname;
|
||||
} else {
|
||||
fname = sf->name;
|
||||
} /* if */
|
||||
if (strcmp(filename, fname) == 0) {
|
||||
break;
|
||||
} /* if */
|
||||
} /* for */
|
||||
return sf;
|
||||
} /* source_file_lookup_name */
|
||||
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:
|
||||
*/
|
||||
for (sf = first_src_file; sf; sf = sf->next)
|
||||
{
|
||||
fname = strrchr (sf->name, '/');
|
||||
if (fname)
|
||||
{
|
||||
++fname;
|
||||
}
|
||||
else
|
||||
{
|
||||
fname = sf->name;
|
||||
} /* if */
|
||||
if (strcmp (filename, fname) == 0)
|
||||
{
|
||||
break;
|
||||
} /* if */
|
||||
} /* for */
|
||||
return sf;
|
||||
} /* source_file_lookup_name */
|
||||
|
||||
|
||||
FILE*
|
||||
DEFUN(annotate_source, (sf, max_width, annote, arg),
|
||||
Source_File *sf AND int max_width
|
||||
AND void (*annote) PARAMS((char *buf, int w, int l, void *arg))
|
||||
AND void *arg)
|
||||
FILE *
|
||||
DEFUN (annotate_source, (sf, max_width, annote, arg),
|
||||
Source_File * sf AND int max_width
|
||||
AND void (*annote) PARAMS ((char *buf, int w, int l, void *arg))
|
||||
AND void *arg)
|
||||
{
|
||||
static bool first_file = TRUE;
|
||||
int i, line_num, nread;
|
||||
bool new_line;
|
||||
char buf[8192];
|
||||
char fname[PATH_MAX];
|
||||
char *annotation, *name_only;
|
||||
FILE *ifp, *ofp;
|
||||
Search_List_Elem *sle = src_search_list.head;
|
||||
static bool first_file = TRUE;
|
||||
int i, line_num, nread;
|
||||
bool new_line;
|
||||
char buf[8192];
|
||||
char fname[PATH_MAX];
|
||||
char *annotation, *name_only;
|
||||
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:
|
||||
*/
|
||||
strcpy(fname, sf->name);
|
||||
if (sf->name[0] == '/') {
|
||||
sle = 0; /* don't use search list for absolute paths */
|
||||
} /* if */
|
||||
name_only = 0;
|
||||
while (TRUE) {
|
||||
DBG(SRCDEBUG, printf("[annotate_source]: looking for %s, trying %s\n",
|
||||
/*
|
||||
* Open input file. If open fails, walk along search-list until
|
||||
* open succeeds or reaching end of list:
|
||||
*/
|
||||
strcpy (fname, sf->name);
|
||||
if (sf->name[0] == '/')
|
||||
{
|
||||
sle = 0; /* don't use search list for absolute paths */
|
||||
} /* if */
|
||||
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;
|
||||
} /* if */
|
||||
if (!sle && !name_only) {
|
||||
name_only = strrchr(sf->name, '/');
|
||||
if (name_only) {
|
||||
/* try search-list again, but this time with name only: */
|
||||
++name_only;
|
||||
sle = src_search_list.head;
|
||||
} /* if */
|
||||
} /* if */
|
||||
if (sle) {
|
||||
strcpy(fname, sle->path);
|
||||
strcat(fname, "/");
|
||||
if (name_only) {
|
||||
strcat(fname, name_only);
|
||||
} else {
|
||||
strcat(fname, sf->name);
|
||||
} /* if */
|
||||
sle = sle->next;
|
||||
} else {
|
||||
if (errno == ENOENT) {
|
||||
fprintf(stderr, "%s: could not locate `%s'\n",
|
||||
whoami, sf->name);
|
||||
} else {
|
||||
perror(sf->name);
|
||||
} /* if */
|
||||
return 0;
|
||||
} /* if */
|
||||
} /* while */
|
||||
ifp = fopen (fname, FOPEN_RB);
|
||||
if (ifp)
|
||||
{
|
||||
break;
|
||||
} /* if */
|
||||
if (!sle && !name_only)
|
||||
{
|
||||
name_only = strrchr (sf->name, '/');
|
||||
if (name_only)
|
||||
{
|
||||
/* try search-list again, but this time with name only: */
|
||||
++name_only;
|
||||
sle = src_search_list.head;
|
||||
} /* if */
|
||||
} /* if */
|
||||
if (sle)
|
||||
{
|
||||
strcpy (fname, sle->path);
|
||||
strcat (fname, "/");
|
||||
if (name_only)
|
||||
{
|
||||
strcat (fname, name_only);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat (fname, sf->name);
|
||||
} /* if */
|
||||
sle = sle->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
fprintf (stderr, "%s: could not locate `%s'\n",
|
||||
whoami, sf->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
perror (sf->name);
|
||||
} /* if */
|
||||
return 0;
|
||||
} /* if */
|
||||
} /* while */
|
||||
|
||||
ofp = stdout;
|
||||
if (create_annotation_files) {
|
||||
/* try to create annotated source file: */
|
||||
const char *filename;
|
||||
ofp = stdout;
|
||||
if (create_annotation_files)
|
||||
{
|
||||
/* try to create annotated source file: */
|
||||
const char *filename;
|
||||
|
||||
/* create annotation files in the current working directory: */
|
||||
filename = strrchr(sf->name, '/');
|
||||
if (filename) {
|
||||
++filename;
|
||||
} else {
|
||||
filename = sf->name;
|
||||
} /* if */
|
||||
/* create annotation files in the current working directory: */
|
||||
filename = strrchr (sf->name, '/');
|
||||
if (filename)
|
||||
{
|
||||
++filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = sf->name;
|
||||
} /* if */
|
||||
|
||||
strcpy(fname, filename);
|
||||
strcat(fname, EXT_ANNO);
|
||||
ofp = fopen(fname, "w");
|
||||
if (!ofp) {
|
||||
perror(fname);
|
||||
return 0;
|
||||
} /* if */
|
||||
} /* if */
|
||||
strcpy (fname, filename);
|
||||
strcat (fname, EXT_ANNO);
|
||||
ofp = fopen (fname, "w");
|
||||
if (!ofp)
|
||||
{
|
||||
perror (fname);
|
||||
return 0;
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* 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;
|
||||
} else {
|
||||
fputc('\n', ofp);
|
||||
} /* if */
|
||||
if (first_output) {
|
||||
first_output = FALSE;
|
||||
} else {
|
||||
fprintf(ofp, "\f\n");
|
||||
} /* if */
|
||||
fprintf(ofp, "*** File %s:\n", sf->name);
|
||||
} /* if */
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
fputc ('\n', ofp);
|
||||
} /* if */
|
||||
if (first_output)
|
||||
{
|
||||
first_output = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (ofp, "\f\n");
|
||||
} /* if */
|
||||
fprintf (ofp, "*** File %s:\n", sf->name);
|
||||
} /* if */
|
||||
|
||||
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) {
|
||||
if (new_line) {
|
||||
(*annote)(annotation, max_width, line_num, arg);
|
||||
fputs(annotation, ofp);
|
||||
++line_num; new_line = FALSE;
|
||||
} /* if */
|
||||
new_line = (buf[i] == '\n');
|
||||
fputc(buf[i], ofp);
|
||||
} /* for */
|
||||
} /* while */
|
||||
free(annotation);
|
||||
return ofp;
|
||||
} /* annotate_source */
|
||||
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)
|
||||
{
|
||||
if (new_line)
|
||||
{
|
||||
(*annote) (annotation, max_width, line_num, arg);
|
||||
fputs (annotation, ofp);
|
||||
++line_num;
|
||||
new_line = FALSE;
|
||||
} /* if */
|
||||
new_line = (buf[i] == '\n');
|
||||
fputc (buf[i], ofp);
|
||||
} /* for */
|
||||
} /* while */
|
||||
free (annotation);
|
||||
return ofp;
|
||||
} /* annotate_source */
|
||||
|
||||
/*** end of source.c ***/
|
||||
/*** end of source.c ***/
|
||||
|
@ -5,14 +5,16 @@
|
||||
#include "gprof.h"
|
||||
#include "search_list.h"
|
||||
|
||||
typedef struct source_file {
|
||||
struct source_file *next;
|
||||
const char *name; /* name of source file */
|
||||
int 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;
|
||||
typedef struct source_file
|
||||
{
|
||||
struct source_file *next;
|
||||
const char *name; /* name of source file */
|
||||
int 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:
|
||||
@ -32,8 +34,8 @@ 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));
|
||||
extern Source_File *source_file_lookup_path PARAMS ((const char *path));
|
||||
extern Source_File *source_file_lookup_name PARAMS ((const char *filename));
|
||||
|
||||
/*
|
||||
* Read source file SF output annotated source. The annotation is at
|
||||
@ -45,9 +47,9 @@ extern Source_File *source_file_lookup_name PARAMS((const char *filename));
|
||||
* 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));
|
||||
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 */
|
||||
|
100
gprof/sparc.c
100
gprof/sparc.c
@ -24,56 +24,62 @@
|
||||
|
||||
|
||||
void
|
||||
find_call(parent, p_lowpc, p_highpc)
|
||||
find_call (parent, p_lowpc, p_highpc)
|
||||
Sym *parent;
|
||||
bfd_vma p_lowpc;
|
||||
bfd_vma p_highpc;
|
||||
{
|
||||
bfd_vma dest_pc, delta;
|
||||
unsigned int *instr;
|
||||
Sym *child;
|
||||
|
||||
delta = (bfd_vma) core_text_space - core_text_sect->vma;
|
||||
|
||||
if (core_text_space == 0) {
|
||||
return;
|
||||
} /* if */
|
||||
if (p_lowpc < s_lowpc) {
|
||||
p_lowpc = s_lowpc;
|
||||
} /* if */
|
||||
if (p_highpc > s_highpc) {
|
||||
p_highpc = s_highpc;
|
||||
} /* if */
|
||||
DBG(CALLDEBUG, printf("[find_call] %s: 0x%lx to 0x%lx\n",
|
||||
parent->name, p_lowpc, p_highpc));
|
||||
for (instr = (unsigned int*)(p_lowpc + delta);
|
||||
instr < (unsigned int*)(p_highpc + delta);
|
||||
++instr)
|
||||
bfd_vma dest_pc, delta;
|
||||
unsigned int *instr;
|
||||
Sym *child;
|
||||
|
||||
delta = (bfd_vma) core_text_space - core_text_sect->vma;
|
||||
|
||||
if (core_text_space == 0)
|
||||
{
|
||||
if ((*instr & CALL)) {
|
||||
DBG(CALLDEBUG,
|
||||
printf("[find_call] 0x%lx: callf", (bfd_vma) instr - delta));
|
||||
/*
|
||||
* Regular pc relative addressing check that this is the
|
||||
* address of a function.
|
||||
*/
|
||||
dest_pc = ((bfd_vma) (instr + (*instr & ~CALL))) - delta;
|
||||
if (dest_pc >= s_lowpc && dest_pc <= s_highpc) {
|
||||
child = sym_lookup(&symtab, dest_pc);
|
||||
DBG(CALLDEBUG,
|
||||
printf("\tdest_pc=0x%lx, (name=%s, addr=0x%lx)\n",
|
||||
return;
|
||||
} /* if */
|
||||
if (p_lowpc < s_lowpc)
|
||||
{
|
||||
p_lowpc = s_lowpc;
|
||||
} /* if */
|
||||
if (p_highpc > s_highpc)
|
||||
{
|
||||
p_highpc = s_highpc;
|
||||
} /* if */
|
||||
DBG (CALLDEBUG, printf ("[find_call] %s: 0x%lx to 0x%lx\n",
|
||||
parent->name, p_lowpc, p_highpc));
|
||||
for (instr = (unsigned int *) (p_lowpc + delta);
|
||||
instr < (unsigned int *) (p_highpc + delta);
|
||||
++instr)
|
||||
{
|
||||
if ((*instr & CALL))
|
||||
{
|
||||
DBG (CALLDEBUG,
|
||||
printf ("[find_call] 0x%lx: callf", (bfd_vma) instr - delta));
|
||||
/*
|
||||
* Regular pc relative addressing check that this is the
|
||||
* address of a function.
|
||||
*/
|
||||
dest_pc = ((bfd_vma) (instr + (*instr & ~CALL))) - delta;
|
||||
if (dest_pc >= s_lowpc && dest_pc <= s_highpc)
|
||||
{
|
||||
child = sym_lookup (&symtab, dest_pc);
|
||||
DBG (CALLDEBUG,
|
||||
printf ("\tdest_pc=0x%lx, (name=%s, addr=0x%lx)\n",
|
||||
dest_pc, child->name, child->addr));
|
||||
if (child->addr == dest_pc) {
|
||||
/* a hit: */
|
||||
arc_add(parent, child, 0);
|
||||
continue;
|
||||
} /* if */
|
||||
} /* if */
|
||||
/*
|
||||
* Something funny going on.
|
||||
*/
|
||||
DBG(CALLDEBUG, printf("\tbut it's a botch\n"));
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* find_call */
|
||||
/*** end of sparc.c ***/
|
||||
if (child->addr == dest_pc)
|
||||
{
|
||||
/* a hit: */
|
||||
arc_add (parent, child, 0);
|
||||
continue;
|
||||
} /* if */
|
||||
} /* if */
|
||||
/*
|
||||
* Something funny going on.
|
||||
*/
|
||||
DBG (CALLDEBUG, printf ("\tbut it's a botch\n"));
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* find_call */
|
||||
/*** end of sparc.c ***/
|
||||
|
@ -16,17 +16,16 @@
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* @(#)tahoe.h 1.4 (Berkeley) 6/1/90
|
||||
* @(#)tahoe.h 1.4 (Berkeley) 6/1/90
|
||||
*/
|
||||
|
||||
/*
|
||||
* opcode of the `callf' instruction
|
||||
* opcode of the `callf' instruction
|
||||
*/
|
||||
#define CALL (0xc0000000)
|
||||
/*
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
*/
|
||||
#define OFFSET_TO_CODE 0
|
||||
#define UNITS_TO_CODE (OFFSET_TO_CODE / sizeof(UNIT))
|
||||
|
||||
|
475
gprof/sym_ids.c
475
gprof/sym_ids.c
@ -2,29 +2,34 @@
|
||||
#include "cg_arcs.h"
|
||||
#include "sym_ids.h"
|
||||
|
||||
struct sym_id {
|
||||
struct sym_id *next;
|
||||
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 */
|
||||
Sym sym;
|
||||
} left, right;
|
||||
} *id_list;
|
||||
struct sym_id
|
||||
{
|
||||
struct sym_id *next;
|
||||
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 */
|
||||
Sym sym;
|
||||
}
|
||||
left, right;
|
||||
}
|
||||
*id_list;
|
||||
|
||||
Sym_Table syms[NUM_TABLES];
|
||||
|
||||
#ifdef DEBUG
|
||||
const char *table_name[] = {
|
||||
"INCL_GRAPH", "EXCL_GRAPH",
|
||||
"INCL_ARCS", "EXCL_ARCS",
|
||||
"INCL_FLAT", "EXCL_FLAT",
|
||||
"INCL_TIME", "EXCL_TIME",
|
||||
"INCL_ANNO", "EXCL_ANNO",
|
||||
"INCL_EXEC", "EXCL_EXEC"
|
||||
const char *table_name[] =
|
||||
{
|
||||
"INCL_GRAPH", "EXCL_GRAPH",
|
||||
"INCL_ARCS", "EXCL_ARCS",
|
||||
"INCL_FLAT", "EXCL_FLAT",
|
||||
"INCL_TIME", "EXCL_TIME",
|
||||
"INCL_ANNO", "EXCL_ANNO",
|
||||
"INCL_EXEC", "EXCL_EXEC"
|
||||
};
|
||||
#endif /* DEBUG */
|
||||
|
||||
@ -37,78 +42,94 @@ const char *table_name[] = {
|
||||
*/
|
||||
static Sym_Table right_ids;
|
||||
|
||||
static Source_File non_existent_file = {
|
||||
0, "<non-existent-file>"
|
||||
static Source_File non_existent_file =
|
||||
{
|
||||
0, "<non-existent-file>"
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
DEFUN(sym_id_add, (spec, which_table),
|
||||
const char *spec AND Table_Id which_table)
|
||||
DEFUN (sym_id_add, (spec, which_table),
|
||||
const char *spec AND Table_Id which_table)
|
||||
{
|
||||
struct sym_id *id;
|
||||
int len = strlen(spec);
|
||||
struct sym_id *id;
|
||||
int len = strlen (spec);
|
||||
|
||||
id = (struct sym_id*) xmalloc(sizeof(*id) + len + 1);
|
||||
memset(id, 0, sizeof(*id));
|
||||
id = (struct sym_id *) xmalloc (sizeof (*id) + len + 1);
|
||||
memset (id, 0, sizeof (*id));
|
||||
|
||||
id->spec = (char*)id + sizeof(*id);
|
||||
strcpy(id->spec, spec);
|
||||
id->which_table = which_table;
|
||||
id->spec = (char *) id + sizeof (*id);
|
||||
strcpy (id->spec, spec);
|
||||
id->which_table = which_table;
|
||||
|
||||
id->next = id_list;
|
||||
id_list = id;
|
||||
} /* sym_id_add */
|
||||
id->next = id_list;
|
||||
id_list = id;
|
||||
} /* sym_id_add */
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
* (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)
|
||||
DEFUN (parse_spec, (spec, sym), char *spec AND Sym * sym)
|
||||
{
|
||||
char *colon;
|
||||
char *colon;
|
||||
|
||||
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;
|
||||
} /* if */
|
||||
} /* if */
|
||||
spec = colon + 1;
|
||||
if (strlen(spec)) {
|
||||
if (isdigit(spec[0])) {
|
||||
sym->line_num = atoi(spec);
|
||||
} else {
|
||||
sym->name = spec;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} else if (strlen(spec)) {
|
||||
/* 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;
|
||||
} /* if */
|
||||
} else if (isdigit(*spec)) {
|
||||
sym->line_num = atoi(spec);
|
||||
} else if (strlen(spec)) {
|
||||
sym->name = spec;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* parse_spec */
|
||||
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;
|
||||
} /* if */
|
||||
} /* if */
|
||||
spec = colon + 1;
|
||||
if (strlen (spec))
|
||||
{
|
||||
if (isdigit (spec[0]))
|
||||
{
|
||||
sym->line_num = atoi (spec);
|
||||
}
|
||||
else
|
||||
{
|
||||
sym->name = spec;
|
||||
} /* if */
|
||||
} /* if */
|
||||
}
|
||||
else if (strlen (spec))
|
||||
{
|
||||
/* 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;
|
||||
} /* if */
|
||||
}
|
||||
else if (isdigit (*spec))
|
||||
{
|
||||
sym->line_num = atoi (spec);
|
||||
}
|
||||
else if (strlen (spec))
|
||||
{
|
||||
sym->name = spec;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* parse_spec */
|
||||
|
||||
|
||||
/*
|
||||
@ -116,79 +137,98 @@ DEFUN(parse_spec, (spec, sym), char *spec AND Sym *sym)
|
||||
* by parse_spec().
|
||||
*/
|
||||
static void
|
||||
DEFUN(parse_id, (id), struct sym_id *id)
|
||||
DEFUN (parse_id, (id), struct sym_id *id)
|
||||
{
|
||||
char *slash;
|
||||
char *slash;
|
||||
|
||||
DBG(IDDEBUG, printf("[parse_id] %s -> ", id->spec));
|
||||
DBG (IDDEBUG, printf ("[parse_id] %s -> ", id->spec));
|
||||
|
||||
slash = strchr(id->spec, '/');
|
||||
if (slash) {
|
||||
parse_spec(slash + 1, &id->right.sym);
|
||||
*slash = '\0';
|
||||
id->has_right = TRUE;
|
||||
} /* if */
|
||||
parse_spec(id->spec, &id->left.sym);
|
||||
slash = strchr (id->spec, '/');
|
||||
if (slash)
|
||||
{
|
||||
parse_spec (slash + 1, &id->right.sym);
|
||||
*slash = '\0';
|
||||
id->has_right = TRUE;
|
||||
} /* if */
|
||||
parse_spec (id->spec, &id->left.sym);
|
||||
|
||||
DBG(IDDEBUG,
|
||||
printf("%s:", id->left.sym.file ? id->left.sym.file->name : "*");
|
||||
if (id->left.sym.name) {
|
||||
printf("%s", id->left.sym.name);
|
||||
} else if (id->left.sym.line_num) {
|
||||
printf("%d", id->left.sym.line_num);
|
||||
} else {
|
||||
printf("*");
|
||||
} /* if */
|
||||
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);
|
||||
} else if (id->right.sym.line_num) {
|
||||
printf("%d", id->right.sym.line_num);
|
||||
} else {
|
||||
printf("*");
|
||||
} /* if */
|
||||
} /* if */
|
||||
printf("\n"));
|
||||
} /* parse_id */
|
||||
#ifdef DEBUG
|
||||
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);
|
||||
}
|
||||
else if (id->left.sym.line_num)
|
||||
{
|
||||
printf ("%d", id->left.sym.line_num);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("*");
|
||||
} /* if */
|
||||
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);
|
||||
}
|
||||
else if (id->right.sym.line_num)
|
||||
{
|
||||
printf ("%d", id->right.sym.line_num);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("*");
|
||||
} /* if */
|
||||
} /* if */
|
||||
printf ("\n");
|
||||
}
|
||||
#endif
|
||||
} /* parse_id */
|
||||
|
||||
|
||||
/*
|
||||
* Return TRUE iff PATTERN matches SYM.
|
||||
*/
|
||||
static bool
|
||||
DEFUN(match, (pattern, sym), Sym *pattern AND Sym *sym)
|
||||
DEFUN (match, (pattern, sym), Sym * pattern AND Sym * sym)
|
||||
{
|
||||
return (pattern->file ? pattern->file == sym->file : TRUE)
|
||||
&& (pattern->line_num ? pattern->line_num == sym->line_num : TRUE)
|
||||
&& (pattern->name ? strcmp(pattern->name, sym->name) == 0 : TRUE);
|
||||
} /* match */
|
||||
return (pattern->file ? pattern->file == sym->file : TRUE)
|
||||
&& (pattern->line_num ? pattern->line_num == sym->line_num : TRUE)
|
||||
&& (pattern->name ? strcmp (pattern->name, sym->name) == 0 : TRUE);
|
||||
} /* match */
|
||||
|
||||
|
||||
static void
|
||||
DEFUN(extend_match, (m, sym, tab, second_pass),
|
||||
struct match *m AND Sym *sym AND Sym_Table *tab AND bool second_pass)
|
||||
DEFUN (extend_match, (m, sym, tab, second_pass),
|
||||
struct match *m AND Sym * sym AND Sym_Table * tab AND bool second_pass)
|
||||
{
|
||||
if (m->prev_match != sym - 1) {
|
||||
/* discontinuity: add new match to table: */
|
||||
if (second_pass) {
|
||||
tab->base[tab->len] = *sym;
|
||||
m->prev_index = tab->len;
|
||||
if (m->prev_match != sym - 1)
|
||||
{
|
||||
/* 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: */
|
||||
tab->base[tab->len].next = m->first_match;
|
||||
m->first_match = &tab->base[tab->len];
|
||||
} /* if */
|
||||
++tab->len;
|
||||
} /* if */
|
||||
/* link match into match's chain: */
|
||||
tab->base[tab->len].next = m->first_match;
|
||||
m->first_match = &tab->base[tab->len];
|
||||
} /* if */
|
||||
++tab->len;
|
||||
} /* if */
|
||||
|
||||
/* extend match to include this symbol: */
|
||||
if (second_pass) {
|
||||
tab->base[m->prev_index].end_addr = sym->end_addr;
|
||||
} /* if */
|
||||
m->prev_match = sym;
|
||||
} /* extend_match */
|
||||
/* extend match to include this symbol: */
|
||||
if (second_pass)
|
||||
{
|
||||
tab->base[m->prev_index].end_addr = sym->end_addr;
|
||||
} /* if */
|
||||
m->prev_match = sym;
|
||||
} /* extend_match */
|
||||
|
||||
|
||||
/*
|
||||
@ -201,91 +241,107 @@ DEFUN(extend_match, (m, sym, tab, second_pass),
|
||||
* requests---you get what you ask for!
|
||||
*/
|
||||
void
|
||||
DEFUN_VOID(sym_id_parse)
|
||||
DEFUN_VOID (sym_id_parse)
|
||||
{
|
||||
Sym *sym, *left, *right;
|
||||
struct sym_id *id;
|
||||
Sym_Table *tab;
|
||||
Sym *sym, *left, *right;
|
||||
struct sym_id *id;
|
||||
Sym_Table *tab;
|
||||
|
||||
/*
|
||||
* Convert symbol ids into Syms, so we can deal with them more easily:
|
||||
*/
|
||||
for (id = id_list; id; id = id->next) {
|
||||
parse_id(id);
|
||||
} /* for */
|
||||
/*
|
||||
* Convert symbol ids into Syms, so we can deal with them more easily:
|
||||
*/
|
||||
for (id = id_list; id; id = id->next)
|
||||
{
|
||||
parse_id (id);
|
||||
} /* for */
|
||||
|
||||
/* first determine size of each table: */
|
||||
/* 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);
|
||||
} /* if */
|
||||
if (id->has_right && match(&id->right.sym, sym)) {
|
||||
extend_match(&id->right, sym, &right_ids, FALSE);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* for */
|
||||
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);
|
||||
} /* if */
|
||||
if (id->has_right && match (&id->right.sym, sym))
|
||||
{
|
||||
extend_match (&id->right, sym, &right_ids, FALSE);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* for */
|
||||
|
||||
/* 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) {
|
||||
tab->base = (Sym*) xmalloc(tab->len * sizeof(Sym));
|
||||
tab->limit = tab->base + tab->len;
|
||||
tab->len = 0;
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (right_ids.len) {
|
||||
right_ids.base = (Sym*) xmalloc(right_ids.len * sizeof(Sym));
|
||||
right_ids.limit = right_ids.base + right_ids.len;
|
||||
right_ids.len = 0;
|
||||
} /* if */
|
||||
for (tab = syms; tab < &syms[NUM_TABLES]; ++tab)
|
||||
{
|
||||
if (tab->len)
|
||||
{
|
||||
tab->base = (Sym *) xmalloc (tab->len * sizeof (Sym));
|
||||
tab->limit = tab->base + tab->len;
|
||||
tab->len = 0;
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (right_ids.len)
|
||||
{
|
||||
right_ids.base = (Sym *) xmalloc (right_ids.len * sizeof (Sym));
|
||||
right_ids.limit = right_ids.base + right_ids.len;
|
||||
right_ids.len = 0;
|
||||
} /* if */
|
||||
|
||||
/* 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);
|
||||
} /* if */
|
||||
if (id->has_right && match(&id->right.sym, sym)) {
|
||||
extend_match(&id->right, sym, &right_ids, TRUE);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* for */
|
||||
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);
|
||||
} /* if */
|
||||
if (id->has_right && match (&id->right.sym, sym))
|
||||
{
|
||||
extend_match (&id->right, sym, &right_ids, TRUE);
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* for */
|
||||
|
||||
/* 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) {
|
||||
for (left = id->left.first_match; left; left = left->next) {
|
||||
for (right = id->right.first_match; right; right = right->next)
|
||||
for (id = id_list; id; id = id->next)
|
||||
{
|
||||
if (id->has_right)
|
||||
{
|
||||
for (left = id->left.first_match; left; left = left->next)
|
||||
{
|
||||
for (right = id->right.first_match; right; right = right->next)
|
||||
{
|
||||
DBG(IDDEBUG,
|
||||
printf(
|
||||
"[sym_id_parse]: arc %s:%s(%lx-%lx) -> %s:%s(%lx-%lx) to %s\n",
|
||||
left->file ? left->file->name : "*",
|
||||
left->name ? left->name : "*", left->addr,
|
||||
left->end_addr,
|
||||
right->file ? right->file->name : "*",
|
||||
right->name ? right->name : "*", right->addr,
|
||||
right->end_addr,
|
||||
table_name[id->which_table]));
|
||||
arc_add(left, right, 0);
|
||||
} /* for */
|
||||
} /* for */
|
||||
} /* if */
|
||||
} /* for */
|
||||
DBG (IDDEBUG,
|
||||
printf (
|
||||
"[sym_id_parse]: arc %s:%s(%lx-%lx) -> %s:%s(%lx-%lx) to %s\n",
|
||||
left->file ? left->file->name : "*",
|
||||
left->name ? left->name : "*", left->addr,
|
||||
left->end_addr,
|
||||
right->file ? right->file->name : "*",
|
||||
right->name ? right->name : "*", right->addr,
|
||||
right->end_addr,
|
||||
table_name[id->which_table]));
|
||||
arc_add (left, right, 0);
|
||||
} /* for */
|
||||
} /* for */
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
/* 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",
|
||||
for (tab = &syms[0]; tab < &syms[NUM_TABLES]; ++tab)
|
||||
{
|
||||
DBG (IDDEBUG, printf ("[sym_id_parse] syms[%s]:\n",
|
||||
table_name[tab - &syms[0]]));
|
||||
symtab_finalize(tab);
|
||||
} /* for */
|
||||
} /* sym_id_parse */
|
||||
symtab_finalize (tab);
|
||||
} /* for */
|
||||
} /* sym_id_parse */
|
||||
|
||||
|
||||
/*
|
||||
@ -297,19 +353,20 @@ DEFUN_VOID(sym_id_parse)
|
||||
* tolerable.
|
||||
*/
|
||||
bool
|
||||
DEFUN(sym_id_arc_is_present, (symtab, from, to),
|
||||
Sym_Table *symtab AND Sym *from AND Sym *to)
|
||||
DEFUN (sym_id_arc_is_present, (symtab, from, to),
|
||||
Sym_Table * symtab AND Sym * from AND Sym * to)
|
||||
{
|
||||
Sym *sym;
|
||||
Sym *sym;
|
||||
|
||||
for (sym = symtab->base; sym < symtab->limit; ++sym) {
|
||||
if (from->addr >= sym->addr && from->addr <= sym->end_addr
|
||||
&& arc_lookup(sym, to))
|
||||
for (sym = symtab->base; sym < symtab->limit; ++sym)
|
||||
{
|
||||
if (from->addr >= sym->addr && from->addr <= sym->end_addr
|
||||
&& arc_lookup (sym, to))
|
||||
{
|
||||
return TRUE;
|
||||
} /* if */
|
||||
} /* for */
|
||||
return FALSE;
|
||||
} /* sym_id_arc_is_present */
|
||||
return TRUE;
|
||||
} /* if */
|
||||
} /* for */
|
||||
return FALSE;
|
||||
} /* sym_id_arc_is_present */
|
||||
|
||||
/*** end of sym_ids.h ***/
|
||||
/*** end of sym_ids.h ***/
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
#include "symtab.h"
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
INCL_GRAPH = 0, EXCL_GRAPH,
|
||||
INCL_ARCS, EXCL_ARCS,
|
||||
INCL_FLAT, EXCL_FLAT,
|
||||
@ -11,13 +12,14 @@ typedef enum {
|
||||
INCL_ANNO, EXCL_ANNO,
|
||||
INCL_EXEC, EXCL_EXEC,
|
||||
NUM_TABLES
|
||||
} Table_Id;
|
||||
}
|
||||
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 *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));
|
||||
|
||||
#endif /* sym_ids_h */
|
||||
|
356
gprof/symtab.c
356
gprof/symtab.c
@ -10,19 +10,19 @@ Sym_Table symtab;
|
||||
* Initialize a symbol (so it's empty).
|
||||
*/
|
||||
void
|
||||
DEFUN(sym_init, (sym), Sym *sym)
|
||||
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:
|
||||
*/
|
||||
sym->hist.time = 0.0;
|
||||
sym->cg.child_time = 0.0;
|
||||
sym->cg.prop.fract = 0.0;
|
||||
sym->cg.prop.self = 0.0;
|
||||
sym->cg.prop.child = 0.0;
|
||||
} /* sym_init */
|
||||
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:
|
||||
*/
|
||||
sym->hist.time = 0.0;
|
||||
sym->cg.child_time = 0.0;
|
||||
sym->cg.prop.fract = 0.0;
|
||||
sym->cg.prop.self = 0.0;
|
||||
sym->cg.prop.child = 0.0;
|
||||
} /* sym_init */
|
||||
|
||||
|
||||
/*
|
||||
@ -36,198 +36,232 @@ DEFUN(sym_init, (sym), Sym *sym)
|
||||
* the global symbol survives.
|
||||
*/
|
||||
static int
|
||||
DEFUN(cmp_addr, (lp, rp), const PTR lp AND const PTR rp)
|
||||
DEFUN (cmp_addr, (lp, rp), const PTR lp AND const PTR rp)
|
||||
{
|
||||
Sym *left = (Sym*) lp;
|
||||
Sym *right = (Sym*) rp;
|
||||
Sym *left = (Sym *) lp;
|
||||
Sym *right = (Sym *) rp;
|
||||
|
||||
if (left->addr > right->addr) {
|
||||
return 1;
|
||||
} else if (left->addr < right->addr) {
|
||||
return -1;
|
||||
} /* if */
|
||||
if (left->addr > right->addr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (left->addr < right->addr)
|
||||
{
|
||||
return -1;
|
||||
} /* if */
|
||||
|
||||
if (left->is_func != right->is_func) {
|
||||
return right->is_func - left->is_func;
|
||||
} /* if */
|
||||
if (left->is_func != right->is_func)
|
||||
{
|
||||
return right->is_func - left->is_func;
|
||||
} /* if */
|
||||
|
||||
return left->is_static - right->is_static;
|
||||
} /* cmp_addr */
|
||||
return left->is_static - right->is_static;
|
||||
} /* cmp_addr */
|
||||
|
||||
|
||||
void
|
||||
DEFUN(symtab_finalize, (tab), Sym_Table *tab)
|
||||
DEFUN (symtab_finalize, (tab), Sym_Table * tab)
|
||||
{
|
||||
Sym *src, *dst;
|
||||
bfd_vma prev_addr;
|
||||
Sym *src, *dst;
|
||||
bfd_vma prev_addr;
|
||||
|
||||
if (!tab->len) {
|
||||
return;
|
||||
} /* if */
|
||||
if (!tab->len)
|
||||
{
|
||||
return;
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* Sort symbol table in order of increasing function addresses:
|
||||
*/
|
||||
qsort(tab->base, tab->len, sizeof(Sym), cmp_addr);
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
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.
|
||||
* If both symbols are either static or global, 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->name[0] != '_' && dst[-1].name[0] == '_')
|
||||
|| (src->name[0]
|
||||
&& src->name[1] != '_' && dst[-1].name[1] == '_')))
|
||||
/*
|
||||
* 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.
|
||||
* If both symbols are either static or global, 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->name[0] != '_' && dst[-1].name[0] == '_')
|
||||
|| (src->name[0]
|
||||
&& src->name[1] != '_' && dst[-1].name[1] == '_')))
|
||||
{
|
||||
DBG(AOUTDEBUG|IDDEBUG,
|
||||
printf("[symtab_finalize] favor %s@%c%c over %s@%c%c",
|
||||
DBG (AOUTDEBUG | IDDEBUG,
|
||||
printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c",
|
||||
src->name, src->is_static ? 't' : 'T',
|
||||
src->is_func ? 'F' : 'f',
|
||||
dst[-1].name, dst[-1].is_static ? 't' : 'T',
|
||||
dst[-1].is_func ? 'F' : 'f');
|
||||
printf(" (addr=%lx)\n", src->addr));
|
||||
dst[-1] = *src;
|
||||
} else {
|
||||
DBG(AOUTDEBUG|IDDEBUG,
|
||||
printf("[symtab_finalize] favor %s@%c%c over %s@%c%c",
|
||||
printf (" (addr=%lx)\n", src->addr));
|
||||
dst[-1] = *src;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG (AOUTDEBUG | IDDEBUG,
|
||||
printf ("[symtab_finalize] favor %s@%c%c over %s@%c%c",
|
||||
dst[-1].name, dst[-1].is_static ? 't' : 'T',
|
||||
dst[-1].is_func ? 'F' : 'f',
|
||||
src->name, src->is_static ? 't' : 'T',
|
||||
src->is_func ? 'F' : 'f');
|
||||
printf(" (addr=%lx)\n", src->addr));
|
||||
} /* if */
|
||||
} else {
|
||||
if (dst > tab->base && dst[-1].end_addr == 0) {
|
||||
dst[-1].end_addr = src->addr - 1;
|
||||
} /* if */
|
||||
printf (" (addr=%lx)\n", src->addr));
|
||||
} /* if */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dst > tab->base && dst[-1].end_addr == 0)
|
||||
{
|
||||
dst[-1].end_addr = src->addr - 1;
|
||||
} /* if */
|
||||
|
||||
/* retain sym only if it has a non-empty address range: */
|
||||
if (!src->end_addr || src->addr <= src->end_addr) {
|
||||
*dst++ = *src;
|
||||
prev_addr = src->addr;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* if */
|
||||
if (tab->len > 0 && dst[-1].end_addr == 0) {
|
||||
dst[-1].end_addr = core_text_sect->vma + core_text_sect->_raw_size - 1;
|
||||
} /* if */
|
||||
/* retain sym only if it has a non-empty address range: */
|
||||
if (!src->end_addr || src->addr <= src->end_addr)
|
||||
{
|
||||
*dst++ = *src;
|
||||
prev_addr = src->addr;
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* if */
|
||||
if (tab->len > 0 && dst[-1].end_addr == 0)
|
||||
{
|
||||
dst[-1].end_addr = core_text_sect->vma + core_text_sect->_raw_size - 1;
|
||||
} /* if */
|
||||
|
||||
DBG(AOUTDEBUG|IDDEBUG,
|
||||
printf("[symtab_finalize]: removed %d duplicate entries\n",
|
||||
DBG (AOUTDEBUG | IDDEBUG,
|
||||
printf ("[symtab_finalize]: removed %d duplicate entries\n",
|
||||
tab->len - (int) (dst - tab->base)));
|
||||
|
||||
tab->limit = dst;
|
||||
tab->len = tab->limit - tab->base;
|
||||
tab->limit = dst;
|
||||
tab->len = tab->limit - tab->base;
|
||||
|
||||
DBG(AOUTDEBUG|IDDEBUG,
|
||||
int j;
|
||||
DBG (AOUTDEBUG | IDDEBUG,
|
||||
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);
|
||||
} /* for */);
|
||||
} /* symtab_finalize */
|
||||
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);
|
||||
} /* for */
|
||||
);
|
||||
} /* symtab_finalize */
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
Sym*
|
||||
DEFUN(dbg_sym_lookup, (symtab, address), Sym_Table *symtab AND bfd_vma address)
|
||||
Sym *
|
||||
DEFUN (dbg_sym_lookup, (symtab, address), Sym_Table * symtab AND bfd_vma address)
|
||||
{
|
||||
long low, mid, high;
|
||||
Sym *sym;
|
||||
long low, mid, high;
|
||||
Sym *sym;
|
||||
|
||||
fprintf(stderr,"[sym_lookup] address 0x%lx\n", address);
|
||||
|
||||
sym = symtab->base;
|
||||
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",
|
||||
sym[mid].addr, sym[mid + 1].addr);
|
||||
if (sym[mid].addr <= address && sym[mid + 1].addr > address) {
|
||||
return &sym[mid];
|
||||
} /* if */
|
||||
if (sym[mid].addr > address) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
} /* if */
|
||||
} /* for */
|
||||
fprintf(stderr, "[sym_lookup] binary search fails???\n");
|
||||
return 0;
|
||||
} /* dbg_sym_lookup */
|
||||
fprintf (stderr, "[sym_lookup] address 0x%lx\n", address);
|
||||
|
||||
#endif DEBUG
|
||||
sym = symtab->base;
|
||||
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",
|
||||
sym[mid].addr, sym[mid + 1].addr);
|
||||
if (sym[mid].addr <= address && sym[mid + 1].addr > address)
|
||||
{
|
||||
return &sym[mid];
|
||||
} /* if */
|
||||
if (sym[mid].addr > address)
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
low = mid + 1;
|
||||
} /* if */
|
||||
} /* for */
|
||||
fprintf (stderr, "[sym_lookup] binary search fails???\n");
|
||||
return 0;
|
||||
} /* dbg_sym_lookup */
|
||||
|
||||
#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.
|
||||
*/
|
||||
Sym*
|
||||
DEFUN(sym_lookup, (symtab, address), Sym_Table *symtab AND bfd_vma address)
|
||||
Sym *
|
||||
DEFUN (sym_lookup, (symtab, address), Sym_Table * symtab AND bfd_vma address)
|
||||
{
|
||||
long low, high;
|
||||
long mid = -1;
|
||||
Sym *sym;
|
||||
#ifdef DEBUG
|
||||
int probes = 0;
|
||||
long low, high;
|
||||
long mid = -1;
|
||||
Sym *sym;
|
||||
#ifdef DEBUG
|
||||
int probes = 0;
|
||||
#endif /* DEBUG */
|
||||
|
||||
if (!symtab->len) {
|
||||
return 0;
|
||||
} /* if */
|
||||
if (!symtab->len)
|
||||
{
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
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]:
|
||||
*/
|
||||
return 0;
|
||||
} else {
|
||||
DBG(LOOKUPDEBUG,
|
||||
printf("[sym_lookup] %d probes (symtab->len=%d)\n",
|
||||
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]:
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG (LOOKUPDEBUG,
|
||||
printf ("[sym_lookup] %d probes (symtab->len=%d)\n",
|
||||
probes, symtab->len - 1));
|
||||
return &sym[mid];
|
||||
} /* if */
|
||||
} /* if */
|
||||
if (sym[mid].addr > address) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (sym[mid + 1].addr <= address) {
|
||||
if (address > sym[mid + 1].end_addr) {
|
||||
/* address is beyond end of sym[mid + 1]: */
|
||||
return 0;
|
||||
} else {
|
||||
DBG(LOOKUPDEBUG, printf("[sym_lookup] %d (%d) probes, fall off\n",
|
||||
return &sym[mid];
|
||||
} /* if */
|
||||
} /* if */
|
||||
if (sym[mid].addr > address)
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
low = mid + 1;
|
||||
} /* if */
|
||||
} /* for */
|
||||
if (sym[mid + 1].addr <= address)
|
||||
{
|
||||
if (address > sym[mid + 1].end_addr)
|
||||
{
|
||||
/* address is beyond end of sym[mid + 1]: */
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG (LOOKUPDEBUG, printf ("[sym_lookup] %d (%d) probes, fall off\n",
|
||||
probes, symtab->len - 1));
|
||||
return &sym[mid + 1];
|
||||
} /* if */
|
||||
} /* if */
|
||||
return 0;
|
||||
} /* sym_lookup */
|
||||
return &sym[mid + 1];
|
||||
} /* if */
|
||||
} /* if */
|
||||
return 0;
|
||||
} /* sym_lookup */
|
||||
|
||||
/*** end of symtab.c ***/
|
||||
/*** end of symtab.c ***/
|
||||
|
100
gprof/symtab.h
100
gprof/symtab.h
@ -20,7 +20,8 @@
|
||||
* 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 {
|
||||
typedef struct sym
|
||||
{
|
||||
/*
|
||||
* Common information:
|
||||
*
|
||||
@ -28,61 +29,72 @@ typedef struct sym {
|
||||
* 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? */
|
||||
int ncalls; /* how many times executed */
|
||||
struct sym *next; /* for building chains of syms */
|
||||
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? */
|
||||
int ncalls; /* how many times executed */
|
||||
struct sym *next; /* for building chains of syms */
|
||||
|
||||
/* profile-specific information: */
|
||||
|
||||
/* histogram specific info: */
|
||||
struct {
|
||||
double time; /* (weighted) ticks in this routine */
|
||||
bfd_vma scaled_addr; /* scaled entry point */
|
||||
} hist;
|
||||
struct
|
||||
{
|
||||
double time; /* (weighted) ticks in this routine */
|
||||
bfd_vma scaled_addr; /* scaled entry point */
|
||||
}
|
||||
hist;
|
||||
|
||||
/* call-graph specific info: */
|
||||
struct {
|
||||
int 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 */
|
||||
} prop;
|
||||
struct {
|
||||
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 */
|
||||
} cg;
|
||||
} Sym;
|
||||
struct
|
||||
{
|
||||
int 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 */
|
||||
}
|
||||
prop;
|
||||
struct
|
||||
{
|
||||
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 */
|
||||
}
|
||||
cg;
|
||||
}
|
||||
Sym;
|
||||
|
||||
/*
|
||||
* Symbol-tables are always assumed to be sorted in increasing order
|
||||
* of addresses:
|
||||
*/
|
||||
typedef struct {
|
||||
int len; /* # of symbols in this table */
|
||||
Sym *base; /* first element in symbol table */
|
||||
Sym *limit; /* limit = base + len */
|
||||
} Sym_Table;
|
||||
typedef struct
|
||||
{
|
||||
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 sym_init PARAMS ((Sym * sym));
|
||||
extern void symtab_finalize PARAMS ((Sym_Table * symtab));
|
||||
extern Sym *sym_lookup PARAMS ((Sym_Table * symtab, bfd_vma address));
|
||||
|
||||
#endif /* symtab_h */
|
||||
|
496
gprof/tahoe.c
496
gprof/tahoe.c
@ -26,279 +26,293 @@ Sym indirectchild;
|
||||
|
||||
|
||||
operandenum
|
||||
operandmode(modep)
|
||||
unsigned char *modep;
|
||||
operandmode (modep)
|
||||
unsigned char *modep;
|
||||
{
|
||||
long usesreg = ((long)*modep) & 0xf;
|
||||
|
||||
switch (((long)*modep) >> 4) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return literal;
|
||||
case 4:
|
||||
return indexed;
|
||||
case 5:
|
||||
return reg;
|
||||
case 6:
|
||||
return regdef;
|
||||
case 7:
|
||||
return autodec;
|
||||
case 8:
|
||||
return usesreg != 0xe ? autoinc : immediate;
|
||||
case 9:
|
||||
return usesreg != PC ? autoincdef : absolute;
|
||||
case 10:
|
||||
return usesreg != PC ? bytedisp : byterel;
|
||||
case 11:
|
||||
return usesreg != PC ? bytedispdef : bytereldef;
|
||||
case 12:
|
||||
return usesreg != PC ? worddisp : wordrel;
|
||||
case 13:
|
||||
return usesreg != PC ? worddispdef : wordreldef;
|
||||
case 14:
|
||||
return usesreg != PC ? longdisp : longrel;
|
||||
case 15:
|
||||
return usesreg != PC ? longdispdef : longreldef;
|
||||
long usesreg = ((long) *modep) & 0xf;
|
||||
|
||||
switch (((long) *modep) >> 4)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return literal;
|
||||
case 4:
|
||||
return indexed;
|
||||
case 5:
|
||||
return reg;
|
||||
case 6:
|
||||
return regdef;
|
||||
case 7:
|
||||
return autodec;
|
||||
case 8:
|
||||
return usesreg != 0xe ? autoinc : immediate;
|
||||
case 9:
|
||||
return usesreg != PC ? autoincdef : absolute;
|
||||
case 10:
|
||||
return usesreg != PC ? bytedisp : byterel;
|
||||
case 11:
|
||||
return usesreg != PC ? bytedispdef : bytereldef;
|
||||
case 12:
|
||||
return usesreg != PC ? worddisp : wordrel;
|
||||
case 13:
|
||||
return usesreg != PC ? worddispdef : wordreldef;
|
||||
case 14:
|
||||
return usesreg != PC ? longdisp : longrel;
|
||||
case 15:
|
||||
return usesreg != PC ? longdispdef : longreldef;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
char *
|
||||
operandname(mode)
|
||||
operandenum mode;
|
||||
operandname (mode)
|
||||
operandenum mode;
|
||||
{
|
||||
|
||||
switch (mode) {
|
||||
case literal:
|
||||
return "literal";
|
||||
case indexed:
|
||||
return "indexed";
|
||||
case reg:
|
||||
return "register";
|
||||
case regdef:
|
||||
return "register deferred";
|
||||
case autodec:
|
||||
return "autodecrement";
|
||||
case autoinc:
|
||||
return "autoincrement";
|
||||
case autoincdef:
|
||||
return "autoincrement deferred";
|
||||
case bytedisp:
|
||||
return "byte displacement";
|
||||
case bytedispdef:
|
||||
return "byte displacement deferred";
|
||||
case byterel:
|
||||
return "byte relative";
|
||||
case bytereldef:
|
||||
return "byte relative deferred";
|
||||
case worddisp:
|
||||
return "word displacement";
|
||||
case worddispdef:
|
||||
return "word displacement deferred";
|
||||
case wordrel:
|
||||
return "word relative";
|
||||
case wordreldef:
|
||||
return "word relative deferred";
|
||||
case immediate:
|
||||
return "immediate";
|
||||
case absolute:
|
||||
return "absolute";
|
||||
case longdisp:
|
||||
return "long displacement";
|
||||
case longdispdef:
|
||||
return "long displacement deferred";
|
||||
case longrel:
|
||||
return "long relative";
|
||||
case longreldef:
|
||||
return "long relative deferred";
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case literal:
|
||||
return "literal";
|
||||
case indexed:
|
||||
return "indexed";
|
||||
case reg:
|
||||
return "register";
|
||||
case regdef:
|
||||
return "register deferred";
|
||||
case autodec:
|
||||
return "autodecrement";
|
||||
case autoinc:
|
||||
return "autoincrement";
|
||||
case autoincdef:
|
||||
return "autoincrement deferred";
|
||||
case bytedisp:
|
||||
return "byte displacement";
|
||||
case bytedispdef:
|
||||
return "byte displacement deferred";
|
||||
case byterel:
|
||||
return "byte relative";
|
||||
case bytereldef:
|
||||
return "byte relative deferred";
|
||||
case worddisp:
|
||||
return "word displacement";
|
||||
case worddispdef:
|
||||
return "word displacement deferred";
|
||||
case wordrel:
|
||||
return "word relative";
|
||||
case wordreldef:
|
||||
return "word relative deferred";
|
||||
case immediate:
|
||||
return "immediate";
|
||||
case absolute:
|
||||
return "absolute";
|
||||
case longdisp:
|
||||
return "long displacement";
|
||||
case longdispdef:
|
||||
return "long displacement deferred";
|
||||
case longrel:
|
||||
return "long relative";
|
||||
case longreldef:
|
||||
return "long relative deferred";
|
||||
}
|
||||
/* NOTREACHED */
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
long
|
||||
operandlength(modep)
|
||||
unsigned char *modep;
|
||||
operandlength (modep)
|
||||
unsigned char *modep;
|
||||
{
|
||||
|
||||
switch (operandmode(modep)) {
|
||||
case literal:
|
||||
case reg:
|
||||
case regdef:
|
||||
case autodec:
|
||||
case autoinc:
|
||||
case autoincdef:
|
||||
return 1;
|
||||
case bytedisp:
|
||||
case bytedispdef:
|
||||
case byterel:
|
||||
case bytereldef:
|
||||
return 2;
|
||||
case worddisp:
|
||||
case worddispdef:
|
||||
case wordrel:
|
||||
case wordreldef:
|
||||
return 3;
|
||||
case immediate:
|
||||
case absolute:
|
||||
case longdisp:
|
||||
case longdispdef:
|
||||
case longrel:
|
||||
case longreldef:
|
||||
return 5;
|
||||
case indexed:
|
||||
return 1+operandlength(modep + 1);
|
||||
|
||||
switch (operandmode (modep))
|
||||
{
|
||||
case literal:
|
||||
case reg:
|
||||
case regdef:
|
||||
case autodec:
|
||||
case autoinc:
|
||||
case autoincdef:
|
||||
return 1;
|
||||
case bytedisp:
|
||||
case bytedispdef:
|
||||
case byterel:
|
||||
case bytereldef:
|
||||
return 2;
|
||||
case worddisp:
|
||||
case worddispdef:
|
||||
case wordrel:
|
||||
case wordreldef:
|
||||
return 3;
|
||||
case immediate:
|
||||
case absolute:
|
||||
case longdisp:
|
||||
case longdispdef:
|
||||
case longrel:
|
||||
case longreldef:
|
||||
return 5;
|
||||
case indexed:
|
||||
return 1 + operandlength (modep + 1);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
bfd_vma
|
||||
reladdr(modep)
|
||||
char *modep;
|
||||
reladdr (modep)
|
||||
char *modep;
|
||||
{
|
||||
operandenum mode = operandmode(modep);
|
||||
char *cp;
|
||||
short *sp;
|
||||
long *lp;
|
||||
int i;
|
||||
long value = 0;
|
||||
operandenum mode = operandmode (modep);
|
||||
char *cp;
|
||||
short *sp;
|
||||
long *lp;
|
||||
int i;
|
||||
long value = 0;
|
||||
|
||||
cp = modep;
|
||||
++cp; /* skip over the mode */
|
||||
switch (mode) {
|
||||
default:
|
||||
fprintf(stderr, "[reladdr] not relative address\n");
|
||||
return (bfd_vma) modep;
|
||||
case byterel:
|
||||
return (bfd_vma) (cp + sizeof *cp + *cp);
|
||||
case wordrel:
|
||||
for (i = 0; i < sizeof *sp; i++)
|
||||
value = (value << 8) + (cp[i] & 0xff);
|
||||
return (bfd_vma) (cp + sizeof *sp + value);
|
||||
case longrel:
|
||||
for (i = 0; i < sizeof *lp; i++)
|
||||
value = (value << 8) + (cp[i] & 0xff);
|
||||
return (bfd_vma) (cp + sizeof *lp + value);
|
||||
cp = modep;
|
||||
++cp; /* skip over the mode */
|
||||
switch (mode)
|
||||
{
|
||||
default:
|
||||
fprintf (stderr, "[reladdr] not relative address\n");
|
||||
return (bfd_vma) modep;
|
||||
case byterel:
|
||||
return (bfd_vma) (cp + sizeof *cp + *cp);
|
||||
case wordrel:
|
||||
for (i = 0; i < sizeof *sp; i++)
|
||||
value = (value << 8) + (cp[i] & 0xff);
|
||||
return (bfd_vma) (cp + sizeof *sp + value);
|
||||
case longrel:
|
||||
for (i = 0; i < sizeof *lp; i++)
|
||||
value = (value << 8) + (cp[i] & 0xff);
|
||||
return (bfd_vma) (cp + sizeof *lp + value);
|
||||
}
|
||||
}
|
||||
|
||||
find_call(parent, p_lowpc, p_highpc)
|
||||
find_call (parent, p_lowpc, p_highpc)
|
||||
Sym *parent;
|
||||
bfd_vma p_lowpc;
|
||||
bfd_vma p_highpc;
|
||||
{
|
||||
unsigned char *instructp;
|
||||
long length;
|
||||
Sym *child;
|
||||
operandenum mode;
|
||||
operandenum firstmode;
|
||||
bfd_vma destpc;
|
||||
static bool inited = FALSE;
|
||||
unsigned char *instructp;
|
||||
long length;
|
||||
Sym *child;
|
||||
operandenum mode;
|
||||
operandenum firstmode;
|
||||
bfd_vma destpc;
|
||||
static bool inited = FALSE;
|
||||
|
||||
if (!inited) {
|
||||
inited = TRUE;
|
||||
sym_init(&indirectchild);
|
||||
indirectchild.cg.prop.fract = 1.0;
|
||||
indirectchild.cg.cyc.head = &indirectchild;
|
||||
} /* if */
|
||||
if (!inited)
|
||||
{
|
||||
inited = TRUE;
|
||||
sym_init (&indirectchild);
|
||||
indirectchild.cg.prop.fract = 1.0;
|
||||
indirectchild.cg.cyc.head = &indirectchild;
|
||||
} /* if */
|
||||
|
||||
if (textspace == 0) {
|
||||
return;
|
||||
if (textspace == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (p_lowpc < s_lowpc) {
|
||||
p_lowpc = s_lowpc;
|
||||
if (p_lowpc < s_lowpc)
|
||||
{
|
||||
p_lowpc = s_lowpc;
|
||||
}
|
||||
if (p_highpc > s_highpc) {
|
||||
p_highpc = s_highpc;
|
||||
if (p_highpc > s_highpc)
|
||||
{
|
||||
p_highpc = s_highpc;
|
||||
}
|
||||
DBG(CALLDEBUG, printf("[findcall] %s: 0x%x to 0x%x\n",
|
||||
parent -> name, p_lowpc, p_highpc));
|
||||
for ( instructp = textspace + p_lowpc ;
|
||||
instructp < textspace + p_highpc ;
|
||||
instructp += length) {
|
||||
length = 1;
|
||||
if (*instructp == CALLF) {
|
||||
/*
|
||||
* maybe a callf, better check it out.
|
||||
* skip the count of the number of arguments.
|
||||
*/
|
||||
DBG(CALLDEBUG, printf("[findcall]\t0x%x:callf",
|
||||
DBG (CALLDEBUG, printf ("[findcall] %s: 0x%x to 0x%x\n",
|
||||
parent->name, p_lowpc, p_highpc));
|
||||
for (instructp = textspace + p_lowpc;
|
||||
instructp < textspace + p_highpc;
|
||||
instructp += length)
|
||||
{
|
||||
length = 1;
|
||||
if (*instructp == CALLF)
|
||||
{
|
||||
/*
|
||||
* maybe a callf, better check it out.
|
||||
* skip the count of the number of arguments.
|
||||
*/
|
||||
DBG (CALLDEBUG, printf ("[findcall]\t0x%x:callf",
|
||||
instructp - textspace));
|
||||
firstmode = operandmode(instructp+length);
|
||||
switch (firstmode) {
|
||||
case literal:
|
||||
case immediate:
|
||||
break;
|
||||
default:
|
||||
goto botched;
|
||||
firstmode = operandmode (instructp + length);
|
||||
switch (firstmode)
|
||||
{
|
||||
case literal:
|
||||
case immediate:
|
||||
break;
|
||||
default:
|
||||
goto botched;
|
||||
}
|
||||
length += operandlength(instructp+length);
|
||||
mode = operandmode(instructp + length);
|
||||
DBG(CALLDEBUG,
|
||||
printf("\tfirst operand is %s", operandname(firstmode));
|
||||
printf("\tsecond operand is %s\n", operandname(mode));
|
||||
);
|
||||
switch (mode) {
|
||||
case regdef:
|
||||
case bytedispdef:
|
||||
case worddispdef:
|
||||
case longdispdef:
|
||||
case bytereldef:
|
||||
case wordreldef:
|
||||
case longreldef:
|
||||
/*
|
||||
* indirect call: call through pointer
|
||||
* either *d(r) as a parameter or local
|
||||
* (r) as a return value
|
||||
* *f as a global pointer
|
||||
* [are there others that we miss?,
|
||||
* e.g. arrays of pointers to functions???]
|
||||
*/
|
||||
arc_add(parent, &indirectchild, (long) 0);
|
||||
length += operandlength(instructp + length);
|
||||
continue;
|
||||
case byterel:
|
||||
case wordrel:
|
||||
case longrel:
|
||||
/*
|
||||
* regular pc relative addressing
|
||||
* check that this is the address of
|
||||
* a function.
|
||||
*/
|
||||
destpc = reladdr(instructp+length)
|
||||
- (bfd_vma) textspace;
|
||||
if (destpc >= s_lowpc && destpc <= s_highpc) {
|
||||
child = sym_lookup(destpc);
|
||||
DBG(CALLDEBUG,
|
||||
printf("[findcall]\tdestpc 0x%x", destpc);
|
||||
printf(" child->name %s", child -> name);
|
||||
printf(" child->addr 0x%x\n", child -> addr);
|
||||
);
|
||||
if (child -> addr == destpc) {
|
||||
/*
|
||||
* a hit
|
||||
*/
|
||||
arc_add(parent, child, (long) 0);
|
||||
length += operandlength(instructp + length);
|
||||
continue;
|
||||
}
|
||||
goto botched;
|
||||
length += operandlength (instructp + length);
|
||||
mode = operandmode (instructp + length);
|
||||
DBG (CALLDEBUG,
|
||||
printf ("\tfirst operand is %s", operandname (firstmode));
|
||||
printf ("\tsecond operand is %s\n", operandname (mode));
|
||||
);
|
||||
switch (mode)
|
||||
{
|
||||
case regdef:
|
||||
case bytedispdef:
|
||||
case worddispdef:
|
||||
case longdispdef:
|
||||
case bytereldef:
|
||||
case wordreldef:
|
||||
case longreldef:
|
||||
/*
|
||||
* indirect call: call through pointer
|
||||
* either *d(r) as a parameter or local
|
||||
* (r) as a return value
|
||||
* *f as a global pointer
|
||||
* [are there others that we miss?,
|
||||
* e.g. arrays of pointers to functions???]
|
||||
*/
|
||||
arc_add (parent, &indirectchild, (long) 0);
|
||||
length += operandlength (instructp + length);
|
||||
continue;
|
||||
case byterel:
|
||||
case wordrel:
|
||||
case longrel:
|
||||
/*
|
||||
* regular pc relative addressing
|
||||
* check that this is the address of
|
||||
* a function.
|
||||
*/
|
||||
destpc = reladdr (instructp + length)
|
||||
- (bfd_vma) textspace;
|
||||
if (destpc >= s_lowpc && destpc <= s_highpc)
|
||||
{
|
||||
child = sym_lookup (destpc);
|
||||
DBG (CALLDEBUG,
|
||||
printf ("[findcall]\tdestpc 0x%x", destpc);
|
||||
printf (" child->name %s", child->name);
|
||||
printf (" child->addr 0x%x\n", child->addr);
|
||||
);
|
||||
if (child->addr == destpc)
|
||||
{
|
||||
/*
|
||||
* a hit
|
||||
*/
|
||||
arc_add (parent, child, (long) 0);
|
||||
length += operandlength (instructp + length);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* else:
|
||||
* it looked like a callf,
|
||||
* but it wasn't to anywhere.
|
||||
*/
|
||||
goto botched;
|
||||
default:
|
||||
botched:
|
||||
/*
|
||||
* something funny going on.
|
||||
*/
|
||||
DBG(CALLDEBUG, printf("[findcall]\tbut it's a botch\n"));
|
||||
length = 1;
|
||||
continue;
|
||||
goto botched;
|
||||
}
|
||||
/*
|
||||
* else:
|
||||
* it looked like a callf,
|
||||
* but it wasn't to anywhere.
|
||||
*/
|
||||
goto botched;
|
||||
default:
|
||||
botched:
|
||||
/*
|
||||
* something funny going on.
|
||||
*/
|
||||
DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
|
||||
length = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,30 +16,31 @@
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* @(#)tahoe.h 1.4 (Berkeley) 6/1/90
|
||||
* @(#)tahoe.h 1.4 (Berkeley) 6/1/90
|
||||
*/
|
||||
|
||||
/*
|
||||
* opcode of the `callf' instruction
|
||||
* opcode of the `callf' instruction
|
||||
*/
|
||||
#define CALLF 0xfe
|
||||
|
||||
/*
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
*/
|
||||
#define OFFSET_TO_CODE 2
|
||||
#define UNITS_TO_CODE (OFFSET_TO_CODE / sizeof(UNIT))
|
||||
|
||||
/*
|
||||
* register for pc relative addressing
|
||||
* register for pc relative addressing
|
||||
*/
|
||||
#define PC 0xf
|
||||
|
||||
enum opermodes {
|
||||
literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
|
||||
enum opermodes
|
||||
{
|
||||
literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
|
||||
bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
|
||||
immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
|
||||
longrel, longreldef
|
||||
};
|
||||
typedef enum opermodes operandenum;
|
||||
};
|
||||
typedef enum opermodes operandenum;
|
||||
|
123
gprof/utils.c
123
gprof/utils.c
@ -26,65 +26,80 @@
|
||||
* Print name of symbol. Return number of characters printed.
|
||||
*/
|
||||
int
|
||||
DEFUN(print_name_only, (self), Sym *self)
|
||||
DEFUN (print_name_only, (self), Sym * self)
|
||||
{
|
||||
const char *name = self->name;
|
||||
const char *filename;
|
||||
char *demangled = 0;
|
||||
char buf[PATH_MAX];
|
||||
int size = 0;
|
||||
const char *name = self->name;
|
||||
const char *filename;
|
||||
char *demangled = 0;
|
||||
char buf[PATH_MAX];
|
||||
int size = 0;
|
||||
|
||||
if (name) {
|
||||
if (!bsd_style_output) {
|
||||
if (name[0] == '_' && name[1] && discard_underscores) {
|
||||
name++;
|
||||
} /* if */
|
||||
demangled = cplus_demangle(name, DMGL_ANSI|DMGL_PARAMS);
|
||||
if (demangled) {
|
||||
name = demangled;
|
||||
} /* if */
|
||||
} /* if */
|
||||
printf("%s", name);
|
||||
size = strlen(name);
|
||||
if (line_granularity && self->file) {
|
||||
filename = self->file->name;
|
||||
if (!print_path) {
|
||||
filename = strrchr(filename, '/');
|
||||
if (filename) {
|
||||
++filename;
|
||||
} else {
|
||||
filename = self->file->name;
|
||||
} /* if */
|
||||
} /* if */
|
||||
sprintf(buf, " (%s:%d)", filename, self->line_num);
|
||||
printf(buf);
|
||||
size += strlen(buf);
|
||||
} /* if */
|
||||
if (demangled) {
|
||||
free(demangled);
|
||||
} /* if */
|
||||
DBG(DFNDEBUG, printf("{%d} ", self->cg.top_order));
|
||||
DBG(PROPDEBUG, printf("%4.0f%% ", 100.0 * self->cg.prop.fract));
|
||||
} /* if */
|
||||
return size;
|
||||
} /* print_name_only */
|
||||
if (name)
|
||||
{
|
||||
if (!bsd_style_output)
|
||||
{
|
||||
if (name[0] == '_' && name[1] && discard_underscores)
|
||||
{
|
||||
name++;
|
||||
} /* if */
|
||||
demangled = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS);
|
||||
if (demangled)
|
||||
{
|
||||
name = demangled;
|
||||
} /* if */
|
||||
} /* if */
|
||||
printf ("%s", name);
|
||||
size = strlen (name);
|
||||
if (line_granularity && self->file)
|
||||
{
|
||||
filename = self->file->name;
|
||||
if (!print_path)
|
||||
{
|
||||
filename = strrchr (filename, '/');
|
||||
if (filename)
|
||||
{
|
||||
++filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = self->file->name;
|
||||
} /* if */
|
||||
} /* if */
|
||||
sprintf (buf, " (%s:%d)", filename, self->line_num);
|
||||
printf (buf);
|
||||
size += strlen (buf);
|
||||
} /* if */
|
||||
if (demangled)
|
||||
{
|
||||
free (demangled);
|
||||
} /* if */
|
||||
DBG (DFNDEBUG, printf ("{%d} ", self->cg.top_order));
|
||||
DBG (PROPDEBUG, printf ("%4.0f%% ", 100.0 * self->cg.prop.fract));
|
||||
} /* if */
|
||||
return size;
|
||||
} /* print_name_only */
|
||||
|
||||
|
||||
void
|
||||
DEFUN(print_name, (self), Sym *self)
|
||||
DEFUN (print_name, (self), Sym * self)
|
||||
{
|
||||
print_name_only(self);
|
||||
print_name_only (self);
|
||||
|
||||
if (self->cg.cyc.num != 0) {
|
||||
printf(" <cycle %d>", self->cg.cyc.num);
|
||||
} /* if */
|
||||
if (self->cg.index != 0) {
|
||||
if (self->cg.print_flag) {
|
||||
printf(" [%d]", self->cg.index);
|
||||
} else {
|
||||
printf(" (%d)", self->cg.index);
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* print_name */
|
||||
if (self->cg.cyc.num != 0)
|
||||
{
|
||||
printf (" <cycle %d>", self->cg.cyc.num);
|
||||
} /* if */
|
||||
if (self->cg.index != 0)
|
||||
{
|
||||
if (self->cg.print_flag)
|
||||
{
|
||||
printf (" [%d]", self->cg.index);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" (%d)", self->cg.index);
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* print_name */
|
||||
|
||||
/*** end of utils.c ***/
|
||||
/*** end of utils.c ***/
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef utils_h
|
||||
#define utils_h
|
||||
|
||||
extern int print_name_only PARAMS((Sym *self));
|
||||
extern void print_name PARAMS((Sym *self));
|
||||
extern int print_name_only PARAMS ((Sym * self));
|
||||
extern void print_name PARAMS ((Sym * self));
|
||||
|
||||
#endif /* utils_h */
|
||||
|
492
gprof/vax.c
492
gprof/vax.c
@ -30,279 +30,293 @@ Sym indirectchild;
|
||||
|
||||
|
||||
static operandenum
|
||||
operandmode(modep)
|
||||
struct modebyte *modep;
|
||||
operandmode (modep)
|
||||
struct modebyte *modep;
|
||||
{
|
||||
long usesreg = modep->regfield;
|
||||
|
||||
switch (modep->modefield) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return literal;
|
||||
case 4:
|
||||
return indexed;
|
||||
case 5:
|
||||
return reg;
|
||||
case 6:
|
||||
return regdef;
|
||||
case 7:
|
||||
return autodec;
|
||||
case 8:
|
||||
return usesreg != PC ? autoinc : immediate;
|
||||
case 9:
|
||||
return usesreg != PC ? autoincdef : absolute;
|
||||
case 10:
|
||||
return usesreg != PC ? bytedisp : byterel;
|
||||
case 11:
|
||||
return usesreg != PC ? bytedispdef : bytereldef;
|
||||
case 12:
|
||||
return usesreg != PC ? worddisp : wordrel;
|
||||
case 13:
|
||||
return usesreg != PC ? worddispdef : wordreldef;
|
||||
case 14:
|
||||
return usesreg != PC ? longdisp : longrel;
|
||||
case 15:
|
||||
return usesreg != PC ? longdispdef : longreldef;
|
||||
long usesreg = modep->regfield;
|
||||
|
||||
switch (modep->modefield)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return literal;
|
||||
case 4:
|
||||
return indexed;
|
||||
case 5:
|
||||
return reg;
|
||||
case 6:
|
||||
return regdef;
|
||||
case 7:
|
||||
return autodec;
|
||||
case 8:
|
||||
return usesreg != PC ? autoinc : immediate;
|
||||
case 9:
|
||||
return usesreg != PC ? autoincdef : absolute;
|
||||
case 10:
|
||||
return usesreg != PC ? bytedisp : byterel;
|
||||
case 11:
|
||||
return usesreg != PC ? bytedispdef : bytereldef;
|
||||
case 12:
|
||||
return usesreg != PC ? worddisp : wordrel;
|
||||
case 13:
|
||||
return usesreg != PC ? worddispdef : wordreldef;
|
||||
case 14:
|
||||
return usesreg != PC ? longdisp : longrel;
|
||||
case 15:
|
||||
return usesreg != PC ? longdispdef : longreldef;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static char *
|
||||
operandname(mode)
|
||||
operandenum mode;
|
||||
operandname (mode)
|
||||
operandenum mode;
|
||||
{
|
||||
|
||||
switch (mode) {
|
||||
case literal:
|
||||
return "literal";
|
||||
case indexed:
|
||||
return "indexed";
|
||||
case reg:
|
||||
return "register";
|
||||
case regdef:
|
||||
return "register deferred";
|
||||
case autodec:
|
||||
return "autodecrement";
|
||||
case autoinc:
|
||||
return "autoincrement";
|
||||
case autoincdef:
|
||||
return "autoincrement deferred";
|
||||
case bytedisp:
|
||||
return "byte displacement";
|
||||
case bytedispdef:
|
||||
return "byte displacement deferred";
|
||||
case byterel:
|
||||
return "byte relative";
|
||||
case bytereldef:
|
||||
return "byte relative deferred";
|
||||
case worddisp:
|
||||
return "word displacement";
|
||||
case worddispdef:
|
||||
return "word displacement deferred";
|
||||
case wordrel:
|
||||
return "word relative";
|
||||
case wordreldef:
|
||||
return "word relative deferred";
|
||||
case immediate:
|
||||
return "immediate";
|
||||
case absolute:
|
||||
return "absolute";
|
||||
case longdisp:
|
||||
return "long displacement";
|
||||
case longdispdef:
|
||||
return "long displacement deferred";
|
||||
case longrel:
|
||||
return "long relative";
|
||||
case longreldef:
|
||||
return "long relative deferred";
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case literal:
|
||||
return "literal";
|
||||
case indexed:
|
||||
return "indexed";
|
||||
case reg:
|
||||
return "register";
|
||||
case regdef:
|
||||
return "register deferred";
|
||||
case autodec:
|
||||
return "autodecrement";
|
||||
case autoinc:
|
||||
return "autoincrement";
|
||||
case autoincdef:
|
||||
return "autoincrement deferred";
|
||||
case bytedisp:
|
||||
return "byte displacement";
|
||||
case bytedispdef:
|
||||
return "byte displacement deferred";
|
||||
case byterel:
|
||||
return "byte relative";
|
||||
case bytereldef:
|
||||
return "byte relative deferred";
|
||||
case worddisp:
|
||||
return "word displacement";
|
||||
case worddispdef:
|
||||
return "word displacement deferred";
|
||||
case wordrel:
|
||||
return "word relative";
|
||||
case wordreldef:
|
||||
return "word relative deferred";
|
||||
case immediate:
|
||||
return "immediate";
|
||||
case absolute:
|
||||
return "absolute";
|
||||
case longdisp:
|
||||
return "long displacement";
|
||||
case longdispdef:
|
||||
return "long displacement deferred";
|
||||
case longrel:
|
||||
return "long relative";
|
||||
case longreldef:
|
||||
return "long relative deferred";
|
||||
}
|
||||
/* NOTREACHED */
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static long
|
||||
operandlength(modep)
|
||||
struct modebyte *modep;
|
||||
operandlength (modep)
|
||||
struct modebyte *modep;
|
||||
{
|
||||
|
||||
switch (operandmode(modep)) {
|
||||
case literal:
|
||||
case reg:
|
||||
case regdef:
|
||||
case autodec:
|
||||
case autoinc:
|
||||
case autoincdef:
|
||||
return 1;
|
||||
case bytedisp:
|
||||
case bytedispdef:
|
||||
case byterel:
|
||||
case bytereldef:
|
||||
return 2;
|
||||
case worddisp:
|
||||
case worddispdef:
|
||||
case wordrel:
|
||||
case wordreldef:
|
||||
return 3;
|
||||
case immediate:
|
||||
case absolute:
|
||||
case longdisp:
|
||||
case longdispdef:
|
||||
case longrel:
|
||||
case longreldef:
|
||||
return 5;
|
||||
case indexed:
|
||||
return 1+operandlength((struct modebyte *) ((char *) modep) + 1);
|
||||
|
||||
switch (operandmode (modep))
|
||||
{
|
||||
case literal:
|
||||
case reg:
|
||||
case regdef:
|
||||
case autodec:
|
||||
case autoinc:
|
||||
case autoincdef:
|
||||
return 1;
|
||||
case bytedisp:
|
||||
case bytedispdef:
|
||||
case byterel:
|
||||
case bytereldef:
|
||||
return 2;
|
||||
case worddisp:
|
||||
case worddispdef:
|
||||
case wordrel:
|
||||
case wordreldef:
|
||||
return 3;
|
||||
case immediate:
|
||||
case absolute:
|
||||
case longdisp:
|
||||
case longdispdef:
|
||||
case longrel:
|
||||
case longreldef:
|
||||
return 5;
|
||||
case indexed:
|
||||
return 1 + operandlength ((struct modebyte *) ((char *) modep) + 1);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static bfd_vma
|
||||
reladdr(modep)
|
||||
struct modebyte *modep;
|
||||
reladdr (modep)
|
||||
struct modebyte *modep;
|
||||
{
|
||||
operandenum mode = operandmode(modep);
|
||||
char *cp;
|
||||
short *sp;
|
||||
long *lp;
|
||||
operandenum mode = operandmode (modep);
|
||||
char *cp;
|
||||
short *sp;
|
||||
long *lp;
|
||||
|
||||
cp = (char *) modep;
|
||||
++cp; /* skip over the mode */
|
||||
switch (mode) {
|
||||
default:
|
||||
fprintf(stderr, "[reladdr] not relative address\n");
|
||||
return (bfd_vma) modep;
|
||||
case byterel:
|
||||
return (bfd_vma) (cp + sizeof *cp + *cp);
|
||||
case wordrel:
|
||||
sp = (short *) cp;
|
||||
return (bfd_vma) (cp + sizeof *sp + *sp);
|
||||
case longrel:
|
||||
lp = (long *) cp;
|
||||
return (bfd_vma) (cp + sizeof *lp + *lp);
|
||||
cp = (char *) modep;
|
||||
++cp; /* skip over the mode */
|
||||
switch (mode)
|
||||
{
|
||||
default:
|
||||
fprintf (stderr, "[reladdr] not relative address\n");
|
||||
return (bfd_vma) modep;
|
||||
case byterel:
|
||||
return (bfd_vma) (cp + sizeof *cp + *cp);
|
||||
case wordrel:
|
||||
sp = (short *) cp;
|
||||
return (bfd_vma) (cp + sizeof *sp + *sp);
|
||||
case longrel:
|
||||
lp = (long *) cp;
|
||||
return (bfd_vma) (cp + sizeof *lp + *lp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
find_call(parent, p_lowpc, p_highpc)
|
||||
find_call (parent, p_lowpc, p_highpc)
|
||||
Sym *parent;
|
||||
bfd_vma p_lowpc;
|
||||
bfd_vma p_highpc;
|
||||
{
|
||||
unsigned char *instructp;
|
||||
long length;
|
||||
Sym *child;
|
||||
operandenum mode;
|
||||
operandenum firstmode;
|
||||
bfd_vma destpc;
|
||||
static bool inited = FALSE;
|
||||
unsigned char *instructp;
|
||||
long length;
|
||||
Sym *child;
|
||||
operandenum mode;
|
||||
operandenum firstmode;
|
||||
bfd_vma destpc;
|
||||
static bool inited = FALSE;
|
||||
|
||||
if (!inited) {
|
||||
inited = TRUE;
|
||||
sym_init(&indirectchild);
|
||||
indirectchild.cg.prop.fract = 1.0;
|
||||
indirectchild.cg.cyc.head = &indirectchild;
|
||||
} /* if */
|
||||
if (!inited)
|
||||
{
|
||||
inited = TRUE;
|
||||
sym_init (&indirectchild);
|
||||
indirectchild.cg.prop.fract = 1.0;
|
||||
indirectchild.cg.cyc.head = &indirectchild;
|
||||
} /* if */
|
||||
|
||||
if (core_text_space == 0) {
|
||||
return;
|
||||
if (core_text_space == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (p_lowpc < s_lowpc) {
|
||||
p_lowpc = s_lowpc;
|
||||
if (p_lowpc < s_lowpc)
|
||||
{
|
||||
p_lowpc = s_lowpc;
|
||||
}
|
||||
if (p_highpc > s_highpc) {
|
||||
p_highpc = s_highpc;
|
||||
if (p_highpc > s_highpc)
|
||||
{
|
||||
p_highpc = s_highpc;
|
||||
}
|
||||
DBG(CALLDEBUG, printf("[findcall] %s: 0x%lx to 0x%lx\n",
|
||||
DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
|
||||
parent->name, p_lowpc, p_highpc));
|
||||
for ( instructp = (unsigned char*) core_text_space + p_lowpc ;
|
||||
instructp < (unsigned char*) core_text_space + p_highpc ;
|
||||
instructp += length) {
|
||||
length = 1;
|
||||
if (*instructp == CALLS) {
|
||||
/*
|
||||
* maybe a calls, better check it out.
|
||||
* skip the count of the number of arguments.
|
||||
*/
|
||||
DBG(CALLDEBUG,
|
||||
printf("[findcall]\t0x%x:calls",
|
||||
instructp - (unsigned char*) core_text_space));
|
||||
firstmode = operandmode((struct modebyte *) (instructp+length));
|
||||
switch (firstmode) {
|
||||
case literal:
|
||||
case immediate:
|
||||
break;
|
||||
default:
|
||||
goto botched;
|
||||
for (instructp = (unsigned char *) core_text_space + p_lowpc;
|
||||
instructp < (unsigned char *) core_text_space + p_highpc;
|
||||
instructp += length)
|
||||
{
|
||||
length = 1;
|
||||
if (*instructp == CALLS)
|
||||
{
|
||||
/*
|
||||
* maybe a calls, better check it out.
|
||||
* skip the count of the number of arguments.
|
||||
*/
|
||||
DBG (CALLDEBUG,
|
||||
printf ("[findcall]\t0x%x:calls",
|
||||
instructp - (unsigned char *) core_text_space));
|
||||
firstmode = operandmode ((struct modebyte *) (instructp + length));
|
||||
switch (firstmode)
|
||||
{
|
||||
case literal:
|
||||
case immediate:
|
||||
break;
|
||||
default:
|
||||
goto botched;
|
||||
}
|
||||
length += operandlength((struct modebyte *) (instructp+length));
|
||||
mode = operandmode((struct modebyte *) (instructp + length));
|
||||
DBG(CALLDEBUG,
|
||||
printf("\tfirst operand is %s", operandname(firstmode));
|
||||
printf("\tsecond operand is %s\n", operandname(mode)));
|
||||
switch (mode) {
|
||||
case regdef:
|
||||
case bytedispdef:
|
||||
case worddispdef:
|
||||
case longdispdef:
|
||||
case bytereldef:
|
||||
case wordreldef:
|
||||
case longreldef:
|
||||
/*
|
||||
* indirect call: call through pointer
|
||||
* either *d(r) as a parameter or local
|
||||
* (r) as a return value
|
||||
* *f as a global pointer
|
||||
* [are there others that we miss?,
|
||||
* e.g. arrays of pointers to functions???]
|
||||
*/
|
||||
arc_add(parent, &indirectchild, (long) 0);
|
||||
length += operandlength(
|
||||
(struct modebyte *) (instructp + length));
|
||||
continue;
|
||||
case byterel:
|
||||
case wordrel:
|
||||
case longrel:
|
||||
/*
|
||||
* regular pc relative addressing
|
||||
* check that this is the address of
|
||||
* a function.
|
||||
*/
|
||||
destpc = reladdr((struct modebyte *) (instructp+length))
|
||||
- (bfd_vma) core_text_space;
|
||||
if (destpc >= s_lowpc && destpc <= s_highpc) {
|
||||
child = sym_lookup(&symtab, destpc);
|
||||
DBG(CALLDEBUG,
|
||||
printf("[findcall]\tdestpc 0x%lx", destpc);
|
||||
printf(" child->name %s", child->name);
|
||||
printf(" child->addr 0x%lx\n", child->addr);
|
||||
);
|
||||
if (child->addr == destpc) {
|
||||
/*
|
||||
* a hit
|
||||
*/
|
||||
arc_add(parent, child, (long) 0);
|
||||
length += operandlength((struct modebyte *)
|
||||
(instructp + length));
|
||||
continue;
|
||||
}
|
||||
goto botched;
|
||||
length += operandlength ((struct modebyte *) (instructp + length));
|
||||
mode = operandmode ((struct modebyte *) (instructp + length));
|
||||
DBG (CALLDEBUG,
|
||||
printf ("\tfirst operand is %s", operandname (firstmode));
|
||||
printf ("\tsecond operand is %s\n", operandname (mode)));
|
||||
switch (mode)
|
||||
{
|
||||
case regdef:
|
||||
case bytedispdef:
|
||||
case worddispdef:
|
||||
case longdispdef:
|
||||
case bytereldef:
|
||||
case wordreldef:
|
||||
case longreldef:
|
||||
/*
|
||||
* indirect call: call through pointer
|
||||
* either *d(r) as a parameter or local
|
||||
* (r) as a return value
|
||||
* *f as a global pointer
|
||||
* [are there others that we miss?,
|
||||
* e.g. arrays of pointers to functions???]
|
||||
*/
|
||||
arc_add (parent, &indirectchild, (long) 0);
|
||||
length += operandlength (
|
||||
(struct modebyte *) (instructp + length));
|
||||
continue;
|
||||
case byterel:
|
||||
case wordrel:
|
||||
case longrel:
|
||||
/*
|
||||
* regular pc relative addressing
|
||||
* check that this is the address of
|
||||
* a function.
|
||||
*/
|
||||
destpc = reladdr ((struct modebyte *) (instructp + length))
|
||||
- (bfd_vma) core_text_space;
|
||||
if (destpc >= s_lowpc && destpc <= s_highpc)
|
||||
{
|
||||
child = sym_lookup (&symtab, destpc);
|
||||
DBG (CALLDEBUG,
|
||||
printf ("[findcall]\tdestpc 0x%lx", destpc);
|
||||
printf (" child->name %s", child->name);
|
||||
printf (" child->addr 0x%lx\n", child->addr);
|
||||
);
|
||||
if (child->addr == destpc)
|
||||
{
|
||||
/*
|
||||
* a hit
|
||||
*/
|
||||
arc_add (parent, child, (long) 0);
|
||||
length += operandlength ((struct modebyte *)
|
||||
(instructp + length));
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* else:
|
||||
* it looked like a calls,
|
||||
* but it wasn't to anywhere.
|
||||
*/
|
||||
goto botched;
|
||||
default:
|
||||
botched:
|
||||
/*
|
||||
* something funny going on.
|
||||
*/
|
||||
DBG(CALLDEBUG, printf("[findcall]\tbut it's a botch\n"));
|
||||
length = 1;
|
||||
continue;
|
||||
goto botched;
|
||||
}
|
||||
/*
|
||||
* else:
|
||||
* it looked like a calls,
|
||||
* but it wasn't to anywhere.
|
||||
*/
|
||||
goto botched;
|
||||
default:
|
||||
botched:
|
||||
/*
|
||||
* something funny going on.
|
||||
*/
|
||||
DBG (CALLDEBUG, printf ("[findcall]\tbut it's a botch\n"));
|
||||
length = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
29
gprof/vax.h
29
gprof/vax.h
@ -16,36 +16,37 @@
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* @(#)vax.h 5.4 (Berkeley) 6/1/90
|
||||
* @(#)vax.h 5.4 (Berkeley) 6/1/90
|
||||
*/
|
||||
|
||||
/*
|
||||
* opcode of the `calls' instruction
|
||||
* opcode of the `calls' instruction
|
||||
*/
|
||||
#define CALLS 0xfb
|
||||
|
||||
/*
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
* offset (in bytes) of the code from the entry address of a routine.
|
||||
* (see asgnsamples for use and explanation.)
|
||||
*/
|
||||
#define OFFSET_TO_CODE 2
|
||||
#define UNITS_TO_CODE (OFFSET_TO_CODE / sizeof(UNIT))
|
||||
|
||||
/*
|
||||
* register for pc relative addressing
|
||||
* register for pc relative addressing
|
||||
*/
|
||||
#define PC 0xf
|
||||
|
||||
enum opermodes {
|
||||
literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
|
||||
enum opermodes
|
||||
{
|
||||
literal, indexed, reg, regdef, autodec, autoinc, autoincdef,
|
||||
bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
|
||||
immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
|
||||
longrel, longreldef
|
||||
};
|
||||
typedef enum opermodes operandenum;
|
||||
|
||||
struct modebyte {
|
||||
unsigned int regfield:4;
|
||||
unsigned int modefield:4;
|
||||
};
|
||||
};
|
||||
typedef enum opermodes operandenum;
|
||||
|
||||
struct modebyte
|
||||
{
|
||||
unsigned int regfield:4;
|
||||
unsigned int modefield:4;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user