Properly handle exclusion of callsites
[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 #include "paradynd/src/blizzard_memory.h"
57 #include "dyninstAPI/src/instPoint.h" // new...for class instPoint
58
59 // The following vrbles were defined in process.C:
60 extern debug_ostream attach_cerr;
61 extern debug_ostream inferiorrpc_cerr;
62 extern debug_ostream shmsample_cerr;
63 extern debug_ostream forkexec_cerr;
64 extern debug_ostream metric_cerr;
65
66
67 // Some global variables
68 static string currentMetric;  // name of the metric that is being processed.
69 static string daemon_flavor;
70 static process *global_proc = NULL;
71 static bool mdl_met=false, mdl_cons=false, mdl_stmt=false, mdl_libs=false;
72
73 inline unsigned ui_hash(const unsigned &u) { return u; }
74
75 // static members of mdl_env
76 vector<unsigned> mdl_env::frames;
77 vector<mdl_var> mdl_env::all_vars;
78
79 // static members of mdl_data
80 dictionary_hash<unsigned, vector<mdl_type_desc> > mdl_data::fields(ui_hash);
81 vector<mdl_focus_element> mdl_data::foci;
82 vector<T_dyninstRPC::mdl_stmt*> mdl_data::stmts;
83 vector<T_dyninstRPC::mdl_constraint*> mdl_data::all_constraints;
84 vector<string> mdl_data::lib_constraints;
85 vector<T_dyninstRPC::mdl_metric*> mdl_data::all_metrics;
86
87 //
88 // walk_deref() is used to process the fields of the MDL_EXPR_DOT
89 // expression.  the MDL_EXPR_DOT expression is used to be called
90 // MDL_EXPR_DEREF, which is inaccurate at best. --chun
91 //
92 static bool walk_deref(mdl_var& ret, vector<unsigned>& types);
93
94 //
95 // these two do_operation()'s are for processing MDL_EXPR_BINOP, 
96 // MDL_EXPR_POSTUP, MDL_EXPR_PREUOP expressions. --chun
97 //
98 static bool do_operation(mdl_var& ret, mdl_var& left, mdl_var& right, unsigned bin_op);
99 static bool do_operation(mdl_var& ret, mdl_var& lval, unsigned u_op, bool is_preop);
100
101
102 class list_closure 
103 {
104 public:
105   list_closure(string& i_name, mdl_var& list_v)
106     : index_name(i_name), element_type(0), index(0), int_list(NULL), 
107     float_list(NULL), string_list(NULL), bool_list(NULL), func_list(NULL), 
108     funcName_list(NULL), mod_list(NULL), point_list(NULL), max_index(0)
109   {
110     assert (list_v.is_list());
111
112     element_type = list_v.element_type();
113     switch(element_type) 
114     {
115       case MDL_T_INT:
116         assert (list_v.get(int_list));
117         max_index = int_list->size();
118         break;
119       case MDL_T_FLOAT:
120         assert (list_v.get(float_list));
121         max_index = float_list->size();
122         break;
123       case MDL_T_STRING:
124         assert (list_v.get(string_list));
125         max_index = string_list->size();
126         break;
127       case MDL_T_PROCEDURE_NAME:
128         assert (list_v.get(funcName_list));
129         max_index = funcName_list->size();
130         break;
131       case MDL_T_PROCEDURE:
132         assert (list_v.get(func_list));
133         max_index = func_list->size();
134         break;
135       case MDL_T_MODULE:
136         assert (list_v.get(mod_list));
137         max_index = mod_list->size();
138         break;
139       case MDL_T_POINT:
140         assert (list_v.get(point_list));
141         max_index = point_list->size();
142         break;
143       default:
144         assert(0);
145     }
146   }
147
148   ~list_closure() { }
149
150   bool next() 
151   {
152     string s;
153     function_base *pdf; module *m;
154     float f; int i;
155     instPoint *ip;
156
157     if (index >= max_index) return false;
158     switch(element_type) 
159     {
160       case MDL_T_INT:
161         i = (*int_list)[index++];
162         return (mdl_env::set(i, index_name));
163       case MDL_T_FLOAT:
164         f = (*float_list)[index++];
165         return (mdl_env::set(f, index_name));
166       case MDL_T_STRING:
167         s = (*string_list)[index++];
168         return (mdl_env::set(s, index_name));
169       case MDL_T_PROCEDURE_NAME:
170         // lookup-up the functions defined in resource lists
171         // the function may not exist in the image, in which case we get the
172         // next one
173         do 
174         {
175           functionName *fn = (*funcName_list)[index++];
176           pdf = global_proc->findOneFunction(fn->get());
177         }
178         while (pdf == NULL && index < max_index);
179         if (pdf == NULL)
180           return false;
181         return (mdl_env::set(pdf, index_name));
182       case MDL_T_PROCEDURE:
183         pdf = (*func_list)[index++];
184         assert(pdf);
185         return (mdl_env::set(pdf, index_name));
186       case MDL_T_MODULE: 
187         m = (*mod_list)[index++];
188         assert (m);
189         return (mdl_env::set(m, index_name));
190       case MDL_T_POINT:
191         ip = (*point_list)[index++];
192         assert (ip);
193         return (mdl_env::set(ip, index_name));
194       default:
195         assert(0);
196     }
197     return false;
198   }
199
200 private:
201   string index_name;
202   unsigned element_type;
203   unsigned index;
204   vector<int> *int_list;
205   vector<float> *float_list;
206   vector<string> *string_list;
207   vector<bool> *bool_list;
208   vector<function_base*> *func_list;
209   vector<functionName*> *funcName_list;
210   vector<module*> *mod_list;
211   vector<instPoint*> *point_list;
212   unsigned max_index;
213 };
214
215 //
216 // Since the metric, constraints, etc. are manufactured in paradyn and
217 // then shipped to daemons over the RPC, the non-noarg constructors of 
218 // mdl_metric, mdl_constraint, mdl_instr_stmt, etc. and their destructors
219 // shoudln't be called here, rather, the paradyn's version should be
220 // called.  But I could be wrong.  Put assert(0)'s to verify this; didn't
221 // encounter any problem.  Should any problem occur in the future, the
222 // assert's need to be removed.  --chun
223 //
224 T_dyninstRPC::mdl_metric::mdl_metric(string id, string name, string units, 
225                                     u_int agg, u_int sty, u_int type,
226                                     vector<T_dyninstRPC::mdl_stmt*> *mv, 
227                                     vector<string> *flav,
228                                     vector<T_dyninstRPC::mdl_constraint*> *cons,
229                                     vector<string> *temp_counters,
230                                     bool developerMode,
231                                     int unitstype)
232 : id_(id), name_(name), units_(units), agg_op_(agg), style_(sty),
233   type_(type), stmts_(mv), flavors_(flav), constraints_(cons),
234   temp_ctr_(temp_counters), developerMode_(developerMode),
235   unitstype_(unitstype) { assert(0); }
236
237 T_dyninstRPC::mdl_metric::mdl_metric() { }
238
239 T_dyninstRPC::mdl_metric::~mdl_metric() {
240   assert (0);
241   if (stmts_) {
242     unsigned size = stmts_->size();
243     for (unsigned u=0; u<size; u++)
244       delete (*stmts_)[u];
245     delete stmts_;
246   }
247   delete flavors_;
248
249   if (constraints_) {
250     unsigned size = constraints_->size();
251     for (unsigned u=0; u<size; u++)
252       delete (*constraints_)[u];
253     delete constraints_;
254   }
255
256 }
257
258 bool mdl_data::new_metric(string id, string name, string units,
259                           u_int agg, u_int sty, u_int type,
260                           vector<T_dyninstRPC::mdl_stmt*> *mv,
261                           vector<string> *flav,
262                           vector<T_dyninstRPC::mdl_constraint*> *cons,
263                           vector<string> *temp_counters,
264                           bool developerMode,
265                           int unitstype) 
266 {
267   assert (0);
268   T_dyninstRPC::mdl_metric *m = new T_dyninstRPC::mdl_metric(id, name, 
269                                                              units, agg,
270                                                              sty, type, mv,
271                                                              flav, cons,
272                                                              temp_counters,
273                                                              developerMode,
274                                                              unitstype);
275   if (!m)
276     return false;
277   else {
278     all_metrics += m;
279     return true;
280   }
281 }
282
283 static bool other_machine_specified(vector< vector<string> > &focus,
284                                     string& machine) {
285   assert(focus[resource::machine][0] == "Machine");
286
287   switch (focus[resource::machine].size()) {
288   case 1: break;
289   case 2:
290     if (machine != focus[resource::machine][1]) return true;
291     break;
292   default:
293     assert(0);
294   }
295   return false;
296 }
297
298 static void add_processes(vector< vector<string> > &focus,
299                                  vector<process*> procs,
300                                  vector<process*> &ip) {
301   assert(focus[resource::process][0] == "Process");
302   unsigned pi, ps;
303
304   switch(focus[resource::process].size()) {
305   case 1:
306     ip = procs;
307     break;
308   case 2:
309 #if defined(MT_THREAD)
310   case 3:
311 #endif
312     ps = procs.size();
313     for (pi=0; pi<ps; pi++)
314       if (procs[pi]->rid->part_name() == focus[resource::process][1]) {
315         ip += procs[pi];
316         break;
317       }
318     break;
319   default:
320     assert(0);
321   }
322 }
323
324 static bool focus_matches(vector<string>& focus, vector<string> *match_path) {
325   unsigned mp_size = match_path->size();
326   unsigned f_size = focus.size();
327
328   if ((mp_size < 1) || (f_size < 2) || (mp_size != (f_size-1))) {
329     return false;
330   }
331
332   for (unsigned u = 0; u < mp_size; u++) {
333     if(((*match_path)[u] != "*") && (focus[u] != (*match_path)[u])) {
334       return false;
335     }
336   }
337
338   return true;
339 }
340
341
342 // Global constraints are specified by giving their name within a metric def
343 // Find the real constraint by searching the dictionary using this name
344 static T_dyninstRPC::mdl_constraint *flag_matches(vector<string>& focus, 
345                                                   T_dyninstRPC::mdl_constraint *match_me,
346                                                   bool& is_default) 
347 {
348   unsigned c_size = mdl_data::all_constraints.size();
349   for (unsigned cs=0; cs<c_size; cs++) 
350     if (mdl_data::all_constraints[cs]->id_ == match_me->id_) {
351       match_me = mdl_data::all_constraints[cs];
352       if (focus_matches(focus, mdl_data::all_constraints[cs]->match_path_)) {
353         if (mdl_data::all_constraints[cs]->data_type_ == MDL_T_NONE)
354           is_default = true;
355         else
356           is_default = false;
357         return match_me;
358       }
359     }
360
361   return NULL;
362 }
363
364 // Determine if the global and local constraints are applicable
365 // Global constraints that are applicable are put on flag_cons
366 // base_used returns the ONE replace constraint that matches
367
368 static bool check_constraints(vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
369                               T_dyninstRPC::mdl_constraint *&base_used,
370                               vector< vector<string> >& focus,
371                               vector<T_dyninstRPC::mdl_constraint*> *cons,
372                               vector<unsigned>& flag_dex, unsigned& base_dex) {
373   unsigned size = cons->size();
374
375   unsigned foc_size = focus.size();
376   for (unsigned fi=0; fi<foc_size; fi++) {
377     unsigned el_size = focus[fi].size();
378     if ((focus[fi][0] == "Machine") || (focus[fi][0] == "Process")) {
379       // do nothing, can't specify constraints for machine or process
380       ;
381     } else if (el_size) {
382       bool matched = false;
383       // Hack allow constraints such as "/SyncObject"
384       // However, these don't have to match
385       // Otherwise a failure to match means that the metric is invalid for the resource
386       unsigned ci=0;
387       while ((ci < size) && !matched) {
388         if (!(*cons)[ci]->match_path_) {
389           // this is an external constraint, apply if applicable
390           T_dyninstRPC::mdl_constraint *mc;
391           bool is_default;
392           if ((mc = flag_matches(focus[fi], (*cons)[ci], is_default))) {
393             matched = true;
394             if (!is_default) {
395               flag_cons += mc; flag_dex += fi;
396             }
397           }
398         } else {
399           // this could be the real constraint to use
400           // this guarantees that the first match is used
401           // TODO -- first matching replace constraint wins
402           if (focus_matches(focus[fi], (*cons)[ci]->match_path_)) {
403             matched = true;
404             base_used = (*cons)[ci]; base_dex = fi; 
405           }
406         }
407         ci++;
408       }
409       if (!matched && (el_size>1)) {
410         return false;
411       }
412     } else {
413       return false;
414     }
415   }
416   return true;
417 }
418
419 // update the interpreter environment for this processor
420 // Variable updated: $procedures, $modules, $exit, $start
421 static bool update_environment(process *proc) {
422
423   // for cases when libc is dynamically linked, the exit symbol is not
424   // correct
425   string vname = "$exit";
426   function_base *pdf = proc->findOneFunction(string(EXIT_NAME));
427    if (pdf) { 
428       mdl_env::add(vname, false, MDL_T_PROCEDURE);
429       mdl_env::set(pdf, vname);
430   }
431
432   vname = "$start";
433   pdf = proc->getMainFunction();
434   if (!pdf) return false;
435
436   vname = "$start";
437   mdl_env::add(vname, false, MDL_T_PROCEDURE);
438   mdl_env::set(pdf, vname);
439
440   vname = "$procedures";
441   mdl_env::add(vname, false, MDL_T_LIST_PROCEDURE);
442   // only get the functions that are not excluded by exclude_lib or 
443   // exclude_func
444   mdl_env::set(proc->getIncludedFunctions(), vname);
445
446   vname = "$modules";
447   mdl_env::add(vname, false, MDL_T_LIST_MODULE);
448   // only get functions that are not excluded by exclude_lib or exclude_func
449   mdl_env::set(proc->getIncludedModules(), vname);
450
451   //Blizzard
452
453     vname = "$gmin";
454     mdl_env::add(vname, false, MDL_T_INT);
455     mdl_env::set(theMemory->getGlobalMin(), vname);
456
457     vname = "$gmax";
458     mdl_env::add(vname, false, MDL_T_INT);
459     mdl_env::set(theMemory->getGlobalMax(), vname);
460
461     vname = "$cmin";
462     mdl_env::add(vname, false, MDL_T_INT);
463     mdl_env::set(theMemory->getCurrentMin(), vname);
464
465     vname = "$cmax";
466     mdl_env::add(vname, false, MDL_T_INT);
467     mdl_env::set(theMemory->getCurrentMax(), vname);
468   //
469
470   return true;
471 }
472
473 dataReqNode *create_data_object(unsigned mdl_data_type,
474                                 metricDefinitionNode *mn,
475                                 bool computingCost) {
476   switch (mdl_data_type) {
477   case MDL_T_COUNTER:
478     return (mn->addSampledIntCounter(0, computingCost));
479
480   case MDL_T_WALL_TIMER:
481     return (mn->addWallTimer(computingCost));
482
483   case MDL_T_PROC_TIMER:
484     return (mn->addProcessTimer(computingCost));
485
486   case MDL_T_NONE:
487     // just to keep mdl apply allocate a dummy un-sampled counter.
488 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
489     // "true" means that we are going to create a sampled int counter but
490     // we are *not* going to sample it, because it is just a temporary
491     // counter - naim 4/22/97
492     // By default, the last parameter is false - naim 4/23/97
493     return (mn->addSampledIntCounter(0, computingCost, true));
494 #else
495     return (mn->addUnSampledIntCounter(0, computingCost));
496 #endif
497
498   default:
499     assert(0);
500     return NULL;
501   }
502 }
503
504
505 metricDefinitionNode *
506 apply_to_process(process *proc, 
507                  string& id, string& name,
508                  vector< vector<string> >& focus,
509                  unsigned& agg_op,
510                  unsigned& type,
511                  vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
512                  T_dyninstRPC::mdl_constraint *base_use,
513                  vector<T_dyninstRPC::mdl_stmt*> *stmts,
514                  vector<unsigned>& flag_dex,
515                  unsigned& base_dex,
516                  vector<string> *temp_ctr,
517                  bool replace_component,
518                  bool computingCost) {
519
520     if (!update_environment(proc)) return NULL;
521
522     // compute the flat_name for this component: the machine and process
523     // are always defined for the component, even if they are not defined
524     // for the aggregate metric.
525     vector< vector<string> > component_focus(focus); // they start off equal
526
527     string component_flat_name(name);
528     for (unsigned u1 = 0; u1 < focus.size(); u1++) {
529       if (focus[u1][0] == "Process") {
530         component_flat_name += focus[u1][0] + proc->rid->part_name();
531         if (focus[u1].size() == 1) {
532            // there was no refinement to a specific process...but the component
533            // focus must have such a refinement.
534            component_focus[u1] += proc->rid->part_name();
535         }
536       }
537       else if (focus[u1][0] == "Machine") {
538         component_flat_name += focus[u1][0] + machineResource->part_name();
539         if (focus[u1].size() == 1) {
540            // there was no refinement to a specific machine...but the component focus
541            // must have such a refinement.
542            component_focus[u1] += machineResource->part_name();
543         }
544       }
545       else
546         for (unsigned u2 = 0; u2 < focus[u1].size(); u2++)
547           component_flat_name += focus[u1][u2];
548     }
549
550     // now assert that focus2flatname(component_focus) equals component_flat_name
551     extern string metricAndCanonFocus2FlatName(const string &met,
552                                                const vector< vector<string> > &focus);
553     assert(component_flat_name == metricAndCanonFocus2FlatName(name, component_focus));
554
555     metricDefinitionNode *existingMI;
556     const bool alreadyThere = allMIComponents.find(component_flat_name, existingMI);
557     if (alreadyThere) {
558        if (replace_component) {
559           // fry old entry...
560           metric_cerr << "apply_to_process: found " << component_flat_name
561                       << " but continuing anyway since replace_component flag set"
562                       << endl;
563           // note that we don't call 'delete'.
564           allMIComponents.undef(component_flat_name);
565        }
566        else {
567          metric_cerr << "mdl apply_to_process: found component for "
568                      << component_flat_name << "...reusing it" << endl;
569
570          return existingMI;
571        }
572     }
573     else
574        metric_cerr << "MDL: creating new component mi since flatname "
575                    << component_flat_name << " doesn't exist" << endl;
576
577     // If the component exists, then we've either already returned, or fried it.
578     assert(!allMIComponents.defines(component_flat_name));
579
580     // TODO -- Using aggOp value for this metric -- what about folds
581     metricDefinitionNode *mn = new metricDefinitionNode(proc, name, focus,
582                                                         component_focus,
583                                                         component_flat_name, agg_op);
584     assert(mn);
585
586     assert(!allMIComponents.defines(component_flat_name));
587     allMIComponents[component_flat_name] = mn;
588
589     // Create the timer, counter
590     dataReqNode *the_node = create_data_object(type, mn, computingCost);
591     assert(the_node);
592     mdl_env::set(the_node, id);
593
594     // Create the temporary counters - are these useful
595     if (temp_ctr) {
596       unsigned tc_size = temp_ctr->size();
597       for (unsigned tc=0; tc<tc_size; tc++) {
598 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
599         // "true" means that we are going to create a sampled int counter but
600         // we are *not* going to sample it, because it is just a temporary
601         // counter - naim 4/22/97
602         // By default, the last parameter is false - naim 4/23/97
603         dataReqNode *temp_node=mn->addSampledIntCounter(0,computingCost,true);
604 #else
605         dataReqNode *temp_node=mn->addUnSampledIntCounter(0,computingCost);
606 #endif
607         mdl_env::set(temp_node, (*temp_ctr)[tc]);
608       }
609     }
610
611     unsigned flag_size = flag_cons.size(); // could be zero
612     vector<dataReqNode*> flags;
613     metric_cerr << "There are " << flag_size << " flags (constraints)" << endl;
614
615     for (unsigned fs=0; fs<flag_size; fs++) {
616         // TODO -- cache these created flags
617         dataReqNode *flag = NULL;
618         // The following calls mdl_constraint::apply():
619         if (!flag_cons[fs]->apply(mn, flag, focus[flag_dex[fs]], proc, computingCost)) {
620           if (!computingCost) mn->cleanup_drn();
621           delete mn;
622           return NULL;
623         }
624         assert(flag);
625         flags += flag;
626
627         metric_cerr << "Applied constraint for " << flag_cons[fs]->id_ << endl;
628     }
629
630     if (base_use) {
631       dataReqNode *flag = NULL;
632       if (!base_use->apply(mn, flag, focus[base_dex], proc, computingCost)) {
633         if (!computingCost) mn->cleanup_drn();  
634         delete mn;
635         return NULL;
636       }
637     } else {
638       unsigned size = stmts->size();
639       for (unsigned u=0; u<size; u++) {
640         if (!(*stmts)[u]->apply(mn, flags)) { // virtual fn call depending on stmt type
641           if (!computingCost) mn->cleanup_drn();  
642           delete mn;
643           return NULL;
644         }
645       }
646     }
647
648     if (!mn->nonNull()) {
649       if (!computingCost) mn->cleanup_drn();
650       delete mn;
651       return NULL;
652     }
653
654     return mn;
655 }
656
657 static bool apply_to_process_list(vector<process*>& instProcess,
658                                   vector<metricDefinitionNode*>& parts,
659                                   string& id, string& name,
660                                   vector< vector<string> >& focus,
661                                   unsigned& agg_op,
662                                   unsigned& type,
663                                   vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
664                                   T_dyninstRPC::mdl_constraint *base_use,
665                                   vector<T_dyninstRPC::mdl_stmt*> *stmts,
666                                   vector<unsigned>& flag_dex,
667                                   unsigned& base_dex,
668                                   vector<string> *temp_ctr,
669                                   bool replace_components_if_present,
670                                   bool computingCost) {
671 #ifdef DEBUG_MDL
672   timer loadTimer, totalTimer;
673   static ofstream *of=NULL;
674   if (!of) {
675     char buffer[100];
676     ostrstream osb(buffer, 100, ios::out);
677     osb << "mdl_" << "__" << getpid() << ends;
678     of = new ofstream(buffer, ios::app);
679   }
680
681   (*of) << "Instrumenting for " << name << " " << instProcess.size() << " processes\n";
682 #endif
683
684   unsigned psize = instProcess.size();
685 #ifdef DEBUG_MDL
686   totalTimer.clear(); totalTimer.start();
687 #endif
688   for (unsigned p=0; p<psize; p++) {
689 #ifdef DEBUG_MDL
690     loadTimer.clear(); loadTimer.start();  // TIMER
691 #endif
692     process *proc = instProcess[p]; assert(proc);
693     global_proc = proc;     // TODO -- global
694
695     // skip neonatal and exited processes.
696     if (proc->status() == exited || proc->status() == neonatal) continue;
697
698     metricDefinitionNode *comp = apply_to_process(proc, id, name, focus, 
699                                                  agg_op, type,
700                                                  flag_cons, base_use, stmts, 
701                                                  flag_dex,
702                                                  base_dex, temp_ctr,
703                                                  replace_components_if_present,
704                                                  computingCost);
705     if (comp)
706       // we have another component (i.e. process-specific) mi
707       parts += comp;
708
709 #ifdef DEBUG_MDL
710     loadTimer.stop();
711     char timeMsg[500];
712     sprintf(timeMsg, "%f::%f  ", (float) loadTimer.usecs(), (float) loadTimer.wsecs());
713     // tp->applicationIO(10, strlen(timeMsg), timeMsg);
714     (*of) << name << ":" << timeMsg << endl;
715 #endif
716
717   }
718 #ifdef DEBUG_MDL
719   totalTimer.stop();
720   char timeMsg[500];
721   sprintf(timeMsg, "\nTotal:  %f:user\t%f:wall\n", (float) totalTimer.usecs(),
722           (float) totalTimer.wsecs());
723   // tp->applicationIO(10, strlen(timeMsg), timeMsg);
724   (*of) << name << ":" << timeMsg << endl;
725 #endif
726
727   if (parts.size() == 0)
728     // no components!
729     return false;
730
731   return true;
732 }
733
734 ///////////////////////////
735 vector<string>global_excluded_funcs;
736
737
738 metricDefinitionNode *T_dyninstRPC::mdl_metric::apply(vector< vector<string> > &focus,
739                                                       string& flat_name,
740                                                       vector<process *> procs,
741                                                       bool replace_components_if_present,
742                                                       bool computingCost) {
743   // TODO -- check to see if this is active ?
744   // TODO -- create counter or timer
745   // TODO -- put it into the environment ?
746   // TODO -- this can be passed directly -- faster - later
747   // TODO -- internal metrics
748   // TODO -- assume no constraints, all processes instrumented
749   // TODO -- support two-level aggregation: one at the daemon, one at paradyn
750   // TODO -- how is folding specified ?
751   // TODO -- are lists updated here ?
752
753   mdl_env::push();
754   mdl_env::add(id_, false, MDL_T_DRN);
755   assert(stmts_);
756
757   const unsigned tc_size = temp_ctr_->size();
758   for (unsigned tc=0; tc<tc_size; tc++) {
759     mdl_env::add((*temp_ctr_)[tc], false, MDL_T_DRN);
760   }
761
762   static string machine;
763   static bool machine_init= false;
764   if (!machine_init) {
765     machine_init = true;
766     machine = getHostName();
767   }
768
769   if (other_machine_specified(focus, machine)) return NULL;
770   vector<process*> instProcess;
771   add_processes(focus, procs, instProcess);
772
773   if (!instProcess.size()) return NULL;
774
775   // build the list of constraints to use
776   vector<T_dyninstRPC::mdl_constraint*> flag_cons;
777
778   // the first replace constraint that matches, if any
779   T_dyninstRPC::mdl_constraint *base_used=NULL;
780
781   // build list of global constraints that match and choose local replace constraint
782   unsigned base_dex; vector<unsigned> flag_dex;
783   if (!check_constraints(flag_cons, base_used, focus, constraints_, flag_dex, base_dex))
784     return NULL;
785
786   //////////
787   /* 
788      Compute the list of excluded functions here. This is the list of functions
789      that should be excluded from the calls sites.
790      We set the global variable global_excluded_functions to the list of excluded
791      functions.
792
793      At this point, the $constraint variable is not in the environment yet,
794      so anything that uses $constraint will not be added to the list,
795      which is what we want.
796    */
797   if (base_used) {
798     base_used->mk_list(global_excluded_funcs);
799   } else {
800     for (unsigned u1 = 0; u1 < flag_cons.size(); u1++)
801       flag_cons[u1]->mk_list(global_excluded_funcs);
802     for (unsigned u2 = 0; u2 < stmts_->size(); u2++)
803       (*stmts_)[u2]->mk_list(global_excluded_funcs);
804   }
805   metric_cerr << "Metric: " << name_ << endl;
806   for (unsigned x1 = 0; x1 < global_excluded_funcs.size(); x1++)
807     metric_cerr << "  " << global_excluded_funcs[x1] << endl;
808   //////////
809
810
811   // build the instrumentation request
812   vector<metricDefinitionNode*> parts; // one per process
813   if (!apply_to_process_list(instProcess, parts, id_, name_, focus,
814                              agg_op_, type_, flag_cons, base_used,
815                              stmts_, flag_dex, base_dex, temp_ctr_,
816                              replace_components_if_present,
817                              computingCost))
818     return NULL;
819
820   // construct aggregate for the metric instance parts
821   metricDefinitionNode *ret = NULL;
822
823   if (parts.size())
824     // create aggregate mi, containing the process components "parts"
825     ret = new metricDefinitionNode(name_, focus, flat_name, parts, agg_op_);
826
827   // cout << "apply of " << name_ << " ok\n";
828   mdl_env::pop();
829
830   ////////////////////
831   global_excluded_funcs.resize(0);
832
833   return ret;
834 }
835
836 T_dyninstRPC::mdl_constraint::mdl_constraint() { }
837 T_dyninstRPC::mdl_constraint::mdl_constraint(string id, vector<string> *match_path,
838                                              vector<T_dyninstRPC::mdl_stmt*> *stmts,
839                                              bool replace, u_int d_type, bool& error)
840 : id_(id), match_path_(match_path), stmts_(stmts), replace_(replace),
841   data_type_(d_type), hierarchy_(0), type_(0) { assert(0); error = false; }
842 T_dyninstRPC::mdl_constraint::~mdl_constraint() {
843   assert (0);
844   delete match_path_;
845   if (stmts_) {
846     for (unsigned u=0; u<stmts_->size(); u++)
847       delete (*stmts_)[u];
848     delete stmts_;
849   }
850 }
851
852
853 static bool do_trailing_resources(vector<string>& resource_,
854                                   process *proc)
855 {
856   vector<string>  resPath;
857
858   for(unsigned pLen = 0; pLen < resource_.size(); pLen++) {
859     string   caStr = string("$constraint") + 
860                      string(resource_.size()-pLen-1);
861     string   trailingRes = resource_[pLen];
862
863     resPath += resource_[pLen];
864     assert(resPath.size() == (pLen+1));
865
866     resource *r = resource::findResource(resPath);
867     if (!r) assert(0);
868
869     switch (r->type()) {
870     case MDL_T_INT: {
871       const char* p = trailingRes.string_of();
872       char*       q;
873       int         val = (int) strtol(p, &q, 0);
874       if (p == q) {
875         string msg = string("unable to convert resource '") + trailingRes + 
876                      string("' to integer.");
877         showErrorCallback(92,msg.string_of());
878         return(false);
879       }
880       mdl_env::add(caStr, false, MDL_T_INT);
881       mdl_env::set(val, caStr);
882       break;
883     }
884     case MDL_T_STRING:
885       mdl_env::add(caStr, false, MDL_T_STRING);
886       mdl_env::set(trailingRes, caStr);
887       break;
888     case MDL_T_PROCEDURE: {
889       // find the resource corresponding to this function's module 
890       vector<string> m_vec;
891       for(u_int i=0; i < resPath.size()-1; i++){
892         m_vec += resPath[i];
893       }
894       assert(m_vec.size());
895       assert(m_vec.size() == (resPath.size()-1));
896       resource *m_resource = resource::findResource(m_vec);
897       if(!m_resource) return(false);
898       
899       function_base *pdf = proc->findOneFunction(r,m_resource);
900       if (!pdf) return(false);
901       mdl_env::add(caStr, false, MDL_T_PROCEDURE);
902       mdl_env::set(pdf, caStr);
903       break;
904     }
905     case MDL_T_MODULE: {
906       module *mod = proc->findModule(trailingRes,true);
907       if (!mod) return(false);
908       mdl_env::add(caStr, false, MDL_T_MODULE);
909       mdl_env::set(mod, caStr);
910       break;
911     }
912     case MDL_T_MEMORY:
913       break ;
914     case MDL_T_VARIABLE: {
915         //bounds is defined in metric.h
916         memory::bounds b = theMemory->getVariableBounds(trailingRes) ;
917         mdl_env::add(caStr, false, MDL_T_VARIABLE) ;
918         mdl_env::set(b, caStr) ;
919     }
920     break ;
921     default:
922       assert(0);
923       break;
924     }
925   }
926   return(true);
927 }
928
929
930 // Replace constraints not working yet
931 // Flag constraints need to return a handle to a data request node -- the flag
932 bool T_dyninstRPC::mdl_constraint::apply(metricDefinitionNode *mn,
933                                          dataReqNode *&flag,
934                                          vector<string>& resource,
935                                          process *proc, bool computingCost) {
936   assert(mn);
937   switch (data_type_) {
938   case MDL_T_COUNTER:
939   case MDL_T_WALL_TIMER:
940   case MDL_T_PROC_TIMER:
941     break;
942   default:
943     assert(0);
944   }
945   mdl_env::push();
946
947   if (!replace_) {
948     // create the counter used as a flag
949     mdl_env::add(id_, false, MDL_T_DRN);
950 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
951     // "true" means that we are going to create a sampled int counter but
952     // we are *not* going to sample it, because it is just a temporary
953     // counter - naim 4/22/97
954     // By default, the last parameter is false - naim 4/23/97
955     dataReqNode *drn = mn->addSampledIntCounter(0,computingCost,true);
956 #else
957     dataReqNode *drn = mn->addUnSampledIntCounter(0,computingCost);
958 #endif
959     // this flag will construct a predicate for the metric -- have to return it
960     flag = drn;
961     assert(drn);
962     mdl_env::set(drn, id_);
963   }
964
965   // put $constraint[X] in the environment
966   if(!do_trailing_resources(resource, proc)) {
967     mdl_env::pop();
968     return(false);
969   }
970
971   // Now evaluate the constraint statements
972   unsigned size = stmts_->size();
973   vector<dataReqNode*> flags;
974   for (unsigned u=0; u<size; u++) {
975     if (!(*stmts_)[u]->apply(mn, flags)) { // virtual fn call; several possibilities
976       // cout << "apply of constraint " << id_ << " failed\n";
977       return(false);
978     }
979   }
980   mdl_env::pop();
981   return(true);
982 }
983
984 T_dyninstRPC::mdl_constraint *mdl_data::new_constraint(string id, vector<string> *path,
985                                                 vector<T_dyninstRPC::mdl_stmt*> *stmts,
986                                                 bool replace, u_int d_type) {
987   assert (0);
988   bool error;
989   return (new T_dyninstRPC::mdl_constraint(id, path, stmts, replace, d_type, error));
990 }
991
992 T_dyninstRPC::mdl_stmt::mdl_stmt() { }
993
994 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt(string index_name, T_dyninstRPC::mdl_expr *list_exp, T_dyninstRPC::mdl_stmt *body) 
995 : for_body_(body), index_name_(index_name), list_expr_(list_exp) {assert(0);}
996 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt() { }
997 T_dyninstRPC::mdl_for_stmt::~mdl_for_stmt() {
998   assert (0);
999   delete for_body_;
1000   delete list_expr_;
1001 }
1002
1003 bool T_dyninstRPC::mdl_for_stmt::apply(metricDefinitionNode *mn,
1004                                        vector<dataReqNode*>& flags) {
1005   mdl_env::push();
1006   mdl_env::add(index_name_, false);
1007   mdl_var list_var(false);
1008
1009   // TODO -- build iterator closure here -- list may be vector or dictionary
1010   if (!list_expr_->apply(list_var))
1011     return false;
1012   if (!list_var.is_list())
1013     return false;
1014
1015   // TODO
1016   //  vector<function_base*> *vp;
1017   //  list_var.get(vp);
1018   list_closure closure(index_name_, list_var);
1019
1020   // mdl_env::set_type(list_var.element_type(), index_name_);
1021   while (closure.next()) {
1022     if (!for_body_->apply(mn, flags)) return false;
1023   }
1024
1025   mdl_env::pop();
1026   return true;
1027 }
1028
1029 T_dyninstRPC::mdl_icode::mdl_icode() { }
1030 T_dyninstRPC::mdl_icode::mdl_icode(
1031   T_dyninstRPC::mdl_expr* expr1, T_dyninstRPC::mdl_expr* expr2)
1032   : if_expr_(expr1), expr_(expr2)
1033 { assert (0); }
1034 T_dyninstRPC::mdl_icode::~mdl_icode() { assert(0); delete if_expr_; delete expr_; }
1035
1036 bool T_dyninstRPC::mdl_icode::apply(AstNode *&mn, bool mn_initialized) 
1037 {
1038   // a return value of true implies that "mn" has been written to
1039
1040   if (!expr_)
1041      return false;
1042
1043   AstNode* pred = NULL;
1044   AstNode* ast = NULL;
1045
1046   if (if_expr_) 
1047   {
1048     if (!if_expr_->apply(pred))
1049        return false;
1050   }
1051   if (!expr_->apply(ast))
1052     return false;
1053
1054   AstNode* code = NULL;
1055   if (pred) 
1056   {
1057     // Note: we don't use assignAst on purpose here
1058     code = createIf(pred, ast);
1059     removeAst(pred);
1060     removeAst(ast);
1061   }
1062   else
1063     code = ast;
1064
1065   if (mn_initialized) 
1066   {
1067     // Note: we don't use assignAst on purpose here
1068     AstNode *tmp=mn;
1069     mn = new AstNode(tmp, code);
1070     removeAst(tmp);
1071   }
1072   else 
1073     mn = assignAst(code);
1074
1075   removeAst(code);
1076   return true;
1077 }
1078
1079 T_dyninstRPC::mdl_expr::mdl_expr() { }
1080 T_dyninstRPC::mdl_expr::~mdl_expr() { }
1081
1082 T_dyninstRPC::mdl_v_expr::mdl_v_expr() 
1083 : type_(MDL_T_NONE), int_literal_(0), bin_op_(0), u_op_(0), left_(NULL), 
1084   right_(NULL), args_(NULL), do_type_walk_(false), ok_(false)
1085 { }
1086
1087 T_dyninstRPC::mdl_v_expr::mdl_v_expr(int int_lit) 
1088 : type_(MDL_EXPR_INT), int_literal_(int_lit), bin_op_(0), u_op_(0),
1089   left_(NULL), right_(NULL), args_(NULL), do_type_walk_(false), ok_(false)
1090 { assert(0); }
1091
1092 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string a_str, bool is_literal) 
1093 : int_literal_(0), bin_op_(0), u_op_(0), left_(NULL),
1094   right_(NULL), args_(NULL), do_type_walk_(false), ok_(false)
1095 {
1096   assert (0);
1097   if (is_literal)
1098   {
1099     type_ = MDL_EXPR_STRING;
1100     str_literal_ = a_str;
1101   }
1102   else
1103   {
1104     type_ = MDL_EXPR_VAR;
1105     var_ = a_str;
1106   }
1107 }
1108
1109 T_dyninstRPC::mdl_v_expr::mdl_v_expr(mdl_expr* expr, vector<string> fields) 
1110 : type_(MDL_EXPR_DOT), int_literal_(0), bin_op_(0),
1111   u_op_(0), left_(expr), right_(NULL), args_(NULL),
1112   fields_(fields), do_type_walk_(false), ok_(false)
1113 { assert(0); }
1114
1115 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string func_name,
1116                                      vector<T_dyninstRPC::mdl_expr *> *a) 
1117 : type_(MDL_EXPR_FUNC), int_literal_(0), var_(func_name), bin_op_(100000),
1118   u_op_(0), left_(NULL), right_(NULL), args_(a), do_type_walk_(false), 
1119   ok_(false)
1120 { assert(0); }
1121
1122 T_dyninstRPC::mdl_v_expr::mdl_v_expr(u_int bin_op, T_dyninstRPC::mdl_expr *left,
1123                                  T_dyninstRPC::mdl_expr *right) 
1124 : type_(MDL_EXPR_BINOP), int_literal_(0), bin_op_(bin_op), u_op_(0),
1125   left_(left), right_(right), args_(NULL), do_type_walk_(false), ok_(false)
1126 { assert(0); }
1127
1128 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, u_int assign_op,
1129     T_dyninstRPC::mdl_expr *expr)
1130 : type_(MDL_EXPR_ASSIGN), int_literal_(0), var_(var), bin_op_(assign_op),
1131   u_op_(0), left_(expr), right_(NULL), args_(NULL), do_type_walk_(false), 
1132   ok_(false)
1133 { assert(0); }
1134
1135 T_dyninstRPC::mdl_v_expr::mdl_v_expr(u_int u_op, T_dyninstRPC::mdl_expr *expr,
1136                  bool is_preop)
1137 : int_literal_(0), bin_op_(0), u_op_(u_op), left_(expr), right_(NULL),
1138   args_(NULL), do_type_walk_(false), ok_(false)
1139 {
1140   assert(0);
1141   if (is_preop)
1142     type_ = MDL_EXPR_PREUOP;
1143   else
1144     type_ = MDL_EXPR_POSTUOP;
1145 }
1146
1147 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, mdl_expr* index_expr) 
1148 : type_(MDL_EXPR_INDEX), int_literal_(0), var_(var), bin_op_(0),
1149   u_op_(0), left_(index_expr), right_(NULL), args_(NULL),
1150   do_type_walk_(false), ok_(false)
1151 { assert(0); }
1152
1153 T_dyninstRPC::mdl_v_expr::~mdl_v_expr() 
1154 {
1155   assert (0);
1156   if (args_) 
1157   {
1158     unsigned size = args_->size();
1159     for (unsigned u=0; u<size; u++)
1160       delete (*args_)[u];
1161     delete args_;
1162   }
1163   delete left_; delete right_;
1164 }
1165
1166 bool T_dyninstRPC::mdl_v_expr::apply(AstNode*& ast)
1167 {
1168   switch (type_) 
1169   {
1170     case MDL_EXPR_INT: 
1171     {
1172       ast = new AstNode(AstNode::Constant, (void*)int_literal_);
1173       return true;
1174     }
1175     case MDL_EXPR_STRING:
1176     {
1177       if (str_literal_ == string("$return"))
1178         ast = new AstNode(AstNode::ReturnVal, (void*)0);
1179       else
1180       {
1181         // create another string here and pass it to AstNode(), instead
1182         // of using str_literal_.string_of() directly, just to get rid
1183         // of the compiler warning of "cast discards const". --chun
1184         //
1185         char* tmp_str = new char[strlen(str_literal_.string_of())+1];
1186         strcpy (tmp_str, str_literal_.string_of());
1187         ast = new AstNode(AstNode::ConstantString, tmp_str);
1188         delete[] tmp_str;
1189       }
1190       return true;
1191     }
1192     case MDL_EXPR_INDEX:
1193     {
1194       mdl_var index_var;
1195       if (!left_->apply (index_var))
1196         return false;
1197       int index_value;
1198       if (!index_var.get(index_value))
1199         return false;
1200
1201       if (var_ == string ("$arg"))
1202         ast = new AstNode (AstNode::Param, (void*)index_value);
1203       else if (var_ == string ("$constraint"))
1204       {
1205         string tmp = string("$constraint") + string(index_value);
1206         mdl_var int_var;
1207         assert (mdl_env::get(int_var, tmp));
1208         int value;
1209         if (!int_var.get(value))
1210         {
1211           fprintf (stderr, "Unable to get value for %s\n", tmp.string_of());
1212           fflush(stderr);
1213           return false;
1214         }
1215         ast = new AstNode(AstNode::Constant, (void*)value);
1216       }
1217       else
1218       {
1219         mdl_var array_var;
1220         if (!mdl_env::get(array_var, var_)) return false;
1221         if (!array_var.is_list()) return false;  
1222         mdl_var element;
1223         assert (array_var.get_ith_element(element, index_value));
1224         switch (element.get_type())
1225         {
1226           case MDL_T_INT:
1227           {
1228             int value;
1229             assert (element.get(value));
1230             ast = new AstNode(AstNode::Constant, (void*)value);
1231             break;
1232           }
1233           case MDL_T_STRING:
1234           {
1235             string value;
1236             assert (element.get(value));
1237             //
1238             // create another string here and pass it to AstNode(), instead
1239             // of using value.string_of() directly, just to get rid of the 
1240             // compiler warning of "cast discards const".  --chun
1241             //
1242             char* tmp_str = new char[strlen(value.string_of())+1];
1243             strcpy (tmp_str, value.string_of());
1244             ast = new AstNode(AstNode::ConstantString, tmp_str);
1245             delete[] tmp_str;
1246
1247             break;
1248           }
1249           default: return false;
1250         }
1251       }
1252       return true;
1253     }
1254     case MDL_EXPR_BINOP:
1255     {
1256       AstNode* lnode;
1257       AstNode* rnode;
1258       if (!left_->apply (lnode)) return false;
1259       if (!right_->apply (rnode)) return false;
1260       switch (bin_op_) 
1261       {
1262         case MDL_PLUS:
1263           ast = new AstNode(plusOp, lnode, rnode);
1264           break;
1265         case MDL_MINUS:
1266           ast = new AstNode(minusOp, lnode, rnode);
1267           break;
1268         case MDL_DIV:
1269           ast = new AstNode(divOp, lnode, rnode);
1270           break;
1271         case MDL_MULT:
1272           ast = new AstNode(timesOp, lnode, rnode);
1273           break;
1274         case MDL_LT:
1275           ast = new AstNode(lessOp, lnode, rnode);
1276           break;
1277         case MDL_GT:
1278           ast = new AstNode(greaterOp, lnode, rnode);
1279           break;
1280         case MDL_LE:
1281           ast = new AstNode(leOp, lnode, rnode);
1282           break;
1283         case MDL_GE:
1284           ast = new AstNode(geOp, lnode, rnode);
1285           break;
1286         case MDL_EQ:
1287           ast = new AstNode(eqOp, lnode, rnode);
1288           break;
1289         case MDL_NE:
1290           ast = new AstNode(neOp, lnode, rnode);
1291           break;
1292         case MDL_AND:
1293           ast = new AstNode(andOp, lnode, rnode);
1294           break;
1295         case MDL_OR:
1296           ast = new AstNode(orOp, lnode, rnode);
1297           break;
1298         default: return false;
1299       }
1300       return true;
1301     }
1302     case MDL_EXPR_FUNC:
1303     {
1304       if (var_ == "startWallTimer" || var_ == "stopWallTimer"
1305       || var_ == "startProcessTimer" || var_ == "stopProcessTimer")
1306       {
1307         if (!args_) return false;
1308         unsigned size = args_->size();
1309         if (size != 1) return false;
1310
1311         mdl_var timer(false);
1312         dataReqNode* drn;
1313         if (!(*args_)[0]->apply(timer)) return false;
1314         if (!timer.get(drn)) return false;
1315
1316         string timer_func;
1317         if (var_ == "startWallTimer")
1318           timer_func = START_WALL_TIMER;
1319         else if (var_ == "stopWallTimer")
1320           timer_func = STOP_WALL_TIMER;
1321         else if (var_ == "startProcessTimer")
1322           timer_func = START_PROC_TIMER;
1323         else if (var_ == "stopProcessTimer")
1324           timer_func = STOP_PROC_TIMER;
1325
1326         vector<AstNode *> ast_args;
1327
1328 #if defined(SHM_SAMPLING)
1329   #if defined(MT_THREAD)
1330         ast = createTimer(timer_func, (void*)(drn->getAllocatedLevel()),
1331           (void *)(drn->getAllocatedIndex()), ast_args);
1332   #else
1333         ast = createTimer(timer_func, 
1334           (void*)(drn->getInferiorPtr(global_proc)), ast_args);
1335   #endif
1336 #else
1337         ast = createTimer(timer_func,(void*)(drn->getInferiorPtr()),ast_args);
1338 #endif
1339       }
1340       else if (var_ == "readSymbol")
1341       {
1342         mdl_var symbol_var;
1343         if (!(*args_)[0]->apply(symbol_var))
1344           return false;
1345         string symbol_name;
1346         if (!symbol_var.get(symbol_name))
1347         {
1348           fprintf (stderr, "Unable to get symbol name for readSymbol()\n");
1349           fflush(stderr);
1350           return false;
1351         }
1352
1353         // relying on global_proc to be set in mdl_metric::apply
1354         if (global_proc) 
1355         {
1356           Symbol info;
1357           Address baseAddr;
1358           if (global_proc->getSymbolInfo(symbol_name, info, baseAddr)) 
1359           {
1360             Address adr = info.addr();
1361             ast = new AstNode(AstNode::DataAddr, (void*)adr);
1362           } 
1363           else 
1364           {
1365             string msg = string("In metric '") + currentMetric + string("': ")
1366               + string("unable to find symbol '") + symbol_name + string("'");
1367             showErrorCallback(95, msg);
1368             return false;
1369           }
1370         }
1371       }
1372       else if (var_ == "readAddress")
1373       {
1374         mdl_var addr_var;
1375         if (!(*args_)[0]->apply (addr_var))
1376           return false;
1377         int addr;
1378         if (!addr_var.get(addr))
1379         {
1380           fprintf (stderr, "Unable to get address readAddress()\n");
1381           fflush(stderr);
1382           return false;
1383         }
1384         ast = new AstNode(AstNode::DataAddr, (void*)addr);
1385       }
1386       else
1387       {
1388         vector<AstNode *> astargs;
1389         for (unsigned u = 0; u < args_->size(); u++) 
1390         {
1391           AstNode *tmparg=NULL;
1392           if (!(*args_)[u]->apply(tmparg)) 
1393           {
1394             removeAst(tmparg);
1395             return false;
1396           }
1397           astargs += assignAst(tmparg);
1398           removeAst(tmparg);
1399         }
1400         function_base* pdf = global_proc->findOneFunctionFromAll(var_);
1401         if (!pdf) 
1402         {
1403           string msg = string("In metric '") + currentMetric + string("': ")
1404             + string("unable to find procedure '") + var_ + string("'");
1405           showErrorCallback(95, msg);
1406           return false;
1407         }
1408         ast = new AstNode(var_, astargs); //Cannot use simple assignment here!
1409         for (unsigned i=0;i<astargs.size();i++)
1410           removeAst(astargs[i]);
1411         break;
1412       }
1413       return true;
1414     }
1415     case MDL_EXPR_DOT:
1416     {
1417       //??? only allow left hand of DOT to be "$constraint[i]"?
1418
1419       mdl_var dot_var;
1420       if (!left_->apply(dot_var))
1421       {
1422         fprintf (stderr, "Invalid expression on the left of DOT.\n");
1423         fflush(stderr);
1424         return false;
1425       }
1426       if (dot_var.get_type() != MDL_T_VARIABLE)
1427       {
1428         fprintf (stderr, "Invalid expression type on the left of DOT.\n");
1429         fflush(stderr);
1430         return false;
1431       }
1432       memory::bounds b ;
1433       if (!dot_var.get(b)) return false;
1434       int value;
1435       if(!strncmp(fields_[0].string_of(), "upper", 5))
1436         value = (int)b.upper ;
1437       else
1438         value = (int)b.lower;
1439       ast = new AstNode(AstNode::Constant, (void*)value);
1440       return true;
1441     }
1442     case MDL_EXPR_ASSIGN:
1443     {
1444       mdl_var get_drn;
1445       dataReqNode* drn;
1446       if (!mdl_env::get(get_drn, var_)) return false;
1447       if (!get_drn.get(drn)) return false;
1448       AstNode* ast_arg;
1449       if (!left_->apply(ast_arg)) return false;
1450
1451       string func_str;
1452       switch (bin_op_)
1453       {
1454         case MDL_ASSIGN: func_str = "setCounter"; break;
1455         case MDL_PLUSASSIGN: func_str = "addCounter"; break;
1456         case MDL_MINUSASSIGN: func_str = "subCounter"; break;
1457         default: return false;
1458       }
1459 #if defined(SHM_SAMPLING)
1460   #if defined(MT_THREAD)
1461       ast = createCounter(func_str, (void*)(drn->getAllocatedLevel()),
1462         (void *)(drn->getAllocatedIndex()), ast_arg);
1463   #else
1464       ast = createCounter(func_str, 
1465         (void*)(drn->getInferiorPtr(global_proc)), ast_arg);
1466   #endif
1467 #else
1468       ast = createCounter(func_str, (void *)(drn->getInferiorPtr()), ast_arg);
1469 #endif
1470       removeAst (ast_arg);
1471       return true;
1472     }
1473     case MDL_EXPR_VAR:
1474     {
1475       mdl_var get_drn;
1476       assert (mdl_env::get(get_drn, var_));
1477       switch (get_drn.type())
1478       {
1479         case MDL_T_INT:
1480         {
1481           int value;
1482           if (!get_drn.get(value)) 
1483           {
1484             fprintf(stderr, "Unable to get value for %s\n", var_.string_of());
1485             fflush(stderr);
1486             return false;
1487           }
1488           else 
1489             ast = new AstNode(AstNode::Constant, (void*)value);
1490           return true;
1491         }
1492         //case MDL_T_COUNTER:
1493         case MDL_T_DRN:
1494         {
1495           dataReqNode* drn;
1496           if (!get_drn.get(drn))
1497           {
1498             fprintf(stderr, "Unable to get value for %s\n", var_.string_of());
1499             fflush(stderr);
1500             return false;
1501           }
1502 #if defined(SHM_SAMPLING)
1503   #if defined(MT_THREAD)
1504           AstNode *tmp_ast;
1505           tmp_ast = computeAddress((void*)(drn->getAllocatedLevel()),
1506                        (void *)(drn->getAllocatedIndex()),
1507                        0); // 0 is for intCounter
1508           // First we get the address, and now we get the value...
1509           ast = new AstNode(AstNode::DataIndir,tmp_ast);
1510           removeAst(tmp_ast);
1511   #else
1512           ast = new AstNode(AstNode::DataValue,
1513                     (void*)(drn->getInferiorPtr(global_proc)));
1514   #endif
1515 #else
1516           // Note: getInferiorPtr could return a NULL pointer here if
1517           // we are just computing cost - naim 2/18/97
1518           ast = new AstNode(AstNode::DataValue,
1519                     (void*)(drn->getInferiorPtr()));
1520 #endif
1521           return true;
1522         }
1523         default:
1524           fprintf(stderr, "type of variable %s is not known\n", 
1525             var_.string_of());
1526           fflush(stderr);
1527           return false;
1528       }
1529     }
1530     case MDL_EXPR_PREUOP:
1531     {
1532       switch (u_op_)
1533       {
1534         case MDL_ADDRESS:
1535         {
1536           mdl_var get_drn;
1537           if (!left_->apply(get_drn))
1538           {
1539             string msg = string("In metric '") + currentMetric 
1540               + string("' : ") + string("error in operand of address operator");
1541             showErrorCallback(92, msg);
1542             return false;
1543           }
1544           dataReqNode *drn;
1545           assert (get_drn.get(drn));
1546 #if defined(SHM_SAMPLING)
1547   #if defined(MT_THREAD)
1548           ast = computeAddress((void *)(drn->getAllocatedLevel()),
1549                (void *)(drn->getAllocatedIndex()),
1550                0); // 0 is for intCounter
1551   #else
1552           ast = new AstNode(AstNode::DataPtr,
1553             (void*)(drn->getInferiorPtr(global_proc)));
1554   #endif
1555 #else
1556           ast = new AstNode(AstNode::DataPtr, (void*)(drn->getInferiorPtr()));
1557 #endif
1558           break;
1559         }
1560         case MDL_MINUS:
1561         {
1562           mdl_var tmp;
1563           if (!left_->apply (tmp)) return false;
1564           int value;
1565           if (!tmp.get(value)) return false;
1566           ast = new AstNode(AstNode::Constant, (void*)(-value));
1567           break;
1568         }
1569         default:
1570           return false;
1571       }
1572       return true;
1573     }
1574     case MDL_EXPR_POSTUOP:
1575     {
1576       switch (u_op_)
1577       {
1578         case MDL_PLUSPLUS:
1579         {
1580           dataReqNode* drn;
1581           mdl_var drn_var;
1582           if (!left_->apply(drn_var)) return false;
1583           if (!drn_var.get(drn)) return false;
1584
1585           int value = 1;
1586           AstNode* ast_arg = new AstNode(AstNode::Constant, (void*)value);
1587
1588 #if defined(SHM_SAMPLING)
1589   #if defined(MT_THREAD)
1590           ast = createCounter("addCounter", (void*)(drn->getAllocatedLevel()),
1591             (void *)(drn->getAllocatedIndex()), ast_arg);
1592   #else
1593           ast = createCounter("addCounter", 
1594             (void*)(drn->getInferiorPtr(global_proc)), ast_arg);
1595   #endif
1596 #else
1597           ast = createCounter("addCounter", (void *)(drn->getInferiorPtr()), 
1598             ast_arg);
1599 #endif
1600           removeAst(ast_arg);       
1601           break;
1602         }
1603         default: return false;
1604       }
1605       return true;
1606     }
1607     default:
1608       return false;
1609   }
1610   return true;
1611 }
1612
1613 bool T_dyninstRPC::mdl_v_expr::apply(mdl_var& ret) 
1614 {
1615   switch (type_) 
1616   {
1617     case MDL_EXPR_INT: 
1618       return (ret.set(int_literal_));
1619     case MDL_EXPR_STRING:
1620       return (ret.set(str_literal_));
1621     case MDL_EXPR_INDEX:
1622     {
1623       if (var_ == string ("$arg"))
1624       {
1625         // we only allow $arg to appear inside icode (is this right?),
1626         // and therefore, the other mdl_v_expr::apply() should be used for
1627         // $arg, and not this one. --chun
1628         assert (0);
1629       }
1630       if (var_ == string ("$constraint"))
1631       {
1632         mdl_var ndx(false);
1633         if (!left_->apply(ndx)) return false;
1634         int x;
1635         if (!ndx.get(x)) return false;
1636         return (mdl_env::get(ret, var_+string(x)));
1637       }
1638       mdl_var array(false);
1639       if (!mdl_env::get(array, var_)) return false;
1640       if (!array.is_list()) return false;  
1641       mdl_var index_var;
1642       if (!left_->apply(index_var)) return false;
1643       int index_value;
1644       if (!index_var.get(index_value)) return false;
1645       if (index_value >= (int)array.list_size()) return false;
1646       return (array.get_ith_element(ret, index_value));
1647     }
1648     case MDL_EXPR_BINOP:
1649     {
1650       mdl_var left_val(false), right_val(false);
1651       if (!left_ || !right_) return false;
1652       if (!left_->apply(left_val)) return false;
1653       if (!right_->apply(right_val)) return false;
1654       return (do_operation(ret, left_val, right_val, bin_op_));
1655     }
1656     case MDL_EXPR_FUNC:
1657     {
1658       if (var_ == "startWallTimer" || var_ == "stopWallTimer"
1659       || var_ == "startProcessTimer" || var_ == "stopProcessTimer")
1660       {
1661         // this mdl_v_expr::apply() is for expressions outside
1662         // instrumentation blocks.  these timer functions are not
1663         // supposed to be used here
1664         return false;
1665       }
1666       else
1667       {
1668         mdl_var arg0(false);
1669         if (!(*args_)[0]->apply(arg0)) return false;
1670         string func_name;
1671         if (!arg0.get(func_name)) return false;
1672         if (global_proc)
1673         {
1674           // TODO -- what if the function is not found ?
1675           function_base *pdf = global_proc->findOneFunction(func_name);
1676           if (!pdf) { assert(0); return false; }
1677           return (ret.set(pdf));
1678         }
1679         else { assert(0); return false; }
1680       }
1681     }
1682     case MDL_EXPR_DOT:
1683     {
1684       if (!left_->apply(ret)) return false;
1685
1686       if (!do_type_walk_)
1687         return true;
1688       else
1689       { // do_type_walk and type_walk are set in paradyn's mdl.C
1690         return (walk_deref(ret, type_walk)); 
1691       }
1692     }
1693     case MDL_EXPR_ASSIGN:
1694     {
1695       mdl_var lval(false), rval(false);
1696       if (!mdl_env::get(lval, var_)) return false;
1697       if (!left_ || !left_->apply(rval))
1698         return false;
1699       if (rval.type() == MDL_T_NONE)
1700       {
1701         ok_ = true;
1702         return ok_;
1703       }
1704       switch (bin_op_)
1705       {
1706         case MDL_ASSIGN:
1707         {
1708           int x;
1709           if (!rval.get(x)) return false;
1710           ok_ = ret.set(x);
1711           return ok_;
1712         }
1713         case MDL_PLUSASSIGN:
1714         {
1715           //chun-- a hack for $arg[i]
1716           if (lval.type() != MDL_T_NONE && rval.type() != MDL_T_NONE)
1717             ok_ = do_operation(ret, lval, rval, MDL_MINUS);
1718           else
1719             ok_ = true;
1720           return ok_;
1721         }
1722         case MDL_MINUSASSIGN:
1723         {
1724           //chun-- a hack for $arg[i]
1725           if (lval.type() != MDL_T_NONE && rval.type() != MDL_T_NONE)
1726             ok_ = do_operation(ret, lval, rval, MDL_PLUS);
1727           else
1728             ok_ = true;
1729           return ok_;
1730         }
1731       }
1732     }
1733     case MDL_EXPR_VAR:
1734     {
1735       if (var_ == string("$cmin") || var_ == string("$cmax"))
1736         ok_ = true;
1737       else
1738         ok_ = mdl_env::get (ret, var_);
1739       return ok_;
1740     }
1741     case MDL_EXPR_PREUOP:
1742     {
1743       mdl_var lval(false);
1744       if (!left_ || !left_->apply (lval)) return false;
1745       ok_ = do_operation(ret, lval, u_op_, true);
1746       return ok_;
1747     }
1748     case MDL_EXPR_POSTUOP:
1749     {
1750       mdl_var lval(false);
1751       if (!left_ || !left_->apply (lval)) return false;
1752       ok_ = do_operation(ret, lval, u_op_, false);
1753       return ok_;
1754     }
1755     default:
1756       return false;
1757   }
1758   return true;
1759 }
1760
1761 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt(T_dyninstRPC::mdl_expr *expr, T_dyninstRPC::mdl_stmt *body) : expr_(expr), body_(body) {assert(0);}
1762 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt() { }
1763 T_dyninstRPC::mdl_if_stmt::~mdl_if_stmt() {
1764   assert (0);
1765   delete expr_; delete body_;
1766 }
1767
1768 bool T_dyninstRPC::mdl_if_stmt::apply(metricDefinitionNode *mn,
1769                                       vector<dataReqNode*>& flags) {
1770   // An if stmt is comprised of (1) the 'if' expr and (2) the body to
1771   // execute if true.
1772   mdl_var res(false);
1773   if (!expr_->apply(res))
1774     return false;
1775
1776   int iv;
1777   switch (res.type()) {
1778   case MDL_T_INT:
1779     if (!res.get(iv))
1780       return false;
1781     if (!iv)
1782       return true;
1783     break;
1784   default:
1785     return false;
1786   }
1787
1788   return body_->apply(mn, flags);
1789 }
1790
1791 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt(vector<T_dyninstRPC::mdl_stmt*> *stmts) : stmts_(stmts) { assert (0); }
1792 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt() { }
1793 T_dyninstRPC::mdl_seq_stmt::~mdl_seq_stmt() {
1794   assert (0);
1795   if (stmts_) {
1796     unsigned size = stmts_->size();
1797     for (unsigned u=0; u<size; u++)
1798       delete (*stmts_)[u];
1799     delete stmts_;
1800   }
1801 }
1802
1803 bool T_dyninstRPC::mdl_seq_stmt::apply(metricDefinitionNode *mn,
1804                                        vector<dataReqNode*>& flags) {
1805   // a seq_stmt is simply a sequence of statements; apply them all.
1806   if (!stmts_)
1807     return true;
1808
1809   unsigned size = stmts_->size();
1810   for (unsigned index=0; index<size; index++)
1811     if (!(*stmts_)[index]->apply(mn, flags)) // virtual fn call
1812       return false;
1813
1814   return true;
1815 }
1816
1817 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt(u_int type, string ident,
1818                                            vector<string> *elems,
1819                                            bool is_lib, vector<string>* flavor) 
1820 : type_(type), id_(ident), elements_(elems), is_lib_(is_lib), flavor_(flavor) 
1821 { assert (0); }
1822 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt() { }
1823 T_dyninstRPC::mdl_list_stmt::~mdl_list_stmt() 
1824 { assert(0); delete elements_; }
1825
1826 bool T_dyninstRPC::mdl_list_stmt::apply(metricDefinitionNode * /*mn*/,
1827                                         vector<dataReqNode*>& /*flags*/) {
1828   bool found = false;
1829   for (unsigned u0 = 0; u0 < flavor_->size(); u0++) {
1830     if ((*flavor_)[u0] == daemon_flavor) {
1831       found = true;
1832       break;
1833     }
1834   }
1835   if (!found) return false;
1836   if (!elements_) return false;
1837   mdl_var expr_var;
1838   mdl_var list_var(id_, false);
1839   unsigned size = elements_->size();
1840   if (!list_var.make_list(type_)) return false;
1841
1842   if (type_ == MDL_T_PROCEDURE_NAME) {
1843     vector<functionName*> *list_fn;
1844     bool aflag;
1845     aflag=list_var.get(list_fn);
1846     assert(aflag);
1847     for (unsigned u=0; u<size; u++) {
1848       functionName *fn = new functionName((*elements_)[u]);
1849       *list_fn += fn;
1850     }
1851   } else if (type_ == MDL_T_PROCEDURE) { 
1852     assert(0);
1853   } else if (type_ == MDL_T_MODULE) {
1854     assert(0);
1855   } else {
1856     for (unsigned u=0; u<size; u++) {
1857       int i; float f; string s; mdl_var expr_var;
1858       switch (type_) {
1859       case MDL_T_INT:
1860         if (sscanf((*elements_)[u].string_of(), "%d", &i) != 1) return false;
1861         if (!expr_var.set(i)) return false; break;
1862       case MDL_T_FLOAT:
1863         if (sscanf((*elements_)[u].string_of(), "%f", &f) != 1) return false;
1864         if (!expr_var.set(f)) return false; break;
1865       case MDL_T_STRING: 
1866         if (!expr_var.set((*elements_)[u])) return false; break;
1867       default:
1868         return false;
1869       }
1870       if (!list_var.add_to_list(expr_var)) return false;
1871     }
1872   }
1873   return (mdl_env::add(list_var));
1874 }
1875
1876 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt(unsigned pos, T_dyninstRPC::mdl_expr *expr,
1877                                       vector<T_dyninstRPC::mdl_icode*> *reqs,
1878                                       unsigned where, bool constrained) 
1879 : position_(pos), point_expr_(expr), icode_reqs_(reqs),
1880   where_instr_(where), constrained_(constrained) 
1881 { assert(0); }
1882 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt() { }
1883 T_dyninstRPC::mdl_instr_stmt::~mdl_instr_stmt() {
1884   assert (0);
1885   delete point_expr_;
1886   if (icode_reqs_) {
1887     unsigned size = icode_reqs_->size();
1888     for (unsigned u=0; u<size; u++)
1889       delete (*icode_reqs_)[u];
1890     delete icode_reqs_;
1891   }
1892 }
1893
1894 bool T_dyninstRPC::mdl_instr_stmt::apply(metricDefinitionNode *mn,
1895                                          vector<dataReqNode*>& inFlags) {
1896    // An instr statement is like:
1897    //    append preInsn $constraint[0].entry constrained
1898    //       (* setCounter(procedureConstraint, 1); *)
1899    // (note that there are other kinds of statements; i.e. there are other classes
1900    //  derived from the base class mdl_stmt; see dyninstRPC.I)
1901
1902   if (icode_reqs_ == NULL)
1903     return false; // no instrumentation code to put in!
1904
1905   mdl_var pointsVar(false);
1906   if (!point_expr_->apply(pointsVar)) // process the 'point(s)' e.g. "$start.entry"
1907     return false;
1908
1909   vector<instPoint *> points;
1910   if (pointsVar.type() == MDL_T_LIST_POINT) {
1911     vector<instPoint *> *pts;
1912     if (!pointsVar.get(pts)) return false;
1913     points = *pts;
1914   } else if (pointsVar.type() == MDL_T_POINT) {
1915     instPoint *p;
1916     if (!pointsVar.get(p)) return false; // where the point is located...
1917     points += p;
1918   } else {
1919     return false;
1920   }
1921
1922   // Let's generate the code now (we used to calculate it in the loop below,
1923   // which was a waste since the code is the same for all points).
1924   AstNode *code = NULL;
1925   unsigned size = icode_reqs_->size();
1926   for (unsigned u=0; u<size; u++) {
1927     if (!(*icode_reqs_)[u]->apply(code, u>0)) {
1928       // when u is 0, code is un-initialized
1929       removeAst(code);
1930       return false;
1931     }
1932   }
1933
1934   // Instantiate all constraints (flags) here (if any)
1935   // (if !constrained_ then don't do the following)
1936   if (constrained_) {
1937      unsigned fsize = inFlags.size();
1938      for (int fi=fsize-1; fi>=0; fi--) { // any reason why we go backwards?
1939 #if defined(SHM_SAMPLING)
1940   #if defined(MT_THREAD)
1941         AstNode *tmp_ast;
1942         tmp_ast = computeAddress((void *)((inFlags[fi])->getAllocatedLevel()),(void *)((inFlags[fi])->getAllocatedIndex()), 0); // 0 is for intCounter
1943         AstNode *temp1 = new AstNode(AstNode::DataIndir,tmp_ast);
1944         removeAst(tmp_ast);
1945   #else
1946         // Note: getInferiorPtr could return a NULL pointer here if we are
1947         // just computing cost - naim 2/18/97
1948         AstNode *temp1 = new AstNode(AstNode::DataValue, 
1949                                      (void*)((inFlags[fi])->getInferiorPtr(global_proc)));
1950   #endif
1951 #else
1952         // Note: getInferiorPtr could return a NULL pointer here if we are
1953         // just computing cost - naim 2/18/97
1954         AstNode *temp1 = new AstNode(AstNode::DataValue, 
1955                                      (void*)((inFlags[fi])->getInferiorPtr()));
1956 #endif
1957         // Note: we don't use assignAst on purpose here
1958         AstNode *temp2 = code;
1959         code = createIf(temp1, temp2);
1960         removeAst(temp1);
1961         removeAst(temp2);
1962      }
1963   }
1964
1965   if (!code) {
1966     // we are probably defining an empty metric
1967     code = new AstNode();
1968   }
1969
1970   callOrder corder;
1971   switch (position_) {
1972       case MDL_PREPEND: 
1973           corder = orderFirstAtPoint; 
1974           break;
1975       case MDL_APPEND: 
1976           corder = orderLastAtPoint; 
1977           break;
1978       default: assert(0);
1979   }
1980
1981   callWhen cwhen;
1982   switch (where_instr_) {
1983       case MDL_PRE_INSN: 
1984           cwhen = callPreInsn; 
1985           break;
1986       case MDL_POST_INSN: 
1987           cwhen = callPostInsn; 
1988           break;
1989       default: assert(0);
1990   }
1991
1992   // Here is where auto-activate should occur.
1993   // If there is 1 point and it is $start.entry then
1994   // do an inferiorRPC right now (of the ast 'code').
1995   // In this way, we can get metrics like cpu and exec-time for whole program
1996   // to work correctly even when the metrics are instantiated after
1997   // the entrypoint of main() is in execution.
1998
1999   bool manuallyTrigger = false; // for now
2000
2001   if (points.size() == 1) {
2002      // now look at the mdl variable to check for $start.entry.
2003      if (pointsVar.get_name() == "$start" && pointsVar.type()==MDL_T_POINT) {
2004         // having a type of MDL_T_POINT should mean $start.entry as opposed to
2005         // $start.exit, since $start.exit would yield a type of MDL_T_LIST_POINT,
2006         // since exit locations are always a list-of-points.  Sorry for the kludge.
2007
2008         instPoint *theVrbleInstPoint; // NOTE: instPoint is defined in arch-specific files!!!
2009         bool aflag = pointsVar.get(theVrbleInstPoint);
2010         // theVrbleInstPoint set to equiv of points[0]
2011         assert(aflag);
2012
2013         assert(theVrbleInstPoint == points[0]); // just a sanity check
2014
2015         mdl_var theVar;
2016         string varName = pointsVar.get_name();
2017         aflag=mdl_env::get(theVar, varName);
2018         assert(aflag);
2019
2020         function_base *theFunction;
2021         aflag=theVar.get(theFunction);
2022         assert(aflag);
2023
2024         // Make a note to do an inferiorRPC to manually execute this code.
2025 //      if (!manuallyTrigger)
2026 //         cerr << "mdl: found $start.entry; going to manually execute via inferior-RPC" << endl;
2027
2028         manuallyTrigger = true;
2029      }
2030   }
2031
2032   // for all of the inst points, insert the predicates and the code itself.
2033   for (unsigned i = 0; i < points.size(); i++) {
2034       mn->addInst(points[i], code, cwhen, corder,
2035                   manuallyTrigger && (i==0)); // manually trigger at most once
2036          // appends an instReqNode to mn's instRequests; actual 
2037          // instrumentation only
2038          // takes place when mn->insertInstrumentation() is later called.
2039   }
2040   removeAst(code); 
2041   return true;
2042 }
2043
2044 bool mdl_can_do(string& met_name) {
2045   // NOTE: We can do better if there's a dictionary of <metric-name> to <anything>
2046   unsigned size = mdl_data::all_metrics.size();
2047   for (unsigned u=0; u<size; u++) 
2048     if (mdl_data::all_metrics[u]->name_ == met_name)
2049       return true;
2050
2051   return false;
2052 }
2053
2054 metricDefinitionNode *mdl_do(vector< vector<string> >& canon_focus, 
2055                              string& met_name,
2056                              string& flat_name,
2057                              vector<process *> procs,
2058                              bool replace_components_if_present,
2059                              bool computingCost) {
2060   currentMetric = met_name;
2061   unsigned size = mdl_data::all_metrics.size();
2062   // NOTE: We can do better if there's a dictionary of <metric-name> to <metric>!
2063   for (unsigned u=0; u<size; u++) {
2064     if (mdl_data::all_metrics[u]->name_ == met_name) {
2065       return (mdl_data::all_metrics[u]->apply(canon_focus, flat_name, procs,
2066                                               replace_components_if_present,
2067                                               computingCost));
2068          // calls mdl_metric::apply()
2069     }
2070   }
2071   return NULL;
2072 }
2073
2074 bool mdl_init(string& flavor) { 
2075
2076   daemon_flavor = flavor;
2077
2078 #ifdef notdef
2079   vector<mdl_type_desc> kids;
2080   mdl_type_desc self, kid;
2081   mdl_focus_element fe;
2082
2083   self.name = "SyncObject"; self.type = 0; self.end_allowed = false; 
2084   kid.name = "Message"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
2085   kid.name = "Barrier"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
2086   kid.name = "Semaphore"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
2087   kid.name = "SpinLock"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
2088   fe.self = self; fe.kids = kids;
2089   mdl_data::foci += fe;
2090   kids.resize(0);
2091
2092 //  self.name = "Procedure"; self.type = MDL_T_MODULE; self.end_allowed = true;
2093   self.name = "Code"; self.type = MDL_T_MODULE; self.end_allowed = true;
2094   kid.name = "Module"; kid.type = MDL_T_PROCEDURE; self.end_allowed = true; kids += kids;
2095   fe.self = self; fe.kids = kids;
2096   mdl_data::foci += fe;
2097   kids.resize(0);
2098
2099   self.name = "Process"; self.type = MDL_T_PROCESS; self.end_allowed = true;
2100   fe.self = self; fe.kids.resize(0);
2101   mdl_data::foci += fe;
2102
2103   self.name = "Machine"; self.type = MDL_T_STRING; self.end_allowed = true;
2104   fe.self = self; fe.kids.resize(0);
2105   mdl_data::foci += fe;
2106 #endif
2107
2108   mdl_env::push();
2109   // These are pushed on per-process
2110   // mdl_env::add("$procedures", false, MDL_T_LIST_PROCEDURE);
2111   // mdl_env::add("$modules", false, MDL_T_LIST_MODULE);
2112
2113   string vname = "$machine";
2114   mdl_env::add(vname, false, MDL_T_STRING);
2115   string nodename = getHostName();
2116   mdl_env::set(nodename, vname);
2117
2118   /* Are these entered by hand at the new scope ? */
2119   /* $arg, $return */
2120
2121   vector<mdl_type_desc> field_list;
2122   mdl_type_desc desc;
2123   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
2124   desc.name = "calls"; desc.type = MDL_T_LIST_POINT; field_list += desc;
2125   desc.name = "entry"; desc.type = MDL_T_POINT; field_list += desc;
2126   desc.name = "return"; desc.type = MDL_T_POINT; field_list += desc;
2127   desc.name = "tag"; desc.type = MDL_T_INT; field_list += desc;
2128   mdl_data::fields[MDL_T_PROCEDURE] = field_list;
2129   field_list.resize(0);
2130
2131   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
2132   desc.name = "funcs"; desc.type = MDL_T_LIST_PROCEDURE; field_list += desc;
2133   mdl_data::fields[MDL_T_MODULE] = field_list;
2134   field_list.resize(0);
2135
2136   desc.name = "upper"; desc.type = MDL_T_INT; field_list += desc;
2137   desc.name = "lower"; desc.type = MDL_T_INT; field_list += desc;
2138   mdl_data::fields[MDL_T_VARIABLE] = field_list;
2139   field_list.resize(0);
2140
2141   return true;
2142 }
2143
2144 void dynRPC::send_metrics(vector<T_dyninstRPC::mdl_metric*>* var_0) {
2145   mdl_met = true;
2146
2147   if (var_0) {
2148     unsigned var_size = var_0->size();
2149     for (unsigned v=0; v<var_size; v++) {
2150       // fprintf(stderr, "Got metric %s\n", (*var_0)[v]->name_.string_of());
2151       // fflush(stderr);
2152       bool found = false;
2153       unsigned f_size = (*var_0)[v]->flavors_->size();
2154
2155       bool flavor_found = false;
2156       for (unsigned f=0; f<f_size; f++) {
2157         if ((*(*var_0)[v]->flavors_)[f] == daemon_flavor) {
2158           flavor_found = true; break;
2159         }
2160       }
2161       if (flavor_found) {
2162         unsigned size=mdl_data::all_metrics.size();
2163         for (unsigned u=0; u<size; u++) 
2164           if (mdl_data::all_metrics[u]->id_ == (*var_0)[v]->id_) {
2165             delete mdl_data::all_metrics[u];
2166             mdl_data::all_metrics[u] = (*var_0)[v];
2167             found = true;
2168           }
2169         if (!found) {
2170           T_dyninstRPC::mdl_metric *m = (*var_0)[v];
2171           mdl_data::all_metrics += m;
2172         }
2173       }
2174     }
2175   } else {
2176      fprintf(stderr, "no metric defined\n");
2177      fflush(stderr);
2178   }
2179 }
2180
2181 void dynRPC::send_constraints(vector<T_dyninstRPC::mdl_constraint*> *cv) {
2182
2183   mdl_cons = true;
2184   if (cv) {
2185     unsigned var_size = cv->size();
2186     for (unsigned v=0; v<var_size; v++) {
2187       bool found = false;
2188       // cout << "Received " << (*cv)[v]->id_ << endl;
2189       for (unsigned u=0; u<mdl_data::all_constraints.size(); u++) 
2190         if (mdl_data::all_constraints[u]->id_ == (*cv)[v]->id_) {
2191           delete mdl_data::all_constraints[u];
2192           mdl_data::all_constraints[u] = (*cv)[v];
2193           found = true;
2194         }
2195       if (!found) {
2196         mdl_data::all_constraints += (*cv)[v];
2197         // cout << *(*cv)[v] << endl;
2198       }
2199     }
2200   }
2201 }
2202
2203
2204 // TODO -- are these executed immediately ?
2205 void dynRPC::send_stmts(vector<T_dyninstRPC::mdl_stmt*> *vs) {
2206   mdl_stmt = true;
2207   if (vs) {
2208     // ofstream of("other_out", (been_here ? ios::app : ios::out));
2209     // been_here = true;
2210     // of << "SEND_STMTS\n";
2211     // unsigned size = vs->size();
2212     // for (unsigned u=0; u<size; u++) 
2213     // (*vs)[u]->print(of);
2214     mdl_data::stmts += *vs;
2215
2216     // TODO -- handle errors here
2217     // TODO -- apply these statements without a metric definition node ?
2218     unsigned s_size = vs->size();
2219     vector<dataReqNode*> flags;
2220
2221     // Application may fail if the list flavor is different than the flavor
2222     // of this daemon
2223
2224     for (unsigned s=0; s<s_size; s++) {
2225       if (!(*vs)[s]->apply(NULL, flags)) 
2226         ;
2227       // (*vs)[s]->print(cout);
2228       // cout << endl;
2229     }
2230   }
2231 }
2232
2233 // recieves the list of shared libraries to exclude 
2234 void dynRPC::send_libs(vector<string> *libs) {
2235
2236     mdl_libs = true;
2237     //cerr << "void dynRPC::send_libs(vector<string> *libs) called" << endl;
2238     for(u_int i=0; i < libs->size(); i++){
2239         mdl_data::lib_constraints += (*libs)[i]; 
2240         //cerr << " send_libs : adding " << (*libs)[i] << " to paradynd set of mdl_data::lib_constraints" << endl;
2241     }
2242
2243 }
2244
2245 // recieves notification that there are no excluded libraries 
2246 void dynRPC::send_no_libs() {
2247     mdl_libs = true;
2248 }
2249
2250 static bool do_operation(mdl_var& ret, mdl_var& lval, unsigned u_op, bool/*is_preop*/) 
2251 {
2252   switch (u_op) 
2253   {
2254     case MDL_PLUSPLUS:
2255     {
2256       if (lval.type() == MDL_T_INT)
2257       {
2258         int x;
2259         if (!lval.get(x)) return false;
2260         return (ret.set(x++));
2261       }
2262       else
2263       {
2264         cerr << "Invalid type for operator ++" << endl;
2265         return false;
2266       }
2267     }
2268     case MDL_MINUS:
2269     {
2270       if (lval.type() == MDL_T_INT)
2271       {
2272         int x;
2273         if (!lval.get(x)) return false;
2274         return ret.set(-x);
2275       }
2276       else
2277       {
2278         cerr << "Invalid type for operator -" << endl;
2279         return false;
2280       }
2281     }
2282     case MDL_ADDRESS:
2283       return true;
2284     case MDL_NOT:
2285     default:
2286       return false;
2287   }
2288   return false;
2289 }
2290
2291 static bool do_operation(mdl_var& ret, mdl_var& left_val,
2292                          mdl_var& right_val, unsigned bin_op) 
2293 {
2294   switch (bin_op) 
2295   {
2296     case MDL_PLUS:
2297     case MDL_MINUS:
2298     case MDL_DIV:
2299     case MDL_MULT:
2300     {
2301       if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) 
2302       {
2303         int v1, v2;
2304         if (!left_val.get(v1)) return false;
2305         if (!right_val.get(v2)) return false;
2306         switch (bin_op) 
2307         {
2308           case MDL_PLUS: return (ret.set(v1+v2));
2309           case MDL_MINUS: return (ret.set(v1-v2));
2310           case MDL_DIV: return (ret.set(v1/v2));
2311           case MDL_MULT: return (ret.set(v1*v2));
2312         }
2313       }
2314       else if (((left_val.type()==MDL_T_INT)||(left_val.type()==MDL_T_FLOAT)) 
2315         && ((right_val.type()==MDL_T_INT)||(right_val.type()==MDL_T_FLOAT)))
2316       {
2317         float v1, v2;
2318         if (left_val.type() == MDL_T_INT) 
2319         {
2320           int i1;
2321           if (!left_val.get(i1)) return false; v1 = (float)i1;
2322         }
2323         else 
2324         {
2325           if (!left_val.get(v1)) return false;
2326         }
2327         if (right_val.type() == MDL_T_INT) 
2328         {
2329           int i1;
2330           if (!right_val.get(i1)) return false; v2 = (float)i1;
2331         } 
2332         else 
2333         {
2334           if (!right_val.get(v2)) return false;
2335         }
2336         switch (bin_op) 
2337         {
2338           case MDL_PLUS: return (ret.set(v1+v2));
2339           case MDL_MINUS: return (ret.set(v1-v2));
2340           case MDL_DIV: return (ret.set(v1/v2));
2341           case MDL_MULT: return (ret.set(v1*v2));
2342         }
2343       }
2344       else
2345         return false;
2346     }
2347     case MDL_LT:
2348     case MDL_GT:
2349     case MDL_LE:
2350     case MDL_GE:
2351     case MDL_EQ:
2352     case MDL_NE:
2353     {
2354       if ((left_val.type()==MDL_T_STRING)&&(right_val.type()==MDL_T_STRING)) 
2355       {
2356         string v1, v2;
2357         if (!left_val.get(v1)) return false;
2358         if (!right_val.get(v2)) return false;
2359         switch (bin_op) 
2360         {
2361           case MDL_LT: return (ret.set(v1 < v2));
2362           case MDL_GT: return (ret.set(v1 > v2));
2363           case MDL_LE: return (ret.set(v1 <= v2));
2364           case MDL_GE: return (ret.set(v1 >= v2));
2365           case MDL_EQ: return (ret.set(v1 == v2));
2366           case MDL_NE: return (ret.set(v1 != v2));
2367         }  
2368       }
2369       if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) 
2370       {
2371         int v1, v2;
2372         if (!left_val.get(v1)) return false;
2373         if (!right_val.get(v2)) return false;
2374         switch (bin_op) 
2375         {
2376           case MDL_LT: return (ret.set(v1 < v2));
2377           case MDL_GT: return (ret.set(v1 > v2));
2378           case MDL_LE: return (ret.set(v1 <= v2));
2379           case MDL_GE: return (ret.set(v1 >= v2));
2380           case MDL_EQ: return (ret.set(v1 == v2));
2381           case MDL_NE: return (ret.set(v1 != v2));
2382         }
2383       }
2384       else if (((left_val.type()==MDL_T_INT)||(left_val.type()==MDL_T_FLOAT))
2385         && ((right_val.type()==MDL_T_INT)||(right_val.type()==MDL_T_FLOAT))) 
2386       {
2387         float v1, v2;
2388         if (left_val.type() == MDL_T_INT) 
2389         {
2390           int i1;
2391           if (!left_val.get(i1)) return false; v1 = (float)i1;
2392         } 
2393         else 
2394         {
2395           if (!left_val.get(v1)) return false;
2396         }
2397         if (right_val.type() == MDL_T_INT) 
2398         {
2399           int i1;
2400           if (!right_val.get(i1)) return false; v2 = (float)i1;
2401         }
2402         else 
2403         {
2404           if (!right_val.get(v2)) return false;
2405         }
2406         switch (bin_op) 
2407         {
2408           case MDL_LT: return (ret.set(v1 < v2));
2409           case MDL_GT: return (ret.set(v1 > v2));
2410           case MDL_LE: return (ret.set(v1 <= v2));
2411           case MDL_GE: return (ret.set(v1 >= v2));
2412           case MDL_EQ: return (ret.set(v1 == v2));
2413           case MDL_NE: return (ret.set(v1 != v2));
2414         }
2415       }
2416       else
2417         return false;
2418     }
2419     case MDL_AND:
2420     case MDL_OR:
2421     {
2422       if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) 
2423       {
2424         int v1, v2;
2425         if (!left_val.get(v1)) return false;
2426         if (!right_val.get(v2)) return false;
2427         switch (bin_op) 
2428         {
2429           case MDL_AND: return (ret.set(v1 && v2));
2430           case MDL_OR: return (ret.set(v1 || v2));
2431         }
2432       }
2433       else
2434         return false;
2435     }
2436     default:
2437       return false;
2438   }
2439   return false;
2440 }
2441
2442 static bool walk_deref(mdl_var& ret, vector<unsigned>& types) 
2443 {
2444   unsigned index=0;
2445   unsigned max = types.size();
2446
2447   while (index < max) 
2448   {
2449     unsigned current_type = types[index++];
2450     unsigned next_field = types[index++];
2451
2452     switch (current_type) 
2453     {
2454       case MDL_T_PROCEDURE_NAME:
2455       case MDL_T_PROCEDURE:
2456       {
2457         function_base *pdf = 0;
2458         if (!ret.get(pdf)) return false;
2459         switch (next_field) 
2460         {
2461           case 0: 
2462           {
2463             string prettyName = pdf->prettyName();
2464             if (!ret.set(prettyName)) return false;
2465             break;
2466             // TODO: should these be passed a process?  yes, they definitely should!
2467           }
2468           case 1:
2469           {
2470             //
2471             /*****
2472              here we should check the calls and exclude the calls to fns in the
2473              global_excluded_funcs list.
2474              *****/
2475             // ARI -- This is probably the spot!
2476
2477             vector<instPoint*> calls = pdf->funcCalls(global_proc);
2478             // makes a copy of the return value (on purpose), since we 
2479             // may delete some items that shouldn't be a call site for 
2480             // this metric.
2481             bool anythingRemoved = false; // so far
2482
2483             metric_cerr << "global_excluded_funcs size is: "
2484               << global_excluded_funcs.size() << endl;
2485
2486             metric_cerr << "pdf->funcCalls() returned the following call sites:" 
2487               << endl;
2488
2489             unsigned oldSize;
2490             for (unsigned u = 0; u < (oldSize = calls.size());
2491                                  (oldSize == calls.size()) ? u++ : u) 
2492             {  // calls.size() can change!
2493               metric_cerr << u << ") ";
2494
2495               instPoint *point = calls[u];
2496               function_base *callee = (function_base*)point->iPgetCallee();
2497                 // cast discards const
2498
2499               const char *callee_name=NULL;
2500
2501               if (callee == NULL) 
2502               {
2503                 // call Tia's new process::findCallee() to fill in point->callee
2504                 if (!global_proc->findCallee(*point, callee)) 
2505                 {
2506                   // an unanalyzable function call; sorry.
2507                   callee_name = NULL;
2508                   metric_cerr << "-unanalyzable-" << endl;
2509                 }
2510                 else 
2511                 {
2512                   // success -- either (a) the call has been bound already, 
2513                   // in which case the instPoint is updated _and_ callee is 
2514                   // set, or (b) the call hasn't yet been bound, in which 
2515                   // case the instPoint isn't updated but callee *is* updated.
2516                   callee_name = callee->prettyName().string_of();
2517                   metric_cerr << "(successful findCallee() was required) "
2518                     << callee_name << endl;
2519                 }
2520               }
2521               else 
2522               {
2523                 callee_name = callee->prettyName().string_of();
2524                 metric_cerr << "(easy case) " << callee->prettyName() << endl;
2525               }
2526
2527               // If this callee is in global_excluded_funcs for this metric 
2528               // (a global vrble...sorry for that), then it's not really a 
2529               // callee (for this metric, at least), and thus, it should be 
2530               // removed from whatever we eventually pass to "ret.set()" below.
2531
2532               if (callee_name != NULL) // could be NULL (e.g. indirect fn call)
2533                 for (unsigned lcv=0; lcv < global_excluded_funcs.size(); lcv++) 
2534                 {
2535                   if (0==strcmp(global_excluded_funcs[lcv].string_of(),callee_name))
2536                   {
2537                     anythingRemoved = true;
2538
2539                     // remove calls[u] from calls.  To do this, swap
2540                     // calls[u] with calls[maxndx], and resize-1.
2541                     const unsigned maxndx = calls.size()-1;
2542                     calls[u] = calls[maxndx];
2543                     calls.resize(maxndx);
2544
2545                     metric_cerr << "removed something! -- " << callee_name << endl;
2546
2547                     break;
2548                   }
2549                 }
2550             }
2551
2552             if (!anythingRemoved) 
2553             {
2554               metric_cerr << "nothing was removed -- doing set() now" << endl;
2555               vector<instPoint*> *setMe = (vector<instPoint*> *) &pdf->funcCalls(global_proc);
2556               if (!ret.set(setMe))
2557                 return false;
2558             }
2559             else 
2560             {
2561               metric_cerr << "something was removed! -- doing set() now" << endl;
2562               vector<instPoint*> *setMe = new vector<instPoint*>(calls);
2563               assert(setMe);
2564              
2565               if (!ret.set(setMe))
2566                 return false;
2567
2568               // WARNING: "setMe" will now be leaked memory!  The culprit is
2569               // "ret", which can only take in a _pointer_ to a vector of 
2570               // instPoint*'s;
2571               // it can't take in a vector of instPoints*'s, which we'd prefer.
2572             }
2573             break;
2574           }
2575           case 2: 
2576           {
2577             if (!ret.set((instPoint *)pdf->funcEntry(global_proc)))
2578               return false; 
2579             break;
2580           }
2581           case 3:
2582           {
2583             if (!ret.set((vector<instPoint *>*)&pdf->funcExits(global_proc)))
2584               return false;
2585             break;
2586           }
2587           case 4:
2588           {
2589             if (!ret.set((int)pdf->tag()))
2590               return false;
2591             break;
2592           }
2593           default:
2594             assert(0);
2595             break;
2596         } //switch(next_field)
2597         break;
2598       }
2599       case MDL_T_MODULE:
2600       {
2601         module *mod;
2602         if (!ret.get(mod)) return false;
2603         switch (next_field) 
2604         {
2605           case 0: 
2606           {
2607             string fileName = mod->fileName();
2608             if (!ret.set(fileName)) return false; 
2609           } break;
2610           case 1: 
2611           {
2612             if (global_proc) 
2613             {
2614               // this is the correct thing to do...get only the included funcs
2615               // associated with this module, but since we seem to be testing
2616               // for global_proc elsewhere in this file I guess we will here too
2617               if (!ret.set(global_proc->getIncludedFunctions(mod))) return false; 
2618             }
2619             else 
2620             {
2621               // if there is not a global_proc, then just get all functions
2622               // associtated with this module....under what circumstances
2623               // would global_proc == 0 ???
2624               if (!ret.set(mod->getFunctions())) return false; 
2625             }
2626             break;
2627           }
2628           default: assert(0); break;           
2629         } //switch (next_field)
2630         break;
2631       }
2632       default:
2633         assert(0); return false;
2634     } // big switch
2635   } // while
2636   return true;
2637 }
2638
2639
2640 bool mdl_get_initial(string flavor, pdRPC *connection) {
2641   mdl_init(flavor);
2642   while (!(mdl_met && mdl_cons && mdl_stmt && mdl_libs)) {
2643     switch (connection->waitLoop()) {
2644     case T_dyninstRPC::error:
2645       cerr << "mdl_get_initial flavor = " << flavor.string_of() \
2646           << " connection = " << connection << \
2647           "  error in connection->waitLoop()" << endl;
2648       return false;
2649     default:
2650       break;
2651     }
2652     while (connection->buffered_requests()) {
2653       switch (connection->process_buffered()) {
2654       case T_dyninstRPC::error:
2655         cerr << "mdl_get_initial flavor = " << flavor.string_of() \
2656           << " connection = " << connection << \
2657           "  error in connection->processBuffered()" << endl;
2658         return false;
2659       default:
2660         break;
2661       }
2662     }
2663   }
2664   return true;
2665 }
2666
2667 bool mdl_get_lib_constraints(vector<string> &lc){
2668     for(u_int i=0; i < mdl_data::lib_constraints.size(); i++){
2669         lc += mdl_data::lib_constraints[i];
2670     }
2671     return (lc.size()>0);
2672 }
2673
2674 void mdl_get_info(vector<T_dyninstRPC::metricInfo>& metInfo) {
2675   unsigned size = mdl_data::all_metrics.size();
2676   T_dyninstRPC::metricInfo element;
2677   for (unsigned u=0; u<size; u++) {
2678     element.name = mdl_data::all_metrics[u]->name_;
2679     element.style = mdl_data::all_metrics[u]->style_;
2680     element.aggregate = mdl_data::all_metrics[u]->agg_op_;
2681     element.units = mdl_data::all_metrics[u]->units_;
2682     element.developerMode = mdl_data::all_metrics[u]->developerMode_;
2683     element.unitstype = mdl_data::all_metrics[u]->unitstype_;
2684     metInfo += element;
2685   }
2686 }
2687
2688 bool mdl_metric_data(const string& met_name, mdl_inst_data& md) {
2689   unsigned size = mdl_data::all_metrics.size();
2690   for (unsigned u=0; u<size; u++)
2691     if (mdl_data::all_metrics[u]->name_ == met_name) {
2692       md.aggregate = mdl_data::all_metrics[u]->agg_op_;
2693       md.style = (metricStyle) mdl_data::all_metrics[u]->style_;
2694       return true;
2695     }
2696   return false;
2697 }
2698
2699 //
2700 // Compute the list of excluded functions recursively. 
2701 // The mk_list functions are similar to apply, but they make a list
2702 // of the excluded functions
2703 // 
2704
2705 bool T_dyninstRPC::mdl_list_stmt::mk_list(vector<string> &funcs);
2706 bool T_dyninstRPC::mdl_for_stmt::mk_list(vector<string> &funcs);
2707 bool T_dyninstRPC::mdl_if_stmt::mk_list(vector<string> &funcs);
2708 bool T_dyninstRPC::mdl_seq_stmt::mk_list(vector<string> &funcs);
2709 bool T_dyninstRPC::mdl_instr_stmt::mk_list(vector<string> &funcs);
2710 bool T_dyninstRPC::mdl_v_expr::mk_list(vector<string> &funcs);
2711
2712 bool T_dyninstRPC::mdl_v_expr::mk_list(vector<string> &funcs) 
2713 {
2714   switch (type_) 
2715   {
2716     case MDL_EXPR_INT: 
2717     case MDL_EXPR_STRING:
2718       return true;
2719     case MDL_EXPR_INDEX:
2720     {
2721 //??? why is the func here excluded?
2722       mdl_var array(false);
2723       mdl_var index_var(false);
2724       mdl_var elem(false);
2725       if (!mdl_env::get(array, var_)) return false;
2726       if (!left_->apply (index_var)) return false;
2727       int index_value;
2728       if (!index_var.get(index_value)) return false;
2729       if (!array.get_ith_element(elem, index_value)) return false;
2730       if (elem.get_type() == MDL_T_PROCEDURE_NAME) 
2731       {
2732         functionName *fn;
2733         elem.get(fn);
2734         funcs += fn->get();
2735       }
2736       return true;
2737     }
2738     case MDL_EXPR_BINOP: 
2739     {
2740       if (!left_ || !right_) return false;
2741       if (!left_->mk_list(funcs)) return false;
2742       if (!right_->mk_list(funcs)) return false;
2743       return true;
2744     }
2745     case MDL_EXPR_FUNC:
2746       return true;
2747       // TODO: should we add anything to the list here?
2748     case MDL_EXPR_DOT:
2749       return true;
2750     default:
2751       return false;
2752   }
2753   return true;
2754 }
2755
2756
2757 bool T_dyninstRPC::mdl_list_stmt::mk_list(vector<string> &funcs) {
2758   if (type_ == MDL_T_PROCEDURE_NAME) {
2759     unsigned size = elements_->size();
2760     for (unsigned u = 0; u < size; u++)
2761       funcs += (*elements_)[u];
2762   }
2763   return true;
2764 }
2765
2766 bool T_dyninstRPC::mdl_for_stmt::mk_list(vector<string> &funcs) {
2767   mdl_env::push();
2768   mdl_var list_var(false);
2769
2770   if (!list_expr_->apply(list_var)) {
2771     mdl_env::pop();
2772    return false;
2773   }
2774   if (!list_var.is_list()) {
2775     mdl_env::pop();
2776     return false;
2777   }
2778
2779   if (list_var.element_type() == MDL_T_PROCEDURE_NAME) {
2780     vector<functionName *> *funcNames;
2781     if (!list_var.get(funcNames)) {
2782       mdl_env::pop();
2783       return false;
2784     }    
2785     for (unsigned u = 0; u < funcNames->size(); u++)
2786        funcs += (*funcNames)[u]->get();
2787   }
2788
2789   if (!for_body_->mk_list(funcs)) {
2790     mdl_env::pop();
2791     return false;
2792   }
2793   mdl_env::pop();
2794   return true;
2795 }
2796
2797 bool T_dyninstRPC::mdl_if_stmt::mk_list(vector<string> &funcs) {
2798   return expr_->mk_list(funcs) && body_->mk_list(funcs);
2799 }
2800
2801 bool T_dyninstRPC::mdl_seq_stmt::mk_list(vector<string> &funcs) {
2802   for (unsigned u = 0; u < stmts_->size(); u++) {
2803     if (!(*stmts_)[u]->mk_list(funcs))
2804       return false;
2805   }
2806   return true;
2807 }
2808
2809 bool T_dyninstRPC::mdl_instr_stmt::mk_list(vector<string> &funcs) {
2810   return point_expr_->mk_list(funcs);
2811 }
2812
2813 bool T_dyninstRPC::mdl_constraint::mk_list(vector<string> &funcs) {
2814   for (unsigned u = 0; u < stmts_->size(); u++)
2815     (*stmts_)[u]->mk_list(funcs);
2816   return true;
2817 }