1 /* Copyright © International Business Machines Corp., 2006
4 * Author: Josh Triplett <josh@freedesktop.org>
5 * Dan Sheridan <djs@adelard.com>
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38 #include "expression.h"
39 #include "linearize.h"
42 /* Draw the subgraph for a given entrypoint. Includes details of loads
43 * and stores for globals, and marks return bbs */
44 static void graph_ep(struct entrypoint
*ep
)
46 struct basic_block
*bb
;
47 struct instruction
*insn
;
49 const char *fname
, *sname
;
51 fname
= show_ident(ep
->name
->ident
);
52 sname
= stream_name(ep
->entry
->bb
->pos
.stream
);
54 printf("subgraph cluster%p {\n"
56 " label=<<TABLE BORDER=\"0\" CELLBORDER=\"0\">\n"
57 " <TR><TD>%s</TD></TR>\n"
58 " <TR><TD><FONT POINT-SIZE=\"21\">%s()</FONT></TD></TR>\n"
63 ep
, sname
, fname
, sname
, fname
, ep
->entry
->bb
);
65 FOR_EACH_PTR(ep
->bbs
, bb
) {
66 struct basic_block
*child
;
68 const char * s
= ", ls=\"[";
71 printf(" bb%p [shape=ellipse,label=%d,line=%d,col=%d",
72 bb
, bb
->pos
.line
, bb
->pos
.line
, bb
->pos
.pos
);
75 /* List loads and stores */
76 FOR_EACH_PTR(bb
->insns
, insn
) {
79 switch(insn
->opcode
) {
81 if (insn
->src
->type
== PSEUDO_SYM
) {
82 printf("%s store(%s)", s
, show_ident(insn
->src
->sym
->ident
));
88 if (insn
->src
->type
== PSEUDO_SYM
) {
89 printf("%s load(%s)", s
, show_ident(insn
->src
->sym
->ident
));
99 } END_FOR_EACH_PTR(insn
);
106 /* Edges between bbs; lower weight for upward edges */
107 FOR_EACH_PTR(bb
->children
, child
) {
108 printf(" bb%p -> bb%p [op=br, %s];\n", bb
, child
,
109 (bb
->pos
.line
> child
->pos
.line
) ? "weight=5" : "weight=10");
110 } END_FOR_EACH_PTR(child
);
111 } END_FOR_EACH_PTR(bb
);
117 /* Insert edges for intra- or inter-file calls, depending on the value
118 * of internal. Bold edges are used for calls with destinations;
119 * dashed for calls to external functions */
120 static void graph_calls(struct entrypoint
*ep
, int internal
)
122 struct basic_block
*bb
;
123 struct instruction
*insn
;
125 show_ident(ep
->name
->ident
);
126 stream_name(ep
->entry
->bb
->pos
.stream
);
128 FOR_EACH_PTR(ep
->bbs
, bb
) {
131 if (!bb
->parents
&& !bb
->children
&& !bb
->insns
&& verbose
< 2)
134 FOR_EACH_PTR(bb
->insns
, insn
) {
137 if (insn
->opcode
== OP_CALL
&&
138 internal
== !(insn
->func
->sym
->ctype
.modifiers
& MOD_EXTERN
)) {
140 /* Find the symbol for the callee's definition */
142 if (insn
->func
->type
== PSEUDO_SYM
) {
143 for (sym
= insn
->func
->sym
->ident
->symbols
;
144 sym
; sym
= sym
->next_id
) {
145 if (sym
->namespace & NS_SYMBOL
&& sym
->ep
)
150 printf("bb%p -> bb%p"
151 "[label=%d,line=%d,col=%d,op=call,style=bold,weight=30];\n",
152 bb
, sym
->ep
->entry
->bb
,
153 insn
->pos
.line
, insn
->pos
.line
, insn
->pos
.pos
);
155 printf("bb%p -> \"%s\" "
156 "[label=%d,line=%d,col=%d,op=extern,style=dashed];\n",
157 bb
, show_pseudo(insn
->func
),
158 insn
->pos
.line
, insn
->pos
.line
, insn
->pos
.pos
);
161 } END_FOR_EACH_PTR(insn
);
162 } END_FOR_EACH_PTR(bb
);
165 int main(int argc
, char **argv
)
167 struct string_list
*filelist
= NULL
;
171 struct symbol_list
*fsyms
, *all_syms
=NULL
;
173 printf("digraph call_graph {\n");
174 fsyms
= sparse_initialize(argc
, argv
, &filelist
);
175 concat_symbol_list(fsyms
, &all_syms
);
177 /* Linearize all symbols, graph internal basic block
178 * structures and intra-file calls */
179 FOR_EACH_PTR(filelist
, file
) {
181 fsyms
= sparse(file
);
182 concat_symbol_list(fsyms
, &all_syms
);
184 FOR_EACH_PTR(fsyms
, sym
) {
186 linearize_symbol(sym
);
187 } END_FOR_EACH_PTR(sym
);
189 FOR_EACH_PTR(fsyms
, sym
) {
192 graph_calls(sym
->ep
, 1);
194 } END_FOR_EACH_PTR(sym
);
196 } END_FOR_EACH_PTR(file
);
198 /* Graph inter-file calls */
199 FOR_EACH_PTR(all_syms
, sym
) {
201 graph_calls(sym
->ep
, 0);
202 } END_FOR_EACH_PTR(sym
);