Minor changes to parseThat help message; Changed loadLibrary routine to support binar...
[dyninst.git] / parseThat / src / dyninstCore.C
1 #include <iostream>
2 #include <map>
3 #include <list>
4 #include <vector>
5 #include <string>
6 #include <algorithm>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11
12 #include "BPatch.h"
13 #include "BPatch_Vector.h"
14 #include "BPatch_thread.h"
15 #include "BPatch_snippet.h"
16 #include "BPatch_function.h"
17
18 #include "dyninstCore.h"
19 #include "config.h"
20 #include "ipc.h"
21 #include "log.h"
22 #include "utils.h"
23
24 using namespace std;
25
26 /*******************************************************************************
27  * Monitor functions
28  */
29 static int numInstsAllowed = 0;
30 bool shouldInsert()
31 {
32    static int numCalled = 0;
33
34    numCalled++;
35
36    if (!config.hunt_crashes || config.hunt_low == -1 || config.hunt_high == -1) {
37       numInstsAllowed++;
38       return true;
39    }
40
41    if (numCalled-1 < config.hunt_low) {
42       return false;
43    }
44    if (numCalled-1 >= config.hunt_high) {
45       return false;
46    }
47
48    numInstsAllowed++;
49    return true;
50 }
51
52 void stateBasedPrint(message *msgData, statusID prevStat, statusID currStat, int *tabDepth, logLevel priority)
53 {
54    switch (currStat) {
55       case ID_PASS:
56          if (priority <= config.verbose) --(*tabDepth);
57          if (prevStat == ID_TEST) {
58             switch (getMsgID(msgData->id_data)) {
59                case ID_INIT_CREATE_PROCESS: dlog(priority, "Mutatee launched as process %d.\n", msgData->int_data); break;
60                case ID_PARSE_MODULE: dlog(priority, "Found %d module(s).\n", msgData->int_data); break;
61                case ID_PARSE_FUNC: dlog(priority, "Found %d function(s).\n", msgData->int_data); break;
62                case ID_INST_GET_FUNCS: dlog(priority, "Retrieved %d function(s).\n", msgData->int_data); break;
63                case ID_SAVE_WORLD: dlog(priority, "Mutated binary saved as '%s'.\n", msgData->str_data); break;
64                default: dlog(priority, "done.\n"); break;
65             }
66             return;
67          }
68          break;
69
70       case ID_WARN:
71          if (priority <= config.verbose) --(*tabDepth);
72          if (prevStat == ID_TEST) {
73             dlog(priority, "%s\n", msgData->str_data);
74             return;
75          }
76          break;
77
78       case ID_FAIL:
79          if (priority <= config.verbose) --(*tabDepth);
80          if (prevStat == ID_TEST) {
81             dlog(priority, "failed.\n");
82          }
83          break;
84
85       case ID_INFO:
86       case ID_TEST:
87          if (prevStat == ID_TEST)
88             dlog(priority, "\n");
89          break;
90
91       default:
92          break;
93    }
94
95    if (*tabDepth < 0) dlog(ERR, "%d ", *tabDepth);
96    for (int i = 0; i < *tabDepth; ++i) dlog(priority, "    ");
97
98    switch (currStat) {
99       case ID_FAIL: dlog(priority, "*** Failure: %s\n", msgData->str_data); break;
100       case ID_PASS: dlog(priority, "done.\n"); break;
101       case ID_WARN: dlog(priority, "Warning: %s\n", msgData->str_data); break;
102       case ID_INFO:
103          switch (getMsgID(msgData->id_data)) {
104             case ID_EXIT_CODE: dlog(priority, "Mutatee exited normally and returned %d\n", msgData->int_data); break;
105             case ID_EXIT_SIGNAL: dlog(priority, "Mutatee exited via signal %d\n", msgData->int_data); break;
106             case ID_DATA_STRING: dlog(priority, "%s\n", msgData->str_data); break;
107             case ID_TRACE_POINT: dlog(priority, "TRACE_POINT: %s\n", msgData->str_data); break;
108             case ID_CRASH_HUNT_NUM_ACTIONS: dlog(priority, "Crash hunting checked %d points\n", msgData->int_data); break;
109             default: dlog(ERR, "Internal error.  Invalid MessageID used with ID_INFO status.\n");
110          }
111          break;
112       case ID_TEST:
113          switch (getMsgID(msgData->id_data)) {
114             case ID_PARSE_FUNC: dlog(priority, "Parsing function data from %s module... ", msgData->str_data); break;
115             case ID_PARSE_MODULE_CFG: dlog(priority, "Parsing CFG data from functions in %s module... ", msgData->str_data); break;
116             case ID_PARSE_FUNC_CFG: dlog(priority, "Parsing CFG data from %s function... ", msgData->str_data); break;
117             case ID_INST_MODULE: dlog(priority, "Instrumenting functions in module %s... ", msgData->str_data); break;
118             case ID_INST_FUNC: dlog(priority, "Instrumenting function %s... ", msgData->str_data); break;
119             default: dlog(priority, "%s... ", msgStr(getMsgID(msgData->id_data))); break;
120          }
121          if (priority <= config.verbose) ++(*tabDepth);
122          break;
123    }
124 }
125
126 int launch_monitor(FILE *infd)
127 {
128    statusID currStat = ID_FAIL;
129    statusID prevStat = ID_FAIL, prevStatLog = ID_FAIL;
130    int tabDepth = 0, tabDepthLog = 0;
131    logLevel priority = INFO;
132    message msgData;
133
134    if (config.time_limit > 0)
135       alarm(config.time_limit);
136
137    while (config.state == NORMAL && readMsg(infd, &msgData)) {
138       prevStatLog = currStat;
139       if (priority <= config.verbose)
140          prevStat = currStat;
141       currStat = getStatID(msgData.id_data);
142       priority = getPriID(msgData.id_data);
143
144       if (getMsgID(msgData.id_data) == ID_POST_FORK ||
145           (getMsgID(msgData.id_data) == ID_INIT_CREATE_PROCESS && currStat == ID_PASS)) {
146          config.grandchildren.insert(msgData.int_data);
147       }
148
149       if (getMsgID(msgData.id_data) == ID_DETACH_CHILD && currStat == ID_PASS) {
150          config.state = DETACHED;
151       }
152
153       if (getMsgID(msgData.id_data) == ID_TRACE_POINT && config.trace_count) {
154          config.trace_history.push_back( msgData.str_data );
155          if (config.trace_history.size() > config.trace_count)
156             config.trace_history.pop_front();
157          continue;
158       }
159
160       if (getMsgID(msgData.id_data) == ID_CRASH_HUNT_NUM_ACTIONS)
161       {
162          config.hunt_high = msgData.int_data;
163       }
164
165       if (priority <= config.verbose) {
166          stateBasedPrint(&msgData, prevStat, currStat, &tabDepth, priority);
167          tabDepthLog = tabDepth;
168       } else {
169          stateBasedPrint(&msgData, prevStatLog, currStat, &tabDepthLog, LOG_ONLY);
170       }
171       free(msgData.str_data);
172    }
173
174    // Unset alarm
175    alarm(0);
176
177    if (config.state == NORMAL) {
178       // Give everybody a chance to catch up.
179       config.state = SIGCHLD_WAIT;
180       dlog(INFO, "Waiting for mutator to exit...\n");
181       sleep(10);
182    }
183
184    // Report trace history, if needed.
185    if (config.trace_inst && config.trace_count) {
186       while (config.trace_history.size()) {
187          dlog(INFO, "TRACE_POINT: %s\n", config.trace_history[0].c_str());
188          config.trace_history.pop_front();
189       }
190    }
191    return 0;
192 }
193
194 /*******************************************************************************
195  * Mutator functions
196  */
197
198 void printSummary(BPatch_thread *, BPatch_exitType);
199 void reportNewProcess(BPatch_thread *, BPatch_thread *);
200 bool insertSummary(BPatch_function *, BPatch_variableExpr *);
201 bool generateInstrumentation(dynHandle *, BPatch_function *, BPatch_snippet *);
202 BPatch_variableExpr *allocateIntegerInMutatee(dynHandle *, BPatch_function *);
203 bool instrumentFunctionEntry(dynHandle *, BPatch_function *);
204 bool instrumentFunctionExit(dynHandle *, BPatch_function *);
205 bool instrumentBasicBlocks(dynHandle *, BPatch_function *);
206 bool instrumentMemoryReads(dynHandle *, BPatch_function *);
207 bool instrumentMemoryWrites(dynHandle *, BPatch_function *);
208
209 // Helpful global variables for instrumentation tracing.
210 static int trace_msglen;
211 static BPatch_variableExpr *trace_fd = NULL;
212 static BPatch_function *trace_write = NULL;
213 static map< void *, BPatch_function * > trace_points;
214
215 bool initTraceInMutatee(dynHandle *);
216 bool generateTraceSnippet(dynHandle *, BPatch_function *);
217 void readTracePipe();
218
219 int launch_mutator()
220 {
221    unsigned i = 0, j = 0;
222    const char *reason = NULL;
223    char buf[STRING_MAX] = {0};
224    BPatch_Vector< BPatch_module * > *appModules = NULL;
225    BPatch_Vector< BPatch_function * > *appFunctions = NULL;
226    BPatch_flowGraph *appCFG = NULL;
227
228    dynHandle *dh = mutatorInit();
229    if (!dh) return(-1);
230
231    /**************************************************************
232     * Parsing Phase
233     */
234    // Is this if redundant?  Will anybody run this without parsing the modules?
235    if (config.parse_level >= PARSE_MODULE) {
236       sendMsg(config.outfd, ID_PARSE_MODULE, INFO);
237       appModules = dh->image->getModules();
238       if (!appModules) {
239          sendMsg(config.outfd, ID_PARSE_MODULE, INFO, ID_FAIL,
240                  "Failure in BPatch_image::getModules()");
241          return(-1);
242       } else
243          sendMsg(config.outfd, ID_PARSE_MODULE, INFO, ID_PASS,
244                  appModules->size());
245    }
246
247    if (config.parse_level >= PARSE_FUNC) {
248       for (i = 0; i < appModules->size(); ++i) {
249          (*appModules)[i]->getName(buf, sizeof(buf));
250
251          // Check module inclusion/exclusion regular expression rules.
252          reason = config.mod_rules.getReason(buf);
253          if (reason) sendMsg(config.outfd, ID_DATA_STRING, INFO, ID_INFO, reason);
254          if (!config.mod_rules.isValid(buf)) continue;
255
256          sendMsg(config.outfd, ID_PARSE_FUNC, INFO, ID_TEST, buf);
257          appFunctions = (*appModules)[i]->getProcedures();
258          if (!appFunctions) {
259             sendMsg(config.outfd, ID_PARSE_FUNC, INFO, ID_FAIL,
260                     "Failure in BPatch_module::getProcedures()");
261             return(-1);
262          } else
263             sendMsg(config.outfd, ID_PARSE_FUNC, INFO, ID_PASS,
264                     appFunctions->size());
265
266          if (config.parse_level >= PARSE_CFG) {
267             sendMsg(config.outfd, ID_PARSE_MODULE_CFG, INFO, ID_TEST,
268                     (*appModules)[i]->getName(buf, sizeof(buf)));
269
270             int cfg_warn_cnt = 0, cfg_pass_cnt = 0;
271             for (j = 0; j < appFunctions->size(); ++j) {
272                (*appFunctions)[j]->getName(buf, sizeof(buf));
273
274                // Check function inclusion/exclusion regular expression rules.
275                reason = config.func_rules.getReason(buf);
276                if (reason) sendMsg(config.outfd, ID_DATA_STRING, INFO, ID_INFO, reason);
277                if (!config.func_rules.isValid(buf)) continue;
278
279                sendMsg(config.outfd, ID_PARSE_FUNC_CFG, VERB1, ID_TEST, buf);
280                appCFG = (*appFunctions)[j]->getCFG();
281                if (!appCFG) {
282                   sendMsg(config.outfd, ID_PARSE_FUNC_CFG, VERB1, ID_WARN,
283                           "Failure in BPatch_function::getCFG()");
284                   ++cfg_warn_cnt;
285                } else {
286                   sendMsg(config.outfd, ID_PARSE_FUNC_CFG, VERB1, ID_PASS);
287                   ++cfg_pass_cnt;
288                }
289             }
290             if (cfg_warn_cnt)
291                sendMsg(config.outfd, ID_PARSE_MODULE_CFG, INFO, ID_WARN,
292                        sprintf_static("%d warning(s), %d passed.", cfg_warn_cnt, cfg_pass_cnt));
293             else
294                sendMsg(config.outfd, ID_PARSE_MODULE_CFG, INFO, ID_PASS);
295          }
296       }
297    }
298
299    /**************************************************************
300     * Instrumentation Phase
301     */
302
303    if (config.trace_inst) 
304    {
305       errno = 0;
306       sendMsg(config.outfd, ID_TRACE_INIT, INFO);
307       sendMsg(config.outfd, ID_TRACE_OPEN_READER, VERB1);
308         
309       if (config.use_process)
310       {
311          config.pipefd = open(config.pipe_filename, O_RDONLY | O_RSYNC | O_NONBLOCK);
312          if (config.pipefd < 0) {
313             sendMsg(config.outfd, ID_TRACE_OPEN_READER, VERB1, ID_FAIL,
314                     sprintf_static("Mutator could not open trace pipe (%s) for read: %s\n",
315                                    config.pipe_filename, strerror(errno)));
316             config.pipefd = -1;
317               
318          } else {
319             sendMsg(config.outfd, ID_TRACE_OPEN_READER, VERB1, ID_PASS);
320               
321             // Run mutatee side of trace initialization.
322             sendMsg(config.outfd, ID_TRACE_INIT_MUTATEE, VERB1);
323               
324             if (!initTraceInMutatee(dh)) {
325                sendMsg(config.outfd, ID_TRACE_INIT_MUTATEE, VERB1, ID_FAIL);
326                config.pipefd = -1;
327             } else
328                sendMsg(config.outfd, ID_TRACE_INIT_MUTATEE, VERB1, ID_PASS);
329          }
330             
331          if (config.pipefd == -1) {
332             sendMsg(config.outfd, ID_TRACE_INIT, INFO, ID_FAIL,
333                     "Disabling instrumentation tracing.");
334          } else
335             sendMsg(config.outfd, ID_TRACE_INIT, INFO, ID_PASS);
336             
337       }
338    }
339     
340    if (config.inst_level >= INST_FUNC_ENTRY) {
341       
342       if (config.transMode == TRANS_PROCESS)
343          if (!dynStartTransaction(dh)) return(-1);
344
345       for (i = 0; i < appModules->size(); ++i) {
346          int mod_warn_cnt = 0, mod_pass_cnt = 0;
347          (*appModules)[i]->getName(buf, sizeof(buf));
348          // Check module inclusion/exclusion regular expression rules.
349          reason = config.mod_rules.getReason(buf);
350          if (reason) 
351             sendMsg(config.outfd, ID_DATA_STRING, INFO, ID_INFO, reason);
352          if (!config.mod_rules.isValid(buf)) {
353             continue;
354          }
355
356          if (config.transMode == TRANS_MODULE)
357             if (!dynStartTransaction(dh)) {
358                continue;
359             }
360
361          sendMsg(config.outfd, ID_INST_MODULE, INFO, ID_TEST, buf);
362
363          sendMsg(config.outfd, ID_INST_GET_FUNCS, VERB1);
364          appFunctions = (*appModules)[i]->getProcedures();
365          if (!appFunctions) {
366             sendMsg(config.outfd, ID_INST_GET_FUNCS, VERB1, ID_FAIL,
367                     "Failure in BPatch_module::getProcedures()");
368             return(-1);
369          } else
370             sendMsg(config.outfd, ID_INST_GET_FUNCS, VERB1, ID_PASS,
371                     appFunctions->size());
372
373          for (j = 0; j < appFunctions->size(); ++j) {
374             int func_warn_cnt = 0, func_pass_cnt = 0;
375             (*appFunctions)[j]->getName(buf, sizeof(buf));
376
377             // Check function inclusion/exclusion regular expression rules.
378             reason = config.func_rules.getReason(buf);
379             if (reason) sendMsg(config.outfd, ID_DATA_STRING, INFO, ID_INFO, reason);
380             if (!config.func_rules.isValid(buf)) continue;
381
382             if (config.transMode == TRANS_FUNCTION)
383                if (!dynStartTransaction(dh)) continue;
384
385             sendMsg(config.outfd, ID_INST_FUNC, VERB1, ID_TEST, buf);
386
387             if (config.inst_level >= INST_FUNC_ENTRY) {
388                if (!instrumentFunctionEntry(dh, (*appFunctions)[j]))
389                   ++func_warn_cnt;
390                else
391                   ++func_pass_cnt;
392             }
393
394             if (config.inst_level >= INST_FUNC_EXIT) {
395                if (!instrumentFunctionExit(dh, (*appFunctions)[j]))
396                   ++func_warn_cnt;
397                else
398                   ++func_pass_cnt;
399             }
400
401             if (config.inst_level >= INST_BASIC_BLOCK) {
402                if (!instrumentBasicBlocks(dh, (*appFunctions)[j]))
403                   ++func_warn_cnt;
404                else
405                   ++func_pass_cnt;
406             }
407
408             if (config.inst_level >= INST_MEMORY_READ) {
409                if (!instrumentMemoryReads(dh, (*appFunctions)[j]))
410                   ++func_warn_cnt;
411                else
412                   ++func_pass_cnt;
413             }
414
415             if (config.inst_level >= INST_MEMORY_WRITE) {
416                if (!instrumentMemoryWrites(dh, (*appFunctions)[j]))
417                   ++func_warn_cnt;
418                else
419                   ++func_pass_cnt;
420             }
421
422             if (config.transMode == TRANS_FUNCTION)
423                if (!dynEndTransaction(dh)) {
424                   func_warn_cnt = func_pass_cnt;
425                   func_pass_cnt = 0;
426                }
427
428             if (func_warn_cnt) {
429                sendMsg(config.outfd, ID_INST_FUNC, VERB1, ID_WARN,
430                        sprintf_static("%d warning(s), %d passed.", func_warn_cnt, func_pass_cnt));
431                ++mod_warn_cnt;
432             } else {
433                sendMsg(config.outfd, ID_INST_FUNC, VERB1, ID_PASS);
434                ++mod_pass_cnt;
435             }
436          }
437
438          if (config.transMode == TRANS_MODULE)
439             if (!dynEndTransaction(dh)) {
440                mod_warn_cnt = mod_pass_cnt;
441                mod_pass_cnt = 0;
442             }
443
444          if (mod_warn_cnt)
445             sendMsg(config.outfd, ID_INST_MODULE, INFO, ID_WARN,
446                     sprintf_static("%d warning(s), %d passed.", mod_warn_cnt, mod_pass_cnt));
447          else
448             sendMsg(config.outfd, ID_INST_MODULE, INFO, ID_PASS);
449       }
450
451       if (config.transMode == TRANS_PROCESS)
452          dynEndTransaction(dh);
453    }
454
455    if (config.use_save_world && config.use_process) {
456       sendMsg(config.outfd, ID_SAVE_WORLD, INFO);
457       char *destdir = dh->proc->dumpPatchedImage(config.saved_mutatee);
458       if (!destdir) {
459          sendMsg(config.outfd, ID_SAVE_WORLD, INFO, ID_FAIL,
460                  "BPatch_process::dumpPatchedImage() returned NULL");
461       } else {
462          sendMsg(config.outfd, ID_SAVE_WORLD, INFO, ID_PASS,
463                  strcat_static(destdir, config.saved_mutatee));
464       }
465    }
466     
467    if (config.hunt_crashes) {
468       sendMsg(config.outfd, ID_CRASH_HUNT_NUM_ACTIONS, INFO, ID_INFO, numInstsAllowed);
469    }
470
471    if (!config.use_process)
472    {
473       BPatch_binaryEdit *writeBE = dynamic_cast<BPatch_binaryEdit *>(dh->addSpace);
474       writeBE->writeFile(config.writeFilePath);
475    }
476
477    if (config.use_process)
478    {
479       sendMsg(config.outfd, ID_RUN_CHILD, INFO);
480       if (!dh->proc->continueExecution()) {
481          sendMsg(config.outfd, ID_RUN_CHILD, INFO, ID_FAIL,
482                  "Failure in BPatch_thread::continueExecution()");
483          return false;
484       }
485       sendMsg(config.outfd, ID_RUN_CHILD, INFO, ID_PASS);
486       
487     
488       //
489       // Child continued.  Start reading from trace pipe, if enabled.
490       //
491       if (config.trace_inst) {
492          while (config.pipefd != -1) {
493             sendMsg(config.outfd, ID_POLL_STATUS_CHANGE, DEBUG);
494             bool change = dh->bpatch->pollForStatusChange();
495             sendMsg(config.outfd, ID_POLL_STATUS_CHANGE, DEBUG, ID_PASS);
496
497             // Recheck conditional if a change was detected.
498             if (change) continue;
499
500             readTracePipe();
501
502             // Eeeew.  I know.  But how else do you wait on a file descriptor,
503             // AND BPatch::pollforStatusChange() == true at the same time?
504
505             // We should probably have BPatch::registerStatusChangeCallback()
506             // or something similar.
507             sleep(1);
508          }
509       }
510       
511
512       //
513       // All processing complete.  Loop indefinitly until exit handler called.
514       //
515       sendMsg(config.outfd, ID_WAIT_TERMINATION, INFO);
516       while (!dh->proc->isTerminated()) {
517          sendMsg(config.outfd, ID_WAIT_STATUS_CHANGE, DEBUG);
518          if (!dh->bpatch->waitForStatusChange())
519             sendMsg(config.outfd, ID_WAIT_STATUS_CHANGE, DEBUG, ID_FAIL);
520          else
521             sendMsg(config.outfd, ID_WAIT_STATUS_CHANGE, DEBUG, ID_PASS);
522          sendMsg(config.outfd, ID_WAIT_TERMINATION, INFO, ID_PASS);
523       }
524       sendMsg(config.outfd, ID_WAIT_TERMINATION, INFO, ID_PASS);
525    }
526    return 0;
527 }
528
529 //
530 // Structures and functions used with DyninstAPI callbacks.
531 //
532 struct summaryElem {
533    BPatch_function *func;
534    vector< BPatch_variableExpr * > count;
535 };
536 static vector< summaryElem * > summary;
537
538 void printSummary(BPatch_thread *proc, BPatch_exitType exit_type)
539 {
540    unsigned int i, j;
541    char buf[STRING_MAX];
542    char *ptr;
543    vector<int> value;
544
545    // Mutatee has closed.  Drain the trace pipe.
546    if (config.pipefd) readTracePipe();
547
548    switch (exit_type) {
549       case ExitedNormally:
550          if (config.summary) {
551             for (i = 0; i < summary.size(); ++i) {
552                value.resize(summary[i]->count.size());
553
554                bool used = false;
555                for (j = 0; j < value.size(); ++j) {
556                   summary[i]->count[j]->readValue(&value[j]);
557                   if (value[j] > 0) used = true;
558                }
559
560                if (used) {
561                   summary[i]->func->getModule()->getName(buf, sizeof(buf));
562                   ptr = sprintf_static("[%s] ", buf);
563
564                   summary[i]->func->getName(buf, sizeof(buf));
565                   ptr = strcat_static(ptr, buf);
566
567                   for (j = 0; j < value.size(); ++j)
568                      ptr = strcat_static(ptr, sprintf_static(" %d", value[j]));
569
570                   sendMsg(config.outfd, ID_DATA_STRING, INFO, ID_INFO, ptr);
571                }
572             }
573          }
574          sendMsg(config.outfd, ID_EXIT_CODE, INFO, ID_INFO, proc->getExitCode());
575          break;
576
577       case ExitedViaSignal:
578          sendMsg(config.outfd, ID_EXIT_SIGNAL, INFO, ID_INFO, proc->getExitSignal());
579          if (config.hunt_crashes) {
580             sendMsg(config.outfd, ID_CRASH_HUNT_NUM_ACTIONS, INFO, ID_INFO, numInstsAllowed);
581          }
582          exit(-1);  // Nothing left to do.  The mutatee is gone.
583          break;
584
585       case NoExit:
586          sendMsg(config.outfd, ID_DATA_STRING, INFO, ID_INFO,
587                  "Conflicting reports about mutatee status.");
588          break;
589
590       default:
591          sendMsg(config.outfd, ID_DATA_STRING, INFO, ID_INFO,
592                  "Monitor error.  Possibly linked with wrong version of DyninstAPI.\n");
593    }
594    return;
595 }
596
597 void reportNewProcess(BPatch_thread *parent, BPatch_thread *child)
598 {
599    sendMsg(config.outfd, ID_POST_FORK, INFO, ID_INFO, child->getPid());
600 }
601
602 //
603 // Helper mutator functions.
604 //
605 bool insertSummary(BPatch_function *func, BPatch_variableExpr *expr)
606 {
607    sendMsg(config.outfd, ID_SUMMARY_INSERT, DEBUG);
608
609    summaryElem *elem;
610    vector< summaryElem * >::iterator iter = summary.begin();
611
612    while (iter != summary.end()) {
613       elem = *iter;
614       if (elem->func == func) break;
615       ++iter;
616    }
617
618    if (iter == summary.end()) {
619       elem = new summaryElem;
620       if (!elem) {
621          sendMsg(config.outfd, ID_SUMMARY_INSERT, DEBUG, ID_FAIL,
622                  "Memory allocation of new summary element failed");
623          return false;
624       }
625       elem->func = func;
626       summary.push_back(elem);
627    }
628
629    elem->count.push_back(expr);
630    sendMsg(config.outfd, ID_SUMMARY_INSERT, DEBUG, ID_PASS);
631
632    return true;
633 }
634
635 BPatch_variableExpr *allocateIntegerInMutatee(dynHandle *dh, int defaultValue = 0)
636 {
637    BPatch_variableExpr *countVar;
638
639    sendMsg(config.outfd, ID_ALLOC_COUNTER, VERB3);
640
641    sendMsg(config.outfd, ID_INST_FIND_INT, VERB4);
642    BPatch_type *intType = dh->image->findType("int");
643    if (!intType) {
644       sendMsg(config.outfd, ID_INST_FIND_INT, VERB4, ID_FAIL,
645               "BPatch_image::findType(\"int\")");
646       goto fail;
647    } else
648       sendMsg(config.outfd, ID_INST_FIND_INT, VERB4, ID_PASS);
649
650    sendMsg(config.outfd, ID_INST_MALLOC_INT, VERB4);
651
652    countVar = dh->addSpace->malloc(*intType);
653    if (!countVar) {
654       sendMsg(config.outfd, ID_INST_MALLOC_INT, VERB4, ID_FAIL,
655               "Failure in BPatch_process::malloc()");
656       goto fail;
657       
658    } else if (!countVar->writeValue(&defaultValue)) {
659       sendMsg(config.outfd, ID_INST_MALLOC_INT, VERB4, ID_FAIL,
660               "Failure initializing counter in mutatee [BPatch_variableExpr::writeValue()]");
661       goto fail;
662       
663    } else {
664       sendMsg(config.outfd, ID_INST_MALLOC_INT, VERB4, ID_PASS);
665    }
666     
667    sendMsg(config.outfd, ID_ALLOC_COUNTER, VERB3, ID_PASS);
668    return(countVar);
669
670  fail:
671    sendMsg(config.outfd, ID_ALLOC_COUNTER, VERB3, ID_FAIL);
672    return(NULL);
673 }
674
675 //
676 // Instrumentation code.
677 //
678
679 bool initTraceInMutatee(dynHandle *dh)
680 {
681    // Chicken: Can't use goto for error handling because it would branch past
682    // variable initialization.
683
684    // Egg: Can't define variables at top of function (with dummy constructors)
685    // because BPatch_funcCallExpr() needs a valid BPatch_function object.
686
687    // Temporary solution: Deviate from similar functions and rely on external
688    // error handling.
689
690    // Permanent solution: BPatch_snippet and derivitives should have default
691    // constructors.
692
693    int value;
694    BPatch_function *openFunc;
695    BPatch_Vector< BPatch_function * > funcs;
696
697    sendMsg(config.outfd, ID_TRACE_FIND_OPEN, VERB2, ID_TEST);
698    if (!dh->image->findFunction("^(__)?open(64)?$", funcs)) {
699       sendMsg(config.outfd, ID_TRACE_FIND_OPEN, VERB2, ID_FAIL,
700               "Failure in BPatch_image::findFunction()");
701       return false;
702
703    } else if (funcs.size() == 0) {
704       sendMsg(config.outfd, ID_TRACE_FIND_OPEN, VERB2, ID_FAIL,
705               "Could not find any functions named 'open' in mutatee");
706       return false;
707    }
708    sendMsg(config.outfd, ID_TRACE_FIND_OPEN, VERB2, ID_PASS);
709    openFunc = funcs[0];
710
711    //
712    // Initialize global variables
713    //
714    trace_msglen = sizeof(void *) * 2;
715    trace_fd = allocateIntegerInMutatee(dh, -1);
716    funcs.clear();
717    sendMsg(config.outfd, ID_TRACE_FIND_WRITE, VERB2);
718    if (!dh->image->findFunction("^(__)?write$", funcs)) {
719       sendMsg(config.outfd, ID_TRACE_FIND_WRITE, VERB2, ID_FAIL,
720               "Failure in BPatch_image::findFunction()");
721       return false;
722
723    } else if (funcs.size() == 0) {
724       sendMsg(config.outfd, ID_TRACE_FIND_WRITE, VERB2, ID_FAIL,
725               "Could not find any functions named 'write' in mutatee");
726       return false;
727    }
728    sendMsg(config.outfd, ID_TRACE_FIND_WRITE, VERB2, ID_PASS);
729    trace_write = funcs[0];
730
731    // "open(config.pipe_filename, O_WRONLY | O_DSYNC)"
732    BPatch_constExpr path(config.pipe_filename);
733    BPatch_constExpr flags(O_WRONLY | O_DSYNC);
734
735    BPatch_Vector< BPatch_snippet * > param;
736    param.push_back( &path );
737    param.push_back( &flags );
738    BPatch_funcCallExpr openCall(*openFunc, param); // Problem child. See above.
739
740    // "fd = open(config.pipe_filename, O_WRONLY)"
741    BPatch_arithExpr assign(BPatch_assign, *trace_fd, openCall);
742
743    // Run the snippet.
744    sendMsg(config.outfd, ID_TRACE_OPEN_WRITER, VERB2);
745    dh->proc->oneTimeCode(assign);
746    trace_fd->readValue(&value);
747    if (value < 0) {
748       sendMsg(config.outfd, ID_TRACE_OPEN_WRITER, VERB2, ID_FAIL,
749               "Error detected in mutatee's call to open()");
750       return false;
751    }
752    sendMsg(config.outfd, ID_TRACE_OPEN_WRITER, VERB2, ID_PASS);
753
754    return true;
755 }
756
757 bool insertTraceSnippet(dynHandle *dh, BPatch_function *func, BPatch_Vector<BPatch_point *> *points)
758 {
759    char *buf;
760    BPatch_point *point;
761    BPatch_callWhen when;
762    BPatch_snippetOrder order;
763
764    int warn_cnt = 0, pass_cnt = 0;
765
766    sendMsg(config.outfd, ID_TRACE_INSERT, VERB3);
767
768    for (unsigned int i = 0; i < points->size(); ++i) {
769       if (!shouldInsert())
770          continue;
771       sendMsg(config.outfd, ID_TRACE_INSERT_ONE, VERB4);
772
773       point = (*points)[i];
774       buf = sprintf_static("%0*lx", trace_msglen, (void *)point);
775
776       BPatch_constExpr data(buf);
777       BPatch_constExpr len(trace_msglen);
778
779       BPatch_Vector< BPatch_snippet * > param;
780       param.push_back( trace_fd );
781       param.push_back( &data );
782       param.push_back( &len );
783
784       // write(trace_fd, buf, trace_msglen);
785       BPatch_funcCallExpr writeCall(*trace_write, param);
786
787       // if (trace_fd > 0)
788       BPatch_boolExpr checkFd(BPatch_gt, *trace_fd, BPatch_constExpr( 0 ));
789
790       BPatch_ifExpr traceSnippet(checkFd, writeCall);
791
792       switch (point->getPointType()) {
793          case BPatch_entry:
794             when = BPatch_callBefore;
795             order = BPatch_firstSnippet;
796             break;
797
798          case BPatch_exit:
799             when = BPatch_callAfter;
800             order = BPatch_lastSnippet;
801             break;
802
803          default:
804             sendMsg(config.outfd, ID_TRACE_INSERT_ONE, VERB4, ID_FAIL,
805                     "Internal error.  Attempting to trace non entry/exit point.");
806             ++warn_cnt;
807             continue;
808       }
809
810       BPatchSnippetHandle *handle = dh->addSpace->insertSnippet(traceSnippet, *point, when, order);
811       if (!handle) {
812          sendMsg(config.outfd, ID_TRACE_INSERT_ONE, VERB4, ID_FAIL,
813                  "Error detected in BPatch_process::insertSnippet().");
814          ++warn_cnt;
815          continue;
816       }
817       sendMsg(config.outfd, ID_TRACE_INSERT_ONE, VERB4, ID_PASS);
818       ++pass_cnt;
819       trace_points[(void *)point] = func;
820    }
821
822    if (warn_cnt) {
823       sendMsg(config.outfd, ID_TRACE_INSERT, VERB3, ID_WARN,
824               sprintf_static("%d warning(s), %d passed.", warn_cnt, pass_cnt));
825    } else {
826       sendMsg(config.outfd, ID_TRACE_INSERT, VERB3, ID_PASS);
827    }
828    return true;
829 }
830
831 void readTracePipe()
832 {
833    int read_len;
834    char buf[ STRING_MAX ] = { '\0' };
835
836    if (config.pipefd < 0) return;
837
838    do {
839       errno = 0;
840       sendMsg(config.outfd, ID_TRACE_READ, DEBUG);
841       read_len = read(config.pipefd, buf, trace_msglen);
842       buf[trace_msglen] = '\0';
843
844       if (read_len < trace_msglen) {
845          if (read_len == -1 && errno == EAGAIN) {
846             // No data on pipe.  Break out of read loop
847             // and re-poll for status change.
848             sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_PASS);
849             break;
850
851          } else if (read_len == 0 && errno == 0) {
852             // Read EOF from pipefd.  Close pipe and break.
853             sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_PASS);
854             close(config.pipefd);
855             config.pipefd = -1;
856             break;
857
858          } else if (read_len > 0) {
859             // Partial data written to trace pipe.  Report to monitor.
860             sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_FAIL,
861                     sprintf_static("Read partial message from trace pipe.  Discarding message '%s'.", buf));
862             break;
863
864          } else if (errno) {
865             // Send error message to monitor.
866             sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_FAIL,
867                     sprintf_static("Mutator encountered error on trace pipe read(): %s", strerror(errno)));
868             close(config.pipefd);
869             config.pipefd = -1;
870             break;
871          }
872       }
873
874       void *traceMsg = (void *)strtol(buf, NULL, 16);
875       map< void *, BPatch_function * >::iterator iter = trace_points.find(traceMsg);
876       if (iter == trace_points.end()) {
877          sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_FAIL,
878                  sprintf_static("Read invalid message from trace pipe.  0x%s does not refer to a valid BPatch_point.", buf));
879          break;
880       }
881       sendMsg(config.outfd, ID_TRACE_READ, DEBUG, ID_PASS);
882
883       BPatch_point *point = (BPatch_point *)traceMsg;
884
885       char *pType = "Unknown ";
886       if (point->getPointType() == BPatch_entry) pType = "Entering ";
887       if (point->getPointType() == BPatch_exit)  pType = "Exiting ";
888
889       char *pName = "anonymous function";
890       BPatch_function *pFunc = (*iter).second;
891       if (pFunc) {
892          if (pFunc->getName(buf, sizeof(buf)))
893             pName = sprintf_static("function %s", buf);
894          else
895             pName = sprintf_static("anonymous function at 0x%0*lx", sizeof(void *), pFunc->getBaseAddr());
896       }
897
898       if (config.pipefd > 0) {
899          // Could have been interrupted by mutatee exit.
900          sendMsg(config.outfd, ID_TRACE_POINT, INFO, ID_INFO, strcat_static(pType, pName));
901       }
902    } while (errno == 0);
903 }
904
905 void closeTracePipe()
906 {
907    int negOne = -1;
908
909    // Should we acutally create snippets to call close()?
910    if (trace_fd) trace_fd->writeValue(&negOne);
911 }
912
913 bool generateInstrumentation(dynHandle *dh, BPatch_function *func, BPatch_snippet* incSnippet) {
914
915    if (config.instType == USER_FUNC) {
916       // Instrument user's function call
917
918       // config.inst_function is of the format library:function_name
919       char *instLibrary  = (char *) malloc (1024);
920       char *instFunction;
921
922       instFunction = strchr(config.inst_function, ':');
923       if (!instFunction) {
924          sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3, ID_FAIL,
925                  "Failure in loading instrumentation function");
926          return false;
927       }
928       instFunction++;
929
930       int offset = strcspn (config.inst_function, ":");
931       strncpy (instLibrary, config.inst_function, offset);
932       instLibrary[offset] = '\0';
933       if(! dh->addSpace->loadLibrary(instLibrary)) {
934          sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3, ID_FAIL,
935                  "Failure in loading library");
936          return false;
937       }
938       BPatch_Vector<BPatch_function *> funcs;
939       if( NULL ==  dh->image->findFunction(instFunction, funcs) || !funcs.size() || NULL == funcs[0]){
940          sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3, ID_FAIL,
941                  "Unable to find function");
942          return false;;
943       }
944       BPatch_function *instCallFunc = funcs[0];
945       BPatch_Vector<BPatch_snippet *> instCallArgs;
946       /* How to push function's argument */
947       BPatch_funcCallExpr instCallExpr(*instCallFunc, instCallArgs);
948       *incSnippet = instCallExpr;
949
950    } else {
951
952       BPatch_variableExpr *countVar = allocateIntegerInMutatee(dh);
953       if (!countVar) return false;
954       if (!insertSummary(func, countVar)) return false;
955
956       // Should we test for errors on this?
957       BPatch_arithExpr instArithExpr( BPatch_assign, *countVar,
958                                       BPatch_arithExpr(BPatch_plus, *countVar,
959                                                        BPatch_constExpr(1)));
960       *incSnippet = instArithExpr; 
961    }
962         
963    return true;
964 }
965
966 bool instrumentFunctionEntry(dynHandle *dh, BPatch_function *func)
967 {
968    BPatch_Vector<BPatch_point *> *points;
969    BPatchSnippetHandle *handle;
970    BPatch_snippet incSnippet; 
971
972    sendMsg(config.outfd, ID_INST_FUNC_ENTRY, VERB2);
973
974    if (! generateInstrumentation(dh, func, &incSnippet) )
975         goto fail;
976
977    sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3);
978    points = func->findPoint(BPatch_entry);
979    if (!points) {
980       sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3, ID_FAIL,
981               "Failure in BPatch_function::findPoint(BPatch_entry)");
982       goto fail;
983
984    } else if (points->size() == 0) {
985       sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3, ID_WARN,
986               "No instrumentation points found in function");
987       goto fail;
988
989    } else {
990       sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3, ID_PASS);
991    }
992
993    if (shouldInsert())
994    {
995       sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB3);
996       handle = dh->addSpace->insertSnippet(incSnippet, *points);
997       if (!handle) {
998          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB3, ID_FAIL,
999                  "Failure in BPatch_process::insertSnippet()");
1000          goto fail;
1001       } else
1002          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB3, ID_PASS);
1003    }
1004
1005    if (trace_fd) insertTraceSnippet(dh, func, points);
1006
1007    sendMsg(config.outfd, ID_INST_FUNC_ENTRY, VERB2, ID_PASS);
1008    return true;
1009
1010  fail:
1011    sendMsg(config.outfd, ID_INST_FUNC_ENTRY, VERB2, ID_WARN,
1012            "Failure while instrumenting function entry.");
1013    return false;
1014 }
1015
1016 bool instrumentFunctionExit(dynHandle *dh, BPatch_function *func)
1017 {
1018    BPatch_Vector<BPatch_point *> *points;
1019    BPatchSnippetHandle *handle;
1020    BPatch_snippet incSnippet; 
1021
1022    sendMsg(config.outfd, ID_INST_FUNC_EXIT, VERB2);
1023
1024    if (! generateInstrumentation (dh, func, &incSnippet))
1025         goto fail;
1026
1027    sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3);
1028    points = func->findPoint(BPatch_exit);
1029    if (!points) {
1030       sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3, ID_FAIL,
1031               "Failure in BPatch_function::findPoint(BPatch_exit)");
1032       goto fail;
1033
1034    } else if (points->size() == 0) {
1035       sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3, ID_WARN,
1036               "No instrumentation points found in function");
1037       goto fail;
1038
1039    } else {
1040       sendMsg(config.outfd, ID_INST_FIND_POINTS, VERB3, ID_PASS);
1041    }
1042
1043    sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB3);
1044    if (shouldInsert()) {
1045       handle = dh->addSpace->insertSnippet(incSnippet, *points);
1046       if (!handle) {
1047          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB3, ID_FAIL,
1048                  "Failure in BPatch_process::insertSnippet()");
1049          goto fail;
1050
1051       } else
1052          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB3, ID_PASS);
1053    }
1054
1055    if (trace_fd) insertTraceSnippet(dh, func, points);
1056
1057    sendMsg(config.outfd, ID_INST_FUNC_EXIT, VERB2, ID_PASS);
1058    return true;
1059
1060  fail:
1061    sendMsg(config.outfd, ID_INST_FUNC_EXIT, VERB2, ID_WARN,
1062            "Failure while instrumenting function exit.");
1063    return false;
1064 }
1065
1066 bool instrumentBasicBlocks(dynHandle *dh, BPatch_function *func)
1067 {
1068    BPatch_Set<BPatch_basicBlock*> allBlocks;
1069    BPatch_snippet incSnippet; 
1070    BPatch_Set<BPatch_opCode> ops;
1071    BPatch_Set<BPatch_basicBlock*>::iterator iter;
1072    int bb_warn_cnt = 0, bb_pass_cnt = 0;
1073
1074    sendMsg(config.outfd, ID_INST_BASIC_BLOCK, VERB2);
1075
1076    sendMsg(config.outfd, ID_GET_CFG, VERB3);
1077    BPatch_flowGraph *appCFG = func->getCFG();
1078    if (!appCFG) {
1079       sendMsg(config.outfd, ID_GET_CFG, VERB3, ID_FAIL,
1080               "Failure in BPatch_function::getCFG()");
1081       goto fail;
1082
1083    } else {
1084       sendMsg(config.outfd, ID_GET_CFG, VERB3, ID_PASS);
1085    }
1086
1087    sendMsg(config.outfd, ID_INST_GET_BB, VERB3);
1088    if (!appCFG->getAllBasicBlocks(allBlocks)) {
1089       sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_FAIL,
1090               "Failure in BPatch_flowGraph::getAllBasicBlocks()");
1091       goto fail;
1092
1093    } else if (allBlocks.size() == 0) {
1094       sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_WARN,
1095               "No basic blocks found in function");
1096       goto fail;
1097
1098    } else {
1099       sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_PASS);
1100    }
1101
1102    if (! generateInstrumentation (dh, func, &incSnippet))
1103         goto fail;
1104
1105    ops.insert(BPatch_opLoad);
1106    ops.insert(BPatch_opStore);
1107
1108    sendMsg(config.outfd, ID_INST_BB_LIST, VERB3);
1109    for (iter = allBlocks.begin(); iter != allBlocks.end(); iter++) {
1110       if (!shouldInsert())
1111          continue;
1112
1113       sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4);
1114       BPatch_Vector<BPatch_point*> *points = (*iter)->findPoint(ops);
1115       if (!points) {
1116          sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4, ID_WARN,
1117                  "Failure in BPatch_basicBlock::findPoint()");
1118          ++bb_warn_cnt;
1119          continue;
1120
1121       } else if (points->size() == 0) {
1122          sendMsg(config.outfd,  ID_INST_GET_BB_POINTS, VERB4, ID_WARN,
1123                  "No instrumentation points found in basic block");
1124          ++bb_warn_cnt;
1125          continue;
1126
1127       } else {
1128          sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4, ID_PASS);
1129       }
1130
1131       sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4);
1132       BPatchSnippetHandle *handle = dh->addSpace->insertSnippet(incSnippet, *(*points)[0]);
1133       if (!handle) {
1134          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4, ID_FAIL,
1135                  "Failure in BPatch_process::insertSnippet()");
1136          ++bb_warn_cnt;
1137          continue;
1138
1139       } else {
1140          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4, ID_PASS);
1141          ++bb_pass_cnt;
1142       }
1143    }
1144    if (bb_warn_cnt)
1145       sendMsg(config.outfd, ID_INST_BB_LIST, VERB3, ID_WARN,
1146               sprintf_static("%d warning(s), %d passed.", bb_warn_cnt, bb_pass_cnt));
1147    else
1148       sendMsg(config.outfd, ID_INST_BB_LIST, VERB3, ID_PASS);
1149
1150    sendMsg(config.outfd, ID_INST_BASIC_BLOCK, VERB2, ID_PASS);
1151    return true;
1152
1153  fail:
1154    sendMsg(config.outfd, ID_INST_BASIC_BLOCK, VERB2, ID_WARN,
1155            "Failure while instrumenting basic blocks.");
1156    return false;
1157 }
1158
1159 bool instrumentMemoryReads(dynHandle *dh, BPatch_function *func)
1160 {
1161    BPatch_Set<BPatch_basicBlock*> allBlocks;
1162    BPatch_snippet incSnippet; 
1163    BPatch_Set<BPatch_opCode> ops;
1164    BPatch_Set<BPatch_basicBlock*>::iterator iter;
1165    int bb_warn_cnt = 0, bb_pass_cnt = 0;
1166
1167    sendMsg(config.outfd, ID_INST_MEM_READ, VERB2);
1168
1169    sendMsg(config.outfd, ID_GET_CFG, VERB3);
1170    BPatch_flowGraph *appCFG = func->getCFG();
1171    if (!appCFG) {
1172       sendMsg(config.outfd, ID_GET_CFG, VERB3, ID_FAIL,
1173               "Failure in BPatch_function::getCFG()");
1174       goto fail;
1175
1176    } else {
1177       sendMsg(config.outfd, ID_GET_CFG, VERB3, ID_PASS);
1178    }
1179
1180    sendMsg(config.outfd, ID_INST_GET_BB, VERB3);
1181    if (!appCFG->getAllBasicBlocks(allBlocks)) {
1182       sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_FAIL,
1183               "Failure in BPatch_flowGraph::getAllBasicBlocks()");
1184       goto fail;
1185
1186    } else if (allBlocks.size() == 0) {
1187       sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_WARN,
1188               "No basic blocks found in function");
1189       goto fail;
1190
1191    } else {
1192       sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_PASS);
1193    }
1194
1195    if (! generateInstrumentation (dh, func, &incSnippet))
1196         goto fail;
1197
1198    ops.insert(BPatch_opLoad);
1199
1200    sendMsg(config.outfd, ID_INST_BB_LIST, VERB3);
1201    for (iter = allBlocks.begin(); iter != allBlocks.end(); iter++) {
1202       if (!shouldInsert())
1203          continue;
1204       sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4);
1205       BPatch_Vector<BPatch_point*> *points = (*iter)->findPoint(ops);
1206       if (!points) {
1207          sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4, ID_WARN,
1208                  "Failure in BPatch_basicBlock::findPoint()");
1209          ++bb_warn_cnt;
1210          continue;
1211
1212       } else if (points->size() == 0) {
1213          sendMsg(config.outfd,  ID_INST_GET_BB_POINTS, VERB4, ID_WARN,
1214                  "No instrumentation points found in basic block");
1215          ++bb_warn_cnt;
1216          continue;
1217
1218       } else {
1219          sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4, ID_PASS);
1220       }
1221
1222       sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4);
1223       BPatchSnippetHandle *handle = dh->addSpace->insertSnippet(incSnippet, *points);
1224       if (!handle) {
1225          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4, ID_FAIL,
1226                  "Failure in BPatch_process::insertSnippet()");
1227          ++bb_warn_cnt;
1228          continue;
1229
1230       } else {
1231          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4, ID_PASS);
1232          ++bb_pass_cnt;
1233       }
1234    }
1235    if (bb_warn_cnt)
1236       sendMsg(config.outfd, ID_INST_BB_LIST, VERB3, ID_WARN,
1237               sprintf_static("%d warning(s), %d passed.", bb_warn_cnt, bb_pass_cnt));
1238    else
1239       sendMsg(config.outfd, ID_INST_BB_LIST, VERB3, ID_PASS);
1240
1241    sendMsg(config.outfd, ID_INST_MEM_READ, VERB2, ID_PASS);
1242    return true;
1243
1244  fail:
1245    sendMsg(config.outfd, ID_INST_MEM_READ, VERB2, ID_WARN,
1246            "Failure while instrumenting memory reads.");
1247    return false;
1248 }
1249
1250 bool instrumentMemoryWrites(dynHandle *dh, BPatch_function *func)
1251 {
1252    BPatch_Set<BPatch_basicBlock*> allBlocks;
1253    BPatch_snippet incSnippet; 
1254    BPatch_Set<BPatch_opCode> ops;
1255    BPatch_Set<BPatch_basicBlock*>::iterator iter;
1256    int bb_warn_cnt = 0, bb_pass_cnt = 0;
1257
1258    sendMsg(config.outfd, ID_INST_MEM_WRITE, VERB2);
1259
1260    sendMsg(config.outfd, ID_GET_CFG, VERB3);
1261    BPatch_flowGraph *appCFG = func->getCFG();
1262    if (!appCFG) {
1263       sendMsg(config.outfd, ID_GET_CFG, VERB3, ID_FAIL,
1264               "Failure in BPatch_function::getCFG()");
1265       goto fail;
1266
1267    } else {
1268       sendMsg(config.outfd, ID_GET_CFG, VERB3, ID_PASS);
1269    }
1270
1271    sendMsg(config.outfd, ID_INST_GET_BB, VERB3);
1272    if (!appCFG->getAllBasicBlocks(allBlocks)) {
1273       sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_FAIL,
1274               "Failure in BPatch_flowGraph::getAllBasicBlocks()");
1275       goto fail;
1276
1277    } else if (allBlocks.size() == 0) {
1278       sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_WARN,
1279               "No basic blocks found in function");
1280       goto fail;
1281
1282    } else {
1283       sendMsg(config.outfd, ID_INST_GET_BB, VERB3, ID_PASS);
1284    }
1285
1286    if (! generateInstrumentation (dh, func, &incSnippet))
1287         goto fail;
1288
1289    ops.insert(BPatch_opStore);
1290
1291    sendMsg(config.outfd, ID_INST_BB_LIST, VERB3);
1292    for (iter = allBlocks.begin(); iter != allBlocks.end(); iter++) {
1293       if (!shouldInsert())
1294          continue;
1295       sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4);
1296       BPatch_Vector<BPatch_point*> *points = (*iter)->findPoint(ops);
1297       if (!points) {
1298          sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4, ID_WARN,
1299                  "Failure in BPatch_basicBlock::findPoint()");
1300          ++bb_warn_cnt;
1301          continue;
1302
1303       } else if (points->size() == 0) {
1304          sendMsg(config.outfd,  ID_INST_GET_BB_POINTS, VERB4, ID_WARN,
1305                  "No instrumentation points found in basic block");
1306          ++bb_warn_cnt;
1307          continue;
1308
1309       } else {
1310          sendMsg(config.outfd, ID_INST_GET_BB_POINTS, VERB4, ID_PASS);
1311       }
1312
1313       sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4);
1314       BPatchSnippetHandle *handle = dh->addSpace->insertSnippet(incSnippet, *points);
1315       if (!handle) {
1316          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4, ID_FAIL,
1317                  "Failure in BPatch_process::insertSnippet()");
1318          ++bb_warn_cnt;
1319          continue;
1320
1321       } else {
1322          sendMsg(config.outfd, ID_INST_INSERT_CODE, VERB4, ID_PASS);
1323          ++bb_pass_cnt;
1324       }
1325    }
1326    if (bb_warn_cnt)
1327       sendMsg(config.outfd, ID_INST_BB_LIST, VERB3, ID_WARN,
1328               sprintf_static("%d warning(s), %d passed.", bb_warn_cnt, bb_pass_cnt));
1329    else
1330       sendMsg(config.outfd, ID_INST_BB_LIST, VERB3, ID_PASS);
1331
1332    sendMsg(config.outfd, ID_INST_MEM_WRITE, VERB2, ID_PASS);
1333    return true;
1334
1335  fail:
1336    sendMsg(config.outfd, ID_INST_MEM_WRITE, VERB2, ID_WARN,
1337            "Failure while instrumenting memory writes.");
1338    return false;
1339
1340 }