00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "vcg.h"
00040 #include "linker.h"
00041
00042
00043 class vcgCCGWalker: public vcgWalker {
00044 private:
00045
00046 typedef map <procNode*,node_list> edge_map;
00047
00048 proc_decl_map proc_map;
00049 node_list nodes;
00050 procNode *current_proc;
00051 string current_proc_name;
00052 edge_map edges;
00053
00054 void at_proc( procNode *proc, Order ord ) {
00055 if(ord==Postorder) currently_excluded = false;
00056 else currently_excluded = excluded(proc);
00057 if (ord == Postorder || currently_excluded) return;
00058 print_node(proc);
00059
00060 declNode* decl = proc->decl();
00061 assert( decl );
00062 current_proc_name = decl->name();
00063 current_proc = proc;
00064 }
00065
00066 void at_call( callNode *call, Order ord ) {
00067
00068 if (ord == Postorder || currently_excluded) return;
00069 if(call->proc())
00070 print_node(call->proc());
00071 else
00072 print_node(call);
00073 print_edge(current_proc, call->proc(), call);
00074 }
00075
00076 void at_threeAddr(threeAddrNode *t, Order ord) {
00077 if (ord == Postorder || currently_excluded) return;
00078 if(t->rhs1() && t->rhs1()->var()->typ()==Id) {
00079 idNode *id = (idNode*) t->rhs1()->var();
00080 declNode *d = id->decl();
00081 if(d->type() && d->type()->typ() == Func) {
00082 procNode *p = proc_map[d];
00083 assert(p);
00084 print_edge(current_proc, p, id);
00085 }
00086 }
00087 }
00088
00089 void print_node(procNode *n) {
00090
00091 if(find(nodes.begin(), nodes.end(), n) != nodes.end()) return;
00092 if(n->typ()!=Unit && excluded(n->coord())) return;
00093
00094 nodes.push_front(n);
00095
00096 graph << endl;
00097 graph << " node: {" << endl;
00098 print_node_attribute( "title", node_title(n));
00099 print_node_attribute( "label", node_label(n) );
00100 graph << " }" << endl;
00101 }
00102
00103
00104
00105 void print_node(callNode *c) {
00106 if(excluded(c->coord())) return;
00107
00108
00109 string title = node_title(c);
00110 for(node_list_p n=nodes.begin(); n!=nodes.end(); n++)
00111 if(node_title(*n) == title) return;
00112
00113 nodes.push_front(c);
00114
00115 graph << endl;
00116 graph << " node: {" << endl;
00117 print_node_attribute( "title", title);
00118 print_node_attribute( "label", node_label(c) );
00119 print_node_value( "shape", "ellipse" );
00120 graph << " }" << endl;
00121 }
00122
00123 void print_edge(procNode *from, procNode *to, callNode *call) {
00124 node_list targets=edges[from];
00125
00126 if(to) {
00127 if(find(targets.begin(), targets.end(), to) != targets.end()) return;
00128 edges[from].push_front(to);
00129 } else {
00130 if(find(targets.begin(), targets.end(), call) != targets.end()) return;
00131 edges[from].push_front(call);
00132 }
00133
00134 graph << endl;
00135 graph << " edge: {";
00136 graph << " sourcename: \"" << node_title(from) << "\"";
00137 if(to)
00138 graph << " targetname: \"" << node_title(to) << "\"";
00139 else
00140 graph << " targetname: \"" << node_title(call) << "\"";
00141 graph << " label: \"" << call->coord().line() << "\"";
00142 graph << " }" << endl;
00143 }
00144
00145
00146 void print_node(idNode *c) {
00147 if(excluded(c->coord())) return;
00148
00149
00150 string title = node_title(c);
00151 for(node_list_p n=nodes.begin(); n!=nodes.end(); n++)
00152 if(node_title(*n) == title) return;
00153
00154 nodes.push_front(c);
00155
00156 graph << endl;
00157 graph << " node: {" << endl;
00158 print_node_attribute( "title", title);
00159 print_node_attribute( "label", node_label(c) );
00160 print_node_value( "shape", "ellipse" );
00161 graph << " }" << endl;
00162 }
00163
00164
00165 void print_edge(procNode *from, procNode *to, idNode *call) {
00166 node_list targets=edges[from];
00167
00168 if(to) {
00169 if(find(targets.begin(), targets.end(), to) != targets.end()) return;
00170 edges[from].push_front(to);
00171 } else {
00172 if(find(targets.begin(), targets.end(), call) != targets.end()) return;
00173 edges[from].push_front(call);
00174 }
00175
00176 graph << endl;
00177 graph << " edge: {";
00178 graph << " sourcename: \"" << node_title(from) << "\"";
00179 if(to)
00180 graph << " targetname: \"" << node_title(to) << "\"";
00181 else
00182 graph << " targetname: \"" << node_title(call) << "\"";
00183 graph << " label: \"" << call->coord().line() << "\"";
00184 graph << " }" << endl;
00185 }
00186
00187 string node_title(Node *n) {
00188 if(n->typ()==Call) return node_name(n);
00189 ostringstream title;
00190 char hex[16];
00191 sprintf(hex, "(%x)\0", n);
00192 title << node_name(n) << '@' << n->coord() << '.' << n->coord().offset()
00193 << hex << '\0';
00194 return title.str();
00195 }
00196
00197 string node_label(Node *n) {
00198 if(n->typ()==Call) return node_name(n);
00199 ostringstream label;
00200 Coord coord = n->coord();
00201 label << node_name(n) << ':' << coord.line() << '.' << coord.offset()
00202 << '\0';
00203 return label.str();
00204 }
00205
00206 #define STRING(s1,s2) (string(s1 + string(" `") + s2 + "'"))
00207
00208 string node_name(Node *n) {
00209 if(!n) return string("");
00210 switch(n->typ()) {
00211 case Proc: return STRING("Proc", ((procNode*)n)->decl()->name());
00212 case Call: {
00213 callNode *call = (callNode*) n;
00214 exprNode *cname = call->name();
00215 switch(cname->typ()) {
00216 case Id: return STRING("Call", ((idNode*) cname)->name());
00217 case Ptr: return "Call <Ptr>";
00218 case Unary: {
00219 ostringstream name;
00220 name <<"Call <Unary "<< ((unaryNode*)cname)->op()->print() <<">\0";
00221 return name.str();
00222 }
00223 default: {
00224 ostringstream name;
00225 name << "Call <unknown " << cname->typ() << ">\0";
00226 return name.str();
00227 }
00228 }
00229 }
00230 default: assert(false);
00231 }
00232 }
00233
00234 public:
00235 vcgCCGWalker(ostream& ostr, const string& comment, string excludefilename,
00236 proc_decl_map p)
00237 : vcgWalker(ostr,comment,excludefilename), current_proc(NULL), proc_map(p){
00238 nodes.clear();
00239
00240 print_comment();
00241 print_comment( "=== C-Breeze Call Graph visualization ===" );
00242 print_comment();
00243 if( !comment.empty() ) {
00244 print_comment( comment );
00245 print_comment();
00246 }
00247
00248 start_graph();
00249 print_graph_attribute( "orientation", "left_to_right" );
00250 print_graph_attribute( "display_edge_labels", "yes" );
00251 }
00252
00253 virtual ~vcgCCGWalker(void) { }
00254 };
00255
00256
00257
00258 class vcgCCGPhase: public Phase {
00259 private:
00260 string excludefilename;
00261 public:
00262 vcgCCGPhase() {}
00263 virtual ~vcgCCGPhase() {}
00264 void run (void) {
00265 Linker L;
00266 L.link();
00267 proc_decl_map proc_map = L.procedures();
00268
00269 string graph_file_name;
00270
00271 if( CBZ::Program.empty() ) return;
00272 else if( CBZ::Program.size()==1 ) {
00273
00274 unitNode* u = CBZ::Program.front();
00275 graph_file_name = u->input_file() + ".callg";
00276 } else {
00277 cout << "Several compilation units present. Creating combined call graph."
00278 << endl;
00279 graph_file_name = "combined.callg";
00280 }
00281
00282
00283 ofstream graph_file( graph_file_name.c_str() );
00284
00285 if( graph_file ) {
00286
00287 vcgCCGWalker callgw(graph_file, "File: " + graph_file_name,
00288 excludefilename, L.procedures());
00289
00290 for(unit_list_p i=CBZ::Program.begin(); i!=CBZ::Program.end(); ++i) {
00291 unitNode* u = *i;
00292 u->walk( callgw );
00293 }
00294
00295 } else {
00296 cerr << "vcgCGPhase: Can not open '" << graph_file_name
00297 << "' for writing." << endl;
00298 }
00299 }
00300
00301 void get_flags(str_list_p & arg) {
00302 string opt = *arg;
00303 if(strncmp("exclude:", opt.c_str(), 8) == 0) {
00304 excludefilename = opt;
00305 excludefilename.erase(0,8);
00306 arg++;
00307 }
00308 };
00309 };
00310
00311 Phases vcgccgPhase( "vcgCCG", new vcgCCGPhase() );