Renamed the resource MsgTag to Message
[dyninst.git] / paradynd / src / mdl.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 #include <iostream.h>
43 #include <stdio.h>
44 #include "dyninstRPC.xdr.SRVR.h"
45 #include "paradyn/src/met/globals.h"
46 #include "paradynd/src/metric.h"
47 #include "dyninstAPI/src/inst.h"
48 #include "dyninstAPI/src/ast.h"
49 #include "paradynd/src/main.h"
50 #include "dyninstAPI/src/symtab.h"
51 #include "util/h/Timer.h"
52 #include "paradynd/src/mdld.h"
53 #include "showerror.h"
54 #include "dyninstAPI/src/process.h"
55 #include "util/h/debugOstream.h"
56
57 // The following vrbles were defined in process.C:
58 extern debug_ostream attach_cerr;
59 extern debug_ostream inferiorrpc_cerr;
60 extern debug_ostream shmsample_cerr;
61 extern debug_ostream forkexec_cerr;
62 extern debug_ostream metric_cerr;
63
64 #ifdef paradyndCM5_blizzard
65 // START_NAME corresponds some routine with $start of your mdl
66 // Usually, main is what you want; blizzard needs something different
67 #define START_NAME "init_blk_acc" 
68 #else
69 #define START_NAME "main"
70 #endif
71
72 // Some global variables used to print error messages:
73 string currentMetric;  // name of the metric that is being processed.
74 string currentFocus;   // the focus
75
76
77 static string daemon_flavor;
78 static process *global_proc = NULL;
79 static bool mdl_met=false, mdl_cons=false, mdl_stmt=false, mdl_libs=false;
80
81 inline unsigned ui_hash(const unsigned &u) { return u; }
82
83 vector<unsigned> mdl_env::frames;
84 vector<mdl_var> mdl_env::all_vars;
85
86 vector<T_dyninstRPC::mdl_stmt*> mdl_data::stmts;
87 vector<T_dyninstRPC::mdl_metric*> mdl_data::all_metrics;
88 dictionary_hash<unsigned, vector<mdl_type_desc> > mdl_data::fields(ui_hash);
89 vector<mdl_focus_element> mdl_data::foci;
90 vector<T_dyninstRPC::mdl_constraint*> mdl_data::all_constraints;
91 vector<string> mdl_data::lib_constraints;
92
93 static bool walk_deref(mdl_var& ret, vector<unsigned>& types, string& var_name);
94 static bool do_operation(mdl_var& ret, mdl_var& left, mdl_var& right, unsigned bin_op);
95
96 class list_closure {
97 public:
98   list_closure(string& i_name, mdl_var& list_v)
99     : index_name(i_name), element_type(0), index(0), int_iter(NULL), float_iter(NULL),
100   string_iter(NULL), bool_iter(NULL), func_iter(NULL), mod_iter(NULL), max_index(0)
101   {
102     bool aflag;
103     aflag=list_v.is_list();
104     assert(aflag);
105
106     element_type = list_v.element_type();
107     switch(element_type) {
108     case MDL_T_INT:
109       aflag=list_v.get(int_iter); assert(aflag);
110       max_index = int_iter->size(); break;
111     case MDL_T_FLOAT:
112       aflag=list_v.get(float_iter); assert(aflag);
113       max_index = float_iter->size(); break;
114     case MDL_T_STRING:
115       aflag=list_v.get(string_iter); assert(aflag);
116       max_index = string_iter->size(); break;
117     case MDL_T_PROCEDURE_NAME:
118       aflag=list_v.get(funcName_iter); assert(aflag);
119       max_index = funcName_iter->size();
120       break;
121     case MDL_T_PROCEDURE:
122       aflag=list_v.get(func_iter); assert(aflag);
123       max_index = func_iter->size();
124       break;
125     case MDL_T_MODULE:
126       aflag=list_v.get(mod_iter); assert(aflag);
127       max_index = mod_iter->size();
128       break;
129     case MDL_T_POINT:
130       aflag=list_v.get(point_iter); assert(aflag);
131       max_index = point_iter->size();
132       break;
133     default:
134       assert(0);
135     }
136   }
137   ~list_closure() { }
138   bool next() {
139     string s;
140     pdFunction *pdf; module *m;
141     float f; int i;
142     instPoint *ip;
143
144     if (index >= max_index) return false;
145     switch(element_type) {
146     case MDL_T_INT:
147       i = (*int_iter)[index++];      return (mdl_env::set(i, index_name));
148     case MDL_T_FLOAT:
149       f = (*float_iter)[index++];    return (mdl_env::set(f, index_name));
150     case MDL_T_STRING:
151       s = (*string_iter)[index++];   return (mdl_env::set(s, index_name));
152     case MDL_T_PROCEDURE_NAME:
153       // lookup-up the functions defined in resource lists
154       // the function may not exist in the image, in which case we get the
155       // next one
156       do {
157         functionName *fn = (*funcName_iter)[index++];
158         pdf = global_proc->findOneFunction(fn->get());
159       } while (pdf == NULL && index < max_index);
160       if (pdf == NULL)
161         return false;
162       return (mdl_env::set(pdf, index_name));
163     case MDL_T_PROCEDURE:
164       pdf = (*func_iter)[index++];
165       assert(pdf);
166       return (mdl_env::set(pdf, index_name));
167     case MDL_T_MODULE: 
168       m = (*mod_iter)[index++];      return (mdl_env::set(m, index_name));
169     case MDL_T_POINT:
170       ip = (*point_iter)[index++];   return (mdl_env::set(ip, index_name));
171     default:
172       assert(0);
173     }
174     return false;
175   }
176
177 private:
178   string index_name;
179   unsigned element_type;
180   unsigned index;
181   vector<int> *int_iter;
182   vector<float> *float_iter;
183   vector<string> *string_iter;
184   vector<bool> *bool_iter;
185   vector<pdFunction*> *func_iter;
186   vector<functionName*> *funcName_iter;
187   vector<module*> *mod_iter;
188   vector<instPoint*> *point_iter;
189   unsigned max_index;
190 };
191
192 T_dyninstRPC::mdl_metric::mdl_metric(string id, string name, string units, 
193                                     u_int agg, u_int sty, u_int type,
194                                     vector<T_dyninstRPC::mdl_stmt*> *mv, 
195                                     vector<string> *flav,
196                                     vector<T_dyninstRPC::mdl_constraint*> *cons,
197                                     vector<string> *temp_counters,
198                                     bool developerMode,
199                                     int unitstype)
200 : id_(id), name_(name), units_(units), agg_op_(agg), style_(sty),
201   type_(type), stmts_(mv), flavors_(flav), constraints_(cons),
202   temp_ctr_(temp_counters), developerMode_(developerMode),
203   unitstype_(unitstype) { }
204
205 T_dyninstRPC::mdl_metric::mdl_metric() { }
206
207 T_dyninstRPC::mdl_metric::~mdl_metric() {
208   if (stmts_) {
209     unsigned size = stmts_->size();
210     for (unsigned u=0; u<size; u++)
211       delete (*stmts_)[u];
212     delete stmts_;
213   }
214   delete flavors_;
215
216   if (constraints_) {
217     unsigned size = constraints_->size();
218     for (unsigned u=0; u<size; u++)
219       delete (*constraints_)[u];
220     delete constraints_;
221   }
222
223 }
224
225 bool mdl_data::new_metric(string id, string name, string units,
226                           u_int agg, u_int sty, u_int type,
227                           vector<T_dyninstRPC::mdl_stmt*> *mv,
228                           vector<string> *flav,
229                           vector<T_dyninstRPC::mdl_constraint*> *cons,
230                           vector<string> *temp_counters,
231                           bool developerMode,
232                           int unitstype) {
233   T_dyninstRPC::mdl_metric *m = new T_dyninstRPC::mdl_metric(id, name, 
234                                                              units, agg,
235                                                              sty, type, mv,
236                                                              flav, cons,
237                                                              temp_counters,
238                                                              developerMode,
239                                                              unitstype);
240   if (!m)
241     return false;
242   else {
243     all_metrics += m;
244     return true;
245   }
246 }
247
248 static bool other_machine_specified(vector< vector<string> > &focus,
249                                     string& machine) {
250   assert(focus[resource::machine][0] == "Machine");
251
252   switch (focus[resource::machine].size()) {
253   case 1: break;
254   case 2:
255     if (machine != focus[resource::machine][1]) return true;
256     break;
257   default:
258     assert(0);
259   }
260   return false;
261 }
262
263 static void add_processes(vector< vector<string> > &focus,
264                                  vector<process*> procs,
265                                  vector<process*> &ip) {
266   assert(focus[resource::process][0] == "Process");
267   unsigned pi, ps;
268
269   switch(focus[resource::process].size()) {
270   case 1:
271     ip = procs;
272     break;
273   case 2:
274 #if defined(MT_THREAD)
275   case 3:
276 #endif
277     ps = procs.size();
278     for (pi=0; pi<ps; pi++)
279       if (procs[pi]->rid->part_name() == focus[resource::process][1]) {
280         ip += procs[pi];
281         break;
282       }
283     break;
284   default:
285     assert(0);
286   }
287 }
288
289 static bool focus_matches(vector<string>& focus, vector<string> *match_path) {
290   unsigned mp_size = match_path->size();
291   unsigned f_size = focus.size();
292
293   if ((mp_size < 1) || (f_size < 2) || (mp_size != (f_size-1))) {
294     return false;
295   }
296
297   for (unsigned u = 0; u < mp_size; u++) {
298     if(((*match_path)[u] != "*") && (focus[u] != (*match_path)[u])) {
299       return false;
300     }
301   }
302
303   return true;
304 }
305
306
307 // Global constraints are specified by giving their name within a metric def
308 // Find the real constraint by searching the dictionary using this name
309 static T_dyninstRPC::mdl_constraint *flag_matches(vector<string>& focus, 
310                                                   T_dyninstRPC::mdl_constraint *match_me,
311                                                   bool& is_default) {
312   unsigned c_size = mdl_data::all_constraints.size();
313   for (unsigned cs=0; cs<c_size; cs++) 
314     if (mdl_data::all_constraints[cs]->id_ == match_me->id_) {
315       match_me = mdl_data::all_constraints[cs];
316       if (focus_matches(focus, mdl_data::all_constraints[cs]->match_path_)) {
317         if (mdl_data::all_constraints[cs]->data_type_ == MDL_T_NONE)
318           is_default = true;
319         else
320           is_default = false;
321         return match_me;
322       }
323     }
324
325   return NULL;
326 }
327
328 // Determine if the global and local constraints are applicable
329 // Global constraints that are applicable are put on flag_cons
330 // base_used returns the ONE replace constraint that matches
331
332 static bool check_constraints(vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
333                               T_dyninstRPC::mdl_constraint *&base_used,
334                               vector< vector<string> >& focus,
335                               vector<T_dyninstRPC::mdl_constraint*> *cons,
336                               vector<unsigned>& flag_dex, unsigned& base_dex) {
337   unsigned size = cons->size();
338
339   unsigned foc_size = focus.size();
340   for (unsigned fi=0; fi<foc_size; fi++) {
341     unsigned el_size = focus[fi].size();
342     if ((focus[fi][0] == "Machine") || (focus[fi][0] == "Process")) {
343       // do nothing, can't specify constraints for machine or process
344       ;
345     } else if (el_size) {
346       bool matched = false;
347       // Hack allow constraints such as "/SyncObject"
348       // However, these don't have to match
349       // Otherwise a failure to match means that the metric is invalid for the resource
350       unsigned ci=0;
351       while ((ci < size) && !matched) {
352         if (!(*cons)[ci]->match_path_) {
353           // this is an external constraint, apply if applicable
354           T_dyninstRPC::mdl_constraint *mc;
355           bool is_default;
356           if ((mc = flag_matches(focus[fi], (*cons)[ci], is_default))) {
357             matched = true;
358             if (!is_default) {
359               flag_cons += mc; flag_dex += fi;
360             }
361           }
362         } else {
363           // this could be the real constraint to use
364           // this guarantees that the first match is used
365           // TODO -- first matching replace constraint wins
366           if (focus_matches(focus[fi], (*cons)[ci]->match_path_)) {
367             matched = true;
368             base_used = (*cons)[ci]; base_dex = fi; 
369           }
370         }
371         ci++;
372       }
373       if (!matched && (el_size>1)) {
374         return false;
375       }
376     } else {
377       return false;
378     }
379   }
380   return true;
381 }
382
383 // update the interpreter environment for this processor
384 // Variable updated: $procedures, $modules, $exit, $start
385 // If the "get_all" flag is set, then  this routine includes procedures and
386 // modlues from all shared objects as well as from the a.out.  If it is not
387 // set, then this routine includes procedures and modlues from the a.out and 
388 // from any shared libraries that are included in foci that are not refined
389 // on the Code heirarcy (ex. WholeProgram). 
390
391 static bool update_environment(process *proc, bool get_all) {
392
393   // for cases when libc is dynamically linked, the exit symbol is not
394   // correct
395   string vname = "$exit";
396   pdFunction *pdf = proc->findOneFunction(string(EXIT_NAME));
397    if (pdf) { 
398       mdl_env::add(vname, false, MDL_T_PROCEDURE);
399       mdl_env::set(pdf, vname);
400   }
401
402   vname = "$start";
403   pdf = proc->findOneFunction(string(START_NAME));
404   if (!pdf) return false;
405
406   vname = "$start";
407   mdl_env::add(vname, false, MDL_T_PROCEDURE);
408   mdl_env::set(pdf, vname);
409
410   vname = "$procedures";
411   mdl_env::add(vname, false, MDL_T_LIST_PROCEDURE);
412   // if get_all is set, get all the functions in the executable
413   // otherwise, only get those that are not excluded by the mdl option
414   if(get_all) {
415       mdl_env::set(proc->getAllFunctions(), vname);
416   }
417   else {
418       mdl_env::set(proc->getIncludedFunctions(), vname);
419   }
420
421   vname = "$modules";
422   mdl_env::add(vname, false, MDL_T_LIST_MODULE);
423   // if get_all is set, get all the modules in the executable
424   // otherwise, only get those that are not excluded by the mdl option
425   if(get_all){
426       mdl_env::set(proc->getAllModules(), vname);
427   }
428   else {
429       mdl_env::set(proc->getIncludedModules(), vname);
430   }
431
432   return true;
433 }
434
435 dataReqNode *create_data_object(unsigned mdl_data_type,
436                                 metricDefinitionNode *mn,
437                                 bool computingCost) {
438   switch (mdl_data_type) {
439   case MDL_T_COUNTER:
440     return (mn->addSampledIntCounter(0, computingCost));
441
442   case MDL_T_WALL_TIMER:
443     return (mn->addWallTimer(computingCost));
444
445   case MDL_T_PROC_TIMER:
446     return (mn->addProcessTimer(computingCost));
447
448   case MDL_T_NONE:
449     // just to keep mdl apply allocate a dummy un-sampled counter.
450     return (mn->addUnSampledIntCounter(0, computingCost));
451
452   default:
453     assert(0);
454     return NULL;
455   }
456 }
457
458
459 metricDefinitionNode *
460 apply_to_process(process *proc, 
461                  string& id, string& name,
462                  vector< vector<string> >& focus,
463                  unsigned& agg_op,
464                  unsigned& type,
465                  vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
466                  T_dyninstRPC::mdl_constraint *base_use,
467                  vector<T_dyninstRPC::mdl_stmt*> *stmts,
468                  vector<unsigned>& flag_dex,
469                  unsigned& base_dex,
470                  vector<string> *temp_ctr,
471                  bool replace_component,
472                  bool computingCost) {
473     // TODO: if this is a dynamic executable check the focus...
474     // if it is not refined on the /Code heirarchy then only get 
475     // functions and modules from shared libraries that are
476     // to be included in this focus, otherwise, get functions and
477     // modules from the a.out and from all shared libraries
478     bool get_all = false;
479     for(u_int i=0; i < focus.size(); i++){
480         if((focus[i][0] == "Code") && (focus[i].size() > 1)){
481             get_all = true;
482         }
483     }
484
485     if (!update_environment(proc, get_all)) return NULL;
486
487     // compute the flat_name for this component: the machine and process
488     // are always defined for the component, even if they are not defined
489     // for the aggregate metric.
490     vector< vector<string> > component_focus(focus); // they start off equal
491
492     string component_flat_name(name);
493     for (unsigned u1 = 0; u1 < focus.size(); u1++) {
494       if (focus[u1][0] == "Process") {
495         component_flat_name += focus[u1][0] + proc->rid->part_name();
496         if (focus[u1].size() == 1) {
497            // there was no refinement to a specific process...but the component
498            // focus must have such a refinement.
499            component_focus[u1] += proc->rid->part_name();
500         }
501       }
502       else if (focus[u1][0] == "Machine") {
503         component_flat_name += focus[u1][0] + machineResource->part_name();
504         if (focus[u1].size() == 1) {
505            // there was no refinement to a specific machine...but the component focus
506            // must have such a refinement.
507            component_focus[u1] += machineResource->part_name();
508         }
509       }
510       else
511         for (unsigned u2 = 0; u2 < focus[u1].size(); u2++)
512           component_flat_name += focus[u1][u2];
513     }
514
515     // now assert that focus2flatname(component_focus) equals component_flat_name
516     extern string metricAndCanonFocus2FlatName(const string &met,
517                                                const vector< vector<string> > &focus);
518     assert(component_flat_name == metricAndCanonFocus2FlatName(name, component_focus));
519
520     metricDefinitionNode *existingMI;
521     const bool alreadyThere = allMIComponents.find(component_flat_name, existingMI);
522     if (alreadyThere) {
523        if (replace_component) {
524           // fry old entry...
525           metric_cerr << "apply_to_process: found " << component_flat_name
526                       << " but continuing anyway since replace_component flag set"
527                       << endl;
528           // note that we don't call 'delete'.
529           allMIComponents.undef(component_flat_name);
530        }
531        else {
532          metric_cerr << "mdl apply_to_process: found component for "
533                      << component_flat_name << "...reusing it" << endl;
534
535          return existingMI;
536        }
537     }
538     else
539        metric_cerr << "MDL: creating new component mi since flatname "
540                    << component_flat_name << " doesn't exist" << endl;
541
542     // If the component exists, then we've either already returned, or fried it.
543     assert(!allMIComponents.defines(component_flat_name));
544
545     // TODO -- Using aggOp value for this metric -- what about folds
546     metricDefinitionNode *mn = new metricDefinitionNode(proc, name, focus,
547                                                         component_focus,
548                                                         component_flat_name, agg_op);
549     assert(mn);
550
551     assert(!allMIComponents.defines(component_flat_name));
552     allMIComponents[component_flat_name] = mn;
553
554     // Create the timer, counter
555     dataReqNode *the_node = create_data_object(type, mn, computingCost);
556     assert(the_node);
557     mdl_env::set(the_node, id);
558
559     // Create the temporary counters - are these useful
560     if (temp_ctr) {
561       unsigned tc_size = temp_ctr->size();
562       for (unsigned tc=0; tc<tc_size; tc++) {
563         dataReqNode *temp_node = mn->addUnSampledIntCounter(0, computingCost);
564         mdl_env::set(temp_node, (*temp_ctr)[tc]);
565       }
566     }
567
568     unsigned flag_size = flag_cons.size();
569     vector<dataReqNode*> flags;
570     if (flag_size) {
571       for (unsigned fs=0; fs<flag_size; fs++) {
572         // TODO -- cache these created flags
573         dataReqNode *flag = NULL;
574         if (! (flag_cons[fs]->apply(mn, flag, focus[flag_dex[fs]], proc, computingCost))) {
575           delete mn;
576           return NULL;
577         }
578         assert(flag);
579         flags += flag;
580         // cout << "Applying constraint for " << flag_cons[fs]->id_ << endl;
581       }
582     }
583
584     if (base_use) {
585       dataReqNode *flag = NULL;
586       if (!base_use->apply(mn, flag, focus[base_dex], proc, computingCost)) {
587         // cout << "apply of " << name << " failed\n";
588         delete mn;
589         return NULL;
590       }
591     } else {
592       unsigned size = stmts->size();
593       for (unsigned u=0; u<size; u++) {
594         if (!(*stmts)[u]->apply(mn, flags)) { // virtual fn call depending on the statement type
595           // cout << "apply of " << name << " failed\n";
596           delete mn;
597           return NULL;
598         }
599       }
600     }
601
602     if (!mn->nonNull()) {
603       delete mn;
604       return NULL;
605     }
606
607     return mn;
608 }
609
610 static bool apply_to_process_list(vector<process*>& instProcess,
611                                   vector<metricDefinitionNode*>& parts,
612                                   string& id, string& name,
613                                   vector< vector<string> >& focus,
614                                   unsigned& agg_op,
615                                   unsigned& type,
616                                   vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
617                                   T_dyninstRPC::mdl_constraint *base_use,
618                                   vector<T_dyninstRPC::mdl_stmt*> *stmts,
619                                   vector<unsigned>& flag_dex,
620                                   unsigned& base_dex,
621                                   vector<string> *temp_ctr,
622                                   bool replace_components_if_present,
623                                   bool computingCost) {
624 #ifdef DEBUG_MDL
625   timer loadTimer, totalTimer;
626   static ofstream *of=NULL;
627   if (!of) {
628     char buffer[100];
629     ostrstream osb(buffer, 100, ios::out);
630     osb << "mdl_" << "__" << getpid() << ends;
631     of = new ofstream(buffer, ios::app);
632   }
633
634   (*of) << "Instrumenting for " << name << " " << instProcess.size() << " processes\n";
635 #endif
636
637   unsigned psize = instProcess.size();
638 #ifdef DEBUG_MDL
639   totalTimer.clear(); totalTimer.start();
640 #endif
641   for (unsigned p=0; p<psize; p++) {
642 #ifdef DEBUG_MDL
643     loadTimer.clear(); loadTimer.start();  // TIMER
644 #endif
645     process *proc = instProcess[p]; assert(proc);
646     global_proc = proc;     // TODO -- global
647
648     // skip neonatal and exited processes.
649     if (proc->status() == exited || proc->status() == neonatal) continue;
650
651     metricDefinitionNode *comp = apply_to_process(proc, id, name, focus, 
652                                                  agg_op, type,
653                                                  flag_cons, base_use, stmts, 
654                                                  flag_dex,
655                                                  base_dex, temp_ctr,
656                                                  replace_components_if_present,
657                                                  computingCost);
658     if (comp)
659       // we have another component (i.e. process-specific) mi
660       parts += comp;
661
662 #ifdef DEBUG_MDL
663     loadTimer.stop();
664     char timeMsg[500];
665     sprintf(timeMsg, "%f::%f  ", (float) loadTimer.usecs(), (float) loadTimer.wsecs());
666     // tp->applicationIO(10, strlen(timeMsg), timeMsg);
667     (*of) << name << ":" << timeMsg << endl;
668 #endif
669
670   }
671 #ifdef DEBUG_MDL
672   totalTimer.stop();
673   char timeMsg[500];
674   sprintf(timeMsg, "\nTotal:  %f:user\t%f:wall\n", (float) totalTimer.usecs(),
675           (float) totalTimer.wsecs());
676   // tp->applicationIO(10, strlen(timeMsg), timeMsg);
677   (*of) << name << ":" << timeMsg << endl;
678 #endif
679
680   if (parts.size() == 0)
681     // no components!
682     return false;
683
684   return true;
685 }
686
687 metricDefinitionNode *T_dyninstRPC::mdl_metric::apply(vector< vector<string> > &focus,
688                                                       string& flat_name,
689                                                       vector<process *> procs,
690                                                       bool replace_components_if_present,
691                                                       bool computingCost) {
692   // TODO -- check to see if this is active ?
693   // TODO -- create counter or timer
694   // TODO -- put it into the environment ?
695   // TODO -- this can be passed directly -- faster - later
696   // TODO -- internal metrics
697   // TODO -- assume no constraints, all processes instrumented
698   // TODO -- support two-level aggregation: one at the daemon, one at paradyn
699   // TODO -- how is folding specified ?
700   // TODO -- are lists updated here ?
701
702   mdl_env::push();
703   mdl_env::add(id_, false, MDL_T_DRN);
704   assert(stmts_);
705
706   const unsigned tc_size = temp_ctr_->size();
707   for (unsigned tc=0; tc<tc_size; tc++) {
708     mdl_env::add((*temp_ctr_)[tc], false, MDL_T_DRN);
709   }
710
711   static string machine;
712   static bool machine_init= false;
713   if (!machine_init) {
714     machine_init = true;
715     machine = getHostName();
716   }
717
718   // TODO -- I am assuming that a canonical resource list is
719   // machine, procedure, process, syncobject
720
721   if (other_machine_specified(focus, machine)) return NULL;
722   vector<process*> instProcess;
723   add_processes(focus, procs, instProcess);
724
725   if (!instProcess.size()) return NULL;
726
727   // build the list of constraints to use
728   vector<T_dyninstRPC::mdl_constraint*> flag_cons;
729
730   // the first replace constraint that matches, if any
731   T_dyninstRPC::mdl_constraint *base_used=NULL;
732
733   // build list of global constraints that match and choose local replace constraint
734   unsigned base_dex; vector<unsigned> flag_dex;
735   if (!check_constraints(flag_cons, base_used, focus, constraints_, flag_dex, base_dex))
736     return NULL;
737
738   // build the instrumentation request
739   vector<metricDefinitionNode*> parts; // one per process
740   if (!apply_to_process_list(instProcess, parts, id_, name_, focus,
741                              agg_op_, type_, flag_cons, base_used,
742                              stmts_, flag_dex, base_dex, temp_ctr_,
743                              replace_components_if_present,
744                              computingCost))
745     return NULL;
746
747   // construct aggregate for the metric instance parts
748   metricDefinitionNode *ret = NULL;
749
750   if (parts.size())
751     // create aggregate mi, containing the process components "parts"
752     ret = new metricDefinitionNode(name_, focus, flat_name, parts, agg_op_);
753
754   // cout << "apply of " << name_ << " ok\n";
755   mdl_env::pop();
756   return ret;
757 }
758
759 T_dyninstRPC::mdl_constraint::mdl_constraint() { }
760 T_dyninstRPC::mdl_constraint::mdl_constraint(string id, vector<string> *match_path,
761                                              vector<T_dyninstRPC::mdl_stmt*> *stmts,
762                                              bool replace, u_int d_type, bool& error)
763 : id_(id), match_path_(match_path), stmts_(stmts), replace_(replace),
764   data_type_(d_type), hierarchy_(0), type_(0) { error = false; }
765 T_dyninstRPC::mdl_constraint::~mdl_constraint() {
766   delete match_path_;
767   if (stmts_) {
768     for (unsigned u=0; u<stmts_->size(); u++)
769       delete (*stmts_)[u];
770     delete stmts_;
771   }
772 }
773
774
775 static bool do_trailing_resources(vector<string>& resource_,
776                                   process *proc)
777 {
778   vector<string>  resPath;
779
780   for(int pLen = 0; pLen < resource_.size(); pLen++) {
781     string   caStr = string("$constraint") + 
782                      string(resource_.size()-pLen-1);
783     string   trailingRes = resource_[pLen];
784
785     resPath += resource_[pLen];
786     assert(resPath.size() == (pLen+1));
787
788     resource *r = resource::findResource(resPath);
789     if (!r) assert(0);
790
791     switch (r->type()) {
792     case MDL_T_INT: {
793       const char* p = trailingRes.string_of();
794       char*       q;
795       int         val = (int) strtol(p, &q, 0);
796       if (p == q) {
797         string msg = string("unable to convert resource '") + trailingRes + 
798                      string("' to integer.");
799         showErrorCallback(92,msg.string_of());
800         return(false);
801       }
802       mdl_env::add(caStr, false, MDL_T_INT);
803       mdl_env::set(val, caStr);
804       break;
805     }
806     case MDL_T_STRING:
807       mdl_env::add(caStr, false, MDL_T_STRING);
808       mdl_env::set(trailingRes, caStr);
809       break;
810     case MDL_T_PROCEDURE: {
811       // find the resource corresponding to this function's module 
812       vector<string> m_vec;
813       for(u_int i=0; i < resPath.size()-1; i++){
814         m_vec += resPath[i];
815       }
816       assert(m_vec.size());
817       assert(m_vec.size() == (resPath.size()-1));
818       resource *m_resource = resource::findResource(m_vec);
819       if(!m_resource) return(false);
820       
821       pdFunction *pdf = proc->findOneFunction(r,m_resource);
822       if (!pdf) return(false);
823       mdl_env::add(caStr, false, MDL_T_PROCEDURE);
824       mdl_env::set(pdf, caStr);
825       break;
826     }
827     case MDL_T_MODULE: {
828       module *mod = proc->findModule(trailingRes);
829       if (!mod) return(false);
830       mdl_env::add(caStr, false, MDL_T_MODULE);
831       mdl_env::set(mod, caStr);
832       break;
833     }
834     default:
835       assert(0);
836       break;
837     }
838   }
839   return(true);
840 }
841
842
843 // Replace constraints not working yet
844 // Flag constraints need to return a handle to a data request node -- the flag
845 bool T_dyninstRPC::mdl_constraint::apply(metricDefinitionNode *mn,
846                                          dataReqNode *&flag,
847                                          vector<string>& resource,
848                                          process *proc, bool computingCost) {
849   assert(mn);
850   switch (data_type_) {
851   case MDL_T_COUNTER:
852   case MDL_T_WALL_TIMER:
853   case MDL_T_PROC_TIMER:
854     break;
855   default:
856     assert(0);
857   }
858   mdl_env::push();
859
860   if (!replace_) {
861     // create the counter used as a flag
862     mdl_env::add(id_, false, MDL_T_DRN);
863     dataReqNode *drn = mn->addUnSampledIntCounter(0, computingCost);
864     // this flag will construct a predicate for the metric -- have to return it
865     flag = drn;
866     assert(drn);
867     mdl_env::set(drn, id_);
868   }
869
870   // put $constraint[X] in the environment
871   if(!do_trailing_resources(resource, proc)) {
872     mdl_env::pop();
873     return(false);
874   }
875
876   // Now evaluate the constraint statements
877   unsigned size = stmts_->size();
878   vector<dataReqNode*> flags;
879   for (unsigned u=0; u<size; u++) {
880     if (!(*stmts_)[u]->apply(mn, flags)) {
881       // cout << "apply of constraint " << id_ << " failed\n";
882       return(false);
883     }
884   }
885   mdl_env::pop();
886   return(true);
887 }
888
889 T_dyninstRPC::mdl_constraint *mdl_data::new_constraint(string id, vector<string> *path,
890                                                 vector<T_dyninstRPC::mdl_stmt*> *stmts,
891                                                 bool replace, u_int d_type) {
892   bool error;
893   return (new T_dyninstRPC::mdl_constraint(id, path, stmts, replace, d_type, error));
894 }
895
896
897 T_dyninstRPC::mdl_rand::mdl_rand() {}
898
899 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand() {}
900
901 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type): type_(type) {}
902
903 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, u_int val)
904 : type_(type), val_(val) {}
905
906 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, string name)
907 : type_(type), name_(name) {}
908
909 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, string name, vector<mdl_instr_rand *>args)
910 : type_(type), name_(name) {
911   for (unsigned u = 0; u < args.size(); u++)
912     args_ += args[u];
913 }
914
915 T_dyninstRPC::mdl_instr_rand::~mdl_instr_rand() { } 
916
917 bool T_dyninstRPC::mdl_instr_rand::apply(AstNode *&ast) {
918   pdFunction *pdf;
919   mdl_var get_drn;
920
921   switch (type_) {
922   case MDL_T_INT:
923     if (name_.length()) {
924       // variable in the expression.
925       mdl_var get_int;
926       int value;
927       bool aflag;
928       aflag=mdl_env::get(get_int, name_);
929       assert(aflag);
930       if (!get_int.get(value)) {
931           fprintf(stderr, "Unable to get value for %s\n", name_.string_of());
932           fflush(stderr);
933           return false;
934       } else {
935           ast = new AstNode(AstNode::Constant, (void*) value);
936       }
937     } else {
938       ast = new AstNode(AstNode::Constant, (void*) val_);
939     }
940     break;
941   case MDL_ARG:
942     ast = new AstNode(AstNode::Param, (void*) val_);
943     break;
944   case MDL_RETURN:
945     ast = new AstNode(AstNode::ReturnVal, (void*)0);
946     break;
947   case MDL_READ_SYMBOL:
948     // TODO -- I am relying on global_proc to be set in mdl_metric::apply
949     if (global_proc) {
950       Symbol info;
951       if (global_proc->getSymbolInfo(name_, info)) {
952         Address adr = info.addr();
953         ast = new AstNode(AstNode::DataAddr, (void*) adr);
954       } else {
955         string msg = string("In metric '") + currentMetric + string("': ") +
956           string("unable to find symbol '") + name_ + string("'");
957         showErrorCallback(95, msg);
958         return false;
959       }
960     }
961     break;
962   case MDL_READ_ADDRESS:
963     // TODO -- check on the range of this address!
964     ast = new AstNode(AstNode::DataAddr, (void*) val_);
965     break;
966   case MDL_CALL_FUNC: {
967     // don't confuse 'args' with 'args_' here!
968     vector<AstNode *> args;
969     for (unsigned u = 0; u < args_.size(); u++) {
970       AstNode *arg=NULL;
971       if (!args_[u]->apply(arg)) { 
972         // fills in 'arg'
973         removeAst(arg);
974         return false;
975       }
976       args += assignAst(arg);
977       removeAst(arg);
978     }
979     string temp = string(name_);
980     pdf = global_proc->findOneFunction(temp);
981     if (!pdf) {
982         string msg = string("In metric '") + currentMetric + string("': ") +
983           string("unable to find procedure '") + name_ + string("'");
984         showErrorCallback(95, msg);
985         return false;
986     }
987     ast = new AstNode(name_, args);
988     for (unsigned i=0;i<args.size();i++) removeAst(args[i]);
989     break;
990   }
991   case MDL_T_COUNTER_PTR:
992     { mdl_var get_drn;
993       dataReqNode *drn;
994       if (!mdl_env::get(get_drn, name_)) {
995         string msg = string("In metric '") + currentMetric + string("' : ") +
996           string("undefined variable '") + name_ + string("'");
997         showErrorCallback(92, msg);
998         return false;
999       }
1000       bool aflag;
1001       aflag=get_drn.get(drn);
1002       assert(aflag);
1003       ast = new AstNode(AstNode::DataPtr, (void *)(drn->getInferiorPtr()));
1004     }
1005     break;
1006   case MDL_T_COUNTER:
1007     {
1008       mdl_var get_drn;
1009       dataReqNode *drn;
1010       bool aflag;
1011       aflag=mdl_env::get(get_drn, name_);
1012       assert(aflag);
1013       //
1014       // This code was added to support additional mdl evaluation time 
1015       //     variables.  To keep it simple, I left the parser alone and so
1016       //     any unknown identifier maps to MDL_T_COUNTER.  We lookup the
1017       //     variable's type here to generate the correct code.  MDL
1018       //     really should have a general type system and all functions
1019       //     signatures. - jkh 7/5/95
1020       //
1021       switch (get_drn.type()) {
1022           case MDL_T_INT:
1023               int value;
1024               if (!get_drn.get(value)) {
1025                   fprintf(stderr, "Unable to get value for %s\n", 
1026                       name_.string_of());
1027                   fflush(stderr);
1028                   return false;
1029               } else {
1030                   ast = new AstNode(AstNode::Constant, (void*) value);
1031               }
1032               break;
1033           case MDL_T_COUNTER:   // is MDL_T_COUNTER used here ??? jkh 7/31/95
1034           case MDL_T_DRN:
1035               if (!get_drn.get(drn)) {
1036                   fprintf(stderr, "Unable to find variable %s\n", 
1037                       name_.string_of());
1038                   fflush(stderr);
1039                   return false;
1040               } else {
1041                   // Note: getInferiorPtr could return a NULL pointer here if
1042                   // we are just computing cost - naim 2/18/97
1043                   ast = new AstNode(AstNode::DataValue, 
1044                                     (void*)(drn->getInferiorPtr()));
1045               }
1046               break;
1047           default:
1048               fprintf(stderr, "type of variable %s is not known\n",
1049                   name_.string_of());
1050               fflush(stderr);
1051               return false;
1052       }
1053     }
1054     break;
1055   default:
1056     break;
1057   }
1058   return true;
1059 }
1060
1061
1062
1063 T_dyninstRPC::mdl_instr_req::mdl_instr_req(T_dyninstRPC::mdl_instr_rand *rand,
1064                                            u_int type, string obj_name)
1065 : type_(type), rand_(rand), timer_counter_name_(obj_name) { }
1066
1067 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int type, string obj_name)
1068 : type_(type), timer_counter_name_(obj_name) { }
1069
1070 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int type,
1071                                            T_dyninstRPC::mdl_instr_rand *rand)
1072 : type_(type), rand_(rand) { }
1073
1074 T_dyninstRPC::mdl_instr_req::mdl_instr_req() : type_(0) { }
1075 T_dyninstRPC::mdl_instr_req::~mdl_instr_req() { }
1076
1077 bool T_dyninstRPC::mdl_instr_req::apply(AstNode *&mn, AstNode *pred,
1078                                         bool mn_initialized) {
1079   // a return value of true implies that "mn" was written to
1080   AstNode *ast_arg=NULL;
1081
1082   vector<AstNode *> ast_args;
1083   string timer_fun;
1084
1085   switch (type_) {
1086   case MDL_SET_COUNTER:
1087   case MDL_ADD_COUNTER:
1088   case MDL_SUB_COUNTER:
1089     if (! rand_->apply(ast_arg))
1090       return false;
1091     break;
1092   case MDL_START_WALL_TIMER:
1093     timer_fun = START_WALL_TIMER;
1094     break;
1095   case MDL_STOP_WALL_TIMER:
1096     timer_fun = STOP_WALL_TIMER;
1097     break;
1098   case MDL_START_PROC_TIMER:
1099     timer_fun = START_PROC_TIMER;
1100     break;
1101   case MDL_STOP_PROC_TIMER:
1102     timer_fun = STOP_PROC_TIMER;
1103     break;
1104   }
1105
1106   dataReqNode *drn;
1107   mdl_var get_drn;
1108   if (type_ != MDL_CALL_FUNC) {
1109       bool aflag;
1110       aflag=mdl_env::get(get_drn, timer_counter_name_);
1111       assert(aflag);
1112       aflag=get_drn.get(drn);
1113       assert(aflag);
1114   }
1115
1116   AstNode *code=NULL;
1117
1118   switch (type_) {
1119   case MDL_SET_COUNTER:
1120 #if defined(MT_THREAD)
1121     code = createCounter("setCounter", (void *)(drn->getSampleId()), ast_arg);
1122 #else
1123     code = createCounter("setCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1124 #endif
1125     break;
1126   case MDL_ADD_COUNTER:
1127 #if defined(MT_THREAD)
1128     code = createCounter("addCounter", (void *)(drn->getSampleId()), ast_arg);
1129 #else
1130     code = createCounter("addCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1131 #endif
1132     break;
1133   case MDL_SUB_COUNTER:
1134 #if defined(MT_THREAD)
1135     code = createCounter("subCounter", (void *)(drn->getSampleId()), ast_arg);
1136 #else
1137     code = createCounter("subCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1138 #endif
1139     break;
1140   case MDL_START_WALL_TIMER:
1141   case MDL_STOP_WALL_TIMER:
1142   case MDL_START_PROC_TIMER:
1143   case MDL_STOP_PROC_TIMER:
1144 #if defined(MT_THREAD)
1145     code = createTimer(timer_fun, (void *)(drn->getSampleId()), ast_args);
1146 #else
1147     code = createTimer(timer_fun, (void *)(drn->getInferiorPtr()), ast_args);
1148 #endif
1149     break;
1150   case MDL_CALL_FUNC:
1151     if (! rand_->apply(code))
1152       return false;
1153     break;
1154   default:
1155     return false;
1156   }
1157   if (pred) {
1158     // Note: we don't use assignAst on purpose here
1159     AstNode *tmp=code;
1160     code = createIf(pred, tmp);
1161     removeAst(tmp);
1162   }
1163
1164   if (mn_initialized) {
1165     // Note: we don't use assignAst on purpose here
1166     AstNode *tmp=mn;
1167     mn = new AstNode(tmp, code);
1168     removeAst(tmp);
1169   } else {
1170     mn = assignAst(code);
1171   }
1172
1173   removeAst(ast_arg);
1174   removeAst(code);
1175   return true;
1176 }
1177
1178 T_dyninstRPC::mdl_stmt::mdl_stmt() { }
1179
1180 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt(string index_name, T_dyninstRPC::mdl_expr *list_exp, T_dyninstRPC::mdl_stmt *body) 
1181 : for_body_(body), index_name_(index_name), list_expr_(list_exp) { }
1182 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt() { }
1183 T_dyninstRPC::mdl_for_stmt::~mdl_for_stmt() {
1184   delete for_body_;
1185   delete list_expr_;
1186 }
1187
1188 bool T_dyninstRPC::mdl_for_stmt::apply(metricDefinitionNode *mn,
1189                                        vector<dataReqNode*>& flags) {
1190   mdl_env::push();
1191   mdl_env::add(index_name_, false);
1192   mdl_var list_var(false);
1193
1194   // TODO -- build iterator closure here -- list may be vector or dictionary
1195   if (!list_expr_->apply(list_var))
1196     return false;
1197   if (!list_var.is_list())
1198     return false;
1199
1200   // TODO
1201   //  vector<pdFunction*> *vp;
1202   //  list_var.get(vp);
1203   list_closure closure(index_name_, list_var);
1204
1205   // mdl_env::set_type(list_var.element_type(), index_name_);
1206   while (closure.next()) {
1207     if (!for_body_->apply(mn, flags)) return false;
1208   }
1209
1210   mdl_env::pop();
1211   return true;
1212 }
1213
1214 T_dyninstRPC::mdl_icode::mdl_icode() { }
1215 T_dyninstRPC::mdl_icode::mdl_icode(T_dyninstRPC::mdl_instr_rand *iop1,
1216                                    T_dyninstRPC::mdl_instr_rand *iop2,
1217                                    u_int bin_op, bool use_if,
1218                                    T_dyninstRPC::mdl_instr_req *ireq)
1219 : if_op1_(iop1), if_op2_(iop2),
1220   bin_op_(bin_op), use_if_(use_if), req_(ireq) { }
1221 T_dyninstRPC::mdl_icode::~mdl_icode() { delete req_; }
1222
1223 static AstNode *do_rel_op(opCode op, T_dyninstRPC::mdl_instr_rand *if_op2,
1224                           AstNode *ast_left) {
1225    // NOTE: ast_left _must_ be defined
1226    AstNode *ast_right=NULL;
1227    AstNode *tmp=NULL;
1228    if (!if_op2->apply(ast_right)) {
1229       removeAst(ast_right);
1230       return(new AstNode());
1231    }
1232    tmp = new AstNode(op, ast_left, ast_right);
1233    removeAst(ast_right);
1234    return(tmp);;
1235 }
1236
1237 bool T_dyninstRPC::mdl_icode::apply(AstNode *&mn, bool mn_initialized) {
1238   // a return value of true implies that "mn" has been written to
1239   // TODO -- handle the if case here
1240   // TODO -- call req_->apply() after building if
1241
1242   if (!req_)
1243      return false;
1244
1245   AstNode *pred=NULL;
1246   AstNode *pred_ptr=NULL;
1247
1248   if (use_if_) {
1249     AstNode *ast1=NULL;
1250     if (!if_op1_->apply(ast1))
1251        return false;
1252     switch (bin_op_) {
1253     case MDL_LT:
1254       pred = do_rel_op(lessOp, if_op2_, ast1);
1255       break;
1256     case MDL_GT:
1257       pred = do_rel_op(greaterOp, if_op2_, ast1);
1258       break;
1259     case MDL_LE:
1260       pred = do_rel_op(leOp, if_op2_, ast1);
1261       break;
1262     case MDL_GE:
1263       pred = do_rel_op(geOp, if_op2_, ast1);
1264       break;
1265     case MDL_EQ:
1266       pred = do_rel_op(eqOp, if_op2_, ast1);
1267       break;
1268     case MDL_NE:
1269       pred = do_rel_op(neOp, if_op2_, ast1);
1270       break;
1271     case MDL_T_NONE:
1272       pred = ast1;
1273       break;
1274     default: return false;
1275     }
1276     removeAst(ast1);
1277     pred_ptr = new AstNode(pred);
1278   } // if ()
1279   else
1280     pred_ptr = NULL;
1281
1282   bool result = req_->apply(mn, pred_ptr, mn_initialized);
1283      // note: a result of true implies that "mn" was written to
1284      // Hence, a result of true from this routine means the same.
1285
1286   removeAst(pred);
1287   removeAst(pred_ptr);
1288   return result;
1289 }
1290
1291 T_dyninstRPC::mdl_expr::mdl_expr() { }
1292 T_dyninstRPC::mdl_expr::~mdl_expr() { }
1293
1294 T_dyninstRPC::mdl_v_expr::mdl_v_expr() 
1295 : args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL), type_(MDL_T_NONE),
1296   do_type_walk_(false), ok_(false) { }
1297
1298 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, vector<string> fields) 
1299 : var_(var), fields_(fields),
1300   args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
1301   type_(MDL_RVAL_DEREF), do_type_walk_(false), ok_(false) { assert(0); }
1302
1303 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string func_name,
1304                                      vector<T_dyninstRPC::mdl_expr *> *a) 
1305 : var_(func_name), args_(a),
1306   literal_(0), arg_(100000), left_(NULL), right_(NULL),
1307   type_(MDL_RVAL_FUNC), do_type_walk_(false), ok_(false) { assert(0); }
1308
1309 T_dyninstRPC::mdl_v_expr::mdl_v_expr(int int_lit) 
1310 : args_(NULL), literal_(int_lit), arg_(0), left_(NULL), right_(NULL),
1311   type_(MDL_RVAL_INT), do_type_walk_(false), ok_(false) { assert(0); }
1312
1313 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string string_lit) 
1314 : var_(string_lit),
1315   args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
1316   type_(MDL_RVAL_STRING), do_type_walk_(false), ok_(false) { assert(0); }
1317
1318 T_dyninstRPC::mdl_v_expr::mdl_v_expr(u_int bin_op, T_dyninstRPC::mdl_expr *left,
1319                                  T_dyninstRPC::mdl_expr *right) 
1320 : args_(NULL), literal_(0),
1321   arg_(bin_op), left_(left), right_(right),
1322   type_(MDL_RVAL_EXPR), do_type_walk_(false), ok_(false) { assert(0); }
1323
1324 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, u_int array_index) 
1325 : var_(var), args_(NULL), literal_(0), arg_(array_index), left_(NULL), right_(NULL),
1326   type_(MDL_RVAL_ARRAY), do_type_walk_(false), ok_(false) { assert(0); }
1327
1328 T_dyninstRPC::mdl_v_expr::~mdl_v_expr() {
1329   delete args_; delete left_; delete right_;
1330   if (args_) {
1331     unsigned size = args_->size();
1332     for (unsigned u=0; u<size; u++)
1333       delete (*args_)[u];
1334     delete args_;
1335   }
1336 }
1337
1338 bool T_dyninstRPC::mdl_v_expr::apply(mdl_var& ret) {
1339   switch (type_) {
1340   case MDL_RVAL_INT: 
1341     return (ret.set(literal_));
1342   case MDL_RVAL_STRING:
1343     return (ret.set(var_));
1344   case MDL_RVAL_ARRAY:
1345     {
1346       mdl_var array(false);
1347       if (!mdl_env::get(array, var_)) return false;
1348       if (!array.is_list()) return false;  
1349       if (arg_ >= array.list_size()) return false;
1350       return (array.get_ith_element(ret, arg_));
1351     }
1352   case MDL_RVAL_EXPR:
1353     {
1354       mdl_var left_val(false), right_val(false);
1355       if (!left_ || !right_) return false;
1356       if (!left_->apply(left_val)) return false;
1357       if (!right_->apply(right_val)) return false;
1358       return (do_operation(ret, left_val, right_val, arg_));
1359     }
1360   case MDL_RVAL_FUNC:
1361     // TODO
1362     switch (arg_) {
1363     case 0:
1364       // lookupFunction
1365       {
1366         mdl_var arg0(false);
1367         if (!(*args_)[0]->apply(arg0)) return false;
1368         string func_name;
1369         if (!arg0.get(func_name)) return false;
1370         if (global_proc) {
1371           // TODO -- what if the function is not found ?
1372           pdFunction *pdf = global_proc->findOneFunction(func_name);
1373           return (ret.set(pdf));
1374         } else {
1375           assert(0); return false;
1376         }
1377       }
1378     case 1:
1379       // lookupModule
1380       {
1381         mdl_var arg0(false);
1382         if (!(*args_)[0]->apply(arg0)) return false;
1383         string mod_name;
1384         if (!arg0.get(mod_name)) return false;
1385         if (global_proc) {
1386           // TODO -- what if the function is not found ?
1387           module *mod = global_proc->findModule(mod_name);
1388           if (!mod) { assert(0); return false; }
1389           return (ret.set(mod));
1390         } else {
1391           assert(0); return false;
1392         }
1393       }
1394     case 2:
1395       // libraryTag
1396       {
1397         mdl_var arg0(false);
1398         if (!(*args_)[0]->apply(arg0)) return false;
1399         int tag;
1400         if (!arg0.get(tag)) return false;
1401         int res = tag & TAG_LIB_FUNC;
1402         return (ret.set(res));
1403       }
1404     default:
1405       return false;
1406     }
1407   case MDL_RVAL_DEREF:
1408     if (!do_type_walk_)
1409       return (mdl_env::get(ret, var_));
1410     else
1411       return (walk_deref(ret, type_walk, var_)); 
1412   default:
1413     return false;
1414   }
1415   return true;
1416 }
1417
1418 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt(T_dyninstRPC::mdl_expr *expr, T_dyninstRPC::mdl_stmt *body) : expr_(expr), body_(body) { }
1419 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt() { }
1420 T_dyninstRPC::mdl_if_stmt::~mdl_if_stmt() {
1421   delete expr_; delete body_;
1422 }
1423
1424 bool T_dyninstRPC::mdl_if_stmt::apply(metricDefinitionNode *mn,
1425                                       vector<dataReqNode*>& flags) {
1426   // An if stmt is comprised of (1) the 'if' expr and (2) the body to
1427   // execute if true.
1428   mdl_var res(false);
1429   if (!expr_->apply(res))
1430     return false;
1431
1432   int iv;
1433   switch (res.type()) {
1434   case MDL_T_INT:
1435     if (!res.get(iv))
1436       return false;
1437     if (!iv)
1438       return true;
1439     break;
1440   default:
1441     return false;
1442   }
1443
1444   return body_->apply(mn, flags);
1445 }
1446
1447 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt(vector<T_dyninstRPC::mdl_stmt*> *stmts) : stmts_(stmts) { }
1448 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt() { }
1449 T_dyninstRPC::mdl_seq_stmt::~mdl_seq_stmt() {
1450   if (stmts_) {
1451     unsigned size = stmts_->size();
1452     for (unsigned u=0; u<size; u++)
1453       delete (*stmts_)[u];
1454     delete stmts_;
1455   }
1456 }
1457
1458 bool T_dyninstRPC::mdl_seq_stmt::apply(metricDefinitionNode *mn,
1459                                        vector<dataReqNode*>& flags) {
1460   // a seq_stmt is simply a sequence of statements; apply them all.
1461   if (!stmts_)
1462     return true;
1463
1464   unsigned size = stmts_->size();
1465   for (unsigned index=0; index<size; index++)
1466     if (!(*stmts_)[index]->apply(mn, flags)) // virtual fn call
1467       return false;
1468
1469   return true;
1470 }
1471
1472 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt(u_int type, string ident,
1473                                            vector<string> *elems,
1474                                            bool is_lib, vector<string>* flavor) 
1475 : type_(type), id_(ident), elements_(elems), is_lib_(is_lib), flavor_(flavor) { }
1476 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt() { }
1477 T_dyninstRPC::mdl_list_stmt::~mdl_list_stmt() { delete elements_; }
1478
1479 bool T_dyninstRPC::mdl_list_stmt::apply(metricDefinitionNode * /*mn*/,
1480                                         vector<dataReqNode*>& /*flags*/) {
1481   bool found = false;
1482   for (unsigned u0 = 0; u0 < flavor_->size(); u0++) {
1483     if ((*flavor_)[u0] == daemon_flavor) {
1484       found = true;
1485       break;
1486     }
1487   }
1488   if (!found) return false;
1489   if (!elements_) return false;
1490   mdl_var expr_var;
1491   mdl_var list_var(id_, false);
1492   unsigned size = elements_->size();
1493   if (!list_var.make_list(type_)) return false;
1494
1495   if (type_ == MDL_T_PROCEDURE_NAME) {
1496     vector<functionName*> *list_fn;
1497     bool aflag;
1498     aflag=list_var.get(list_fn);
1499     assert(aflag);
1500     for (unsigned u=0; u<size; u++) {
1501       functionName *fn = new functionName((*elements_)[u]);
1502       *list_fn += fn;
1503     }
1504   } else if (type_ == MDL_T_PROCEDURE) { 
1505     assert(0);
1506   } else if (type_ == MDL_T_MODULE) {
1507     assert(0);
1508   } else {
1509     for (unsigned u=0; u<size; u++) {
1510       int i; float f; string s; mdl_var expr_var;
1511       switch (type_) {
1512       case MDL_T_INT:
1513         if (sscanf((*elements_)[u].string_of(), "%d", &i) != 1) return false;
1514         if (!expr_var.set(i)) return false; break;
1515       case MDL_T_FLOAT:
1516         if (sscanf((*elements_)[u].string_of(), "%f", &f) != 1) return false;
1517         if (!expr_var.set(f)) return false; break;
1518       case MDL_T_STRING: 
1519         if (!expr_var.set((*elements_)[u])) return false; break;
1520       default:
1521         return false;
1522       }
1523       if (!list_var.add_to_list(expr_var)) return false;
1524     }
1525   }
1526   return (mdl_env::add(list_var));
1527 }
1528
1529 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt(unsigned pos, T_dyninstRPC::mdl_expr *expr,
1530                                       vector<T_dyninstRPC::mdl_icode*> *reqs,
1531                                       unsigned where, bool constrained) 
1532 : position_(pos), point_expr_(expr), icode_reqs_(reqs),
1533   where_instr_(where), constrained_(constrained) { }
1534 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt() { }
1535 T_dyninstRPC::mdl_instr_stmt::~mdl_instr_stmt() {
1536   delete point_expr_;
1537   if (icode_reqs_) {
1538     unsigned size = icode_reqs_->size();
1539     for (unsigned u=0; u<size; u++)
1540       delete (*icode_reqs_)[u];
1541     delete icode_reqs_;
1542   }
1543 }
1544
1545 bool T_dyninstRPC::mdl_instr_stmt::apply(metricDefinitionNode *mn,
1546                                          vector<dataReqNode*>& inFlags) {
1547    // An instr statement is like:
1548    //    append preInsn $start.entry constrained (* startWallTimer(a_wallTime); *)
1549    // (note that there are other kinds of statements; i.e. there are other classes
1550    //  derived from the base class mdl_stmt; see dyninstRPC.I)
1551
1552   if (icode_reqs_ == NULL)
1553     return false; // no instrumentation code to put in!
1554
1555   mdl_var pointsVar(false);
1556   if (!point_expr_->apply(pointsVar)) // process the 'point(s)' e.g. "$start.entry"
1557     return false;
1558
1559   vector<instPoint *> points;
1560   if (pointsVar.type() == MDL_T_LIST_POINT) {
1561     vector<instPoint *> *pts;
1562     if (!pointsVar.get(pts)) return false;
1563     points = *pts;
1564   } else if (pointsVar.type() == MDL_T_POINT) {
1565     instPoint *p;
1566     if (!pointsVar.get(p)) return false; // where the point is located...
1567     points += p;
1568   } else {
1569     return false;
1570   }
1571
1572   // Let's generate the code now (we used to calculate it in the loop below,
1573   // which was a waste since the code is the same for all points).
1574   AstNode *code = NULL;
1575   unsigned size = icode_reqs_->size();
1576   for (unsigned u=0; u<size; u++) {
1577     if (!(*icode_reqs_)[u]->apply(code, u>0)) {
1578       // when u is 0, code is un-initialized
1579       removeAst(code);
1580       return false;
1581     }
1582   }
1583
1584   // Instantiate all constraints (flags) here (if any)
1585   // (if !constrained_ then don't do the following)
1586   if (constrained_) {
1587      unsigned fsize = inFlags.size();
1588      for (int fi=fsize-1; fi>=0; fi--) { // any reason why we go backwards?
1589         // Note: getInferiorPtr could return a NULL pointer here if we are
1590         // just computing cost - naim 2/18/97
1591         AstNode *temp1 = new AstNode(AstNode::DataValue, 
1592                                      (void*)((inFlags[fi])->getInferiorPtr()));
1593         // Note: we don't use assignAst on purpose here
1594         AstNode *temp2 = code;
1595         code = createIf(temp1, temp2);
1596         removeAst(temp1);
1597         removeAst(temp2);
1598      }
1599   }
1600
1601   if (!code) {
1602     // we are probably defining an empty metric
1603     code = new AstNode();
1604   }
1605
1606   callOrder corder;
1607   switch (position_) {
1608       case MDL_PREPEND: 
1609           corder = orderFirstAtPoint; 
1610           break;
1611       case MDL_APPEND: 
1612           corder = orderLastAtPoint; 
1613           break;
1614       default: assert(0);
1615   }
1616
1617   callWhen cwhen;
1618   switch (where_instr_) {
1619       case MDL_PRE_INSN: 
1620           cwhen = callPreInsn; 
1621           break;
1622       case MDL_POST_INSN: 
1623           cwhen = callPostInsn; 
1624           break;
1625       default: assert(0);
1626   }
1627
1628   // Here is where auto-activate should occur.
1629   // If there is 1 point and it is $start.entry then
1630   // do an inferiorRPC right now (of the ast 'code').
1631   // In this way, we can get metrics like cpu and exec-time for whole program
1632   // to work correctly even when the metrics are instantiated after
1633   // the entrypoint of main() is in execution.
1634
1635   bool manuallyTrigger = false; // for now
1636
1637   if (points.size() == 1) {
1638      // now look at the mdl variable to check for $start.entry.
1639      if (pointsVar.name() == "$start" && pointsVar.type()==MDL_T_POINT) {
1640         // having a type of MDL_T_POINT should mean $start.entry as opposed to
1641         // $start.exit, since $start.exit would yield a type of MDL_T_LIST_POINT,
1642         // since exit locations are always a list-of-points.  Sorry for the kludge.
1643
1644         instPoint *theVrbleInstPoint; // NOTE: instPoint is defined in arch-specific files!!!
1645         bool aflag = pointsVar.get(theVrbleInstPoint);
1646         // theVrbleInstPoint set to equiv of points[0]
1647         assert(aflag);
1648
1649         assert(theVrbleInstPoint == points[0]); // just a sanity check
1650
1651         mdl_var theVar;
1652         string varName = pointsVar.name();
1653         aflag=mdl_env::get(theVar, varName);
1654         assert(aflag);
1655
1656         pdFunction *theFunction;
1657         aflag=theVar.get(theFunction);
1658         assert(aflag);
1659
1660         // Make a note to do an inferiorRPC to manually execute this code.
1661 //      if (!manuallyTrigger)
1662 //         cerr << "mdl: found $start.entry; going to manually execute via inferior-RPC" << endl;
1663
1664         manuallyTrigger = true;
1665      }
1666   }
1667
1668   // for all of the inst points, insert the predicates and the code itself.
1669   for (unsigned i = 0; i < points.size(); i++) {
1670       mn->addInst(points[i], code, cwhen, corder,
1671                   manuallyTrigger && (i==0)); // manually trigger at most once
1672          // appends an instReqNode to mn's instRequests; actual 
1673          // instrumentation only
1674          // takes place when mn->insertInstrumentation() is later called.
1675   }
1676   removeAst(code); 
1677   return true;
1678 }
1679
1680 bool mdl_can_do(string& met_name) {
1681   // NOTE: We can do better if there's a dictionary of <metric-name> to <anything>
1682   unsigned size = mdl_data::all_metrics.size();
1683   for (unsigned u=0; u<size; u++) 
1684     if (mdl_data::all_metrics[u]->name_ == met_name)
1685       return true;
1686
1687   return false;
1688 }
1689
1690 metricDefinitionNode *mdl_do(vector< vector<string> >& canon_focus, 
1691                              string& met_name,
1692                              string& flat_name,
1693                              vector<process *> procs,
1694                              bool replace_components_if_present,
1695                              bool computingCost) {
1696   currentMetric = met_name;
1697   unsigned size = mdl_data::all_metrics.size();
1698   // NOTE: We can do better if there's a dictionary of <metric-name> to <metric>!
1699   for (unsigned u=0; u<size; u++) {
1700     if (mdl_data::all_metrics[u]->name_ == met_name) {
1701       return (mdl_data::all_metrics[u]->apply(canon_focus, flat_name, procs,
1702                                               replace_components_if_present,
1703                                               computingCost));
1704          // calls mdl_metric::apply()
1705     }
1706   }
1707   return NULL;
1708 }
1709
1710 bool mdl_init(string& flavor) { 
1711
1712   daemon_flavor = flavor;
1713
1714 #ifdef notdef
1715   vector<mdl_type_desc> kids;
1716   mdl_type_desc self, kid;
1717   mdl_focus_element fe;
1718
1719   self.name = "SyncObject"; self.type = 0; self.end_allowed = false; 
1720   kid.name = "Message"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1721   kid.name = "Barrier"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1722   kid.name = "Semaphore"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1723   kid.name = "SpinLock"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1724   fe.self = self; fe.kids = kids;
1725   mdl_data::foci += fe;
1726   kids.resize(0);
1727
1728 //  self.name = "Procedure"; self.type = MDL_T_MODULE; self.end_allowed = true;
1729   self.name = "Code"; self.type = MDL_T_MODULE; self.end_allowed = true;
1730   kid.name = "Module"; kid.type = MDL_T_PROCEDURE; self.end_allowed = true; kids += kids;
1731   fe.self = self; fe.kids = kids;
1732   mdl_data::foci += fe;
1733   kids.resize(0);
1734
1735   self.name = "Process"; self.type = MDL_T_PROCESS; self.end_allowed = true;
1736   fe.self = self; fe.kids.resize(0);
1737   mdl_data::foci += fe;
1738
1739   self.name = "Machine"; self.type = MDL_T_STRING; self.end_allowed = true;
1740   fe.self = self; fe.kids.resize(0);
1741   mdl_data::foci += fe;
1742 #endif
1743
1744   mdl_env::push();
1745   // These are pushed on per-process
1746   // mdl_env::add("$procedures", false, MDL_T_LIST_PROCEDURE);
1747   // mdl_env::add("$modules", false, MDL_T_LIST_MODULE);
1748
1749   string vname = "$machine";
1750   mdl_env::add(vname, false, MDL_T_STRING);
1751   string nodename = getHostName();
1752   mdl_env::set(nodename, vname);
1753
1754   /* Are these entered by hand at the new scope ? */
1755   /* $arg, $return */
1756
1757   vector<mdl_type_desc> field_list;
1758   mdl_type_desc desc;
1759   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1760   desc.name = "calls"; desc.type = MDL_T_LIST_POINT; field_list += desc;
1761   desc.name = "entry"; desc.type = MDL_T_POINT; field_list += desc;
1762   desc.name = "return"; desc.type = MDL_T_POINT; field_list += desc;
1763   desc.name = "tag"; desc.type = MDL_T_INT; field_list += desc;
1764   mdl_data::fields[MDL_T_PROCEDURE] = field_list;
1765   field_list.resize(0);
1766
1767   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1768   desc.name = "funcs"; desc.type = MDL_T_LIST_PROCEDURE; field_list += desc;
1769   mdl_data::fields[MDL_T_MODULE] = field_list;
1770   field_list.resize(0);
1771
1772   return true;
1773 }
1774
1775 void dynRPC::send_metrics(vector<T_dyninstRPC::mdl_metric*>* var_0) {
1776   mdl_met = true;
1777
1778   if (var_0) {
1779     unsigned var_size = var_0->size();
1780     for (unsigned v=0; v<var_size; v++) {
1781       // fprintf(stderr, "Got metric %s\n", (*var_0)[v]->name_.string_of());
1782       // fflush(stderr);
1783       bool found = false;
1784       unsigned f_size = (*var_0)[v]->flavors_->size();
1785
1786       bool flavor_found = false;
1787       for (unsigned f=0; f<f_size; f++) {
1788         if ((*(*var_0)[v]->flavors_)[f] == daemon_flavor) {
1789           flavor_found = true; break;
1790         }
1791       }
1792       if (flavor_found) {
1793         unsigned size=mdl_data::all_metrics.size();
1794         for (unsigned u=0; u<size; u++) 
1795           if (mdl_data::all_metrics[u]->id_ == (*var_0)[v]->id_) {
1796             delete mdl_data::all_metrics[u];
1797             mdl_data::all_metrics[u] = (*var_0)[v];
1798             found = true;
1799           }
1800         if (!found) {
1801           T_dyninstRPC::mdl_metric *m = (*var_0)[v];
1802           mdl_data::all_metrics += m;
1803         }
1804       }
1805     }
1806   } else {
1807      fprintf(stderr, "no metric defined\n");
1808      fflush(stderr);
1809   }
1810 }
1811
1812 void dynRPC::send_constraints(vector<T_dyninstRPC::mdl_constraint*> *cv) {
1813
1814   mdl_cons = true;
1815   if (cv) {
1816     unsigned var_size = cv->size();
1817     for (unsigned v=0; v<var_size; v++) {
1818       bool found = false;
1819       // cout << "Received " << (*cv)[v]->id_ << endl;
1820       for (unsigned u=0; u<mdl_data::all_constraints.size(); u++) 
1821         if (mdl_data::all_constraints[u]->id_ == (*cv)[v]->id_) {
1822           delete mdl_data::all_constraints[u];
1823           mdl_data::all_constraints[u] = (*cv)[v];
1824           found = true;
1825         }
1826       if (!found) {
1827         mdl_data::all_constraints += (*cv)[v];
1828         // cout << *(*cv)[v] << endl;
1829       }
1830     }
1831   }
1832 }
1833
1834
1835 // TODO -- are these executed immediately ?
1836 void dynRPC::send_stmts(vector<T_dyninstRPC::mdl_stmt*> *vs) {
1837   mdl_stmt = true;
1838   if (vs) {
1839     // ofstream of("other_out", (been_here ? ios::app : ios::out));
1840     // been_here = true;
1841     // of << "SEND_STMTS\n";
1842     // unsigned size = vs->size();
1843     // for (unsigned u=0; u<size; u++) 
1844     // (*vs)[u]->print(of);
1845     mdl_data::stmts += *vs;
1846
1847     // TODO -- handle errors here
1848     // TODO -- apply these statements without a metric definition node ?
1849     unsigned s_size = vs->size();
1850     vector<dataReqNode*> flags;
1851
1852     // Application may fail if the list flavor is different than the flavor
1853     // of this daemon
1854
1855     for (unsigned s=0; s<s_size; s++) {
1856       if (!(*vs)[s]->apply(NULL, flags)) 
1857         ;
1858       // (*vs)[s]->print(cout);
1859       // cout << endl;
1860     }
1861   }
1862 }
1863
1864 // recieves the list of shared libraries to exclude from 
1865 // foci that are not refined on the Code heirarchy
1866 void dynRPC::send_libs(vector<string> *libs) {
1867
1868     mdl_libs = true;
1869     for(u_int i=0; i < libs->size(); i++){
1870         mdl_data::lib_constraints += (*libs)[i]; 
1871     }
1872
1873 }
1874
1875 // recieves notification that there are no excluded libraries 
1876 void dynRPC::send_no_libs() {
1877
1878     mdl_libs = true;
1879
1880 }
1881
1882 static bool do_operation(mdl_var& ret, mdl_var& left_val,
1883                          mdl_var& right_val, unsigned bin_op) {
1884   switch (bin_op) {
1885   case MDL_PLUS:
1886   case MDL_MINUS:
1887   case MDL_DIV:
1888   case MDL_MULT:
1889     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
1890       int v1, v2;
1891       if (!left_val.get(v1)) return false;
1892       if (!right_val.get(v2)) return false;
1893       switch (bin_op) {
1894       case MDL_PLUS: return (ret.set(v1+v2));
1895       case MDL_MINUS: return (ret.set(v1-v2));
1896       case MDL_DIV: return (ret.set(v1/v2));
1897       case MDL_MULT: return (ret.set(v1*v2));
1898       }
1899     } else if (((left_val.type() == MDL_T_INT) || (left_val.type() == MDL_T_FLOAT)) &&
1900                ((right_val.type() == MDL_T_INT) || (right_val.type() == MDL_T_FLOAT))) {
1901       float v1, v2;
1902       if (left_val.type() == MDL_T_INT) {
1903         int i1; if (!left_val.get(i1)) return false; v1 = (float)i1;
1904       } else {
1905         if (!left_val.get(v1)) return false;
1906       }
1907       if (right_val.type() == MDL_T_INT) {
1908         int i1; if (!right_val.get(i1)) return false; v2 = (float)i1;
1909       } else {
1910         if (!right_val.get(v2)) return false;
1911       }
1912       switch (bin_op) {
1913       case MDL_PLUS: return (ret.set(v1+v2));
1914       case MDL_MINUS: return (ret.set(v1-v2));
1915       case MDL_DIV: return (ret.set(v1/v2));
1916       case MDL_MULT: return (ret.set(v1*v2));
1917       }
1918     } else
1919       return false;
1920   case MDL_LT:
1921   case MDL_GT:
1922   case MDL_LE:
1923   case MDL_GE:
1924   case MDL_EQ:
1925   case MDL_NE:
1926     if ((left_val.type() == MDL_T_STRING) && (right_val.type() == MDL_T_STRING)) {
1927       string v1, v2;
1928       if (!left_val.get(v1)) return false;
1929       if (!right_val.get(v2)) return false;
1930       switch (bin_op) {
1931       case MDL_LT: return (ret.set(v1 < v2));
1932       case MDL_GT: return (ret.set(v1 > v2));
1933       case MDL_LE: return (ret.set(v1 <= v2));
1934       case MDL_GE: return (ret.set(v1 >= v2));
1935       case MDL_EQ: return (ret.set(v1 == v2));
1936       case MDL_NE: return (ret.set(v1 != v2));
1937       }  
1938     }
1939     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
1940       int v1, v2;
1941       if (!left_val.get(v1)) return false;
1942       if (!right_val.get(v2)) return false;
1943       switch (bin_op) {
1944       case MDL_LT: return (ret.set(v1 < v2));
1945       case MDL_GT: return (ret.set(v1 > v2));
1946       case MDL_LE: return (ret.set(v1 <= v2));
1947       case MDL_GE: return (ret.set(v1 >= v2));
1948       case MDL_EQ: return (ret.set(v1 == v2));
1949       case MDL_NE: return (ret.set(v1 != v2));
1950       }
1951     } else if (((left_val.type() == MDL_T_INT) ||
1952                 (left_val.type() == MDL_T_FLOAT)) &&
1953                ((right_val.type() == MDL_T_INT) ||
1954                 (right_val.type() == MDL_T_FLOAT))) {
1955       float v1, v2;
1956       if (left_val.type() == MDL_T_INT) {
1957         int i1; if (!left_val.get(i1)) return false; v1 = (float)i1;
1958       } else {
1959         if (!left_val.get(v1)) return false;
1960       }
1961       if (right_val.type() == MDL_T_INT) {
1962         int i1; if (!right_val.get(i1)) return false; v2 = (float)i1;
1963       } else {
1964         if (!right_val.get(v2)) return false;
1965       }
1966       switch (bin_op) {
1967       case MDL_LT: return (ret.set(v1 < v2));
1968       case MDL_GT: return (ret.set(v1 > v2));
1969       case MDL_LE: return (ret.set(v1 <= v2));
1970       case MDL_GE: return (ret.set(v1 >= v2));
1971       case MDL_EQ: return (ret.set(v1 == v2));
1972       case MDL_NE: return (ret.set(v1 != v2));
1973       }
1974     } else
1975       return false;
1976   case MDL_AND:
1977   case MDL_OR:
1978     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
1979       int v1, v2;
1980       if (!left_val.get(v1)) return false;
1981       if (!right_val.get(v2)) return false;
1982       switch (bin_op) {
1983       case MDL_AND: return (ret.set(v1 && v2));
1984       case MDL_OR: return (ret.set(v1 || v2));
1985       }
1986     } else
1987       return false;
1988   default:
1989       return false;
1990   }
1991   return false;
1992 }
1993
1994 static bool walk_deref(mdl_var& ret, vector<unsigned>& types, string& var_name) {
1995
1996   pdFunction *pdf = 0;
1997   if (!mdl_env::get(ret, var_name)) return false;
1998   
1999   unsigned index=0;
2000   unsigned max = types.size();
2001
2002   while (index < max) {
2003     unsigned current_type = types[index++];
2004     unsigned next_field = types[index++];
2005
2006     switch (current_type) {
2007     case MDL_T_PROCEDURE:
2008       // pdFunction *pdf = 0;
2009       if (!ret.get(pdf)) return false;
2010       switch (next_field) {
2011       case 0: {
2012         string prettyName = pdf->prettyName();
2013         if (!ret.set(prettyName)) return false;
2014         break;
2015       }
2016       // TODO: should these be passed a process?
2017       case 1:
2018         if (!ret.set((vector<instPoint *>*)&pdf->funcCalls(global_proc)))
2019           return false;
2020         break;
2021       case 2: 
2022         if (!ret.set((instPoint *)pdf->funcEntry(global_proc)))
2023         return false; 
2024         break;
2025       case 3:
2026         if (!ret.set((vector<instPoint *>*)&pdf->funcExits(global_proc)))
2027           return false;
2028         break;
2029       case 4:
2030         if (!ret.set((int)pdf->tag()))
2031           return false;
2032         break;
2033       default:
2034         assert(0);
2035         break;
2036       }
2037       break;
2038     case MDL_T_MODULE:
2039       module *mod;
2040       if (!ret.get(mod)) return false;
2041       switch (next_field) {
2042       case 0: { string fileName = mod->fileName();
2043                 if (!ret.set(fileName)) return false; 
2044               } break;
2045       case 1: if (!ret.set(&mod->funcs)) return false; break;
2046       default: assert(0); break;               
2047       }
2048       break;
2049     default:
2050       assert(0); return false;
2051     }
2052   }
2053   return true;
2054 }
2055
2056
2057 bool mdl_get_initial(string flavor, pdRPC *connection) {
2058   mdl_init(flavor);
2059   while (!(mdl_met && mdl_cons && mdl_stmt && mdl_libs)) {
2060     switch (connection->waitLoop()) {
2061     case T_dyninstRPC::error:
2062       return false;
2063     default:
2064       break;
2065     }
2066     while (connection->buffered_requests()) {
2067       switch (connection->process_buffered()) {
2068       case T_dyninstRPC::error:
2069         return false;
2070       default:
2071         break;
2072       }
2073     }
2074   }
2075   return true;
2076 }
2077
2078 bool mdl_get_lib_constraints(vector<string> &lc){
2079     for(u_int i=0; i < mdl_data::lib_constraints.size(); i++){
2080         lc += mdl_data::lib_constraints[i];
2081     }
2082     return (lc.size()>0);
2083 }
2084
2085 void mdl_get_info(vector<T_dyninstRPC::metricInfo>& metInfo) {
2086   unsigned size = mdl_data::all_metrics.size();
2087   T_dyninstRPC::metricInfo element;
2088   for (unsigned u=0; u<size; u++) {
2089     element.name = mdl_data::all_metrics[u]->name_;
2090     element.style = mdl_data::all_metrics[u]->style_;
2091     element.aggregate = mdl_data::all_metrics[u]->agg_op_;
2092     element.units = mdl_data::all_metrics[u]->units_;
2093     element.developerMode = mdl_data::all_metrics[u]->developerMode_;
2094     element.unitstype = mdl_data::all_metrics[u]->unitstype_;
2095     metInfo += element;
2096   }
2097 }
2098
2099 bool mdl_metric_data(const string& met_name, mdl_inst_data& md) {
2100   unsigned size = mdl_data::all_metrics.size();
2101   for (unsigned u=0; u<size; u++)
2102     if (mdl_data::all_metrics[u]->name_ == met_name) {
2103       md.aggregate = mdl_data::all_metrics[u]->agg_op_;
2104       md.style = (metricStyle) mdl_data::all_metrics[u]->style_;
2105       return true;
2106     }
2107   return false;
2108 }