callgrph.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 351 行
C
351 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include "plusplus.h"
#include "callgrph.h"
#include "dbg.h"
#include "stats.h"
#include "cgfront.h"
ExtraRptCtr( ctr_nodes ); // # nodes
ExtraRptCtr( ctr_edges ); // # edges
static void cgrfInit( // INITIALIZATION FOR CALL GRAPHING INFO.
CALLGRAPH *ctl ) // - control information
{
ctl->carve_nodes = CarveCreate( sizeof( CALLNODE ), 64 );
ctl->carve_edges = CarveCreate( sizeof( CALLEDGE ), 64 );
ctl->pruned = FALSE;
}
static void cgrfFini( // COMPLETION OF CALL GRAPHING INFO.
CALLGRAPH *ctl ) // - control information
{
CarveDestroy( ctl->carve_nodes );
CarveDestroy( ctl->carve_edges );
}
static DIRGRAPH_NODE *cgrfAllocNode( // ALLOCATE A NODE
CALLGRAPH *ctl ) // - control information
{
ExtraRptIncrementCtr( ctr_nodes );
return CarveAlloc( ctl->carve_nodes );
}
static DIRGRAPH_EDGE *cgrfAllocEdge( // ALLOCATE AN EDGE
CALLGRAPH *ctl ) // - control information
{
ExtraRptIncrementCtr( ctr_edges );
return CarveAlloc( ctl->carve_edges );
}
static void cgrfFreeNode( // FREE A NODE
CALLGRAPH *ctl, // - control information
CALLNODE *node ) // - node to be freed
{
CarveFree( ctl->carve_nodes, node );
}
static void cgrfFreeEdge( // ALLOCATE AN EDGE
CALLGRAPH *ctl, // - control information
CALLEDGE *edge ) // - edge to be freed
{
CarveFree( ctl->carve_edges, edge );
}
static DIRGRAPH_NODE *cgrfInitNode( // INIT A NODE
CALLGRAPH *ctl, // - control information
CALLNODE *node ) // - node to be initialized
{
ctl = ctl;
node->refs = 0;
node->depth = 0;
node->opcodes = 0;
node->addrs = 0;
node->state_table = FALSE;
node->calls_done = FALSE;
node->cond_flags = 0;
node->is_vft = FALSE;
node->inline_fun = FALSE;
node->inlineable = FALSE;
node->inlineable_oe = FALSE;
node->flowed_recurse = FALSE;
node->rescan = FALSE;
node->stab_gen = FALSE;
node->cgfile = NULL;
node->unresolved = NULL;
node->stmt_state = STS_NONE;
node->dtor_method = DTM_DIRECT;
return &node->base;
}
static void changeNodeReference(// INCREMENT REFERENCE COUNT FOR AN EDGE
int incr_refs, // - signed amount to increment refs
int incr_addrs, // - signed amount to increment addrs
CALLEDGE *edge ) // - edge to be updated
{
CALLNODE *node; // - node referenced by edge
edge->refs += incr_refs;
edge->addrs += incr_addrs;
node = (CALLNODE*)edge->base.target;
node->refs += incr_refs;
node->addrs += incr_addrs;
}
static void changeCtlCounts( // UPDATE COUNTS FROM CONTROL INFORMATION
CALLGRAPH *ctl, // - control information
CALLEDGE *edge ) // - edge to be initialized
{
changeNodeReference( ctl->incr_refs, ctl->incr_addrs, edge );
}
static DIRGRAPH_EDGE *cgrfInitEdge( // INIT AN EDGE
CALLGRAPH *ctl, // - control information
CALLEDGE *edge ) // - edge to be initialized
{
edge->refs = 0;
edge->addrs = 0;
changeCtlCounts( ctl, edge );
return &edge->base;
}
static DIRGRAPH_EDGE *cgrfDupEdge( // PROCESS DUPLICATED EDGE
CALLGRAPH *ctl, // - control information
CALLEDGE *edge ) // - duplicated edge
{
changeCtlCounts( ctl, edge );
return &edge->base;
}
static void cgrfPruneNode( // PRUNE A NODE
CALLGRAPH *ctl, // - control information
DIRGRAPH_NODE *node ) // - node to be pruned
{
ctl = ctl;
node = node;
}
static void cgrfPruneEdge( // PRUNE AN EDGE
CALLGRAPH *ctl, // - control information
CALLEDGE *edge ) // - edge to be pruned
{
ctl = ctl;
changeNodeReference( -edge->refs, -edge->addrs, edge );
}
static DIRGRAPH_VFT cgrfVft = // VIRTUAL FUNCTIONS FOR CALL GRAPHING
{ (void *)&cgrfInit, // - init call-graph info.
(void *)&cgrfFini, // - fini call-graph info.
(void *)&cgrfAllocNode, // - allocate node
(void *)&cgrfAllocEdge, // - allocate edge
(void *)&cgrfFreeNode, // - allocate node
(void *)&cgrfFreeEdge, // - allocate edge
(void *)&cgrfInitNode, // - init node
(void *)&cgrfInitEdge, // - init edge
(void *)&cgrfDupEdge, // - duplicated edge
(void *)&cgrfPruneNode, // - prune node
(void *)&cgrfPruneEdge, // - prune edge
};
void CgrfFini( // FINALIZE FOR CALL-GRAPHING
CALLGRAPH *ctl ) // - call graph information
{
DgrfDestruct( &ctl->base );
}
void CgrfInit( // INITIALIZE FOR CALL-GRAPHING
CALLGRAPH *ctl ) // - call graph information
{
DgrfConstruct( &ctl->base, &cgrfVft );
ExtraRptRegisterCtr( &ctr_nodes, "# call-graph nodes" );
ExtraRptRegisterCtr( &ctr_edges, "# call-graph edges" );
}
// note: when a call is added, an addr-of has already been added
//
void CgrfAddCall( // ADD A CALL
CALLGRAPH *ctl, // - call graph information
CALLNODE *node_src, // - node for caller
CALLNODE *node_tgt ) // - node for callee
{
ctl->incr_refs = 1;
ctl->incr_addrs = -1;
DgrfAddEdge( &ctl->base, &node_src->base, &node_tgt->base );
}
void CgrfAddAddrOf( // ADD AN ADDRESS OF
CALLGRAPH *ctl, // - call graph information
CALLNODE *node_src, // - node for caller
CALLNODE *node_tgt ) // - node for callee
{
ctl->incr_refs = 0;
ctl->incr_addrs = 1;
DgrfAddEdge( &ctl->base, &node_src->base, &node_tgt->base );
}
CALLNODE *CgrfAddFunction( // ADD A FUNCTION
CALLGRAPH *ctl, // - call graph information
SYMBOL func ) // - function
{
return (CALLNODE*)DgrfAddNode( &ctl->base, func );
}
#if 0
CALLNODE *CgrfFindFunction( // FIND A FUNCTION
CALLGRAPH *ctl, // - call graph information
SYMBOL func ) // - function
{
return (CALLNODE*)DgrfFindNode( &ctl->base, func );
}
#endif
void CgrfPruneFunction( // PRUNE FUNCTION (AND CALLS) FROM GRAPH
CALLGRAPH *ctl, // - call graph information
CALLNODE *node ) // - node for function
{
if( node->refs == 0 && node->addrs == 0 ) {
ctl->pruned = TRUE;
DgrfPruneNode( &ctl->base, &node->base );
}
}
void CgrfWalkFunctions( // WALK FUNCTIONS IN GRAPH
CALLGRAPH *ctl, // - call graph information
boolean (*walker) // - walking routine
( CALLGRAPH * // - - control information
, CALLNODE * ) ) // - - function
{
DgrfWalkObjects( &ctl->base
, (boolean (*)( DIRGRAPH_CTL*, DIRGRAPH_NODE*))walker );
}
boolean CgrfWalkCalls( // WALK CALLS FROM NODE IN GRAPH
CALLGRAPH *ctl, // - call graph information
CALLNODE *node, // - source node
boolean (*walker) // - walking routine
( CALLGRAPH * // - - control information
, CALLEDGE * ) ) // - - edge
{
ctl->curr_node = node;
return DgrfWalkEdges
( &ctl->base
, &node->base
, (boolean (*)( DIRGRAPH_CTL*, DIRGRAPH_EDGE*))walker );
}
#ifndef NDEBUG
#include <stdio.h>
#include "dbg.h"
static boolean cgrfDumpCall( // DUMP CALL GRAPH EDGE
CALLGRAPH *ctl, // - call graph information
CALLEDGE *edge ) // - edge in graph
{
ctl = ctl;
printf( "- calls[%p] refs(%d) addrs(%d) %s\n"
, edge
, edge->refs
, edge->addrs
, DbgSymNameFull( edge->base.target->object ) );
return FALSE;
}
static boolean cgrfDumpNode( // DUMP CALL GRAPH NODE
CALLGRAPH *ctl, // - call graph information
CALLNODE *node ) // - node to dump
{
SYMBOL func;
func = node->base.object;
if( func == NULL ) {
func = ModuleInitFuncSym();
}
printf( "\nNode[%p] depth(%d) refs(%d) addrs(%d) opcodes(%d) cflags(%d)\n"
" inline_fun(%d) inlineable(%d) oe(%d) cgfile(%x)\n"
" state_table(%d) rescan(%d) stab_gen(%d)\n"
" %s flags(%x)\n"
, node
, node->depth
, node->refs
, node->addrs
, node->opcodes
, node->cond_flags
, node->inline_fun
, node->inlineable
, node->inlineable_oe
, node->cgfile
, node->state_table
, node->rescan
, node->stab_gen
, DbgSymNameFull( node->base.object )
, func->flag );
CgrfWalkCalls( ctl, node, &cgrfDumpCall );
return FALSE;
}
void CgrfDump( // DUMP CALL GRAPH
CALLGRAPH *ctl ) // - call graph information
{
printf( "===================== CALL GRAPH (start) ===============\n" );
CgrfWalkFunctions( ctl, &cgrfDumpNode );
printf( "===================== CALL GRAPH (end) ===============\n" );
}
#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?