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