1 /* Copyright � International Business Machines Corp., 2006 2 * Adelard LLP, 2007 3 * 4 * Author: Josh Triplett <josh@freedesktop.org> 5 * Dan Sheridan <djs@adelard.com> 6 * 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: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 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 23 * THE SOFTWARE. 24 */ 25 #include <stdarg.h> 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <string.h> 29 #include <ctype.h> 30 #include <unistd.h> 31 #include <fcntl.h> 32 33 #include "lib.h" 34 #include "allocate.h" 35 #include "token.h" 36 #include "parse.h" 37 #include "symbol.h" 38 #include "expression.h" 39 #include "linearize.h" 40 41 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) 45 { 46 struct basic_block *bb; 47 struct instruction *insn; 48 49 const char *fname, *sname; 50 51 fname = show_ident(ep->name->ident); 52 sname = stream_name(ep->entry->bb->pos.stream); 53 54 printf("subgraph cluster%p {\n" 55 " color=blue;\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" 59 " </TABLE>>;\n" 60 " file=\"%s\";\n" 61 " fun=\"%s\";\n" 62 " ep=bb%p;\n", 63 ep, sname, fname, sname, fname, ep->entry->bb); 64 65 FOR_EACH_PTR(ep->bbs, bb) { 66 struct basic_block *child; 67 int ret = 0; 68 const char * s = ", ls=\"["; 69 70 /* Node for the bb */ 71 printf(" bb%p [shape=ellipse,label=%d,line=%d,col=%d", 72 bb, bb->pos.line, bb->pos.line, bb->pos.pos); 73 74 75 /* List loads and stores */ 76 FOR_EACH_PTR(bb->insns, insn) { 77 switch(insn->opcode) { 78 case OP_STORE: 79 if (insn->symbol->type == PSEUDO_SYM) { 80 printf("%s store(%s)", s, show_ident(insn->symbol->sym->ident)); 81 s = ","; 82 } 83 break; 84 85 case OP_LOAD: 86 if (insn->symbol->type == PSEUDO_SYM) { 87 printf("%s load(%s)", s, show_ident(insn->symbol->sym->ident)); 88 s = ","; 89 } 90 break; 91 92 case OP_RET: 93 ret = 1; 94 break; 95 96 } 97 } END_FOR_EACH_PTR(insn); 98 if (s[1] == 0) 99 printf("]\""); 100 if (ret) 101 printf(",op=ret"); 102 printf("];\n"); 103 104 /* Edges between bbs; lower weight for upward edges */ 105 FOR_EACH_PTR(bb->children, child) { 106 printf(" bb%p -> bb%p [op=br, %s];\n", bb, child, 107 (bb->pos.line > child->pos.line) ? "weight=5" : "weight=10"); 108 } END_FOR_EACH_PTR(child); 109 } END_FOR_EACH_PTR(bb); 110 111 printf("}\n"); 112 } 113 114 115 /* Insert edges for intra- or inter-file calls, depending on the value 116 * of internal. Bold edges are used for calls with destinations; 117 * dashed for calls to external functions */ 118 static void graph_calls(struct entrypoint *ep, int internal) 119 { 120 struct basic_block *bb; 121 struct instruction *insn; 122 123 show_ident(ep->name->ident); 124 stream_name(ep->entry->bb->pos.stream); 125 126 FOR_EACH_PTR(ep->bbs, bb) { 127 if (!bb) 128 continue; 129 if (!bb->parents && !bb->children && !bb->insns && verbose < 2) 130 continue; 131 132 FOR_EACH_PTR(bb->insns, insn) { 133 if (insn->opcode == OP_CALL && 134 internal == !(insn->func->sym->ctype.modifiers & MOD_EXTERN)) { 135 136 /* Find the symbol for the callee's definition */ 137 struct symbol * sym; 138 if (insn->func->type == PSEUDO_SYM) { 139 for (sym = insn->func->sym->ident->symbols; 140 sym; sym = sym->next_id) { 141 if (sym->namespace & NS_SYMBOL && sym->ep) 142 break; 143 } 144 145 if (sym) 146 printf("bb%p -> bb%p" 147 "[label=%d,line=%d,col=%d,op=call,style=bold,weight=30];\n", 148 bb, sym->ep->entry->bb, 149 insn->pos.line, insn->pos.line, insn->pos.pos); 150 else 151 printf("bb%p -> \"%s\" " 152 "[label=%d,line=%d,col=%d,op=extern,style=dashed];\n", 153 bb, show_pseudo(insn->func), 154 insn->pos.line, insn->pos.line, insn->pos.pos); 155 } 156 } 157 } END_FOR_EACH_PTR(insn); 158 } END_FOR_EACH_PTR(bb); 159 } 160 161 int main(int argc, char **argv) 162 { 163 struct string_list *filelist = NULL; 164 char *file; 165 struct symbol *sym; 166 167 struct symbol_list *fsyms, *all_syms=NULL; 168 169 printf("digraph call_graph {\n"); 170 fsyms = sparse_initialize(argc, argv, &filelist); 171 concat_symbol_list(fsyms, &all_syms); 172 173 /* Linearize all symbols, graph internal basic block 174 * structures and intra-file calls */ 175 FOR_EACH_PTR_NOTAG(filelist, file) { 176 177 fsyms = sparse(file); 178 concat_symbol_list(fsyms, &all_syms); 179 180 FOR_EACH_PTR(fsyms, sym) { 181 expand_symbol(sym); 182 linearize_symbol(sym); 183 } END_FOR_EACH_PTR(sym); 184 185 FOR_EACH_PTR(fsyms, sym) { 186 if (sym->ep) { 187 graph_ep(sym->ep); 188 graph_calls(sym->ep, 1); 189 } 190 } END_FOR_EACH_PTR_NOTAG(sym); 191 192 } END_FOR_EACH_PTR_NOTAG(file); 193 194 /* Graph inter-file calls */ 195 FOR_EACH_PTR(all_syms, sym) { 196 if (sym->ep) 197 graph_calls(sym->ep, 0); 198 } END_FOR_EACH_PTR_NOTAG(sym); 199 200 printf("}\n"); 201 return 0; 202 } 203