1f08c3bdfSopenharmony_ci/* Copyright © International Business Machines Corp., 2006
2f08c3bdfSopenharmony_ci *              Adelard LLP, 2007
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * Author: Josh Triplett <josh@freedesktop.org>
5f08c3bdfSopenharmony_ci *         Dan Sheridan <djs@adelard.com>
6f08c3bdfSopenharmony_ci *
7f08c3bdfSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
8f08c3bdfSopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
9f08c3bdfSopenharmony_ci * in the Software without restriction, including without limitation the rights
10f08c3bdfSopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11f08c3bdfSopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
12f08c3bdfSopenharmony_ci * furnished to do so, subject to the following conditions:
13f08c3bdfSopenharmony_ci *
14f08c3bdfSopenharmony_ci * The above copyright notice and this permission notice shall be included in
15f08c3bdfSopenharmony_ci * all copies or substantial portions of the Software.
16f08c3bdfSopenharmony_ci *
17f08c3bdfSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18f08c3bdfSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19f08c3bdfSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20f08c3bdfSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21f08c3bdfSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22f08c3bdfSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23f08c3bdfSopenharmony_ci * THE SOFTWARE.
24f08c3bdfSopenharmony_ci */
25f08c3bdfSopenharmony_ci#include <stdarg.h>
26f08c3bdfSopenharmony_ci#include <stdlib.h>
27f08c3bdfSopenharmony_ci#include <stdio.h>
28f08c3bdfSopenharmony_ci#include <string.h>
29f08c3bdfSopenharmony_ci#include <ctype.h>
30f08c3bdfSopenharmony_ci#include <unistd.h>
31f08c3bdfSopenharmony_ci#include <fcntl.h>
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_ci#include "lib.h"
34f08c3bdfSopenharmony_ci#include "allocate.h"
35f08c3bdfSopenharmony_ci#include "token.h"
36f08c3bdfSopenharmony_ci#include "parse.h"
37f08c3bdfSopenharmony_ci#include "symbol.h"
38f08c3bdfSopenharmony_ci#include "expression.h"
39f08c3bdfSopenharmony_ci#include "linearize.h"
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_ci/* Draw the subgraph for a given entrypoint. Includes details of loads
43f08c3bdfSopenharmony_ci * and stores for globals, and marks return bbs */
44f08c3bdfSopenharmony_cistatic void graph_ep(struct entrypoint *ep)
45f08c3bdfSopenharmony_ci{
46f08c3bdfSopenharmony_ci	struct basic_block *bb;
47f08c3bdfSopenharmony_ci	struct instruction *insn;
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_ci	const char *fname, *sname;
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci	fname = show_ident(ep->name->ident);
52f08c3bdfSopenharmony_ci	sname = stream_name(ep->entry->bb->pos.stream);
53f08c3bdfSopenharmony_ci
54f08c3bdfSopenharmony_ci	printf("subgraph cluster%p {\n"
55f08c3bdfSopenharmony_ci	       "    color=blue;\n"
56f08c3bdfSopenharmony_ci	       "    label=<<TABLE BORDER=\"0\" CELLBORDER=\"0\">\n"
57f08c3bdfSopenharmony_ci	       "             <TR><TD>%s</TD></TR>\n"
58f08c3bdfSopenharmony_ci	       "             <TR><TD><FONT POINT-SIZE=\"21\">%s()</FONT></TD></TR>\n"
59f08c3bdfSopenharmony_ci	       "           </TABLE>>;\n"
60f08c3bdfSopenharmony_ci	       "    file=\"%s\";\n"
61f08c3bdfSopenharmony_ci	       "    fun=\"%s\";\n"
62f08c3bdfSopenharmony_ci	       "    ep=bb%p;\n",
63f08c3bdfSopenharmony_ci	       ep, sname, fname, sname, fname, ep->entry->bb);
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci	FOR_EACH_PTR(ep->bbs, bb) {
66f08c3bdfSopenharmony_ci		struct basic_block *child;
67f08c3bdfSopenharmony_ci		int ret = 0;
68f08c3bdfSopenharmony_ci		const char * s = ", ls=\"[";
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci		/* Node for the bb */
71f08c3bdfSopenharmony_ci		printf("    bb%p [shape=ellipse,label=%d,line=%d,col=%d",
72f08c3bdfSopenharmony_ci		       bb, bb->pos.line, bb->pos.line, bb->pos.pos);
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci		/* List loads and stores */
76f08c3bdfSopenharmony_ci		FOR_EACH_PTR(bb->insns, insn) {
77f08c3bdfSopenharmony_ci			if (!insn->bb)
78f08c3bdfSopenharmony_ci				continue;
79f08c3bdfSopenharmony_ci			switch(insn->opcode) {
80f08c3bdfSopenharmony_ci			case OP_STORE:
81f08c3bdfSopenharmony_ci				if (insn->src->type == PSEUDO_SYM) {
82f08c3bdfSopenharmony_ci				  printf("%s store(%s)", s, show_ident(insn->src->sym->ident));
83f08c3bdfSopenharmony_ci				  s = ",";
84f08c3bdfSopenharmony_ci				}
85f08c3bdfSopenharmony_ci				break;
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci			case OP_LOAD:
88f08c3bdfSopenharmony_ci				if (insn->src->type == PSEUDO_SYM) {
89f08c3bdfSopenharmony_ci				  printf("%s load(%s)", s, show_ident(insn->src->sym->ident));
90f08c3bdfSopenharmony_ci				  s = ",";
91f08c3bdfSopenharmony_ci				}
92f08c3bdfSopenharmony_ci				break;
93f08c3bdfSopenharmony_ci
94f08c3bdfSopenharmony_ci			case OP_RET:
95f08c3bdfSopenharmony_ci				ret = 1;
96f08c3bdfSopenharmony_ci				break;
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci			}
99f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(insn);
100f08c3bdfSopenharmony_ci		if (s[1] == 0)
101f08c3bdfSopenharmony_ci			printf("]\"");
102f08c3bdfSopenharmony_ci		if (ret)
103f08c3bdfSopenharmony_ci			printf(",op=ret");
104f08c3bdfSopenharmony_ci		printf("];\n");
105f08c3bdfSopenharmony_ci
106f08c3bdfSopenharmony_ci		/* Edges between bbs; lower weight for upward edges */
107f08c3bdfSopenharmony_ci		FOR_EACH_PTR(bb->children, child) {
108f08c3bdfSopenharmony_ci			printf("    bb%p -> bb%p [op=br, %s];\n", bb, child,
109f08c3bdfSopenharmony_ci			       (bb->pos.line > child->pos.line) ? "weight=5" : "weight=10");
110f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(child);
111f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(bb);
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_ci	printf("}\n");
114f08c3bdfSopenharmony_ci}
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ci/* Insert edges for intra- or inter-file calls, depending on the value
118f08c3bdfSopenharmony_ci * of internal. Bold edges are used for calls with destinations;
119f08c3bdfSopenharmony_ci * dashed for calls to external functions */
120f08c3bdfSopenharmony_cistatic void graph_calls(struct entrypoint *ep, int internal)
121f08c3bdfSopenharmony_ci{
122f08c3bdfSopenharmony_ci	struct basic_block *bb;
123f08c3bdfSopenharmony_ci	struct instruction *insn;
124f08c3bdfSopenharmony_ci
125f08c3bdfSopenharmony_ci	show_ident(ep->name->ident);
126f08c3bdfSopenharmony_ci	stream_name(ep->entry->bb->pos.stream);
127f08c3bdfSopenharmony_ci
128f08c3bdfSopenharmony_ci	FOR_EACH_PTR(ep->bbs, bb) {
129f08c3bdfSopenharmony_ci		if (!bb)
130f08c3bdfSopenharmony_ci			continue;
131f08c3bdfSopenharmony_ci		if (!bb->parents && !bb->children && !bb->insns && verbose < 2)
132f08c3bdfSopenharmony_ci			continue;
133f08c3bdfSopenharmony_ci
134f08c3bdfSopenharmony_ci		FOR_EACH_PTR(bb->insns, insn) {
135f08c3bdfSopenharmony_ci			if (!insn->bb)
136f08c3bdfSopenharmony_ci				continue;
137f08c3bdfSopenharmony_ci			if (insn->opcode == OP_CALL &&
138f08c3bdfSopenharmony_ci			    internal == !(insn->func->sym->ctype.modifiers & MOD_EXTERN)) {
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_ci				/* Find the symbol for the callee's definition */
141f08c3bdfSopenharmony_ci				struct symbol * sym;
142f08c3bdfSopenharmony_ci				if (insn->func->type == PSEUDO_SYM) {
143f08c3bdfSopenharmony_ci					for (sym = insn->func->sym->ident->symbols;
144f08c3bdfSopenharmony_ci					     sym; sym = sym->next_id) {
145f08c3bdfSopenharmony_ci						if (sym->namespace & NS_SYMBOL && sym->ep)
146f08c3bdfSopenharmony_ci							break;
147f08c3bdfSopenharmony_ci					}
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_ci					if (sym)
150f08c3bdfSopenharmony_ci						printf("bb%p -> bb%p"
151f08c3bdfSopenharmony_ci						       "[label=%d,line=%d,col=%d,op=call,style=bold,weight=30];\n",
152f08c3bdfSopenharmony_ci						       bb, sym->ep->entry->bb,
153f08c3bdfSopenharmony_ci						       insn->pos.line, insn->pos.line, insn->pos.pos);
154f08c3bdfSopenharmony_ci					else
155f08c3bdfSopenharmony_ci						printf("bb%p -> \"%s\" "
156f08c3bdfSopenharmony_ci						       "[label=%d,line=%d,col=%d,op=extern,style=dashed];\n",
157f08c3bdfSopenharmony_ci						       bb, show_pseudo(insn->func),
158f08c3bdfSopenharmony_ci						       insn->pos.line, insn->pos.line, insn->pos.pos);
159f08c3bdfSopenharmony_ci				}
160f08c3bdfSopenharmony_ci			}
161f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(insn);
162f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(bb);
163f08c3bdfSopenharmony_ci}
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_ciint main(int argc, char **argv)
166f08c3bdfSopenharmony_ci{
167f08c3bdfSopenharmony_ci	struct string_list *filelist = NULL;
168f08c3bdfSopenharmony_ci	char *file;
169f08c3bdfSopenharmony_ci	struct symbol *sym;
170f08c3bdfSopenharmony_ci
171f08c3bdfSopenharmony_ci	struct symbol_list *fsyms, *all_syms=NULL;
172f08c3bdfSopenharmony_ci
173f08c3bdfSopenharmony_ci	printf("digraph call_graph {\n");
174f08c3bdfSopenharmony_ci	fsyms = sparse_initialize(argc, argv, &filelist);
175f08c3bdfSopenharmony_ci	concat_symbol_list(fsyms, &all_syms);
176f08c3bdfSopenharmony_ci
177f08c3bdfSopenharmony_ci	/* Linearize all symbols, graph internal basic block
178f08c3bdfSopenharmony_ci	 * structures and intra-file calls */
179f08c3bdfSopenharmony_ci	FOR_EACH_PTR(filelist, file) {
180f08c3bdfSopenharmony_ci
181f08c3bdfSopenharmony_ci		fsyms = sparse(file);
182f08c3bdfSopenharmony_ci		concat_symbol_list(fsyms, &all_syms);
183f08c3bdfSopenharmony_ci
184f08c3bdfSopenharmony_ci		FOR_EACH_PTR(fsyms, sym) {
185f08c3bdfSopenharmony_ci			expand_symbol(sym);
186f08c3bdfSopenharmony_ci			linearize_symbol(sym);
187f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(sym);
188f08c3bdfSopenharmony_ci
189f08c3bdfSopenharmony_ci		FOR_EACH_PTR(fsyms, sym) {
190f08c3bdfSopenharmony_ci			if (sym->ep) {
191f08c3bdfSopenharmony_ci				graph_ep(sym->ep);
192f08c3bdfSopenharmony_ci				graph_calls(sym->ep, 1);
193f08c3bdfSopenharmony_ci			}
194f08c3bdfSopenharmony_ci		} END_FOR_EACH_PTR(sym);
195f08c3bdfSopenharmony_ci
196f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(file);
197f08c3bdfSopenharmony_ci
198f08c3bdfSopenharmony_ci	/* Graph inter-file calls */
199f08c3bdfSopenharmony_ci	FOR_EACH_PTR(all_syms, sym) {
200f08c3bdfSopenharmony_ci		if (sym->ep)
201f08c3bdfSopenharmony_ci			graph_calls(sym->ep, 0);
202f08c3bdfSopenharmony_ci	} END_FOR_EACH_PTR(sym);
203f08c3bdfSopenharmony_ci
204f08c3bdfSopenharmony_ci	printf("}\n");
205f08c3bdfSopenharmony_ci	return 0;
206f08c3bdfSopenharmony_ci}
207