Fix instrumentation regressions for libc-2.29 on ARM (#653)
[dyninst.git] / dyninstAPI / src / dynProcess.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include "dynProcess.h"
32 #include "dynThread.h"
33 #include "pcEventHandler.h"
34 #include "pcEventMuxer.h"
35 #include "function.h"
36 #include "os.h"
37 #include "debug.h"
38 #include "instPoint.h"
39 #include "BPatch.h"
40 #include "mapped_module.h"
41 #include "baseTramp.h"
42 #include "registerSpace.h"
43 #include "mapped_object.h"
44 #include "image.h"
45
46 #include "common/src/pathName.h"
47
48 #include "PCErrors.h"
49 #include "MemoryEmulator/memEmulator.h"
50 #include <boost/tuple/tuple.hpp>
51
52 #include "symtabAPI/h/SymtabReader.h"
53 #include "patchAPI/h/PatchMgr.h"
54 #include "patchAPI/h/Point.h"
55
56
57 #include <sstream>
58
59 using namespace Dyninst::ProcControlAPI;
60 using std::map;
61 using std::vector;
62 using std::string;
63 using std::stringstream;
64
65 Dyninst::SymtabAPI::SymtabReaderFactory *PCProcess::symReaderFactory_;
66
67 PCProcess *PCProcess::createProcess(const string file, pdvector<string> &argv,
68                                     BPatch_hybridMode analysisMode,
69                                     pdvector<string> &envp,
70                                     const string dir, int stdin_fd, int stdout_fd,
71                                     int stderr_fd)
72 {
73     // Debugging information
74     startup_cerr << "Creating process " << file << " in directory " << dir << endl;
75
76     startup_cerr << "Arguments: (" << argv.size() << ")" << endl;
77     for (unsigned a = 0; a < argv.size(); a++)
78         startup_cerr << "   " << a << ": " << argv[a] << endl;
79
80     startup_cerr << "Environment: (" << envp.size() << ")" << endl;
81     for (unsigned e = 0; e < envp.size(); e++)
82         startup_cerr << "   " << e << ": " << envp[e] << endl;
83
84     startup_printf("%s[%d]: stdin: %d, stdout: %d, stderr: %d\n", FILE__, __LINE__,
85             stdin_fd, stdout_fd, stderr_fd);
86
87     initSymtabReader();
88
89     // Create a full path to the executable
90     string path = createExecPath(file, dir);
91
92     std::map<int, int> fdMap;
93     redirectFds(stdin_fd, stdout_fd, stderr_fd, fdMap);
94
95     if( !setEnvPreload(envp, path) ) {
96         startup_cerr << "Failed to set environment var to preload RT library" << endl;
97         return NULL;
98     }
99
100     // Create the ProcControl process
101     Process::ptr tmpPcProc = Process::createProcess(path, argv, envp, fdMap);
102
103     if( !tmpPcProc ) {
104        cerr << "Failed to create process " << path << endl;
105        const char *lastErrMsg = getLastErrorMsg();
106         startup_printf("%s[%d]: failed to create process for %s: %s\n", __FILE__,
107                 __LINE__, file.c_str(), lastErrMsg);
108         string msg = string("Failed to create process for ") + file +
109            string(": ") + lastErrMsg;
110         showErrorCallback(68, msg.c_str());
111         return NULL;
112     }
113
114     startup_cerr << "Created process " << tmpPcProc->getPid() << endl;
115
116     PCProcess *ret = new PCProcess(tmpPcProc, file, analysisMode);
117     assert(ret);
118     tmpPcProc->setData(ret);
119
120     if( !ret->bootstrapProcess() ) {
121         startup_cerr << "Failed to bootstrap process " << ret->getPid()
122                      << ": terminating..." << endl;
123         ret->terminateProcess();
124
125         delete ret;
126         return NULL;
127     }
128
129     return ret;
130 }
131
132 PCProcess *PCProcess::attachProcess(const string &progpath, int pid,
133                                     BPatch_hybridMode analysisMode)
134 {
135     initSymtabReader();
136
137     startup_cerr << "Attaching to process " << pid << endl;
138     Process::ptr tmpPcProc = Process::attachProcess(pid, progpath);
139
140     if( !tmpPcProc ) {
141         const char *lastErrMsg = getLastErrorMsg();
142         startup_printf("%s[%d]: Failed to attach process %d: %s\n",
143                 __FILE__, __LINE__, pid, lastErrMsg);
144         stringstream msg;
145         msg << "Failed to attach to process " << pid << ": " << lastErrMsg;
146         showErrorCallback(26, msg.str());
147         return NULL;
148     }
149     startup_cerr << "Attached to process " << tmpPcProc->getPid() << endl;
150         
151     PCProcess *ret = new PCProcess(tmpPcProc, analysisMode);
152     assert(ret);
153
154     tmpPcProc->setData(ret);
155
156     ret->runningWhenAttached_ = tmpPcProc->allThreadsRunningWhenAttached();
157     ret->file_ = tmpPcProc->libraries().getExecutable()->getAbsoluteName();
158
159     if( !ret->bootstrapProcess() ) {
160         startup_cerr << "Failed to bootstrap process " << pid 
161                      << ": terminating..." << endl;
162         ret->terminateProcess();
163
164         delete ret;
165         return NULL;
166     }
167
168     return ret;
169 }
170
171 PCProcess *PCProcess::setupForkedProcess(PCProcess *parent, Process::ptr pcProc) {
172     startup_printf("%s[%d]: setting up forked process %d\n",
173             FILE__, __LINE__, pcProc->getPid());
174
175     PCProcess *ret = new PCProcess(parent, pcProc);
176     assert(ret);
177
178     pcProc->setData(ret);
179
180     ret->copyAddressSpace(parent);
181
182     // This requires the AddressSpace be copied from the parent
183     if (parent->tracedSyscalls_)
184       ret->tracedSyscalls_ = new syscallNotification(parent->tracedSyscalls_, ret);
185     else
186       ret->tracedSyscalls_ = NULL;
187
188     // Check if RT library exists in child
189     if( ret->runtime_lib.size() == 0 ) {
190         // Set the RT library name
191         if( !ret->getDyninstRTLibName() ) {
192             startup_printf("%s[%d]: failed to get Dyninst RT lib name\n",
193                     FILE__, __LINE__);
194             delete ret;
195             return NULL;
196         }
197         startup_printf("%s[%d]: Got Dyninst RT libname: %s\n", FILE__, __LINE__,
198                        ret->dyninstRT_name.c_str());
199
200         for(unsigned i = 0; i < ret->mapped_objects.size(); ++i) {
201             const fileDescriptor &desc = ret->mapped_objects[i]->getFileDesc();
202             fileDescriptor tmpDesc(ret->dyninstRT_name,
203                     desc.code(), desc.data(), true);
204             if( desc == tmpDesc ) {
205                 ret->runtime_lib.insert(ret->mapped_objects[i]);
206                 break;
207             }
208         }
209     }
210
211     // TODO hybrid mode stuff
212
213     // Copy signal handlers
214     pdvector<codeRange *> sigHandlers;
215     parent->signalHandlerLocations_.elements(sigHandlers);
216     for(unsigned i = 0; i < sigHandlers.size(); ++i) {
217         signal_handler_location *oldSig = dynamic_cast<signal_handler_location *>(sigHandlers[i]);
218         assert(oldSig);
219         signal_handler_location *newSig = new signal_handler_location(*oldSig);
220         ret->signalHandlerLocations_.insert(newSig);
221     }
222
223     // If required
224     if( !ret->copyDanglingMemory(parent) ) {
225         startup_printf("%s[%d]: failed to copy dangling memory from parent %d to child %d\n",
226                 FILE__, __LINE__, parent->getPid(), ret->getPid());
227         ret->terminateProcess();
228
229         delete ret;
230         return NULL;
231     }
232
233     ret->setInEventHandling(true);
234
235     if( !ret->bootstrapProcess() ) {
236         startup_cerr << "Failed to bootstrap process " << ret->getPid()
237                      << ": terminating..." << endl;
238         ret->terminateProcess();
239
240         delete ret;
241         return NULL;
242     }
243
244     ret->setDesiredProcessState(parent->getDesiredProcessState());
245
246     return ret;
247 }
248
249 PCProcess *PCProcess::setupExecedProcess(PCProcess *oldProc, std::string execPath) {
250     BPatch::bpatch->registerExecCleanup(oldProc, NULL);
251
252     PCProcess *newProc = new PCProcess(oldProc->pcProc_, execPath, oldProc->analysisMode_);
253
254     oldProc->pcProc_->setData(newProc);
255     newProc->setExecing(true);
256
257     if( !newProc->bootstrapProcess() ) {
258         proccontrol_printf("%s[%d]: failed to bootstrap execed process %d\n",
259                 FILE__, __LINE__, newProc->getPid());
260         delete newProc;
261         return NULL;
262     }
263
264     delete oldProc;
265     oldProc = NULL;
266
267     newProc->setInEventHandling(true);
268     //newProc->incPendingEvents();
269
270     BPatch::bpatch->registerExecExit(newProc);
271
272     newProc->setExecing(false);
273     newProc->setDesiredProcessState(ps_running);
274
275     return newProc;
276 }
277
278 PCProcess::~PCProcess() {
279         proccontrol_printf("%s[%d]: destructing PCProcess %d\n",
280                 FILE__, __LINE__, getPid());
281
282     if( tracedSyscalls_ ) delete tracedSyscalls_;
283     tracedSyscalls_ = NULL;
284
285     if( irpcTramp_ ) delete irpcTramp_;
286     irpcTramp_ = NULL;
287
288     signalHandlerLocations_.clear();
289
290     trapMapping.clearTrapMappings();
291
292     if(pcProc_ && pcProc_->getData() == this) pcProc_->setData(NULL);
293 }
294
295 void PCProcess::initSymtabReader()
296 {
297    //Set SymbolReaderFactory in Stackwalker before create/attach
298    if (!symReaderFactory_) {
299       symReaderFactory_ = new Dyninst::SymtabAPI::SymtabReaderFactory();
300       Dyninst::Stackwalker::Walker::setSymbolReader(symReaderFactory_);
301    }
302 }
303
304 /***************************************************************************
305  **** Runtime library initialization code (Dyninst)                     ****
306  ***************************************************************************/
307
308 /*
309  *
310  * Gratuitously large comment. This diagrams the startup flow of
311  * messages between the mutator and mutatee. Entry points
312  * for create and attach process are both given.
313  *     Mutator           Signal              Mutatee
314  * Create:
315  *     Fork/Exec
316  *                     <-- Trap              Halted in exec (handled by ProcControlAPI)
317  *     Install trap in main
318  *                     <-- Trap              Halted in main
319  *  Attach: (also paused, not in main)
320  *     Install call to dlopen/
321  *     LoadLibrary
322  *                     <-- Trap              In library load
323  *     Set parameters in library
324  *                     <-- Trap              Finished loading
325  *     Restore code and leave paused
326  *     Finalize library
327  *       If finalizing fails, init via iRPC
328  */
329
330 /*
331  * In all cases, the process is left paused at the entry of main
332  * (create) or where it was (attach). No permanent instrumentation
333  * is inserted.
334  */
335
336 bool PCProcess::hasReachedBootstrapState(bootstrapState_t state) const {
337     return state <= bootstrapState_;
338 }
339
340 void PCProcess::setBootstrapState(bootstrapState_t newState) {
341     bootstrapState_ = newState;
342 }
343
344 bool PCProcess::bootstrapProcess() {
345     assert( pcProc_->allThreadsStopped() );
346
347     startup_printf("%s[%d]: attempting to bootstrap process %d\n", 
348             FILE__, __LINE__, getPid());
349
350     if( !wasCreatedViaFork() ) {
351         // Initialize the inferior heaps
352         initializeHeap();
353
354         for(unsigned i = 0; i < mapped_objects.size(); ++i) {
355             addInferiorHeap(mapped_objects[i]);
356         }
357
358         // Create the mapped_objects for the executable and shared libraries
359         if( !createInitialMappedObjects() ) {
360             startup_printf("%s[%d]: bootstrap failed while creating mapped objects\n",
361                     FILE__, __LINE__);
362             return false;
363         }
364     }
365
366     // Create the initial threads
367     createInitialThreads();
368
369     // Initialize StackwalkerAPI
370     if ( !createStackwalker() )
371     {
372       startup_printf("Bootstrap failed while initializing Stackwalker\n");
373       return false;
374     }
375
376     // Insert a breakpoint at the entry point of main (and possibly __libc_start_main)
377     if( !hasPassedMain() ) {
378       startup_printf("%s[%d]: inserting breakpoint at main\n", FILE__, __LINE__);
379         if( !insertBreakpointAtMain() ) {
380             startup_printf("%s[%d]: bootstrap failed while setting a breakpoint at main\n",
381                     FILE__, __LINE__);
382             return false;
383         }
384         startup_printf("%s[%d]: continuing process to breakpoint\n", FILE__, __LINE__);
385         if( !continueProcess() ) {
386             startup_printf("%s[%d]: bootstrap failed while continuing the process\n",
387                     FILE__, __LINE__);
388             return false;
389         }
390
391         while( !hasReachedBootstrapState(bs_readyToLoadRTLib) ) {
392           startup_printf("%s[%d]: waiting for main() loop\n", FILE__, __LINE__);
393             if( isStopped() ) {
394               startup_printf("%s[%d]: We think the process is stopped, continuing\n", FILE__, __LINE__);
395                 if( !continueProcess() ) {
396                     startup_printf("%s[%d]: bootstrap failed while continuing the process\n",
397                             FILE__, __LINE__);
398                     return false;
399                 }
400             }
401
402             if( isTerminated() ) {
403                 bperr("The process exited during startup.  This is likely due to one "
404                       "of two reasons:\n"
405                       "A). The application is mis-built and unable to load.  Try "
406                       "running the application outside of Dyninst and see if it "
407                       "loads properly.\n"
408                       "B). libdyninstAPI_RT is mis-built.  Try loading the library "
409                       "into another application and see if it reports any errors.  "
410                       "Ubuntu users - You may need to rebuild the RT library "
411                       "with the DISABLE_STACK_PROT line enabled in "
412                       "core/make.config.local");
413                 startup_printf("%s[%d]: program exited early, never reached "
414                                "initialized state\n", FILE__, __LINE__);
415                 startup_printf("Error is likely due to the application or RT "
416                                "library having missing symbols or dependencies\n");
417                 return false;
418             }
419
420             startup_printf("%s[%d]: bootstrap waiting for process to initialize\n",
421                     FILE__, __LINE__);
422             if( PCEventMuxer::wait(true) == PCEventMuxer::Error) {
423                 startup_printf("%s[%d]: bootstrap failed to wait for events\n",
424                         FILE__, __LINE__);
425                 return false;
426             }
427         }
428     }else{
429         bootstrapState_ = bs_readyToLoadRTLib;
430     }
431     startup_printf("%s[%d]: process initialized, loading the RT library\n",
432             FILE__, __LINE__);
433
434     // Load the RT library
435     if( !loadRTLib() ) {
436         bperr("Dyninst was unable to load the dyninst runtime library "
437               "into the application.  This may be caused by statically "
438               "linked executables, or by having dyninst linked against a "
439               "different version of libelf than it was built with.");
440         startup_printf("%s[%d]: bootstrap failed to load RT library\n",
441                 FILE__, __LINE__);
442         return false;
443     }
444
445
446     pdvector<int_variable *> obsCostVec;
447     if( !findVarsByAll("DYNINSTobsCostLow", obsCostVec) ) {
448         startup_printf("%s[%d]: failed to find DYNINSTobsCostLow\n",
449                 FILE__, __LINE__);
450         return false;
451     }
452
453     costAddr_ = obsCostVec[0]->getAddress();
454     assert(costAddr_);
455
456     if( !wasCreatedViaFork() ) {
457         // Install system call tracing
458         startup_printf("%s[%d]: installing default Dyninst instrumentation into process %d\n", 
459             FILE__, __LINE__, getPid());
460
461         tracedSyscalls_ = new syscallNotification(this);
462
463         // TODO 
464         // pre-fork and pre-exit should depend on whether a callback is defined
465         // 
466         // This will require checking whether BPatch holds a defined callback and also
467         // adding a way for BPatch enable this instrumentation in all processes when
468         // a callback is registered
469
470         if (!tracedSyscalls_->installPreFork()) {
471             startup_printf("%s[%d]: failed pre-fork notification setup\n",
472                     FILE__, __LINE__);
473             return false;
474         }
475
476         if (!tracedSyscalls_->installPostFork()) {
477             startup_printf("%s[%d]: failed post-fork notification setup\n",
478                     FILE__, __LINE__);
479             return false;
480         }
481
482         if (!tracedSyscalls_->installPreExec()) {
483             startup_printf("%s[%d]: failed pre-exec notification setup\n",
484                     FILE__, __LINE__);
485             return false;
486         }
487
488         if (!tracedSyscalls_->installPostExec()) {
489             startup_printf("%s[%d]: failed post-exec notification setup\n",
490                     FILE__, __LINE__);
491             return false;
492         }
493
494         if (!tracedSyscalls_->installPreExit()) {
495             startup_printf("%s[%d]: failed pre-exit notification setup\n",
496                     FILE__, __LINE__);
497             return false;
498         }
499
500         if (!tracedSyscalls_->installPreLwpExit()) {
501             startup_printf("%s[%d]: failed pre-lwp-exit notification setup\n",
502                     FILE__, __LINE__);
503             return false;
504         }
505
506         // Initialize the MT stuff
507         if (multithread_capable()) {
508             if( !instrumentMTFuncs() ) {
509                 startup_printf("%s[%d]: Failed to instrument MT funcs\n",
510                         FILE__, __LINE__);
511                 return false;
512             }
513         }
514     }
515
516     // use heuristics to set hybrid analysis mode
517     if (BPatch_heuristicMode == analysisMode_) {
518         if (getAOut()->parse_img()->codeObject()->defensiveMode()) {
519             analysisMode_ = BPatch_defensiveMode;
520         } else {
521             analysisMode_ = BPatch_normalMode;
522         }
523     }
524
525     bootstrapState_ = bs_initialized;
526     startup_printf("%s[%d]: finished bootstrapping process %d\n", FILE__, __LINE__, getPid());
527
528     return true;
529 }
530
531 bool PCProcess::createStackwalker()
532 {
533   using namespace Stackwalker;
534   ProcDebug *procDebug = NULL;
535   StackwalkSymLookup *symLookup = NULL;
536
537   // Create ProcessState
538   if (NULL == (procDebug = ProcDebug::newProcDebug(pcProc_)))
539   {
540     startup_printf("Could not create Stackwalker process state\n");
541     return false;
542   }
543
544   // Create SymbolLookup
545   symLookup = new StackwalkSymLookup(this);
546
547   // Create Walker without default steppers
548   if (NULL == (stackwalker_ = Walker::newWalker(procDebug,
549                                                 NULL,
550                                                 symLookup,
551                                                 false)))
552   {
553     startup_printf("Could not create Stackwalker\n");
554     return false;
555   }
556
557   return createStackwalkerSteppers();
558 }
559
560 void PCProcess::createInitialThreads() {
561     ThreadPool &pcThreads = pcProc_->threads();
562     initialThread_ = PCThread::createPCThread(this, pcThreads.getInitialThread());
563     addThread(initialThread_);
564
565     for(ThreadPool::iterator i = pcThreads.begin(); i != pcThreads.end(); ++i) {
566         if( *i == pcThreads.getInitialThread() ) continue;
567
568         // Wait to create threads until they have user thread information available
569         if( !(*i)->haveUserThreadInfo() ) continue;
570
571         PCThread *newThr = PCThread::createPCThread(this, *i);
572         addThread(newThr);
573     }
574 }
575
576 bool PCProcess::createInitialMappedObjects() {
577     if( file_.empty() ) {
578         startup_printf("%s[%d]: failed to determine executable for process %d\n",
579                 FILE__, __LINE__, getPid());
580         return false;
581     }
582
583     startup_printf("Processing initial shared objects\n");
584     startup_printf("----\n");
585
586     initPatchAPI();
587
588     // Do the a.out first...
589     mapped_object *aout = mapped_object::createMappedObject(pcProc_->libraries().getExecutable(), this, analysisMode_);
590     addASharedObject(aout);
591
592     // Set the RT library name
593     if( !getDyninstRTLibName() ) {
594       bperr("Dyninst was unable to find the dyninst runtime library.");
595         startup_printf("%s[%d]: failed to get Dyninst RT lib name\n",
596                 FILE__, __LINE__);
597         return false;
598     }
599
600     // Find main
601     startup_printf("%s[%d]:  leave setAOut/setting main\n", FILE__, __LINE__);
602     setMainFunction();
603
604     // Create mapped objects for any loaded shared libraries
605     const LibraryPool &libraries = pcProc_->libraries();
606     for(LibraryPool::const_iterator i = libraries.begin(); i != libraries.end(); ++i) {
607        // Some platforms don't use the data load address field
608        if ((*i) == libraries.getExecutable()) continue;
609
610        startup_cerr << "Library: " << (*i)->getAbsoluteName() 
611             << hex << " / " << (*i)->getLoadAddress() 
612             << ", " << ((*i)->isSharedLib() ? "<lib>" : "<aout>") << dec << endl;
613
614        mapped_object *newObj = mapped_object::createMappedObject(*i, 
615                                                                  this, analysisMode_);
616        if( newObj == NULL ) {
617            startup_printf("%s[%d]: failed to create mapped object for library %s\n",
618                    FILE__, __LINE__, (*i)->getAbsoluteName().c_str());
619            return false;
620        }
621
622        const fileDescriptor &desc = newObj->getFileDesc();
623        fileDescriptor tmpDesc(dyninstRT_name, desc.code(), desc.data(), true);
624        if( desc == tmpDesc ) {
625           startup_printf("%s[%d]: RT library already loaded, manual loading not necessary\n",
626                          FILE__, __LINE__);
627           runtime_lib.insert(newObj);
628        }
629
630        if (analysisMode_ == BPatch_defensiveMode) {
631            std::string lib_name = newObj->fileName();
632            if (lib_name == "dyninstAPI_RT.dll" ||
633                lib_name == "ntdll.dll" ||
634                lib_name == "kernel32.dll" ||
635                lib_name == "user32.dll" ||
636                lib_name == "KERNELBASE.dll" ||
637                lib_name == "msvcrt.dll" ||
638                lib_name == "msvcr80.dll" ||
639                lib_name == "msvcr100d.dll" ||
640                lib_name == "msvcp100d.dll" ||
641                lib_name == "MSVCR100.dll") {
642                    startup_cerr << "Running library " << lib_name
643                        << " in normal mode because it is trusted.\n";
644                    newObj->enableDefensiveMode(false);
645            }
646        }
647
648        addASharedObject(newObj);
649     }
650
651
652     startup_printf("----\n");
653
654     return true;
655 }
656
657 // creates an image, creates new resources for a new shared object
658 // adds it to the collection of mapped_objects
659 void PCProcess::addASharedObject(mapped_object *newObj) {
660     assert(newObj);
661
662     addMappedObject(newObj);
663
664     findSignalHandler(newObj);
665
666     startup_printf("%s[%d]: adding shared object %s, addr range 0x%lx to 0x%lx\n",
667             FILE__, __LINE__,
668             newObj->fileName().c_str(),
669             newObj->getBaseAddress(),
670             newObj->getBaseAddress() + newObj->get_size());
671     parsing_printf("Adding shared object %s, addr range 0x%x to 0x%x\n",
672             newObj->fileName().c_str(),
673             newObj->getBaseAddress(),
674             newObj->getBaseAddress() + newObj->get_size());
675
676     if( heapInitialized_ ) {
677         addInferiorHeap(newObj);
678     }else{
679         startup_printf("%s[%d]: skipping check for new inferior heaps, heap uninitialized\n",
680                                        FILE__, __LINE__);
681     }
682 }
683
684 void PCProcess::removeASharedObject(mapped_object *obj) {
685     // Remove from mapped_objects list
686     for (unsigned j = 0; j < mapped_objects.size(); j++) {
687         if (obj == mapped_objects[j]) {
688             mapped_objects[j] = mapped_objects.back();
689             mapped_objects.pop_back();
690             deletedObjects_.push_back(obj);
691             break;
692         }
693     }
694
695     if (runtime_lib.end() != runtime_lib.find(obj)) {
696         runtime_lib.erase( runtime_lib.find(obj) );
697     }
698     proccontrol_printf("Removing shared object %s, addr range 0x%x to 0x%x\n",
699                   obj->fileName().c_str(),
700                   obj->getBaseAddress(),
701                   obj->get_size());
702
703     // TODO Signal handler...
704 }
705
706 bool PCProcess::setAOut(fileDescriptor &desc) {
707     startup_printf("%s[%d]:  enter setAOut\n", FILE__, __LINE__);
708
709     assert(mapped_objects.size() == 0);
710
711     mapped_object *aout = mapped_object::createMappedObject
712                           (desc, this, getHybridMode());
713     if (!aout) {
714         startup_printf("%s[%d]:  fail setAOut\n", FILE__, __LINE__);
715         return false;
716     }
717
718
719     return true;
720 }
721
722 // We keep a vector of all signal handler locations
723 void PCProcess::findSignalHandler(mapped_object *obj) {
724     startup_printf("%s[%d]: findSignalhandler(%p)\n", FILE__, __LINE__, obj);
725     assert(obj);
726
727     int_symbol sigSym;
728     string signame(SIGNAL_HANDLER);
729
730     startup_printf("%s[%d]: findSignalhandler(%p): gettingSymbolInfo\n", FILE__, __LINE__, obj);
731     if (obj->getSymbolInfo(signame, sigSym)) {
732         // Symbols often have a size of 0. This b0rks the codeRange code,
733         // so override to 1 if this is true...
734         unsigned size_to_use = sigSym.getSize();
735         if (!size_to_use) size_to_use = 1;
736
737         startup_printf("%s[%d]: findSignalhandler(%p): addingSignalHandler(%p, %d)\n", FILE__, __LINE__, obj, (void *) sigSym.getAddr(), size_to_use);
738         addSignalHandler(sigSym.getAddr(), size_to_use);
739     }
740
741     startup_printf("%s[%d]: leaving findSignalhandler(%p)\n", FILE__, __LINE__, obj);
742 }
743
744 // NUMBER_OF_MAIN_POSSIBILITIES is defined in image.h
745 void PCProcess::setMainFunction() {
746     assert(!main_function_);
747
748     for (unsigned i = 0; i < NUMBER_OF_MAIN_POSSIBILITIES; i++) {
749         main_function_ = findOnlyOneFunction(main_function_names[i]);
750         if (main_function_) {
751            break;
752         }
753     }
754 }
755  
756 /*
757  * Given an image, add all static heaps inside it
758  * (DYNINSTstaticHeap...) to the buffer pool.
759  */
760 void PCProcess::addInferiorHeap(mapped_object *obj) {
761     pdvector<heapDescriptor> infHeaps;
762     /* Get a list of inferior heaps in the new image */
763     if (obj->getInfHeapList(infHeaps)) {
764         /* Add the vector to the inferior heap structure */
765         for (u_int j=0; j < infHeaps.size(); j++) {
766             infmalloc_printf("%s[%d]: adding heap at 0x%lx to 0x%lx, name %s\n",
767                              FILE__, __LINE__,
768                              infHeaps[j].addr(),
769                              infHeaps[j].addr() + infHeaps[j].size(),
770                              infHeaps[j].name().c_str());
771
772             // platform-specific check to ignore this heap
773             if( skipHeap(infHeaps[j]) ) continue;
774
775             heapItem *h = new heapItem (infHeaps[j].addr(), infHeaps[j].size(),
776                                         infHeaps[j].type(), false);
777
778             infmalloc_printf("%s[%d]: Adding heap from 0x%lx - 0x%lx (%d bytes, type %d) from mapped object %s\n",
779                              FILE__, __LINE__,
780                              infHeaps[j].addr(),
781                              infHeaps[j].addr() + infHeaps[j].size(),
782                              infHeaps[j].size(),
783                              infHeaps[j].type(),
784                              obj->fileName().c_str());
785
786             addHeap(h);
787
788             // set rtlib heaps (runtime_lib hasn't been set yet)
789             if ( ! obj->fullName().compare( dyninstRT_name ) ) {
790                 dyninstRT_heaps_.push_back(h);
791             }
792         }
793     }
794 }
795
796 static const unsigned MAX_THREADS = 32; // Should match MAX_THREADS in RTcommon.c
797
798 bool PCProcess::loadRTLib() {
799     // Check if the RT library has already been loaded
800    if( runtime_lib.size() != 0 ) {
801       startup_printf("%s[%d]: RT library already loaded\n",
802                      FILE__, __LINE__);
803
804       bootstrapState_ = bs_loadedRTLib;
805    }
806    else {
807      if (!pcProc_->addLibrary(dyninstRT_name)) {
808        startup_printf("%s[%d]: failed to start loading RT lib\n", FILE__,
809                       __LINE__);
810        return false;
811      }
812      bootstrapState_ = bs_loadedRTLib;
813      
814      // Process the library load (we hope)
815      PCEventMuxer::handle(this);
816      
817      if( runtime_lib.size() == 0 ) {
818        startup_printf("%s[%d]: failed to load RT lib\n", FILE__,
819                       __LINE__);
820        return false;
821      }
822      
823      bootstrapState_ = bs_loadedRTLib;
824    }
825    int loaded_ok = 0;
826    pdvector<int_variable *> vars;
827    if (!findVarsByAll("DYNINSThasInitialized", vars)) {
828         startup_printf("%s[%d]: no DYNINSThasInitialized variable\n", FILE__, __LINE__);
829                 return false;
830    }
831    if (!readDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *)&loaded_ok, false)) {
832         startup_printf("%s[%d]: readDataWord failed\n", FILE__, __LINE__);
833         return false;
834    }
835    if(!loaded_ok)
836    {
837            startup_printf("%s[%d]: DYNINSTinit not called automatically\n", FILE__, __LINE__);
838    }
839
840    // Install a breakpoint in DYNINSTtrapFunction.
841    // This is used as RT signal.
842    Address addr = getRTTrapFuncAddr();
843    if (addr == 0) {
844        startup_printf("%s[%d]: Cannot find DYNINSTtrapFunction. Needed as RT signal\n", FILE__, __LINE__);
845        return false;
846    }
847    if (!setBreakpoint(addr)) {
848        startup_printf("%s[%d]: Cannot set breakpoint in DYNINSTtrapFunction.\n", FILE__, __LINE__);
849        return false;
850    }
851    startup_printf("%s[%d]: DYNINSTinit succeeded\n", FILE__, __LINE__);
852    return setRTLibInitParams();
853 }
854
855 // Set up the parameters for DYNINSTinit in the RT lib
856 bool PCProcess::setRTLibInitParams() {
857     startup_printf("%s[%d]: welcome to PCProcess::setRTLibInitParams\n",
858             FILE__, __LINE__);
859
860     int pid = P_getpid();
861
862
863     // Now we write these variables into the following global vrbles
864     // in the dyninst library:
865     // libdyninstAPI_RT_init_localCause
866     // libdyninstAPI_RT_init_localPid
867
868     pdvector<int_variable *> vars;
869
870
871     if (!findVarsByAll("libdyninstAPI_RT_init_localPid", vars)) {
872         if (!findVarsByAll("_libdyninstAPI_RT_init_localPid", vars)) {
873             startup_printf("%s[%d]: could not find necessary internal variable\n",
874                     FILE__, __LINE__);
875             return false;
876         }
877     }
878
879     assert(vars.size() >= 1);
880     if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *)&pid)) {
881         startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
882         return false;
883     }
884     vars.clear();
885
886     if (!findVarsByAll("libdyninstAPI_RT_init_maxthreads", vars)) {
887         if (!findVarsByAll("_libdyninstAPI_RT_init_maxthreads", vars)) {
888             startup_printf("%s[%d]: could not find necessary internal variable\n",
889                     FILE__, __LINE__);
890             return false;
891         }
892     }
893
894     unsigned numThreads = MAX_THREADS;
895     if( !multithread_capable() ) numThreads = 1;
896
897     assert(vars.size() >= 1);
898     if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *) &numThreads)) {
899         startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
900         return false;
901     }
902     vars.clear();
903
904     if (!findVarsByAll("libdyninstAPI_RT_init_debug_flag", vars)) {
905         if (!findVarsByAll("_libdyninstAPI_RT_init_debug_flag", vars)) {
906             startup_printf("%s[%d]: could not find necessary internal variable\n",
907                     FILE__, __LINE__);
908             return false;
909         }
910     }
911
912     assert(vars.size() >= 1);
913     if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *) &dyn_debug_rtlib)) {
914         startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
915         return false;
916     }
917     vars.clear();
918     if (dyn_debug_rtlib) {
919         fprintf(stderr, "%s[%d]:  set var in RTlib for debug...\n", FILE__, __LINE__);
920     }
921
922     int static_mode = 0;
923     if (!findVarsByAll("DYNINSTstaticMode", vars)) {
924         if (!findVarsByAll("DYNINSTstaticMode", vars)) {
925             startup_printf("%s[%d]: could not find necessary internal variable\n",
926                     FILE__, __LINE__);
927             return false;
928         }
929     }
930
931     assert(vars.size() >= 1);
932     if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *) &static_mode)) {
933         startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
934         return false;
935     }
936     vars.clear();
937     return true;
938 }
939
940
941 #if defined(os_vxworks)
942 bool PCProcess::insertBreakpointAtMain() {
943     // We don't need any extra processing of the RTlib.
944     return true;
945 }
946 #else
947 bool PCProcess::insertBreakpointAtMain() {
948     if( main_function_ == NULL ) {
949         startup_printf("%s[%d]: main function not yet found, cannot insert breakpoint\n",
950                 FILE__, __LINE__);
951         return false;
952     }
953     Address addr = main_function_->addr();
954
955     // Create the breakpoint
956     mainBrkPt_ = Breakpoint::newBreakpoint();
957     if( !pcProc_->addBreakpoint(addr, mainBrkPt_) ) {
958         startup_printf("%s[%d]: failed to insert a breakpoint at main entry: 0x%x\n",
959                 FILE__, __LINE__, addr);
960         return false;
961     }
962
963     startup_printf("%s[%d]: added trap to entry of main, address 0x%x\n", 
964             FILE__, __LINE__, addr);
965
966     return true;
967 }
968 #endif
969
970 bool PCProcess::removeBreakpointAtMain() {
971     if( main_function_ == NULL || mainBrkPt_ == Breakpoint::ptr() ) {
972         startup_printf("%s[%d]: no breakpoint set at main function, not removing\n",
973                 FILE__, __LINE__);
974         return true;
975     }
976
977     Address addr = main_function_->addr();
978
979     if( !pcProc_->rmBreakpoint(addr, mainBrkPt_) ) {
980         startup_printf("%s[%d]: failed to remove breakpoint at main entry: 0x%x\n",
981                 FILE__, __LINE__, addr);
982         return false;
983     }
984     mainBrkPt_ = Breakpoint::ptr();
985
986     return true;
987 }
988
989 Breakpoint::ptr PCProcess::getBreakpointAtMain() const {
990     return mainBrkPt_;
991 }
992
993 // End Runtime library initialization code
994
995 bool PCProcess::continueProcess() {
996     proccontrol_printf("%s[%d]: Continuing process %d\n", FILE__, __LINE__, getPid());
997
998     if( !isAttached() || isTerminated() ) {
999         bpwarn("Warning: continue attempted on non-attached process\n");
1000         return false;
1001     }
1002
1003     // If the process is in event handling, the process should not be continued, 
1004     // the processState_t value will be used after event handling to determine the
1005     // state of the process
1006     if( isInEventHandling() ) {
1007         proccontrol_printf("%s[%d]: process currently in event handling, not continuing\n",
1008                 FILE__, __LINE__);
1009         return true;
1010     }
1011
1012     for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
1013             i != threadsByTid_.end(); ++i)
1014     {
1015         i->second->clearStackwalk();
1016     }
1017
1018     return pcProc_->continueProc();
1019 }
1020
1021 bool PCProcess::stopProcess() {
1022     proccontrol_printf("%s[%d]: Stopping process %d\n", FILE__, __LINE__, getPid());
1023
1024     if( !isAttached() || isTerminated() ) {
1025         bpwarn("Warning: stop attempted on non-attached process\n");
1026         return false;
1027     }
1028
1029     // See comment in continueProcess about this
1030     if( isInEventHandling() ) {
1031         proccontrol_printf("%s[%d]: process currently in event handling, not stopping\n",
1032                 FILE__, __LINE__);
1033         return true;
1034     }
1035
1036     return pcProc_->stopProc();
1037 }
1038
1039 bool PCProcess::terminateProcess() {
1040     if( isTerminated() ) return true;
1041
1042     if( !isAttached() ) return false;
1043
1044     forcedTerminating_ = true;
1045
1046     proccontrol_printf("%s[%d]: Terminating process %d\n", FILE__, __LINE__, getPid());
1047     if( !pcProc_->terminate() ) {
1048         proccontrol_printf("%s[%d]: Failed to terminate process %d\n", FILE__, __LINE__, 
1049                 getPid());
1050         return false;
1051     }
1052     PCEventMuxer::handle();
1053
1054     proccontrol_printf("%s[%d]: finished terminating process %d\n", FILE__, __LINE__, getPid());
1055
1056     return true;
1057 }
1058
1059 bool PCProcess::detachProcess(bool cont = true) {
1060     if( isTerminated() ) return true;
1061
1062     if( !isAttached() ) return false;
1063
1064     if (tracedSyscalls_) {
1065         // Process needs to be stopped to change instrumentation
1066         bool needToContinue = false;
1067         if( !isStopped() ) {
1068             needToContinue = true;
1069             if( !stopProcess() ) {
1070                 proccontrol_printf("%s[%d]: failed to stop process for removing syscalls\n",
1071                         FILE__, __LINE__);
1072                         return false;
1073             }
1074         }
1075
1076         tracedSyscalls_->removePreFork();
1077         tracedSyscalls_->removePostFork();
1078         tracedSyscalls_->removePreExec();
1079         tracedSyscalls_->removePostExec();
1080         tracedSyscalls_->removePreExit();
1081         tracedSyscalls_->removePreLwpExit();
1082         if (cont) {
1083             if( needToContinue ) {
1084                 if( !continueProcess() ) {
1085                     proccontrol_printf("%s[%d]: failed to continue process after removing syscalls\n",
1086                             FILE__, __LINE__);
1087                 }
1088             }
1089         }
1090     }
1091
1092     // TODO figure out if ProcControl should care about continuing a process
1093     // after detach
1094
1095     // NB: it's possible to get markExited() while handling events for the
1096     // tracedSyscalls_->remove* calls above, clearing pcProc_.
1097     if( isTerminated() || pcProc_->detach(!cont) ) {
1098         attached_ = false;
1099         return true;
1100     }
1101
1102     return false;
1103 }
1104
1105 bool PCProcess::isBootstrapped() const {
1106     return bootstrapState_ == bs_initialized;
1107 }
1108
1109 bool PCProcess::isAttached() const {
1110     return attached_;
1111 }
1112
1113 bool PCProcess::isStopped() const {
1114     if( pcProc_ == Process::ptr() ) return true;
1115     return pcProc_->allThreadsStopped();
1116 }
1117
1118 bool PCProcess::isTerminated() const {
1119     if( pcProc_ == Process::ptr() ) return true;
1120     return pcProc_->isTerminated();
1121 }
1122
1123 bool PCProcess::hasExitedNormally() const {
1124     if( pcProc_ == Process::ptr() ) return true;
1125     return pcProc_->isExited();
1126 }
1127
1128 bool PCProcess::isExecing() const {
1129     return execing_;
1130 }
1131
1132 void PCProcess::setExecing(bool b) {
1133     execing_ = b;
1134 }
1135
1136 bool PCProcess::isExiting() const {
1137     return exiting_;
1138 }
1139
1140 void PCProcess::setExiting(bool b) {
1141     exiting_ = b;
1142 }
1143
1144 bool PCProcess::isInEventHandling() const {
1145     return inEventHandling_;
1146 }
1147
1148 void PCProcess::setInEventHandling(bool b) {
1149     inEventHandling_ = b;
1150 }
1151
1152 bool PCProcess::hasReportedEvent() const {
1153     return reportedEvent_;
1154 }
1155
1156 void PCProcess::setReportingEvent(bool b) {
1157     reportedEvent_ = b;
1158 }
1159
1160 void PCProcess::markExited() {
1161     pcProc_.reset();
1162 }
1163
1164 void PCProcess::writeDebugDataSpace(void *inTracedProcess, u_int amount,
1165         const void *inSelf)
1166 {
1167     static unsigned write_no = 0;
1168
1169     if( !dyn_debug_write ) return;
1170
1171     write_printf("const unsigned char ");
1172     switch(getArch()) {
1173         case Arch_x86:
1174             write_printf("x86_");
1175             break;
1176         case Arch_x86_64:
1177             write_printf("amd64_");
1178             break;
1179         case Arch_ppc32:
1180         case Arch_ppc64:
1181             write_printf("power_");
1182             break;
1183         default:
1184             write_printf("unknown_");
1185             break;
1186     }
1187     write_printf("%lx_%d_%u[] = {", inTracedProcess, getPid(), write_no++);
1188
1189     if( amount > 0 ) {
1190        const unsigned char *buffer = (const unsigned char *)inSelf;
1191        for(unsigned i = 0; i < amount-1; ++i) {
1192            if( i % 10 == 0 ) write_printf("\n");
1193            write_printf("0x%02hhx, ", buffer[i]);
1194        }
1195        write_printf("0x%02hhx", buffer[amount-1]);
1196     }
1197     write_printf("\n};\n");
1198 }
1199
1200 bool PCProcess::writeDataSpace(void *inTracedProcess, u_int amount,
1201                                const void *inSelf) {
1202     if( isTerminated() ) {
1203        cerr << "Writing to terminated process!" << endl;
1204        return false;
1205     }
1206     bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf,
1207                                        amount);
1208
1209     if( BPatch_defensiveMode == proc()->getHybridMode() && !result ) {
1210         // the write may have failed because we've removed write permissions
1211         // from the page, remove them and try again
1212
1213         PCMemPerm origRights, rights(true, true, true);
1214         if (!pcProc_->setMemoryAccessRights((Address)inTracedProcess,
1215                                             amount, rights, origRights)) {
1216             cerr << "Fail to set memory permissions!" << endl;
1217             return false;
1218         }
1219
1220         /*
1221         int oldRights = pcProc_->setMemoryAccessRights((Address)inTracedProcess,
1222                                                        amount,
1223                                                        PAGE_EXECUTE_READWRITE);
1224
1225         if( oldRights == PAGE_EXECUTE_READ || oldRights == PAGE_READONLY ) {
1226         */
1227
1228         if( origRights.isRX() || origRights.isR() ) {
1229             result = pcProc_->writeMemory((Address)inTracedProcess, inSelf,
1230                                           amount);
1231
1232             /*
1233             if( pcProc_->setMemoryAccessRights((Address)inTracedProcess,
1234                                                amount, oldRights) == false ) {
1235             */
1236
1237             PCMemPerm tmpRights;
1238             if( !pcProc_->setMemoryAccessRights((Address)inTracedProcess,
1239                                                 amount, origRights, tmpRights)) {
1240                 result = false;
1241             }
1242         } else {
1243             result = false;
1244         }
1245     }
1246
1247     if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
1248
1249     return result;
1250 }
1251
1252 bool PCProcess::writeDataWord(void *inTracedProcess,
1253                    u_int amount, const void *inSelf) 
1254 {
1255     if( isTerminated() ) return false;
1256
1257     // XXX ProcControlAPI should support word writes in the future
1258     bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf, amount);
1259     if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
1260     return result;
1261 }
1262
1263 bool PCProcess::readDataSpace(const void *inTracedProcess, u_int amount,
1264                    void *inSelf, bool displayErrMsg)
1265 {
1266     if( isTerminated() ) return false;
1267
1268     bool result = pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
1269     if( !result && displayErrMsg ) {
1270         stringstream msg;
1271         msg << "System error: unable to read " << amount << "@" 
1272             << Address_str((Address)inTracedProcess) << " from process data space: "
1273             << getLastErrorMsg() << "(pid = " << getPid() << ")";
1274        showErrorCallback(38, msg.str()); 
1275     }
1276     return result;
1277 }
1278
1279 bool PCProcess::readDataWord(const void *inTracedProcess, u_int amount,
1280                   void *inSelf, bool displayErrMsg)
1281 {
1282     if( isTerminated() ) return false;
1283
1284     // XXX see writeDataWord above
1285     bool result = pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
1286     if( !result && displayErrMsg ) {
1287         stringstream msg;
1288         msg << "System error: unable to read " << amount << "@" 
1289             << Address_str((Address)inTracedProcess) << " from process data space: "
1290             << getLastErrorMsg() << "(pid = " << getPid() << ")";
1291        showErrorCallback(38, msg.str());
1292     }
1293
1294     return result;
1295 }
1296
1297 bool PCProcess::writeTextSpace(void *inTracedProcess, u_int amount, const void *inSelf)
1298 {
1299     if( isTerminated() ) return false;
1300     bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf, amount);
1301
1302     if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
1303
1304     return result;
1305 }
1306
1307 bool PCProcess::writeTextWord(void *inTracedProcess, u_int amount, const void *inSelf)
1308 {
1309     if( isTerminated() ) return false;
1310
1311     // XXX see writeDataWord above
1312     bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf, amount);
1313
1314     if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
1315
1316     return result;
1317 }
1318
1319 bool PCProcess::readTextSpace(const void *inTracedProcess, u_int amount,
1320                    void *inSelf)
1321 {
1322     if( isTerminated() ) return false;
1323
1324     return pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
1325 }
1326
1327 bool PCProcess::readTextWord(const void *inTracedProcess, u_int amount,
1328                   void *inSelf)
1329 {
1330     if( isTerminated() ) return false;
1331
1332     // XXX see writeDataWord above
1333     return pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
1334 }
1335
1336 PCThread *PCProcess::getInitialThread() const {
1337     return initialThread_;
1338 }
1339
1340 PCThread *PCProcess::getThread(dynthread_t tid) const {
1341     map<dynthread_t, PCThread *>::const_iterator findIter;
1342     findIter = threadsByTid_.find(tid);
1343     if( findIter == threadsByTid_.end() ) {
1344         return NULL;
1345     }
1346
1347     return findIter->second;
1348 }
1349
1350 bool PCProcess::removeThread(dynthread_t tid) {
1351     map<dynthread_t, PCThread *>::iterator result;
1352     result = threadsByTid_.find(tid);
1353
1354     if( result == threadsByTid_.end() ) return false;
1355
1356     PCThread *toDelete = result->second;
1357
1358     //if( !unregisterThread(toDelete) ) return false;
1359
1360     threadsByTid_.erase(result);
1361
1362     if( toDelete == initialThread_ ) {
1363         initialThread_ = NULL;
1364     }
1365
1366     toDelete->markExited();
1367
1368     // Note: don't delete the thread here, the BPatch_thread takes care of it
1369     proccontrol_printf("%s[%d]: removed thread %lu from process %d\n",
1370             FILE__, __LINE__, toDelete->getLWP(), getPid());
1371     return true;
1372 }
1373 extern Address getVarAddr(PCProcess *proc, std::string str);
1374
1375 #if 0
1376 bool PCProcess::registerThread(PCThread *thread) {
1377   
1378    Address tid = (Address) thread->getTid();
1379    Address index = thread->getIndex();
1380    
1381    Address tmp = 0;
1382    unsigned ptrsize = getAddressWidth();
1383
1384    if (tid == (Address) -1) return true;
1385    if (index == (Address) -1) return true;
1386
1387    if (!initializeRegisterThread()) {
1388       startup_printf("%s[%d]: initializeRegisterThread failed\n",
1389                      FILE__, __LINE__);
1390            
1391            return false;
1392    }
1393    // Must match the "hash" algorithm used in the RT lib
1394    int working = (tid % thread_hash_size);
1395    while(1) {
1396       tmp = 0;
1397       if (!readDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &tmp, false)) {
1398          startup_printf("%s[%d]: Failed to read index slot, base 0x%lx, active 0x%lx\n", FILE__, __LINE__,
1399                         thread_hash_indices, thread_hash_indices + (working * ptrsize));
1400          return false;
1401       }
1402       startup_printf("%s[%d]: value of tid in slot %p is 0x%lx\n",
1403                      FILE__, __LINE__, thread_hash_indices + (working * ptrsize), tmp);
1404       if (ptrsize == 4 && tmp == 0xffffffff) {
1405          int index_int = (int) index;
1406          int tid_int = (int) tid;
1407          startup_printf("%s[%d]: writing %d to %p and 0x%x to %p\n",
1408                         FILE__, __LINE__, index_int, thread_hash_indices + (working * ptrsize),
1409                         tid_int, thread_hash_tids + (working * ptrsize));
1410          writeDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &index_int);
1411          writeDataWord(( void *)(thread_hash_tids + (working * ptrsize)), ptrsize, &tid_int);
1412          break;
1413       }
1414       else if (ptrsize == 8 && tmp == (Address)-1)  {
1415          writeDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &index);
1416          writeDataWord(( void *)(thread_hash_tids + (working * ptrsize)), ptrsize, &tid);
1417          break;
1418       }
1419       working++;
1420       if (working == thread_hash_size) working = 0;
1421       if (working == (int) (tid % thread_hash_size)) {
1422          startup_printf("%s[%d]: Failed to find empty tid slot\n", FILE__, __LINE__);
1423          return false;
1424       }
1425    }
1426    return true;
1427 }
1428 bool PCProcess::unregisterThread(PCThread *thread) {    
1429    return true;
1430    Address tid = (Address) thread->getTid();
1431    Address index = thread->getIndex();
1432    Address tmp = 0;
1433    
1434    unsigned ptrsize = getAddressWidth();
1435    if (tid == (Address) -1) return true;
1436    if (index == (Address) -1) return true;
1437
1438    initializeRegisterThread();
1439
1440    // Must match the "hash" algorithm used in the RT lib
1441    int working = tid % thread_hash_size;
1442    while(1) {
1443       tmp = 0;
1444       if (!readDataWord((void *)(thread_hash_tids + (working * ptrsize)), ptrsize, &tmp, false)) return false;
1445       if (tmp == tid) {
1446          // Zero it out
1447          tmp = (Address) -1;
1448          writeDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &tmp);
1449          break;
1450       }
1451       working++;
1452       if (working == thread_hash_size) working = 0;
1453       if (working == (int) (tid % thread_hash_size)) return false;
1454    }
1455    return true;
1456 }
1457
1458 bool PCProcess::initializeRegisterThread() {
1459 //   if (thread_hash_tids) return true;
1460
1461    unsigned ptrsize = getAddressWidth();
1462    
1463    Address tidPtr = getVarAddr(this, "DYNINST_thread_hash_tids");
1464    if (!tidPtr) return false;
1465    Address indexPtr = getVarAddr(this, "DYNINST_thread_hash_indices");
1466    if (!indexPtr) return false;
1467    Address sizePtr = getVarAddr(this, "DYNINST_thread_hash_size");
1468    if (!sizePtr) return false;
1469    
1470    if (!readDataWord((const void *)tidPtr, ptrsize, &thread_hash_tids, false)) return false;
1471
1472    if (!readDataWord((const void *)indexPtr, ptrsize, &thread_hash_indices, false)) return false;
1473
1474    if (!readDataWord((const void *)sizePtr, sizeof(int), &thread_hash_size, false)) return false;
1475
1476    return true;
1477 }
1478 #endif
1479
1480
1481 void PCProcess::addThread(PCThread *thread) {
1482     pair<map<dynthread_t, PCThread *>::iterator, bool> result;
1483     result = threadsByTid_.insert(make_pair(thread->getTid(), thread));
1484
1485     assert( result.second && "Thread already in collection of threads" );
1486     proccontrol_printf("%s[%d]: added thread %lu to process %d\n",
1487             FILE__, __LINE__, thread->getLWP(), getPid());
1488 }
1489
1490 void PCProcess::getThreads(vector<PCThread* > &threads) const {
1491     for(map<dynthread_t, PCThread *>::const_iterator i = threadsByTid_.begin();
1492             i != threadsByTid_.end(); ++i)
1493     {
1494         threads.push_back(i->second);
1495     }
1496 }
1497
1498 bool PCProcess::wasRunningWhenAttached() const {
1499     return runningWhenAttached_;
1500 }
1501
1502 bool PCProcess::wasCreatedViaAttach() const {
1503     return createdViaAttach_;
1504 }
1505
1506 bool PCProcess::wasCreatedViaFork() const {
1507     return parent_ != NULL;
1508 }
1509
1510 unsigned PCProcess::getMemoryPageSize() const {
1511    assert(pcProc_);
1512    return pcProc_->getMemoryPageSize();
1513 }
1514
1515 int PCProcess::getPid() const {
1516     return savedPid_;
1517 }
1518
1519 int PCProcess::incrementThreadIndex() {
1520     int ret = curThreadIndex_;
1521     curThreadIndex_++;
1522     return ret;
1523 }
1524
1525 unsigned PCProcess::getAddressWidth() const {
1526     if( mapped_objects.size() > 0 ) {
1527         return mapped_objects[0]->parse_img()->codeObject()->cs()->getAddressWidth();
1528     }
1529
1530     // We can call this before we've attached...best effort guess
1531     return sizeof(Address);
1532 }
1533
1534 PCEventHandler * PCProcess::getPCEventHandler() const {
1535     return eventHandler_;
1536 }
1537
1538 bool PCProcess::walkStacks(pdvector<pdvector<Frame> > &stackWalks) {
1539     bool needToContinue = false;
1540     bool retval = true;
1541
1542     // sanity check
1543         if( stackwalker_ == NULL ) return false;
1544
1545     // Process needs to be stopped before doing a stackwalk
1546     if( !isStopped() ) {
1547         needToContinue = true;
1548         if( !stopProcess() ) {
1549             proccontrol_printf("%s[%d]: failed to stop process for stackwalking\n",
1550                     FILE__, __LINE__);
1551             return false;
1552         }
1553     }
1554
1555     for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
1556            i != threadsByTid_.end(); ++i)
1557     {
1558         PCThread *curThr = i->second;
1559
1560         pdvector<Frame> stackWalk;
1561         if( !curThr->walkStack(stackWalk) ) {
1562             retval = false;
1563             proccontrol_printf("%s[%d]: failed to walk stack for thread 0x%lx(%d)\n",
1564                     FILE__, __LINE__,
1565                     curThr->getTid(), curThr->getLWP());
1566         }else{
1567             stackWalks.push_back(stackWalk);
1568         }
1569     }
1570
1571     if( needToContinue ) {
1572         if( !continueProcess() ) {
1573             proccontrol_printf("%s[%d]: failed to continue process after performing stackwalking\n",
1574                     FILE__, __LINE__);
1575             return false;
1576         }
1577     }
1578
1579     return retval;
1580 }
1581
1582 // Return a vector (possibly with one object) of active frames in the process
1583 bool PCProcess::getAllActiveFrames(pdvector<Frame> &activeFrames) {
1584     Frame active;
1585     if( threadsByTid_.size() == 0 ) return false;
1586
1587     for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
1588             i != threadsByTid_.end(); ++i)
1589     {
1590         Frame active = i->second->getActiveFrame();
1591         if( active == Frame() ) return false;
1592         activeFrames.push_back(active);
1593     }
1594
1595     return true;
1596 }
1597
1598 //
1599 // dynamic inferior heap stuff
1600 //
1601
1602 #if defined(os_vxworks)
1603 #include "vxworks.h"
1604 #define HEAP_DYN_BUF_SIZE (0x4000)
1605 #else
1606 #define HEAP_DYN_BUF_SIZE (0x100000)
1607 #endif
1608
1609 static const Address ADDRESS_LO = ((Address)0x10000);
1610 static const Address ADDRESS_HI = ((Address)~((Address)0));
1611
1612 Address PCProcess::inferiorMalloc(unsigned size, inferiorHeapType type,
1613                                   Address near_, bool *err) 
1614 {
1615    if(bootstrapState_ <= bs_readyToLoadRTLib) {
1616       return 0;
1617    }
1618
1619     enum MallocAttempt {
1620         AsIs = 0,
1621         DeferredFree = 1, // compact free blocks
1622         NewSegment1MBConstrained = 2, // allocate new segment (1 MB, constrained)
1623         NewSegmentSizedConstrained = 3, // allocate new segment (sized, constrained)
1624         RemoveRangeConstraints = 4,
1625         NewSegment1MBUnconstrained = 5,
1626         NewSegmentSizedUnconstrained = 6,
1627         DeferredFreeAgain = 7 // why again?
1628     };
1629
1630     Address ret = 0;
1631     if (err) *err = false;
1632
1633     if( size <= 0 ) {
1634         infmalloc_printf("%s[%d]: inferior malloc cannot be <= 0\n",
1635                 FILE__, __LINE__);
1636         if( err ) *err = true;
1637         return 0;
1638     }
1639
1640     // allocation range
1641     Address lo = ADDRESS_LO; // Should get reset to a more reasonable value
1642     Address hi = ADDRESS_HI; // Should get reset to a more reasonable value
1643
1644     //#if defined(cap_dynamic_heap)
1645     inferiorMallocAlign(size); // align size
1646     // Set the lo/hi constraints (if necessary)
1647     inferiorMallocConstraints(near_, lo, hi, type);
1648     //#else
1649     /* align to cache line size (32 bytes on SPARC) */
1650     //size = (size + 0x1f) & ~0x1f;
1651     //#endif
1652
1653     infmalloc_printf("%s[%d]: inferiorMalloc entered; size %d, type %d, near 0x%lx (0x%lx to 0x%lx)\n",
1654                      FILE__, __LINE__, size, type, near_, lo, hi);
1655
1656     // find free memory block (multiple attempts)
1657     int freeIndex = -1;
1658     int ntry = 0;
1659     for (ntry = 0; freeIndex == -1; ntry++) {
1660         switch(ntry) {
1661         case AsIs: 
1662             infmalloc_printf("%s[%d]:  (1) AsIs\n", FILE__, __LINE__);
1663             break;
1664             //#if defined(cap_dynamic_heap)
1665         case DeferredFree: 
1666             infmalloc_printf("%s[%d]:  (2) garbage collecting and compacting\n",
1667                              FILE__, __LINE__);
1668             inferiorFreeCompact();
1669             break;
1670         case NewSegment1MBConstrained: 
1671             infmalloc_printf("%s[%d]:  (3) inferiorMallocDynamic "
1672                     "for %d (0x%x) bytes between 0x%lx - 0x%lx\n", FILE__, __LINE__,
1673                     HEAP_DYN_BUF_SIZE, HEAP_DYN_BUF_SIZE, lo, hi);
1674             inferiorMallocDynamic(HEAP_DYN_BUF_SIZE, lo, hi);
1675             break;
1676         case NewSegmentSizedConstrained: 
1677             infmalloc_printf("%s[%d]:  (4) inferiorMallocDynamic "
1678                     "for %d (0x%x) bytes between 0x%lx - 0x%lx\n",
1679                              FILE__, __LINE__, size, size, lo, hi);
1680             inferiorMallocDynamic(size, lo, hi);
1681             break;
1682         case RemoveRangeConstraints: 
1683             infmalloc_printf("%s[%d]:  (5) inferiorMalloc: removing range constraints\n",
1684                              FILE__, __LINE__);
1685             lo = ADDRESS_LO;
1686             hi = ADDRESS_HI;
1687             if (err) {
1688                 infmalloc_printf("%s[%d]: error in inferiorMalloc\n", FILE__, __LINE__);
1689                 *err = true;
1690             }
1691             break;
1692         case NewSegment1MBUnconstrained: 
1693             infmalloc_printf("%s[%d]:  (6) inferiorMallocDynamic for %d (0x%x) bytes between 0x%lx - 0x%lx\n",
1694                              FILE__, __LINE__, HEAP_DYN_BUF_SIZE, HEAP_DYN_BUF_SIZE, lo, hi);
1695             inferiorMallocDynamic(HEAP_DYN_BUF_SIZE, lo, hi);
1696             break;
1697         case NewSegmentSizedUnconstrained: 
1698             infmalloc_printf("%s[%d]:  (7) inferiorMallocDynamic for %d (0x%x) bytes between 0x%lx - 0x%lx\n",
1699                              FILE__, __LINE__, size, size, lo, hi);
1700             inferiorMallocDynamic(size, lo, hi);
1701             break;
1702         case DeferredFreeAgain: 
1703             infmalloc_printf("%s[%d]: inferiorMalloc: recompacting\n", FILE__, __LINE__);
1704             inferiorFreeCompact();
1705             break;
1706             //#else /* !(cap_dynamic_heap) */
1707             //case DeferredFree: // deferred free, compact free blocks
1708             //inferiorFreeCompact();
1709             //break;
1710             //#endif /* cap_dynamic_heap */
1711
1712         default: // error - out of memory
1713             infmalloc_printf("%s[%d]: failed to allocate memory\n", FILE__, __LINE__);
1714             if( err ) *err = true;
1715             return 0;
1716         }
1717
1718         ret = inferiorMallocInternal(size, lo, hi, type);
1719         if (ret) break;
1720     }
1721     infmalloc_printf("%s[%d]: inferiorMalloc, returning address 0x%lx\n", FILE__, __LINE__, ret);
1722     return ret;
1723 }
1724
1725 void PCProcess::inferiorFree(Dyninst::Address item) {
1726     inferiorFreeInternal(item);
1727 }
1728
1729 bool PCProcess::inferiorRealloc(Dyninst::Address item, unsigned int newSize) {
1730         if(bootstrapState_ <= bs_readyToLoadRTLib) {
1731       return true;
1732    }
1733    return inferiorReallocInternal(item, newSize);
1734 }
1735
1736 static
1737 void alignUp(int &val, int align) {
1738     assert(val >= 0);
1739     assert(align >= 0);
1740
1741     if (val % align != 0) {
1742         val = ((val / align) + 1) * align;
1743     }
1744 }
1745
1746 bool PCProcess::inferiorMallocDynamic(int size, Address lo, Address hi) {
1747     const int MallocFailed = 0;
1748     const int UnalignedBuffer = -1;
1749
1750     infmalloc_printf("%s[%d]: entering inferiorMallocDynamic\n", FILE__, __LINE__);
1751
1752     // word-align buffer size
1753     // (see "DYNINSTheap_align" in rtinst/src/RTheap-<os>.c)
1754     alignUp(size, 4);
1755     // build AstNode for "DYNINSTos_malloc" call
1756     std::string callee = "DYNINSTos_malloc";
1757     pdvector<AstNodePtr> args(3);
1758     args[0] = AstNode::operandNode(AstNode::Constant, (void *)(Address)size);
1759     args[1] = AstNode::operandNode(AstNode::Constant, (void *)lo);
1760     args[2] = AstNode::operandNode(AstNode::Constant, (void *)hi);
1761     AstNodePtr code = AstNode::funcCallNode(callee, args);
1762
1763     // issue RPC and wait for result
1764     bool wasRunning = !isStopped();
1765
1766     proccontrol_printf("%s[%d]: running inferiorMalloc via iRPC on process %d\n",
1767             FILE__, __LINE__, getPid());
1768
1769     Address result = 0;
1770     if( !postIRPC(code,
1771                   NULL, // only care about the result
1772                   wasRunning, // run when finished?
1773                   NULL, // no specific thread
1774                   true, // wait for completion
1775                   (void **)&result,
1776                   false, // internal iRPC
1777                   true) ) // is a memory allocation RPC
1778     {
1779         infmalloc_printf("%s[%d]: failed to post iRPC for inferior malloc\n",
1780                 FILE__, __LINE__);
1781         return false;
1782     }
1783     proccontrol_printf("%s[%d]: inferiorMalloc via iRPC returned 0x%lx\n",
1784             FILE__, __LINE__, result);
1785
1786     switch ((int)result) {
1787         case MallocFailed:
1788             infmalloc_printf("%s[%d]: DYNINSTos_malloc() failed\n",
1789                                FILE__, __LINE__);
1790             return false;
1791         case UnalignedBuffer:
1792             infmalloc_printf("%s[%d]: DYNINSTos_malloc(): unaligned buffer size\n",
1793                                FILE__, __LINE__);
1794             return false;
1795         default:
1796             // add new segment to buffer pool
1797             heapItem *h = new heapItem(result, size, getDynamicHeapType(),
1798                     true, HEAPfree);
1799             addHeap(h);
1800             break;
1801     }
1802
1803     return true;
1804 }
1805
1806 // A copy of the BPatch-level instrumentation installer
1807 void PCProcess::installInstrRequests(const pdvector<instMapping*> &requests) {
1808     if (requests.size() == 0) {
1809         return;
1810     }
1811
1812     // Instrumentation is now generated on a per-function basis, while
1813     // the requests are per-inst, not per-function. So 
1814     // accumulate functions, then generate afterwards. 
1815
1816     vector<func_instance *> instrumentedFuncs;
1817
1818     for (unsigned lcv=0; lcv < requests.size(); lcv++) {
1819       inst_printf("%s[%d]: handling request %d of %d\n", FILE__, __LINE__, lcv+1, requests.size());
1820
1821         instMapping *req = requests[lcv];
1822         pdvector<miniTramp *> minis;
1823         
1824         if(!multithread_capable() && req->is_MTonly())
1825             continue;
1826         
1827         pdvector<func_instance *> matchingFuncs;
1828         
1829         if (!findFuncsByAll(req->func, matchingFuncs, req->lib)) {
1830             inst_printf("%s[%d]: failed to find any functions matching %s (lib %s), returning failure from installInstrRequests\n", FILE__, __LINE__, req->func.c_str(), req->lib.c_str());
1831             return;
1832         }
1833         else {
1834             inst_printf("%s[%d]: found %d functions matching %s (lib %s), instrumenting...\n",
1835                         FILE__, __LINE__, matchingFuncs.size(), req->func.c_str(), req->lib.c_str());
1836         }
1837
1838         for (unsigned funcIter = 0; funcIter < matchingFuncs.size(); funcIter++) {
1839            func_instance *func = matchingFuncs[funcIter];
1840            if (!func) {
1841               inst_printf("%s[%d]: null int_func detected\n",
1842                           FILE__,__LINE__);
1843               continue;  // probably should have a flag telling us whether errors
1844            }
1845
1846            inst_printf("%s[%d]: Instrumenting %s at 0x%lx, offset 0x%lx in %s\n",
1847                        FILE__, __LINE__, 
1848                        func->symTabName().c_str(),
1849                        func->addr(),
1850                        func->addr() - func->obj()->codeBase(),
1851                        func->obj()->fullName().c_str());
1852             
1853            // should be silently handled or not
1854            AstNodePtr ast;
1855            if ((req->where & FUNC_ARG) && req->args.size()>0) {
1856               ast = AstNode::funcCallNode(req->inst, 
1857                                           req->args,
1858                                           this);
1859            }
1860            else {
1861               pdvector<AstNodePtr> def_args;
1862               def_args.push_back(AstNode::operandNode(AstNode::Constant,
1863                                                       (void *)0));
1864               ast = AstNode::funcCallNode(req->inst,
1865                                           def_args);
1866            }
1867            // We mask to strip off the FUNC_ARG bit...
1868            std::vector<Point *> points;
1869            switch ( ( req->where & 0x7) ) {
1870               case FUNC_EXIT:
1871                  mgr()->findPoints(Dyninst::PatchAPI::Scope(func),
1872                                    Point::FuncExit,
1873                                    std::back_inserter(points));
1874                  break;
1875               case FUNC_ENTRY:
1876                  mgr()->findPoints(Dyninst::PatchAPI::Scope(func),
1877                                    Point::FuncEntry,
1878                                    std::back_inserter(points));
1879                  break;
1880               case FUNC_CALL:
1881                  mgr()->findPoints(Dyninst::PatchAPI::Scope(func),
1882                                    Point::PreCall,
1883                                    std::back_inserter(points));
1884                  break;
1885               default:
1886                  fprintf(stderr, "Unknown where: %d\n",
1887                          req->where);
1888                  break;
1889            } // switch
1890            inst_printf("%s[%d]: found %d points to instrument\n", FILE__, __LINE__, points.size());
1891            for (std::vector<Point *>::iterator iter = points.begin();
1892                 iter != points.end(); ++iter) {
1893               Dyninst::PatchAPI::Instance::Ptr inst = (req->order == orderFirstAtPoint) ? 
1894                  (*iter)->pushFront(ast) :
1895                  (*iter)->pushBack(ast);
1896               if (inst) {
1897                  if (!req->useTrampGuard) inst->disableRecursiveGuard();
1898                  req->instances.push_back(inst);
1899               }
1900               else {
1901                  fprintf(stderr, "%s[%d]:  failed to addInst here\n", FILE__, __LINE__);
1902               }
1903            }        } // matchingFuncs        
1904         
1905     } // requests
1906     relocate();
1907     return;
1908 }
1909
1910 static const unsigned MAX_IRPC_SIZE = 0x100000;
1911
1912
1913 bool PCProcess::postIRPC(void* buffer, int size, void* userData, bool runProcessWhenDone,
1914                          PCThread* thread, bool synchronous, void** result,
1915                          bool userRPC, bool isMemAlloc, Address addr)
1916 {
1917    return postIRPC_internal(buffer,
1918                             size,
1919                             size,
1920                             REG_NULL,
1921                             addr,
1922                             userData,
1923                             runProcessWhenDone,
1924                             thread,
1925                             synchronous,
1926                             userRPC,
1927                             isMemAlloc,
1928                             result);    
1929 }
1930
1931 bool PCProcess::postIRPC(AstNodePtr action, void *userData, 
1932                          bool runProcessWhenDone, PCThread *thread, bool synchronous,
1933                          void **result, bool userRPC, bool isMemAlloc, Address addr)
1934 {   
1935    // Generate the code for the iRPC
1936    codeGen irpcBuf(MAX_IRPC_SIZE);
1937    irpcBuf.setAddrSpace(this);
1938    irpcBuf.setRegisterSpace(registerSpace::irpcRegSpace(proc()));
1939    irpcBuf.beginTrackRegDefs();
1940    irpcBuf.setThread(thread);
1941    
1942 #if defined(bug_syscall_changepc_rewind)
1943    // Reported by SGI, during attach to a process in a system call:
1944    
1945    // Insert eight NOP instructions before the actual call to dlopen(). Loading
1946    // the runtime library when the mutatee was in a system call will sometimes
1947    // cause the process to (on IA32 anyway) execute the instruction four bytes
1948    // PREVIOUS to the PC we actually set here. No idea why. Prepending the
1949    // actual dlopen() call with eight NOP instructions insures this doesn't
1950    // really matter. Eight was selected rather than four because I don't know
1951    // if x86-64 does the same thing (and jumps eight bytes instead of four).
1952    
1953    // We will put in <addr width> rather than always 8; this will be 4 on x86 and
1954    // 32-bit AMD64, and 8 on 64-bit AMD64.
1955    irpcBuf.fill(proc()->getAddressWidth(), codeGen::cgNOP);
1956 #endif
1957
1958    irpcTramp_->setIRPCAST(action);
1959    
1960    // Create a stack frame for the RPC
1961    if( !irpcTramp_->generateSaves(irpcBuf, irpcBuf.rs()) ) {
1962       proccontrol_printf("%s[%d]: failed to generate saves via baseTramp\n",
1963                          FILE__, __LINE__);
1964       return false;
1965    }
1966    
1967    Register resultReg = REG_NULL;
1968    if( !action->generateCode(irpcBuf, false, resultReg) ) {
1969       proccontrol_printf("%s[%d]: failed to generate code from AST\n",
1970                          FILE__, __LINE__);
1971       return false;
1972    }
1973
1974     // Note: we should not do a corresponding baseTramp restore here:
1975     // 1) It isn't necessary because ProcControl will restore the
1976     //    registers
1977     // 2) We need to be able to read registers to get the result of the iRPC
1978     //    If we restore, we can't do that
1979
1980     // Emit the trailer for the iRPC
1981
1982     // breakOffset: where the irpc ends
1983     unsigned breakOffset = irpcBuf.used();
1984     insnCodeGen::generateTrap(irpcBuf);
1985     insnCodeGen::generateTrap(irpcBuf);
1986
1987     irpcBuf.endTrackRegDefs();
1988
1989     //#sasha printing code patch for DYNINSTos_malloc
1990     //cerr << "BUFFER for IRPC" << endl;
1991     //cerr << irpcBuf.format() << endl;
1992
1993     return postIRPC_internal(irpcBuf.start_ptr(),
1994                              irpcBuf.used(),
1995                              breakOffset,
1996                              resultReg,
1997                              addr,
1998                              userData,
1999                              runProcessWhenDone,
2000                              thread,
2001                              synchronous,
2002                              userRPC,
2003                              isMemAlloc,
2004                              result);    
2005 }
2006
2007 // DEBUG
2008 #include "instructionAPI/h/InstructionDecoder.h"
2009
2010 bool PCProcess::postIRPC_internal(void *buf,
2011                                   unsigned size,
2012                                   unsigned breakOffset,
2013                                   Register resultReg,
2014                                   Address addr,
2015                                   void *userData,
2016                                   bool runProcessWhenDone,
2017                                   PCThread *thread,
2018                                   bool synchronous,
2019                                   bool userRPC,
2020                                   bool isMemAlloc,
2021                                   void **result) {
2022    if( isTerminated() ) {
2023       proccontrol_printf("%s[%d]: cannot post RPC to exited or terminated process %d\n",
2024                          FILE__, __LINE__, getpid());
2025       return false;
2026    }
2027    
2028    if( thread && !thread->isLive() ) {
2029       proccontrol_printf("%s[%d]: attempted to post RPC to dead thread %d\n",
2030                          FILE__, __LINE__, thread->getLWP());
2031       return false;
2032    }
2033
2034
2035    inferiorRPCinProgress *newRPC = new inferiorRPCinProgress;
2036    newRPC->runProcWhenDone = runProcessWhenDone;
2037    newRPC->deliverCallbacks = userRPC;
2038    newRPC->userData = userData;
2039    newRPC->synchronous = synchronous;
2040
2041    newRPC->resultRegister = resultReg;
2042    
2043    // Create the iRPC at the ProcControl level
2044    if( addr == 0 ) {
2045       bool err = false;
2046       if( isMemAlloc ) {
2047          // This assumes that there will always be space
2048          addr = inferiorMalloc(size, lowmemHeap, 0, &err);
2049       }else{
2050          // recursive RPCs are okay when this isn't an inferiorMalloc RPC
2051          addr = inferiorMalloc(size, anyHeap, 0, &err);
2052       }
2053       
2054       if( err ) {
2055          proccontrol_printf("%s[%d]: failed to allocate memory for RPC\n",
2056                             FILE__, __LINE__);
2057          delete newRPC;
2058          return false;
2059       }
2060       newRPC->memoryAllocated = true;
2061    }
2062    
2063     if (addr)
2064        newRPC->rpc = IRPC::createIRPC(buf, size, addr);
2065     else
2066        newRPC->rpc = IRPC::createIRPC(buf, size);
2067
2068 #if 0
2069    // DEBUG
2070    InstructionAPI::InstructionDecoder d(buf,size,getArch());
2071    Address foo = addr;
2072    InstructionAPI::Instruction::Ptr insn = d.decode();
2073    while(insn) {
2074       cerr << "\t" << hex << foo << ": " << insn->format(foo) << dec << endl;
2075       foo += insn->size();
2076       insn = d.decode();
2077    }
2078 #endif
2079     newRPC->rpc->setData(newRPC);
2080
2081     unsigned int start_offset = 0;
2082 #if defined(bug_syscall_changepc_rewind)
2083     // Some Linux kernels have the following behavior:
2084     // Process is in a system call;
2085     // We interrupt the system call;
2086     // We say "change PC to address N"
2087     // The kernel helpfully changes it to (N - address width)
2088     // The program crashes
2089     // See a more complete comment above.
2090     // For now, we pad the start of our code with NOOPS and change to just
2091     // after those; if we hit rewind behavior, then we're executing safe code.
2092     //
2093     // Matt Note:  The above comment is slightly incorrect.  The kernel subracts
2094     //  the length of the syscall/int instruction that triggered the system call,
2095     //  not the address width.  Still address width is big enough, so I'm not
2096     //  changing anything.
2097     start_offset = proc()->getAddressWidth();
2098     newRPC->rpcStartAddr += start_offset;
2099 #endif
2100     newRPC->rpc->setStartOffset(start_offset);
2101     newRPC->rpcCompletionAddr = addr + breakOffset;
2102
2103     // Post the iRPC
2104     Thread::ptr t;
2105     if (thread) {
2106        t = thread->pcThr();
2107     }
2108     newRPC->thread = t;
2109     
2110     bool res = false;
2111     proccontrol_printf("%s[%d]: Launching IRPC\n", FILE__, __LINE__);
2112     if (synchronous) {
2113        // We have an interesting problem here. ProcControl allows callbacks to specify whether the 
2114        // process should stop or run; however, that allows us to stop a process in the middle of an
2115        // inferior RPC. If that happens, manually execute a continue and wait for completion ourselves.
2116        if (t)
2117           res = t->runIRPCSync(newRPC->rpc);
2118        else
2119           res = pcProc_->runIRPCSync(newRPC->rpc);
2120        if (!res) {
2121           bool done = false;
2122           while (!done) {
2123              proccontrol_printf("%s[%d]: Iterating in loop waiting for IRPC to complete\n", FILE__, __LINE__);
2124              if (isTerminated()) {
2125                 fprintf(stderr, "IRPC on terminated process, ret false!\n");
2126                 delete newRPC;
2127                 return false;
2128              }
2129
2130             if (ProcControlAPI::getLastError() != ProcControlAPI::err_notrunning) {
2131                 // Something went wrong
2132                proccontrol_printf("%s[%d]: failed to post %s RPC to %s, error %s\n",
2133                                   FILE__, __LINE__, (synchronous ? "sync" : "async"), 
2134                                   ((thread == NULL) ? "thread" : "process"),
2135                                   ProcControlAPI::getLastErrorMsg());
2136                delete newRPC;
2137                return false;
2138             }
2139             else {
2140                proccontrol_printf("%s[%d]: ProcControl reported IRPC thread stopped, continuing and consuming events\n", FILE__, __LINE__);
2141                newRPC->rpc->continueStoppedIRPC();
2142                proccontrol_printf("%s[%d]: handling events in ProcControl\n", FILE__, __LINE__);
2143                res = pcProc_->handleEvents(true);
2144                PCEventMuxer::muxer().handle(NULL);
2145                if (newRPC->rpc->state() == ProcControlAPI::IRPC::Done) {
2146                   proccontrol_printf("%s[%d]: IRPC complete\n", FILE__, __LINE__);
2147                   done = true;
2148                }
2149             }
2150           }
2151        }
2152     }
2153     else {
2154        if (t)
2155           res = t->runIRPCAsync(newRPC->rpc);
2156        else
2157           res = pcProc_->runIRPCAsync(newRPC->rpc);
2158     }
2159     if(!res) {
2160        proccontrol_printf("%s[%d]: failed to post %s RPC to %s\n",
2161                           FILE__, __LINE__, (synchronous ? "sync" : "async"), ((thread == NULL) ? "thread" : "process"));
2162        delete newRPC;
2163        return false;
2164     }
2165     
2166     if( result ) {
2167        *result = newRPC->returnValue;
2168     }
2169     
2170     // Make sure Dyninst has worked everything out
2171     PCEventMuxer::muxer().wait(false);
2172
2173    return true;
2174 }
2175
2176
2177 BPatch_hybridMode PCProcess::getHybridMode() {
2178     return analysisMode_;
2179 }
2180
2181 bool PCProcess::isExploratoryModeOn() const {
2182     return BPatch_exploratoryMode == analysisMode_ ||
2183            BPatch_defensiveMode   == analysisMode_;
2184 }
2185
2186 bool PCProcess::isRuntimeHeapAddr(Address addr) const {
2187     for (unsigned hidx=0; hidx < dyninstRT_heaps_.size(); hidx++) {
2188         if (addr >= dyninstRT_heaps_[hidx]->addr &&
2189             addr < dyninstRT_heaps_[hidx]->addr + dyninstRT_heaps_[hidx]->length) {
2190             return true;
2191         }
2192     }
2193     return false;
2194 }
2195
2196 /* returns true if blocks were overwritten, initializes overwritten
2197  * blocks and ranges by contrasting shadow pages with current memory
2198  * contents
2199  * 1. reads shadow pages in from memory
2200  * 2. constructs overwritten region list
2201  * 3. constructs overwrittn basic block list
2202  * 4. determines if the last of the blocks has an abrupt end, in which
2203  *    case it marks it as overwritten
2204  */
2205 bool PCProcess::getOverwrittenBlocks
2206   ( std::map<Address, unsigned char *>& overwrittenPages,//input
2207     std::list<std::pair<Address,Address> >& overwrittenRanges,//output
2208     std::list<block_instance *> &writtenBBIs)//output
2209 {
2210     const unsigned MEM_PAGE_SIZE = getMemoryPageSize();
2211     unsigned char * memVersion = (unsigned char *) ::malloc(MEM_PAGE_SIZE);
2212     Address regionStart = 0;
2213     bool foundStart = false;
2214     map<Address, unsigned char*>::iterator pIter = overwrittenPages.begin();
2215     set<mapped_object*> owObjs;
2216     for (; pIter != overwrittenPages.end(); pIter++) {
2217         Address curPageAddr = (*pIter).first / MEM_PAGE_SIZE * MEM_PAGE_SIZE;
2218         unsigned char *curShadow = (*pIter).second;
2219
2220         // 0. check to make sure curShadow is non-null, if it is null, 
2221         //    that means it hasn't been written to
2222         if ( ! curShadow ) {
2223                         cerr << "\t\t No current shadow, continuing" << endl;
2224                         continue;
2225         }
2226
2227         mapped_object* obj = findObject(curPageAddr);
2228         if (owObjs.end() != owObjs.find(obj)) {
2229             obj->setCodeBytesUpdated(false);
2230         }
2231
2232         // 1. Read the modified page in from memory
2233         Address readAddr = curPageAddr;
2234         if (isMemoryEmulated()) {
2235             bool valid = false;
2236             boost::tie(valid,readAddr) = getMemEm()->translate(curPageAddr);
2237                         cerr << "\t\t Reading from shadow page " << hex << readAddr << " instead of original " << curPageAddr << endl;
2238             assert(valid);
2239         }
2240         readTextSpace((void*)readAddr, MEM_PAGE_SIZE, memVersion);
2241
2242         // 2. build overwritten region list by comparing shadow, memory
2243         for (unsigned mIdx = 0; mIdx < MEM_PAGE_SIZE; mIdx++) {
2244             if ( ! foundStart && curShadow[mIdx] != memVersion[mIdx] ) {
2245                 foundStart = true;
2246                 regionStart = curPageAddr+mIdx;
2247             } else if (foundStart && curShadow[mIdx] == memVersion[mIdx]) {
2248                 foundStart = false;
2249                                 cerr << "\t\t Adding overwritten range " << hex << regionStart << " -> " << curPageAddr + mIdx << dec << endl;
2250
2251                 overwrittenRanges.push_back(
2252                     pair<Address,Address>(regionStart,curPageAddr+mIdx));
2253             }
2254         }
2255         if (foundStart) {
2256
2257             foundStart = false;
2258                         cerr << "\t\t Adding overwritten range " << hex << regionStart << " -> " << curPageAddr + MEM_PAGE_SIZE << dec << endl;
2259
2260             overwrittenRanges.push_back(
2261                 pair<Address,Address>(regionStart,curPageAddr+MEM_PAGE_SIZE));
2262         }
2263     }
2264
2265     // 3. Determine which basic blocks have been overwritten
2266     list<pair<Address,Address> >::const_iterator rIter = overwrittenRanges.begin();
2267     std::list<block_instance*> curBBIs;
2268     while (rIter != overwrittenRanges.end()) {
2269         mapped_object *curObject = findObject((*rIter).first);
2270
2271         curObject->findBlocksByRange((*rIter).first,(*rIter).second,curBBIs);
2272         if (curBBIs.size()) {
2273             mal_printf("overwrote %d blocks in range %lx %lx \n",
2274                        curBBIs.size(),(*rIter).first,(*rIter).second);
2275             writtenBBIs.splice(writtenBBIs.end(), curBBIs);
2276         }
2277
2278         curBBIs.clear();
2279         rIter++;
2280     }
2281
2282     free(memVersion);
2283     if (writtenBBIs.size()) {
2284         return true;
2285     } else {
2286         return false;
2287     }
2288 }
2289
2290 // distribute the work to mapped_objects
2291 void PCProcess::updateCodeBytes
2292     ( const list<pair<Address, Address> > &owRanges ) // input
2293 {
2294     std::map<mapped_object *,list<pair<Address,Address> >*> objRanges;
2295     list<pair<Address,Address> >::const_iterator rIter = owRanges.begin();
2296     for (; rIter != owRanges.end(); rIter++) {
2297         mapped_object *obj = findObject((*rIter).first);
2298         if (objRanges.find(obj) == objRanges.end()) {
2299             objRanges[obj] = new list<pair<Address,Address> >();
2300         }
2301         objRanges[obj]->push_back(pair<Address,Address>(rIter->first, rIter->second));
2302     }
2303
2304     std::map<mapped_object *,list<pair<Address,Address> > *>::iterator oIter = 
2305         objRanges.begin();
2306     for (; oIter != objRanges.end(); oIter++) 
2307     {
2308         oIter->first->updateCodeBytes( *(oIter->second) );
2309         delete (oIter->second);
2310     }
2311     assert(objRanges.size() <= 1); //o/w analysis code may not be prepared for other cases
2312 }
2313
2314 #if 0
2315 static void otherFuncBlocks(func_instance *func, 
2316                             const set<block_instance*> &blks, 
2317                             set<block_instance*> &otherBlks)
2318 {
2319     const func_instance::BlockSet &allBlocks = 
2320         func->blocks();
2321     for (func_instance::BlockSet::const_iterator bit =
2322          allBlocks.begin();
2323          bit != allBlocks.end(); 
2324          bit++) 
2325     {
2326         if (blks.end() == blks.find((*bit))) {
2327             otherBlks.insert((*bit));
2328         }
2329     }
2330 }
2331 #endif
2332
2333 /* Summary
2334  * Given a list of overwritten blocks, find blocks that are unreachable,
2335  * functions that have been overwritten at their entry points and can go away,
2336  * and new function entry for functions that are being overwritten while still
2337  * executing
2338  *
2339  * variables
2340  * f:  the overwritten function
2341  * ow: the set of overwritten blocks
2342  * ex: the set of blocks that are executing on the call stack that were not overwritten
2343  * 
2344  * primitives
2345  * R(b,s): yields set of reachable blocks for collection of blocks b, starting
2346  *         at seed blocks s.
2347  * B(f):   the blocks pertaining to function f
2348  * EP(f):  the entry point of function f
2349  * F(b):   functions containing block b
2350  * 
2351  * calculations
2352  * Elim(f): the set of blocks to eliminate from function f.
2353  *          Elim(f) = B(f) - R( B(f)-ow , EP(f) )
2354  * New(f):  new function entry candidates for f's surviving blocks.
2355  *          If EB(f) not in ow(f), empty set
2356  *          Else, all blocks b such that ( b in ex AND e in Elim(f) )
2357  *          Eliminate New(f) elements that have ancestors in New(f)
2358  * Del(f):  A block can be deleted altogether if
2359  *          forall f in F(b): B(F) - R( B(f) - ow , New(f) U (EP(f) \ ow(f)) U (ex(f) intersect Elim(f)) ),
2360  *          b is not in the resulting set. In other words, b is not
2361  *          reachable from non-overwritten blocks in the functions in
2362  *          which it appears, seeded at new entry points and original
2363  *          non-overwritten entry points to the function, and at f's
2364  *          executing blocks if these will be deleted from the
2365  *          function (they constitute an entry point into the function 
2366  *          even if they've been overwritten). 
2367  * DeadF:   the set of functions that have no executing blocks 
2368  *          and were overwritten in their entry blocks
2369  *          EP(f) in ow(f) AND ex(f) is empty
2370  */
2371 bool PCProcess::getDeadCode
2372 ( const std::list<block_instance*> & /*owBlocks*/, // input
2373   std::set<block_instance*> & /*delBlocks*/, //output: Del(for all f)
2374   std::map<func_instance*,set<block_instance*> > & /*elimMap*/, //output: elimF
2375   std::list<func_instance*> & /*deadFuncs*/, //output: DeadF
2376   std::map<func_instance*,block_instance*> & /*newFuncEntries*/) //output: newF
2377 {
2378    assert(0 && "TODO");
2379    return false;
2380 #if 0
2381     // do a stackwalk to see which functions are currently executing
2382     pdvector<pdvector<Frame> >  stacks;
2383     pdvector<Address> pcs;
2384     if (!walkStacks(stacks)) {
2385         inst_printf("%s[%d]:  walkStacks failed\n", FILE__, __LINE__);
2386         return false;
2387     }
2388     for (unsigned i = 0; i < stacks.size(); ++i) {
2389         pdvector<Frame> &stack = stacks[i];
2390         for (unsigned int j = 0; j < stack.size(); ++j) {
2391             Address origPC = 0;
2392             vector<func_instance*> dontcare1;
2393             baseTramp *dontcare2 = NULL;
2394             getAddrInfo(stack[j].getPC(), origPC, dontcare1, dontcare2);
2395             pcs.push_back( origPC );
2396         }
2397     }
2398
2399     // group blocks by function
2400     std::map<func_instance*,set<block_instance*> > deadMap;
2401     std::set<func_instance*> deadEntryFuncs;
2402     std::set<Address> owBlockAddrs;
2403     for (list<block_instance*>::const_iterator bIter=owBlocks.begin();
2404          bIter != owBlocks.end(); 
2405          bIter++) 
2406     {
2407        deadMap[(*bIter)->func()].insert(*bIter);
2408        owBlockAddrs.insert((*bIter)->start());
2409        if ((*bIter)->llb() == (*bIter)->func()->ifunc()->entry()) {
2410           deadEntryFuncs.insert((*bIter)->func());
2411        }
2412     }
2413
2414     // for each modified function, calculate ex, ElimF, NewF, DelF
2415     for (map<func_instance*,set<block_instance*> >::iterator fit = deadMap.begin();
2416          fit != deadMap.end(); 
2417          fit++) 
2418     {
2419
2420         // calculate ex(f)
2421         set<block_instance*> execBlocks;
2422         for (unsigned pidx=0; pidx < pcs.size(); pidx++) {
2423             std::set<block_instance *> candidateBlocks;
2424             fit->first->findBlocksByAddr(pcs[pidx], candidateBlocks);
2425             for (std::set<block_instance *>::iterator cb_iter = candidateBlocks.begin();
2426                 cb_iter != candidateBlocks.end(); ++cb_iter) {
2427                 block_instance *exB = *cb_iter;
2428                 if (exB && owBlockAddrs.end() == owBlockAddrs.find(
2429                                                         exB->start())) 
2430                 {
2431                     execBlocks.insert(exB);
2432                 }
2433             }
2434         }
2435
2436         // calculate DeadF: EP(f) in ow and EP(f) not in ex
2437         if ( 0 == execBlocks.size() ) {
2438             set<block_instance*>::iterator eb = fit->second.find(
2439                 fit->first->entryBlock());
2440             if (eb != fit->second.end()) {
2441                 deadFuncs.push_back(fit->first);
2442                 continue;// treated specially, don't need elimF, NewF or DelF
2443             }
2444         } 
2445
2446         // calculate elimF
2447         set<block_instance*> keepF;
2448         list<block_instance*> seedBs;
2449         seedBs.push_back(fit->first->entryBlock());
2450         fit->first->getReachableBlocks(fit->second, seedBs, keepF);
2451         otherFuncBlocks(fit->first, keepF, elimMap[fit->first]);
2452
2453         // calculate NewF
2454         if (deadEntryFuncs.end() != deadEntryFuncs.find(fit->first)) {
2455             for (set<block_instance*>::iterator bit = execBlocks.begin();
2456                  bit != execBlocks.end();
2457                  bit++) 
2458             {
2459                 if (elimMap[fit->first].end() != 
2460                     elimMap[fit->first].find(*bit)) 
2461                 {
2462                     newFuncEntries[fit->first] = *bit;
2463                     break; // just need one candidate
2464                 }
2465             }
2466         }
2467
2468         // calculate Del(f)
2469         seedBs.clear();
2470         if (deadEntryFuncs.end() == deadEntryFuncs.find(fit->first)) {
2471             seedBs.push_back(fit->first->entryBlock());
2472         }
2473         else if (newFuncEntries.end() != newFuncEntries.find(fit->first)) {
2474             seedBs.push_back(newFuncEntries[fit->first]);
2475         }
2476         for (set<block_instance*>::iterator xit = execBlocks.begin();
2477              xit != execBlocks.end();
2478              xit++) 
2479         {
2480             if (elimMap[fit->first].end() != elimMap[fit->first].find(*xit)) {
2481                 seedBs.push_back(*xit);
2482             }
2483         }
2484         keepF.clear();
2485         fit->first->getReachableBlocks(fit->second, seedBs, keepF);
2486         otherFuncBlocks(fit->first, keepF, delBlocks);
2487         
2488     }
2489
2490     return true;
2491 #endif
2492 }
2493
2494 // will flush addresses of all addresses in the specified range, if the
2495 // range is null, flush all addresses from the cache.  Also flush 
2496 // rt-lib heap addrs that correspond to the range
2497 void PCProcess::flushAddressCache_RT(Address start, unsigned size)
2498 {
2499     if (start != 0) {
2500         mal_printf("Flushing address cache of range [%lx %lx]\n",
2501                    start, 
2502                    start + size);
2503     } else {
2504         mal_printf("Flushing address cache of rt_lib heap addrs only \n");
2505     }
2506
2507     // Find the runtime cache's address if it hasn't been set yet
2508     if (0 == RT_address_cache_addr_) {
2509         std::string arg_str ("DYNINST_target_cache");
2510         pdvector<int_variable *> vars;
2511         if ( ! findVarsByAll(arg_str, vars) ) {
2512             fprintf(stderr, "%s[%d]:  cannot find var %s\n", 
2513                     FILE__, __LINE__, arg_str.c_str());
2514             assert(0);
2515         }
2516         if (vars.size() != 1) {
2517             fprintf(stderr, "%s[%d]:  ERROR:  %d vars matching %s, not 1\n", 
2518                     FILE__, __LINE__, (int)vars.size(), arg_str.c_str());
2519             assert(0);
2520         }
2521         RT_address_cache_addr_ = vars[0]->getAddress();
2522     }
2523
2524     // Clear all cache entries that match the runtime library
2525     // Read in the contents of the cache
2526     Address* cacheCopy = (Address*)malloc(TARGET_CACHE_WIDTH*sizeof(Address));
2527     if ( ! readDataSpace( (void*)RT_address_cache_addr_, 
2528                           sizeof(Address)*TARGET_CACHE_WIDTH,(void*)cacheCopy,
2529                           false ) ) 
2530     {
2531         assert(0);
2532     }
2533
2534     assert(dyninstRT_heaps_.size());
2535     bool flushedHeaps = false;
2536
2537     while ( true ) // iterate twice, once to flush the heaps, 
2538     {              // and once to flush the flush range
2539         Address flushStart=0;
2540         Address flushEnd=0;
2541         if (!flushedHeaps) {
2542             // figure out the range of addresses we'll want to flush from
2543
2544             flushStart = dyninstRT_heaps_[0]->addr;
2545             flushEnd = flushStart + dyninstRT_heaps_[0]->length;
2546             for (unsigned idx=1; idx < dyninstRT_heaps_.size(); idx++) {
2547                 Address curAddr = dyninstRT_heaps_[idx]->addr;
2548                 if (flushStart > curAddr) {
2549                     flushStart = curAddr;
2550                 }
2551                 curAddr += dyninstRT_heaps_[idx]->length;
2552                 if (flushEnd < curAddr) {
2553                     flushEnd = curAddr;
2554                 }
2555             }
2556         } else {
2557             flushStart = start;
2558             flushEnd = start + size;
2559         }
2560         //zero out entries that lie in the runtime heaps
2561         for(int idx=0; idx < TARGET_CACHE_WIDTH; idx++) {
2562             //printf("cacheCopy[%d]=%lx\n",idx,cacheCopy[idx]);
2563             if (flushStart <= cacheCopy[idx] &&
2564                 flushEnd   >  cacheCopy[idx]) {
2565                 cacheCopy[idx] = 0;
2566             }
2567         }
2568         if ( flushedHeaps || (start == 0) ) {
2569             break;
2570         }
2571         flushedHeaps = true;
2572     }
2573
2574     // write the modified cache back into the RT_library
2575     if ( ! writeDataSpace( (void*)RT_address_cache_addr_,
2576                            sizeof(Address)*TARGET_CACHE_WIDTH,
2577                            (void*)cacheCopy ) ) {
2578         assert(0);
2579     }
2580     free(cacheCopy);
2581 }
2582
2583 /* Given an address that's on the call stack, find the function that's
2584  * actively executing that address.  This makes most sense for finding the
2585  * address that's triggered a context switch back to Dyninst, either
2586  * through instrumentation or a signal
2587  */
2588 func_instance *PCProcess::findActiveFuncByAddr(Address addr)
2589 {
2590     std::set<func_instance *> funcs;
2591     // error checking by size...
2592     (void)findFuncsByAddr(addr, funcs, true);
2593     if (funcs.empty()) return NULL;
2594
2595     if (funcs.size() == 1) {
2596         return *(funcs.begin());
2597     }
2598
2599     // unrelocated shared function address, do a stack walk to figure 
2600     // out which of the shared functions is on the call stack
2601     bool foundFrame = false;
2602     func_instance *activeFunc = NULL; 
2603     pdvector<pdvector<Frame> >  stacks;
2604     if ( false == walkStacks(stacks) ) {
2605         fprintf(stderr,"ERROR: %s[%d], walkStacks failed\n", 
2606                 FILE__, __LINE__);
2607         assert(0);
2608     }
2609     for (unsigned int i = 0; !foundFrame && i < stacks.size(); ++i) {
2610         pdvector<Frame> &stack = stacks[i];
2611         for (unsigned int j = 0; !foundFrame && j < stack.size(); ++j) {
2612             Frame *curFrame = &stack[j];
2613             Address framePC = curFrame->getPC();
2614
2615             // if we're at a relocated address, we can translate 
2616             // back to the right function, if translation fails 
2617             // frameFunc will still be NULL
2618             RelocInfo ri;
2619             func_instance *frameFunc = NULL;
2620
2621             if (getRelocInfo(framePC, ri) &&
2622                 ri.func) {
2623                frameFunc = ri.func;
2624             }
2625             else if (j < (stack.size() - 1)) {
2626                 // Okay, crawl original code. 
2627                 // Step 1: get our current function
2628                 std::set<func_instance *> curFuncs;
2629                 findFuncsByAddr(framePC, curFuncs);
2630                 // Step 2: get return addresses one frame up and map to possible callers
2631                 std::set<block_instance *> callerBlocks;
2632                 findBlocksByAddr(stack[j+1].getPC() - 1, callerBlocks);
2633                 for (std::set<block_instance *>::iterator cb_iter = callerBlocks.begin();
2634                     cb_iter != callerBlocks.end(); ++cb_iter)
2635                 {
2636                     if (!(*cb_iter)->containsCall()) continue;
2637                     // We have a call point; now see if it called the entry of any function
2638                     // that maps to a curFunc.
2639                     for (std::set<func_instance *>::iterator cf_iter = curFuncs.begin();
2640                          cf_iter != curFuncs.end(); ++cf_iter) {
2641                        if ((*cf_iter) == (*cb_iter)->callee()) {
2642                           frameFunc = *cf_iter;
2643                        }
2644                     }
2645                 }
2646             }
2647             if (frameFunc) {
2648                 foundFrame = true;
2649                 activeFunc = frameFunc;
2650             }
2651         }
2652     }
2653     if (!foundFrame) {
2654         activeFunc = *(funcs.begin());
2655     }
2656                 
2657     return activeFunc;
2658 }
2659
2660 bool PCProcess::patchPostCallArea(instPoint *callPt) {
2661    // 1) Find all the post-call patch areas that correspond to this 
2662    //    call point
2663    // 2) Generate and install the branches that will be inserted into 
2664    //    these patch areas
2665    
2666    // 1...
2667    AddrPairSet patchAreas;
2668    if ( ! generateRequiredPatches(callPt, patchAreas) ) {
2669       return false;
2670    }
2671    
2672    // 2...
2673    generatePatchBranches(patchAreas);
2674    return true;
2675 }
2676
2677 bool PCProcess::generateRequiredPatches(instPoint *callPoint, 
2678                                         AddrPairSet &patchAreas)
2679 {
2680     // We need to figure out where this patch should branch to.
2681     // To do that, we're going to:
2682     // 1) Forward map the entry of the ft block to
2683     //    its most recent relocated version (if that exists)
2684     // 2) For each padding area, create a (padAddr,target) pair
2685
2686     // 3)
2687
2688     block_instance *callB = callPoint->block();
2689     block_instance *ftBlk = callB->getFallthrough()->trg();
2690     if (!ftBlk) {
2691         // find the block at the next address, if there's no fallthrough block
2692         ftBlk = callB->obj()->findBlockByEntry(callB->end());
2693         assert(ftBlk);
2694     }
2695
2696     // ensure that we patch other callPts at the same address
2697
2698     vector<ParseAPI::Function*> callFuncs;
2699     callPoint->block()->llb()->getFuncs(callFuncs);
2700     for (vector<ParseAPI::Function*>::iterator fit = callFuncs.begin();
2701          fit != callFuncs.end();
2702          fit++)
2703     {
2704         func_instance *callF = findFunction((parse_func*)*fit);
2705         instPoint *callP = instPoint::preCall(callF, callB);
2706         Relocation::CodeTracker::RelocatedElements reloc;
2707         CodeTrackers::reverse_iterator rit;
2708         for (rit = relocatedCode_.rbegin(); rit != relocatedCode_.rend(); rit++)
2709         {
2710             if ((*rit)->origToReloc(ftBlk->start(), ftBlk, callF, reloc)) {
2711                 break;
2712             }
2713         }
2714         if (rit == relocatedCode_.rend()) {
2715             mal_printf("WARNING: no relocs of call-fallthrough at %lx "
2716                        "in func at %lx, will not patch its post-call "
2717                        "padding\n", callP->block()->last(),callF->addr());
2718             (*relocatedCode_.rbegin())->debug();
2719             continue;
2720         }
2721
2722         Address to = reloc.instruction;
2723         if (!reloc.instrumentation.empty()) {
2724            // There could be a lot of instrumentation at this point. Bias towards the lowest,
2725            // non-edge instrumentation
2726            for (std::map<instPoint *, Address>::iterator inst_iter = reloc.instrumentation.begin();
2727                 inst_iter != reloc.instrumentation.end(); ++inst_iter) {
2728               if (inst_iter->first->type() == PatchAPI::Point::EdgeDuring) continue;
2729               to = (inst_iter->second < to) ? inst_iter->second : to;
2730            }
2731         }
2732
2733         // 2) 
2734         Address callInsnAddr = callP->block()->last();
2735         if (forwardDefensiveMap_.end() != forwardDefensiveMap_.find(callInsnAddr)) {
2736             map<func_instance*,set<DefensivePad> >::iterator mit = forwardDefensiveMap_[callInsnAddr].begin();
2737             for (; mit != forwardDefensiveMap_[callInsnAddr].end(); ++mit) {
2738               if (callF == mit->first) {
2739                   set<DefensivePad>::iterator dit = mit->second.begin();
2740                   for (; dit != mit->second.end(); ++dit) {
2741                      Address jumpAddr = dit->first;
2742                      patchAreas.insert(std::make_pair(jumpAddr, to));
2743                      mal_printf("patching post-call pad for %lx[%lx] with %lx %s[%d]\n",
2744                                 callB->end(), jumpAddr, to, FILE__,__LINE__);
2745                   }
2746               }
2747             }
2748         }
2749     }
2750     if (patchAreas.empty()) {
2751        mal_printf("WARNING: no relocs to patch for call at %lx, block end %lx\n", 
2752                   callPoint->addr_compat(),ftBlk->start());
2753     }
2754     return ! patchAreas.empty();
2755 }
2756
2757 void PCProcess::generatePatchBranches(AddrPairSet &branchesNeeded) {
2758   for (AddrPairSet::iterator iter = branchesNeeded.begin();
2759        iter != branchesNeeded.end(); ++iter) 
2760   {
2761     Address from = iter->first;
2762     Address to = iter->second;
2763
2764     codeGen gen(64);
2765     insnCodeGen::generateBranch(gen, from, to);
2766
2767     // Safety check: make sure we didn't overrun the patch area
2768     Address lb = 0, ub = 0;
2769     std::pair<func_instance*,Address> tmp;
2770     if (!reverseDefensiveMap_.find(from, lb, ub, tmp)) {
2771       // Huh? This worked before!
2772       assert(0);
2773     }
2774     assert((from + gen.used()) <= ub);
2775     if (!writeTextSpace((void *)from, 
2776                         gen.used(),
2777                         gen.start_ptr())) {
2778       assert(0);
2779     }
2780   }
2781 }
2782
2783 /* debugSuicide is a kind of alternate debugging continueProc.  It runs the
2784  * process until terminated in single step mode, printing each instruction as
2785  * it executes.
2786  */
2787 void PCProcess::debugSuicide() {
2788     if( isTerminated() ) return;
2789
2790     isInDebugSuicide_ = true;
2791
2792     pdvector<Frame> activeFrames;
2793     getAllActiveFrames(activeFrames);
2794
2795     for(unsigned i=0; i < activeFrames.size(); ++i) {
2796         Address addr = activeFrames[i].getPC();
2797         fprintf(stderr, "Frame %u @ 0x%lx\n", i , addr);
2798     }
2799
2800     Thread::ptr initialThread = pcProc_->threads().getInitialThread();
2801
2802     initialThread->setSingleStepMode(true);
2803     while( !isTerminated() && isAttached() && initialThread->isLive() ) {
2804         // Get the current PC
2805         MachRegister pcReg = MachRegister::getPC(getArch());
2806         MachRegisterVal resultVal;
2807         if( !initialThread->getRegister(pcReg, resultVal) ) {
2808             fprintf(stderr, "%s[%d]: failed to retreive register from thread %d/%d\n",
2809                     FILE__, __LINE__, getPid(), initialThread->getLWP());
2810             return;
2811         }
2812     }
2813 }
2814
2815 pdvector<func_instance *> PCProcess::pcsToFuncs(pdvector<Frame> stackWalk) {
2816     pdvector <func_instance *> ret;
2817     unsigned i;
2818     func_instance *fn;
2819     for(i=0;i<stackWalk.size();i++) {
2820         fn = (func_instance *)findOneFuncByAddr(stackWalk[i].getPC());
2821         // no reason to add a null function to ret
2822         if (fn != 0) ret.push_back(fn);
2823     }
2824     return ret;
2825 }
2826
2827 bool PCProcess::isInSignalHandler(Address addr) {
2828     codeRange *range;
2829     if( signalHandlerLocations_.find(addr, range) ) {
2830         return true;
2831     }
2832
2833     return false;
2834 }
2835
2836 void PCProcess::addSignalHandler(Address addr, unsigned size) {
2837     codeRange *handlerLoc;
2838     if (signalHandlerLocations_.find(addr, handlerLoc)) {
2839         return; // we're already tracking this location
2840     }
2841     handlerLoc = new signal_handler_location(addr, size);
2842     signalHandlerLocations_.insert((signal_handler_location *)handlerLoc);
2843 }
2844
2845 bool PCProcess::mappedObjIsDeleted(mapped_object *obj) {
2846     for(unsigned i = 0; i < deletedObjects_.size(); ++i) {
2847         if( obj == deletedObjects_[i] ) return true;
2848     }
2849
2850     return false;
2851 }
2852
2853 // AddressSpace Implementation //
2854 Address PCProcess::offset() const {
2855     assert(!"This function is not implemented");
2856     return 0;
2857 }
2858
2859 Address PCProcess::length() const {
2860     assert(!"This function is not implemented");
2861     return 0;
2862 }
2863
2864 Architecture PCProcess::getArch() const {
2865     return savedArch_;
2866 }
2867
2868 bool PCProcess::multithread_ready(bool ignoreIfMtNotSet) {
2869     // Since ProcControlAPI has taken over handling thread creation
2870     // and destruction from the RT library, as soon as the process reaches
2871     // the initialized state, the process is multithread ready if it
2872     // is multithread capable.
2873
2874     if( !hasReachedBootstrapState(bs_initialized) ) return false;
2875     if( !multithread_capable(ignoreIfMtNotSet) ) return false;
2876
2877     return true;
2878 }
2879
2880 bool PCProcess::needsPIC() {
2881     return false;
2882 }
2883
2884 bool PCProcess::isInDebugSuicide() const {
2885     return isInDebugSuicide_;
2886 }
2887
2888 PCProcess::processState_t PCProcess::getDesiredProcessState() const {
2889     return processState_;
2890 }
2891
2892 void PCProcess::setDesiredProcessState(PCProcess::processState_t pc) {
2893     processState_ = pc;
2894 }
2895
2896 bool PCProcess::walkStack(pdvector<Frame> &stackWalk,
2897                           PCThread *thread)
2898 {
2899   if( stackwalker_ == NULL ) return false;
2900
2901   vector<Dyninst::Stackwalker::Frame> swWalk;
2902
2903   if (!stackwalker_->walkStack(swWalk, thread->getLWP()))
2904   {
2905     return false;
2906   }
2907
2908   for (vector<Dyninst::Stackwalker::Frame>::iterator SWB = swWalk.begin(),
2909        SWI = SWB,
2910        SWE = swWalk.end();
2911        SWI != SWE;
2912        ++SWI)
2913   {
2914     stackWalk.push_back(Frame(*SWI, this, thread, (SWI == SWB)));
2915   }
2916
2917   return true;
2918 }
2919
2920 bool PCProcess::getActiveFrame(Frame &frame, PCThread *thread)
2921 {
2922   Dyninst::Stackwalker::Frame swFrame;
2923   if (!stackwalker_->getInitialFrame(swFrame, thread->getLWP()))
2924   {
2925     return false;
2926   }
2927
2928   frame = Frame(swFrame, this, thread, true);
2929   return true;
2930 }
2931
2932 /* This is the simple version
2933  * 1. Need three pieces of information:
2934  * 1a. The instrumentation point that triggered the stopThread event (pointAddress)
2935  * 1b. The ID of the callback function given at the registration
2936  *     of the stopThread snippet
2937  * 1c. The result of the snippet calculation that was given by the user,
2938  *     if the point is a return instruction, read the return address
2939  * 2. If the calculation is an address that is meant to be interpreted, do that
2940  * 3. Invoke the callback
2941  */
2942 bool PCProcess::triggerStopThread(Address pointAddress, int callbackID, void *calculation) {
2943     AddressSpace::RelocInfo ri;
2944     if( !getRelocInfo(pointAddress, ri) ) {
2945         assert(0);
2946         return false;
2947     }
2948
2949     // get instPoint from point address
2950     func_instance *pointfunc = ri.func;
2951     if (!pointfunc) {
2952         mal_printf("%s[%d]: failed to find active function at 0x%lx\n",
2953                 FILE__, __LINE__, pointAddress);
2954         return false;
2955     }
2956
2957     instPoint *intPoint = ri.bt->point();
2958     if (!intPoint) {
2959         mal_printf("%s[%d]: failed to find inst point at 0x%lx\n",
2960                 FILE__, __LINE__, pointAddress);
2961         return false;
2962     }
2963
2964     mal_printf("handling stopThread %lx[%lx]=>%lx %s[%d]\n",
2965             ri.reloc, pointAddress, (long)calculation, FILE__, __LINE__);
2966
2967     /* 2. If the callbackID is negative, the calculation is meant to be
2968       interpreted as the address of code, so we call stopThreadCtrlTransfer
2969       to translate the target to an unrelocated address */
2970     if (callbackID < 0) {
2971         callbackID *= -1;
2972         calculation = (void*)
2973             stopThreadCtrlTransfer(intPoint, (Address)calculation);
2974     }
2975
2976     /* 3. Trigger the callback for the stopThread
2977       using the correct snippet instance ID & event type */
2978     ((BPatch_process*)up_ptr())->triggerStopThread
2979         (intPoint, pointfunc, callbackID, (void*)calculation);
2980
2981     return true;
2982 }
2983
2984 /*    If calculation is a relocated address, translate it to the original addr
2985  *    case 1: The point is at a return instruction
2986  *    case 2: The point is a control transfer into the runtime library
2987  *    Mark returning functions as returning
2988  *    Save the targets of indirect control transfers (not regular returns)
2989  */
2990 Address PCProcess::stopThreadCtrlTransfer (instPoint* intPoint, 
2991                                          Address target)
2992 {
2993    Address pointAddr = intPoint->addr_compat();
2994
2995     // if the point is a real return instruction and its target is a stack 
2996     // address, get the return address off of the stack 
2997     if (intPoint->type() == instPoint::FuncExit &&
2998         intPoint->block()->isFuncExit() &&
2999         !intPoint->func()->isSignalHandler()) 
3000     {
3001         mal_printf("%s[%d]: return address is %lx\n", FILE__,
3002                     __LINE__,target);
3003     }
3004
3005     Address unrelocTarget = target;
3006
3007     if ( isRuntimeHeapAddr( target ) ) {
3008         // get unrelocated target address, there are three possibilities
3009         // a. We're in post-call padding, and targBBI is the call block
3010         // b. We're in an analyzed fallthrough block
3011         // c. The stack was tampered with and we need the (mod_pc - pc) 
3012         //    offset to figure out where we should be
3013         malware_cerr << "Looking for matches to incoming address " 
3014             << hex << target << dec << endl;
3015         std::pair<func_instance*,Address> tmp;
3016
3017         if ( reverseDefensiveMap_.find(target,tmp) ) {
3018             // a. 
3019            std::set<block_instance*> callBs;
3020            tmp.first->getBlocks(tmp.second, callBs);
3021            block_instance *callB = (*callBs.begin());
3022            edge_instance *fallthrough = callB->getFallthrough();
3023            if (fallthrough) {
3024               unrelocTarget = fallthrough->trg()->start();
3025            } else {
3026               unrelocTarget = callB->end();
3027            }
3028         }
3029         else {
3030             // b. 
3031             // if we're in the fallthrough block, match to call block, 
3032             // and if necessary, add fallthrough edge
3033            AddressSpace::RelocInfo ri;
3034            bool hasFT = getRelocInfo(target, ri);
3035            assert(hasFT); // otherwise we should be in the defensive map
3036            if (ri.pad) {
3037                unrelocTarget = ri.block->end();
3038            } else {
3039                unrelocTarget = ri.block->start();
3040            }
3041         }
3042         mal_printf("translated target %lx to %lx %s[%d]\n",
3043             target, unrelocTarget, FILE__, __LINE__);
3044     }
3045     else { // target is not relocated, nothing to do but find the 
3046            // mapped_object, creating one if necessary, for transfers
3047            // into memory regions that are allocated at runtime
3048         mapped_object *obj = findObject(target);
3049         if (!obj) {
3050
3051 #if 0           
3052            Frame activeFrame = threads[0]->get_lwp()->getActiveFrame();
3053            for (unsigned i = 0; i < 0x100; ++i) {
3054                           Address stackTOP = activeFrame.esp;
3055                           Address stackTOPVAL =0;
3056                 readDataSpace((void *) (stackTOP + 4*i), 
3057                               sizeof(getAddressWidth()), 
3058                               &stackTOPVAL, false);
3059                           malware_cerr << "\tSTACK[" << hex << stackTOP+4*i << "]=" 
3060                              << stackTOPVAL << dec << endl;
3061            }
3062 #endif
3063
3064             obj = createObjectNoFile(target);
3065             if (!obj) {
3066                 fprintf(stderr,"ERROR, point %lx has target %lx that responds "
3067                         "to no object %s[%d]\n", pointAddr, target, 
3068                         FILE__,__LINE__);
3069                 assert(0 && "stopThread snippet has an invalid target");
3070                 return 0;
3071             }
3072         }
3073     }
3074
3075 #if 0
3076            Frame activeFrame = threads[0]->get_lwp()->getActiveFrame();
3077            Address stackTOP = activeFrame.esp;
3078            Address stackTOPVAL =0;
3079            for (unsigned i = 0; 
3080                 i < 0x100 && 0 != ((stackTOP + 4*i) % memoryPageSize_); 
3081                 ++i) 
3082            {
3083                 readDataSpace((void *) (stackTOP + 4*i), 
3084                               sizeof(getAddressWidth()), 
3085                               &stackTOPVAL, false);
3086                           malware_cerr << "\tSTACK[" << hex << stackTOP+4*i << "]=" 
3087                              << stackTOPVAL << dec << endl;
3088            }
3089 #endif
3090
3091     return unrelocTarget;
3092 }
3093
3094 void PCProcess::triggerNormalExit(int exitcode) {
3095     for(std::map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
3096             i != threadsByTid_.end(); ++i)
3097     {
3098         if( i->second != initialThread_ ) 
3099             BPatch::bpatch->registerThreadExit(this, i->second);
3100     }
3101     BPatch::bpatch->registerNormalExit(this, exitcode);
3102
3103     // Let the event handler know that the process should be moved to
3104     // an exited state
3105     setExiting(true);
3106 }
3107
3108 // Debugging only
3109 bool PCProcess::setBreakpoint(Address addr) {
3110     Breakpoint::ptr brkPt = Breakpoint::newBreakpoint();
3111     if( !pcProc_->addBreakpoint(addr, brkPt) ) {
3112         proccontrol_printf("%s[%d]: failed to set breakpoint at 0x%lx\n",
3113                 FILE__, __LINE__, addr);
3114         return false;
3115     }
3116
3117     return true;
3118 }
3119
3120 bool PCProcess::launchDebugger() {
3121     // Stop the process on detach 
3122     pdvector<func_instance *> breakpointFuncs;
3123     if( !findFuncsByAll("DYNINSTsafeBreakPoint", breakpointFuncs) ) {
3124         fprintf(stderr, "Failed to find function DYNINSTsafeBreakPoint\n");
3125         return false;
3126     }
3127
3128     func_instance *safeBreakpoint = breakpointFuncs[0];
3129     for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
3130             i != threadsByTid_.end(); ++i)
3131     {
3132         if( !i->second->pcThr_->setRegister(MachRegister::getPC(getArch()),
3133                     safeBreakpoint->addr()) )
3134         {
3135             fprintf(stderr, "Failed to set PC to 0x%lx\n", 
3136                     safeBreakpoint->addr());
3137             return false;
3138         }
3139     }
3140
3141     // Detach the process
3142     if( !detachProcess(true) ) {
3143         fprintf(stderr, "Failed to detach from process %d\n", getPid());
3144         return false;
3145     }
3146
3147     if( !startDebugger() ) {
3148         fprintf(stderr, "Failed to start debugger on process %d\n", getPid());
3149         return false;
3150     }
3151
3152     return true;
3153 }
3154
3155 // End debugging
3156
3157 Address getVarAddr(PCProcess *proc, std::string str) {
3158     Address retAddr = 0;
3159
3160     pdvector<int_variable *> vars;
3161     if( proc->findVarsByAll(str, vars) ) {
3162         if( vars.size() != 1 ) {
3163             proccontrol_printf("%s[%d]: WARNING: multiple copies of %s found\n",
3164                     FILE__, __LINE__, str.c_str());
3165         }else{
3166             retAddr = vars[0]->getAddress();
3167         }
3168     }else{
3169         proccontrol_printf("%s[%d]: failed to find variable %s\n",
3170                 FILE__, __LINE__, str.c_str());
3171     }
3172     return retAddr;
3173 }
3174
3175 Address PCProcess::getRTEventBreakpointAddr() {
3176     if( sync_event_breakpoint_addr_ == 0 ) {
3177         sync_event_breakpoint_addr_ = getVarAddr(this, "DYNINST_break_point_event");
3178     }
3179
3180     return sync_event_breakpoint_addr_;
3181 }
3182
3183 Address PCProcess::getRTEventIdAddr() {
3184     if( sync_event_id_addr_ == 0 ) {
3185         sync_event_id_addr_ = getVarAddr(this, "DYNINST_synch_event_id");
3186     }
3187
3188     return sync_event_id_addr_;
3189 }
3190
3191 Address PCProcess::getRTEventArg1Addr() {
3192     if( sync_event_arg1_addr_ == 0 ) {
3193         sync_event_arg1_addr_ = getVarAddr(this, "DYNINST_synch_event_arg1");
3194     }
3195
3196     return sync_event_arg1_addr_;
3197 }
3198
3199 Address PCProcess::getRTEventArg2Addr() {
3200     if( sync_event_arg2_addr_ == 0 ) {
3201         sync_event_arg2_addr_ = getVarAddr(this, "DYNINST_synch_event_arg2");
3202     }
3203
3204     return sync_event_arg2_addr_;
3205 }
3206
3207 Address PCProcess::getRTEventArg3Addr() {
3208     if( sync_event_arg3_addr_ == 0 ) {
3209         sync_event_arg3_addr_ = getVarAddr(this, "DYNINST_synch_event_arg3");
3210     }
3211
3212     return sync_event_arg3_addr_;
3213 }
3214
3215 Address PCProcess::getRTTrapFuncAddr() {
3216     if (rt_trap_func_addr_ == 0) {
3217         func_instance* func = findOnlyOneFunction("DYNINSTtrapFunction");
3218         rt_trap_func_addr_ = func->addr();
3219     }
3220     return rt_trap_func_addr_;
3221 }
3222
3223 bool PCProcess::hasPendingEvents() {
3224    // Go to the muxer as a final arbiter
3225    return PCEventMuxer::muxer().hasPendingEvents(this);
3226 }
3227
3228 bool PCProcess::hasRunningSyncRPC() const {
3229     return (syncRPCThreads_.size() > 0);
3230 }
3231
3232 void PCProcess::addSyncRPCThread(Thread::ptr thr) {
3233    proccontrol_printf("%s[%d]: added sync rpc thread %d/%d\n",
3234                       FILE__, __LINE__, getPid(), thr ? thr->getLWP() : 0);
3235     syncRPCThreads_.insert(thr);
3236 }
3237
3238 void PCProcess::removeSyncRPCThread(Thread::ptr thr) {
3239     proccontrol_printf("%s[%d]: removed sync rpc thread %d/%d\n",
3240                 FILE__, __LINE__, getPid(), thr ? thr->getLWP() : 0);
3241     syncRPCThreads_.erase(thr);
3242 }
3243
3244 bool PCProcess::continueSyncRPCThreads() {
3245         for(set<Thread::ptr>::iterator i = syncRPCThreads_.begin();
3246             i != syncRPCThreads_.end(); ++i)
3247     {
3248                 if(!(*i)) {
3249                         if(!pcProc_->continueProc())
3250                         {
3251                                 proccontrol_printf("%s[%d]: failed to continue entire process %d for sync RPC\n",
3252                                                 FILE__, __LINE__, getPid());
3253                                 return false;
3254                         }
3255                 } else if( !(*i)->continueThread() ) {
3256             proccontrol_printf("%s[%d]: failed to continue thread %d/%d for sync RPC\n",
3257                     FILE__, __LINE__, getPid(), (*i)->getLWP());
3258             return false;
3259         }
3260     }
3261
3262     return true;
3263 }
3264
3265 void PCProcess::addTrap(Address from, Address to, codeGen &gen) {
3266    gen.invalidate();
3267    gen.allocate(4);
3268    gen.setAddrSpace(this);
3269    gen.setAddr(from);
3270    insnCodeGen::generateTrap(gen);
3271    trapMapping.addTrapMapping(from, to, true);
3272    springboard_cerr << "Generated springboard trap " << hex << from << "->" << to << dec << endl;
3273 }
3274
3275 void PCProcess::removeTrap(Address from) {
3276     map<Address, Breakpoint::ptr>::iterator breakIter = 
3277         installedCtrlBrkpts.find(from);
3278     if( breakIter == installedCtrlBrkpts.end() ) return;
3279
3280     if( !pcProc_->rmBreakpoint(from, breakIter->second) ) {
3281         proccontrol_printf("%s[%d]: failed to remove ctrl transfer breakpoint from 0x%lx\n",
3282                 FILE__, __LINE__, from);
3283     }
3284
3285     installedCtrlBrkpts.erase(breakIter);
3286 }
3287
3288 void PCProcess::invalidateMTCache() {
3289     mt_cache_result_ = not_cached;
3290 }
3291
3292 bool PCProcess::supportsUserThreadEvents() {
3293     if (!pcProc_) return false;
3294     return pcProc_->supportsUserThreadEvents();
3295 }
3296
3297 StackwalkSymLookup::StackwalkSymLookup(PCProcess *p)
3298   : proc_(p)
3299 {}
3300
3301 StackwalkSymLookup::~StackwalkSymLookup()
3302 {}
3303
3304 bool StackwalkSymLookup::lookupAtAddr(Dyninst::Address addr, std::string &out_name, void* &out_value)
3305 {
3306   func_instance *func = proc_->findOneFuncByAddr(addr);
3307   if( func == NULL ) return false;
3308
3309   // set out_name to the name of the function at this addr
3310   // set out_value to NULL, this value is no longer used
3311
3312   out_value = NULL;
3313
3314   if (func)
3315   {
3316     out_name = func->prettyName();
3317   }
3318   else
3319   {
3320     out_name = string("[UNKNOWN]");
3321   }
3322   
3323   return true;
3324 }
3325
3326 StackwalkInstrumentationHelper::StackwalkInstrumentationHelper(PCProcess *p)
3327   : proc_(p)
3328 {}
3329
3330 StackwalkInstrumentationHelper::~StackwalkInstrumentationHelper()
3331 {}
3332
3333 DynFrameHelper::DynFrameHelper(PCProcess *p)
3334   : FrameFuncHelper(NULL),
3335   proc_(p)
3336 {}
3337
3338 DynFrameHelper::~DynFrameHelper()
3339 {}
3340
3341 DynWandererHelper::DynWandererHelper(PCProcess *p)
3342   : WandererHelper(NULL),
3343   proc_(p)
3344 {}
3345
3346 DynWandererHelper::~DynWandererHelper()
3347 {}
3348
3349
3350