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