2 * See the dyninst/COPYRIGHT file for copyright information.
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.
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.
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.
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.
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
31 #include "dynProcess.h"
32 #include "dynThread.h"
33 #include "pcEventHandler.h"
34 #include "pcEventMuxer.h"
38 #include "instPoint.h"
40 #include "mapped_module.h"
41 #include "baseTramp.h"
42 #include "registerSpace.h"
43 #include "mapped_object.h"
46 #include "common/src/pathName.h"
48 #include "proccontrol/h/PCErrors.h"
49 #include "MemoryEmulator/memEmulator.h"
50 #include <boost/tuple/tuple.hpp>
52 #include "symtabAPI/h/SymtabReader.h"
53 #include "patchAPI/h/PatchMgr.h"
54 #include "patchAPI/h/Point.h"
59 using namespace Dyninst::ProcControlAPI;
63 using std::stringstream;
65 Dyninst::SymtabAPI::SymtabReaderFactory *PCProcess::symReaderFactory_;
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,
73 // Debugging information
74 startup_cerr << "Creating process " << file << " in directory " << dir << endl;
76 startup_cerr << "Arguments: (" << argv.size() << ")" << endl;
77 for (unsigned a = 0; a < argv.size(); a++)
78 startup_cerr << " " << a << ": " << argv[a] << endl;
80 startup_cerr << "Environment: (" << envp.size() << ")" << endl;
81 for (unsigned e = 0; e < envp.size(); e++)
82 startup_cerr << " " << e << ": " << envp[e] << endl;
84 startup_printf("%s[%d]: stdin: %d, stdout: %d, stderr: %d\n", FILE__, __LINE__,
85 stdin_fd, stdout_fd, stderr_fd);
89 // Create a full path to the executable
90 string path = createExecPath(file, dir);
92 std::map<int, int> fdMap;
93 redirectFds(stdin_fd, stdout_fd, stderr_fd, fdMap);
95 if( !setEnvPreload(envp, path) ) {
96 startup_cerr << "Failed to set environment var to preload RT library" << endl;
100 // Create the ProcControl process
101 Process::ptr tmpPcProc = Process::createProcess(path, argv, envp, fdMap);
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());
114 startup_cerr << "Created process " << tmpPcProc->getPid() << endl;
116 PCProcess *ret = new PCProcess(tmpPcProc, file, analysisMode);
118 tmpPcProc->setData(ret);
120 if( !ret->bootstrapProcess() ) {
121 startup_cerr << "Failed to bootstrap process " << ret->getPid()
122 << ": terminating..." << endl;
123 ret->terminateProcess();
132 PCProcess *PCProcess::attachProcess(const string &progpath, int pid,
133 BPatch_hybridMode analysisMode)
137 startup_cerr << "Attaching to process " << pid << endl;
138 Process::ptr tmpPcProc = Process::attachProcess(pid, progpath);
141 const char *lastErrMsg = getLastErrorMsg();
142 startup_printf("%s[%d]: Failed to attach process %d: %s\n",
143 __FILE__, __LINE__, pid, lastErrMsg);
145 msg << "Failed to attach to process " << pid << ": " << lastErrMsg;
146 showErrorCallback(26, msg.str());
149 startup_cerr << "Attached to process " << tmpPcProc->getPid() << endl;
151 PCProcess *ret = new PCProcess(tmpPcProc, analysisMode);
154 tmpPcProc->setData(ret);
156 ret->runningWhenAttached_ = tmpPcProc->allThreadsRunningWhenAttached();
157 ret->file_ = tmpPcProc->libraries().getExecutable()->getAbsoluteName();
159 if( !ret->bootstrapProcess() ) {
160 startup_cerr << "Failed to bootstrap process " << pid
161 << ": terminating..." << endl;
162 ret->terminateProcess();
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());
175 PCProcess *ret = new PCProcess(parent, pcProc);
178 pcProc->setData(ret);
180 ret->copyAddressSpace(parent);
182 // This requires the AddressSpace be copied from the parent
183 if (parent->tracedSyscalls_)
184 ret->tracedSyscalls_ = new syscallNotification(parent->tracedSyscalls_, ret);
186 ret->tracedSyscalls_ = NULL;
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",
197 startup_printf("%s[%d]: Got Dyninst RT libname: %s\n", FILE__, __LINE__,
198 ret->dyninstRT_name.c_str());
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]);
211 // TODO hybrid mode stuff
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]);
219 signal_handler_location *newSig = new signal_handler_location(*oldSig);
220 ret->signalHandlerLocations_.insert(newSig);
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();
233 ret->setInEventHandling(true);
235 if( !ret->bootstrapProcess() ) {
236 startup_cerr << "Failed to bootstrap process " << ret->getPid()
237 << ": terminating..." << endl;
238 ret->terminateProcess();
244 ret->setDesiredProcessState(parent->getDesiredProcessState());
249 PCProcess *PCProcess::setupExecedProcess(PCProcess *oldProc, std::string execPath) {
250 BPatch::bpatch->registerExecCleanup(oldProc, NULL);
252 PCProcess *newProc = new PCProcess(oldProc->pcProc_, execPath, oldProc->analysisMode_);
254 oldProc->pcProc_->setData(newProc);
255 newProc->setExecing(true);
257 if( !newProc->bootstrapProcess() ) {
258 proccontrol_printf("%s[%d]: failed to bootstrap execed process %d\n",
259 FILE__, __LINE__, newProc->getPid());
267 newProc->setInEventHandling(true);
268 //newProc->incPendingEvents();
270 BPatch::bpatch->registerExecExit(newProc);
272 newProc->setExecing(false);
273 newProc->setDesiredProcessState(ps_running);
278 PCProcess::~PCProcess() {
279 if( tracedSyscalls_ ) delete tracedSyscalls_;
280 tracedSyscalls_ = NULL;
282 if( irpcTramp_ ) delete irpcTramp_;
285 signalHandlerLocations_.clear();
287 trapMapping.clearTrapMappings();
290 void PCProcess::initSymtabReader()
292 //Set SymbolReaderFactory in Stackwalker before create/attach
293 if (!symReaderFactory_) {
294 symReaderFactory_ = new Dyninst::SymtabAPI::SymtabReaderFactory();
295 Dyninst::Stackwalker::Walker::setSymbolReader(symReaderFactory_);
299 /***************************************************************************
300 **** Runtime library initialization code (Dyninst) ****
301 ***************************************************************************/
305 * Gratuitously large comment. This diagrams the startup flow of
306 * messages between the mutator and mutatee. Entry points
307 * for create and attach process are both given.
308 * Mutator Signal Mutatee
311 * <-- Trap Halted in exec (handled by ProcControlAPI)
312 * Install trap in main
313 * <-- Trap Halted in main
314 * Attach: (also paused, not in main)
315 * Install call to dlopen/
317 * <-- Trap In library load
318 * Set parameters in library
319 * <-- Trap Finished loading
320 * Restore code and leave paused
322 * If finalizing fails, init via iRPC
326 * In all cases, the process is left paused at the entry of main
327 * (create) or where it was (attach). No permanent instrumentation
331 bool PCProcess::hasReachedBootstrapState(bootstrapState_t state) const {
332 return state <= bootstrapState_;
335 void PCProcess::setBootstrapState(bootstrapState_t newState) {
336 bootstrapState_ = newState;
339 bool PCProcess::bootstrapProcess() {
340 assert( pcProc_->allThreadsStopped() );
342 startup_printf("%s[%d]: attempting to bootstrap process %d\n",
343 FILE__, __LINE__, getPid());
345 if( !wasCreatedViaFork() ) {
346 // Initialize the inferior heaps
349 for(unsigned i = 0; i < mapped_objects.size(); ++i) {
350 addInferiorHeap(mapped_objects[i]);
353 // Create the mapped_objects for the executable and shared libraries
354 if( !createInitialMappedObjects() ) {
355 startup_printf("%s[%d]: bootstrap failed while creating mapped objects\n",
361 // Create the initial threads
362 createInitialThreads();
364 // Initialize StackwalkerAPI
365 if ( !createStackwalker() )
367 startup_printf("Bootstrap failed while initializing Stackwalker\n");
371 // Insert a breakpoint at the entry point of main (and possibly __libc_start_main)
372 if( !hasPassedMain() ) {
373 startup_printf("%s[%d]: inserting breakpoint at main\n", FILE__, __LINE__);
374 if( !insertBreakpointAtMain() ) {
375 startup_printf("%s[%d]: bootstrap failed while setting a breakpoint at main\n",
379 startup_printf("%s[%d]: continuing process to breakpoint\n", FILE__, __LINE__);
380 if( !continueProcess() ) {
381 startup_printf("%s[%d]: bootstrap failed while continuing the process\n",
386 while( !hasReachedBootstrapState(bs_readyToLoadRTLib) ) {
387 startup_printf("%s[%d]: waiting for main() loop\n", FILE__, __LINE__);
389 startup_printf("%s[%d]: We think the process is stopped, continuing\n", FILE__, __LINE__);
390 if( !continueProcess() ) {
391 startup_printf("%s[%d]: bootstrap failed while continuing the process\n",
397 if( isTerminated() ) {
398 bperr("The process exited during startup. This is likely due to one "
400 "A). The application is mis-built and unable to load. Try "
401 "running the application outside of Dyninst and see if it "
403 "B). libdyninstAPI_RT is mis-built. Try loading the library "
404 "into another application and see if it reports any errors. "
405 "Ubuntu users - You may need to rebuild the RT library "
406 "with the DISABLE_STACK_PROT line enabled in "
407 "core/make.config.local");
408 startup_printf("%s[%d]: program exited early, never reached "
409 "initialized state\n", FILE__, __LINE__);
410 startup_printf("Error is likely due to the application or RT "
411 "library having missing symbols or dependencies\n");
415 startup_printf("%s[%d]: bootstrap waiting for process to initialize\n",
417 if( PCEventMuxer::wait(true) == PCEventMuxer::Error) {
418 startup_printf("%s[%d]: bootstrap failed to wait for events\n",
424 bootstrapState_ = bs_readyToLoadRTLib;
426 startup_printf("%s[%d]: process initialized, loading the RT library\n",
429 // Load the RT library
431 bperr("Dyninst was unable to load the dyninst runtime library "
432 "into the application. This may be caused by statically "
433 "linked executables, or by having dyninst linked against a "
434 "different version of libelf than it was built with.");
435 startup_printf("%s[%d]: bootstrap failed to load RT library\n",
441 pdvector<int_variable *> obsCostVec;
442 if( !findVarsByAll("DYNINSTobsCostLow", obsCostVec) ) {
443 startup_printf("%s[%d]: failed to find DYNINSTobsCostLow\n",
448 costAddr_ = obsCostVec[0]->getAddress();
451 if( !wasCreatedViaFork() ) {
452 // Install system call tracing
453 startup_printf("%s[%d]: installing default Dyninst instrumentation into process %d\n",
454 FILE__, __LINE__, getPid());
456 tracedSyscalls_ = new syscallNotification(this);
459 // pre-fork and pre-exit should depend on whether a callback is defined
461 // This will require checking whether BPatch holds a defined callback and also
462 // adding a way for BPatch enable this instrumentation in all processes when
463 // a callback is registered
465 if (!tracedSyscalls_->installPreFork()) {
466 startup_printf("%s[%d]: failed pre-fork notification setup\n",
471 if (!tracedSyscalls_->installPostFork()) {
472 startup_printf("%s[%d]: failed post-fork notification setup\n",
477 if (!tracedSyscalls_->installPreExec()) {
478 startup_printf("%s[%d]: failed pre-exec notification setup\n",
483 if (!tracedSyscalls_->installPostExec()) {
484 startup_printf("%s[%d]: failed post-exec notification setup\n",
489 if (!tracedSyscalls_->installPreExit()) {
490 startup_printf("%s[%d]: failed pre-exit notification setup\n",
495 if (!tracedSyscalls_->installPreLwpExit()) {
496 startup_printf("%s[%d]: failed pre-lwp-exit notification setup\n",
501 // Initialize the tramp guard
502 startup_printf("%s[%d]: initializing tramp guard\n", FILE__, __LINE__);
503 if( !initTrampGuard() ) {
504 startup_printf("%s[%d]: failed to initalize tramp guards\n", FILE__, __LINE__);
508 // Initialize the MT stuff
509 if (multithread_capable()) {
510 if( !instrumentMTFuncs() ) {
511 startup_printf("%s[%d]: Failed to instrument MT funcs\n",
518 // Register the initial threads
519 startup_printf("%s[%d]: registering initial threads with RT library\n",
521 vector<pair<dynthread_t, PCThread *> > toUpdate;
522 for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
523 i != threadsByTid_.end(); ++i)
525 if( !registerThread(i->second) ) {
526 startup_printf("%s[%d]: bootstrap failed while registering threads with RT library\n",
531 // If the information available has improved, update the mapping to reflect this
532 if( i->first != i->second->getTid() ) toUpdate.push_back(*i);
535 for(vector<pair<dynthread_t, PCThread *> >::iterator i = toUpdate.begin();
536 i != toUpdate.end(); ++i)
538 threadsByTid_.erase(i->first);
539 threadsByTid_.insert(make_pair(i->second->getTid(), i->second));
542 startup_printf("%s[%d]: finished registering initial threads with RT library\n",
545 // use heuristics to set hybrid analysis mode
546 if (BPatch_heuristicMode == analysisMode_) {
547 if (getAOut()->parse_img()->codeObject()->defensiveMode()) {
548 analysisMode_ = BPatch_defensiveMode;
550 analysisMode_ = BPatch_normalMode;
554 bootstrapState_ = bs_initialized;
555 startup_printf("%s[%d]: finished bootstrapping process %d\n", FILE__, __LINE__, getPid());
560 bool PCProcess::initTrampGuard() {
561 const std::string vrbleName = "DYNINST_tramp_guards";
562 pdvector<int_variable *> vars;
563 if (!findVarsByAll(vrbleName, vars)) {
566 assert(vars.size() == 1);
568 Address allocedTrampAddr = 0;
570 if (getAddressWidth() == 4) {
571 // Don't write directly into trampGuardBase_ as a buffer,
572 // in case we're on a big endian architechture.
574 readDataWord((void *)vars[0]->getAddress(), 4, &value, true);
575 allocedTrampAddr = value;
577 } else if (getAddressWidth() == 8) {
578 readDataWord((void *)vars[0]->getAddress(), 8, &allocedTrampAddr, true);
579 } else assert(0 && "Incompatible mutatee address width");
581 trampGuardBase_ = getAOut()->getDefaultModule()->createVariable("DYNINST_tramp_guard",
582 allocedTrampAddr, getAddressWidth());
587 bool PCProcess::createStackwalker()
589 using namespace Stackwalker;
590 ProcDebug *procDebug = NULL;
591 StackwalkSymLookup *symLookup = NULL;
593 // Create ProcessState
594 if (NULL == (procDebug = ProcDebug::newProcDebug(pcProc_)))
596 startup_printf("Could not create Stackwalker process state\n");
600 // Create SymbolLookup
601 symLookup = new StackwalkSymLookup(this);
603 // Create Walker without default steppers
604 if (NULL == (stackwalker_ = Walker::newWalker(procDebug,
609 startup_printf("Could not create Stackwalker\n");
613 return createStackwalkerSteppers();
616 void PCProcess::createInitialThreads() {
617 ThreadPool &pcThreads = pcProc_->threads();
618 initialThread_ = PCThread::createPCThread(this, pcThreads.getInitialThread());
619 addThread(initialThread_);
621 for(ThreadPool::iterator i = pcThreads.begin(); i != pcThreads.end(); ++i) {
622 if( *i == pcThreads.getInitialThread() ) continue;
624 // Wait to create threads until they have user thread information available
625 if( !(*i)->haveUserThreadInfo() ) continue;
627 PCThread *newThr = PCThread::createPCThread(this, *i);
632 bool PCProcess::createInitialMappedObjects() {
633 if( file_.empty() ) {
634 startup_printf("%s[%d]: failed to determine executable for process %d\n",
635 FILE__, __LINE__, getPid());
639 startup_printf("Processing initial shared objects\n");
640 startup_printf("----\n");
644 // Do the a.out first...
645 mapped_object *aout = mapped_object::createMappedObject(pcProc_->libraries().getExecutable(), this, analysisMode_);
646 addASharedObject(aout);
648 // Set the RT library name
649 if( !getDyninstRTLibName() ) {
650 startup_printf("%s[%d]: failed to get Dyninst RT lib name\n",
656 startup_printf("%s[%d]: leave setAOut/setting main\n", FILE__, __LINE__);
659 // Create mapped objects for any loaded shared libraries
660 const LibraryPool &libraries = pcProc_->libraries();
661 for(LibraryPool::const_iterator i = libraries.begin(); i != libraries.end(); ++i) {
662 // Some platforms don't use the data load address field
663 if ((*i) == libraries.getExecutable()) continue;
665 startup_cerr << "Library: " << (*i)->getAbsoluteName()
666 << hex << " / " << (*i)->getLoadAddress()
667 << ", " << ((*i)->isSharedLib() ? "<lib>" : "<aout>") << dec << endl;
669 mapped_object *newObj = mapped_object::createMappedObject(*i,
670 this, analysisMode_);
671 if( newObj == NULL ) {
672 startup_printf("%s[%d]: failed to create mapped object for library %s\n",
673 FILE__, __LINE__, (*i)->getAbsoluteName().c_str());
677 const fileDescriptor &desc = newObj->getFileDesc();
678 fileDescriptor tmpDesc(dyninstRT_name, desc.code(), desc.data(), true);
679 if( desc == tmpDesc ) {
680 startup_printf("%s[%d]: RT library already loaded, manual loading not necessary\n",
682 runtime_lib.insert(newObj);
685 addASharedObject(newObj);
689 startup_printf("----\n");
694 // creates an image, creates new resources for a new shared object
695 // adds it to the collection of mapped_objects
696 void PCProcess::addASharedObject(mapped_object *newObj) {
699 addMappedObject(newObj);
701 findSignalHandler(newObj);
703 startup_printf("%s[%d]: adding shared object %s, addr range 0x%lx to 0x%lx\n",
705 newObj->fileName().c_str(),
706 newObj->getBaseAddress(),
707 newObj->getBaseAddress() + newObj->get_size());
708 parsing_printf("Adding shared object %s, addr range 0x%x to 0x%x\n",
709 newObj->fileName().c_str(),
710 newObj->getBaseAddress(),
711 newObj->getBaseAddress() + newObj->get_size());
713 if( heapInitialized_ ) {
714 addInferiorHeap(newObj);
716 startup_printf("%s[%d]: skipping check for new inferior heaps, heap uninitialized\n",
721 void PCProcess::removeASharedObject(mapped_object *obj) {
722 // Remove from mapped_objects list
723 for (unsigned j = 0; j < mapped_objects.size(); j++) {
724 if (obj == mapped_objects[j]) {
725 mapped_objects[j] = mapped_objects.back();
726 mapped_objects.pop_back();
727 deletedObjects_.push_back(obj);
732 if (runtime_lib.end() != runtime_lib.find(obj)) {
733 runtime_lib.erase( runtime_lib.find(obj) );
735 proccontrol_printf("Removing shared object %s, addr range 0x%x to 0x%x\n",
736 obj->fileName().c_str(),
737 obj->getBaseAddress(),
740 // TODO Signal handler...
743 bool PCProcess::setAOut(fileDescriptor &desc) {
744 startup_printf("%s[%d]: enter setAOut\n", FILE__, __LINE__);
746 assert(mapped_objects.size() == 0);
748 mapped_object *aout = mapped_object::createMappedObject
749 (desc, this, getHybridMode());
751 startup_printf("%s[%d]: fail setAOut\n", FILE__, __LINE__);
759 // We keep a vector of all signal handler locations
760 void PCProcess::findSignalHandler(mapped_object *obj) {
761 startup_printf("%s[%d]: findSignalhandler(%p)\n", FILE__, __LINE__, obj);
765 string signame(SIGNAL_HANDLER);
767 startup_printf("%s[%d]: findSignalhandler(%p): gettingSymbolInfo\n", FILE__, __LINE__, obj);
768 if (obj->getSymbolInfo(signame, sigSym)) {
769 // Symbols often have a size of 0. This b0rks the codeRange code,
770 // so override to 1 if this is true...
771 unsigned size_to_use = sigSym.getSize();
772 if (!size_to_use) size_to_use = 1;
774 startup_printf("%s[%d]: findSignalhandler(%p): addingSignalHandler(%p, %d)\n", FILE__, __LINE__, obj, (void *) sigSym.getAddr(), size_to_use);
775 addSignalHandler(sigSym.getAddr(), size_to_use);
778 startup_printf("%s[%d]: leaving findSignalhandler(%p)\n", FILE__, __LINE__, obj);
781 // NUMBER_OF_MAIN_POSSIBILITIES is defined in image.h
782 void PCProcess::setMainFunction() {
783 assert(!main_function_);
785 for (unsigned i = 0; i < NUMBER_OF_MAIN_POSSIBILITIES; i++) {
786 main_function_ = findOnlyOneFunction(main_function_names[i]);
787 if (main_function_) {
794 * Given an image, add all static heaps inside it
795 * (DYNINSTstaticHeap...) to the buffer pool.
797 void PCProcess::addInferiorHeap(mapped_object *obj) {
798 pdvector<heapDescriptor> infHeaps;
799 /* Get a list of inferior heaps in the new image */
800 if (obj->getInfHeapList(infHeaps)) {
801 /* Add the vector to the inferior heap structure */
802 for (u_int j=0; j < infHeaps.size(); j++) {
803 infmalloc_printf("%s[%d]: adding heap at 0x%lx to 0x%lx, name %s\n",
806 infHeaps[j].addr() + infHeaps[j].size(),
807 infHeaps[j].name().c_str());
809 // platform-specific check to ignore this heap
810 if( skipHeap(infHeaps[j]) ) continue;
812 heapItem *h = new heapItem (infHeaps[j].addr(), infHeaps[j].size(),
813 infHeaps[j].type(), false);
815 infmalloc_printf("%s[%d]: Adding heap from 0x%lx - 0x%lx (%d bytes, type %d) from mapped object %s\n",
818 infHeaps[j].addr() + infHeaps[j].size(),
821 obj->fileName().c_str());
825 // set rtlib heaps (runtime_lib hasn't been set yet)
826 if ( ! obj->fullName().compare( dyninstRT_name ) ) {
827 dyninstRT_heaps_.push_back(h);
833 static const unsigned MAX_THREADS = 32; // Should match MAX_THREADS in RTcommon.c
835 bool PCProcess::loadRTLib() {
836 // Check if the RT library has already been loaded
837 if( runtime_lib.size() != 0 ) {
838 startup_printf("%s[%d]: RT library already loaded\n",
841 bootstrapState_ = bs_loadedRTLib;
844 if (!pcProc_->addLibrary(dyninstRT_name)) {
845 startup_printf("%s[%d]: failed to start loading RT lib\n", FILE__,
849 bootstrapState_ = bs_loadedRTLib;
851 // Process the library load (we hope)
852 PCEventMuxer::handle();
854 if( runtime_lib.size() == 0 ) {
855 startup_printf("%s[%d]: failed to load RT lib\n", FILE__,
860 bootstrapState_ = bs_loadedRTLib;
863 pdvector<int_variable *> vars;
864 if (!findVarsByAll("DYNINSThasInitialized", vars)) {
865 startup_printf("%s[%d]: no DYNINSThasInitialized variable\n", FILE__, __LINE__);
868 if (!readDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *)&loaded_ok, false)) {
869 startup_printf("%s[%d]: readDataWord failed\n", FILE__, __LINE__);
874 startup_printf("%s[%d]: DYNINSTinit not called automatically\n", FILE__, __LINE__);
876 startup_printf("%s[%d]: DYNINSTinit succeeded\n", FILE__, __LINE__);
877 return setRTLibInitParams();
880 // Set up the parameters for DYNINSTinit in the RT lib
881 bool PCProcess::setRTLibInitParams() {
882 startup_printf("%s[%d]: welcome to PCProcess::setRTLibInitParams\n",
885 int pid = P_getpid();
888 // Now we write these variables into the following global vrbles
889 // in the dyninst library:
890 // libdyninstAPI_RT_init_localCause
891 // libdyninstAPI_RT_init_localPid
893 pdvector<int_variable *> vars;
896 if (!findVarsByAll("libdyninstAPI_RT_init_localPid", vars)) {
897 if (!findVarsByAll("_libdyninstAPI_RT_init_localPid", vars)) {
898 startup_printf("%s[%d]: could not find necessary internal variable\n",
904 assert(vars.size() == 1);
905 if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *)&pid)) {
906 startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
911 if (!findVarsByAll("libdyninstAPI_RT_init_maxthreads", vars)) {
912 if (!findVarsByAll("_libdyninstAPI_RT_init_maxthreads", vars)) {
913 startup_printf("%s[%d]: could not find necessary internal variable\n",
919 unsigned numThreads = MAX_THREADS;
920 if( !multithread_capable() ) numThreads = 1;
922 assert(vars.size() == 1);
923 if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *) &numThreads)) {
924 startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
929 if (!findVarsByAll("libdyninstAPI_RT_init_debug_flag", vars)) {
930 if (!findVarsByAll("_libdyninstAPI_RT_init_debug_flag", vars)) {
931 startup_printf("%s[%d]: could not find necessary internal variable\n",
937 assert(vars.size() == 1);
938 if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *) &dyn_debug_rtlib)) {
939 startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
943 if (dyn_debug_rtlib) {
944 fprintf(stderr, "%s[%d]: set var in RTlib for debug...\n", FILE__, __LINE__);
948 if (!findVarsByAll("DYNINSTstaticMode", vars)) {
949 if (!findVarsByAll("DYNINSTstaticMode", vars)) {
950 startup_printf("%s[%d]: could not find necessary internal variable\n",
956 assert(vars.size() == 1);
957 if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *) &static_mode)) {
958 startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
966 #if defined(os_vxworks)
967 bool PCProcess::insertBreakpointAtMain() {
968 // We don't need any extra processing of the RTlib.
972 bool PCProcess::insertBreakpointAtMain() {
973 if( main_function_ == NULL ) {
974 startup_printf("%s[%d]: main function not yet found, cannot insert breakpoint\n",
978 Address addr = main_function_->addr();
980 // Create the breakpoint
981 mainBrkPt_ = Breakpoint::newBreakpoint();
982 if( !pcProc_->addBreakpoint(addr, mainBrkPt_) ) {
983 startup_printf("%s[%d]: failed to insert a breakpoint at main entry: 0x%x\n",
984 FILE__, __LINE__, addr);
988 startup_printf("%s[%d]: added trap to entry of main, address 0x%x\n",
989 FILE__, __LINE__, addr);
995 bool PCProcess::removeBreakpointAtMain() {
996 if( main_function_ == NULL || mainBrkPt_ == Breakpoint::ptr() ) {
997 startup_printf("%s[%d]: no breakpoint set at main function, not removing\n",
1002 Address addr = main_function_->addr();
1004 if( !pcProc_->rmBreakpoint(addr, mainBrkPt_) ) {
1005 startup_printf("%s[%d]: failed to remove breakpoint at main entry: 0x%x\n",
1006 FILE__, __LINE__, addr);
1009 mainBrkPt_ = Breakpoint::ptr();
1014 Breakpoint::ptr PCProcess::getBreakpointAtMain() const {
1018 // End Runtime library initialization code
1020 bool PCProcess::continueProcess() {
1021 proccontrol_printf("%s[%d]: Continuing process %d\n", FILE__, __LINE__, getPid());
1023 if( !isAttached() || isTerminated() ) {
1024 bpwarn("Warning: continue attempted on non-attached process\n");
1028 // If the process is in event handling, the process should not be continued,
1029 // the processState_t value will be used after event handling to determine the
1030 // state of the process
1031 if( isInEventHandling() ) {
1032 proccontrol_printf("%s[%d]: process currently in event handling, not continuing\n",
1037 for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
1038 i != threadsByTid_.end(); ++i)
1040 i->second->clearStackwalk();
1043 return pcProc_->continueProc();
1046 bool PCProcess::stopProcess() {
1047 proccontrol_printf("%s[%d]: Stopping process %d\n", FILE__, __LINE__, getPid());
1049 if( !isAttached() || isTerminated() ) {
1050 bpwarn("Warning: stop attempted on non-attached process\n");
1054 // See comment in continueProcess about this
1055 if( isInEventHandling() ) {
1056 proccontrol_printf("%s[%d]: process currently in event handling, not stopping\n",
1061 return pcProc_->stopProc();
1064 bool PCProcess::terminateProcess() {
1065 if( isTerminated() ) return true;
1067 if( !isAttached() ) return false;
1069 forcedTerminating_ = true;
1071 proccontrol_printf("%s[%d]: Terminating process %d\n", FILE__, __LINE__, getPid());
1072 if( !pcProc_->terminate() ) {
1073 proccontrol_printf("%s[%d]: Failed to terminate process %d\n", FILE__, __LINE__,
1077 PCEventMuxer::handle();
1079 proccontrol_printf("%s[%d]: finished terminating process %d\n", FILE__, __LINE__, getPid());
1084 bool PCProcess::detachProcess(bool /*cont*/) {
1085 if( isTerminated() ) return true;
1087 if( !isAttached() ) return false;
1089 if (tracedSyscalls_) {
1090 tracedSyscalls_->removePreFork();
1091 tracedSyscalls_->removePostFork();
1092 tracedSyscalls_->removePreExec();
1093 tracedSyscalls_->removePostExec();
1094 tracedSyscalls_->removePreExit();
1095 tracedSyscalls_->removePreLwpExit();
1098 // TODO figure out if ProcControl should care about continuing a process
1101 // NB: it's possible to get markExited() while handling events for the
1102 // tracedSyscalls_->remove* calls above, clearing pcProc_.
1103 if( isTerminated() || pcProc_->detach() ) {
1111 bool PCProcess::isBootstrapped() const {
1112 return bootstrapState_ == bs_initialized;
1115 bool PCProcess::isAttached() const {
1119 bool PCProcess::isStopped() const {
1120 if( pcProc_ == Process::ptr() ) return true;
1121 return pcProc_->allThreadsStopped();
1124 bool PCProcess::isTerminated() const {
1125 if( pcProc_ == Process::ptr() ) return true;
1126 return pcProc_->isTerminated();
1129 bool PCProcess::hasExitedNormally() const {
1130 if( pcProc_ == Process::ptr() ) return true;
1131 return pcProc_->isExited();
1134 bool PCProcess::isExecing() const {
1138 void PCProcess::setExecing(bool b) {
1142 bool PCProcess::isExiting() const {
1146 void PCProcess::setExiting(bool b) {
1150 bool PCProcess::isInEventHandling() const {
1151 return inEventHandling_;
1154 void PCProcess::setInEventHandling(bool b) {
1155 inEventHandling_ = b;
1158 bool PCProcess::hasReportedEvent() const {
1159 return reportedEvent_;
1162 void PCProcess::setReportingEvent(bool b) {
1166 void PCProcess::markExited() {
1167 pcProc_ = Process::ptr();
1170 void PCProcess::writeDebugDataSpace(void *inTracedProcess, u_int amount,
1173 static unsigned write_no = 0;
1175 if( !dyn_debug_write ) return;
1177 write_printf("const unsigned char ");
1180 write_printf("x86_");
1183 write_printf("amd64_");
1187 write_printf("power_");
1190 write_printf("unknown_");
1193 write_printf("%lx_%d_%u[] = {", inTracedProcess, getPid(), write_no++);
1195 const unsigned char *buffer = (const unsigned char *)inSelf;
1196 for(unsigned i = 0; i < amount-1; ++i) {
1197 if( amount && (i % 10 == 0) ) write_printf("\n");
1198 write_printf("0x%02hhx, ", buffer[i]);
1200 if(amount) write_printf("0x%02hhx", buffer[amount-1]);
1201 write_printf("\n};\n");
1204 bool PCProcess::writeDataSpace(void *inTracedProcess, u_int amount,
1205 const void *inSelf) {
1206 if( isTerminated() ) {
1207 cerr << "Writing to terminated process!" << endl;
1210 bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf,
1213 if( BPatch_defensiveMode == proc()->getHybridMode() && !result ) {
1214 // the write may have failed because we've removed write permissions
1215 // from the page, remove them and try again
1217 PCMemPerm origRights, rights(true, true, true);
1218 if (!pcProc_->setMemoryAccessRights((Address)inTracedProcess,
1219 amount, rights, origRights)) {
1220 cerr << "Fail to set memory permissions!" << endl;
1225 int oldRights = pcProc_->setMemoryAccessRights((Address)inTracedProcess,
1227 PAGE_EXECUTE_READWRITE);
1229 if( oldRights == PAGE_EXECUTE_READ || oldRights == PAGE_READONLY ) {
1232 if( origRights.isRX() || origRights.isR() ) {
1233 result = pcProc_->writeMemory((Address)inTracedProcess, inSelf,
1237 if( pcProc_->setMemoryAccessRights((Address)inTracedProcess,
1238 amount, oldRights) == false ) {
1241 PCMemPerm tmpRights;
1242 if( !pcProc_->setMemoryAccessRights((Address)inTracedProcess,
1243 amount, origRights, tmpRights)) {
1251 if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
1256 bool PCProcess::writeDataWord(void *inTracedProcess,
1257 u_int amount, const void *inSelf)
1259 if( isTerminated() ) return false;
1261 // XXX ProcControlAPI should support word writes in the future
1262 bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf, amount);
1263 if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
1267 bool PCProcess::readDataSpace(const void *inTracedProcess, u_int amount,
1268 void *inSelf, bool displayErrMsg)
1270 if( isTerminated() ) return false;
1272 bool result = pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
1273 if( !result && displayErrMsg ) {
1275 msg << "System error: unable to read " << amount << "@"
1276 << Address_str((Address)inTracedProcess) << " from process data space: "
1277 << getLastErrorMsg() << "(pid = " << getPid() << ")";
1278 showErrorCallback(38, msg.str());
1283 bool PCProcess::readDataWord(const void *inTracedProcess, u_int amount,
1284 void *inSelf, bool displayErrMsg)
1286 if( isTerminated() ) return false;
1288 // XXX see writeDataWord above
1289 bool result = pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
1290 if( !result && displayErrMsg ) {
1292 msg << "System error: unable to read " << amount << "@"
1293 << Address_str((Address)inTracedProcess) << " from process data space: "
1294 << getLastErrorMsg() << "(pid = " << getPid() << ")";
1295 showErrorCallback(38, msg.str());
1301 bool PCProcess::writeTextSpace(void *inTracedProcess, u_int amount, const void *inSelf)
1303 if( isTerminated() ) return false;
1304 bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf, amount);
1306 if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
1311 bool PCProcess::writeTextWord(void *inTracedProcess, u_int amount, const void *inSelf)
1313 if( isTerminated() ) return false;
1315 // XXX see writeDataWord above
1316 bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf, amount);
1318 if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
1323 bool PCProcess::readTextSpace(const void *inTracedProcess, u_int amount,
1326 if( isTerminated() ) return false;
1328 return pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
1331 bool PCProcess::readTextWord(const void *inTracedProcess, u_int amount,
1334 if( isTerminated() ) return false;
1336 // XXX see writeDataWord above
1337 return pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
1340 PCThread *PCProcess::getInitialThread() const {
1341 return initialThread_;
1344 PCThread *PCProcess::getThread(dynthread_t tid) const {
1345 map<dynthread_t, PCThread *>::const_iterator findIter;
1346 findIter = threadsByTid_.find(tid);
1347 if( findIter == threadsByTid_.end() ) {
1351 return findIter->second;
1354 bool PCProcess::removeThread(dynthread_t tid) {
1355 map<dynthread_t, PCThread *>::iterator result;
1356 result = threadsByTid_.find(tid);
1358 if( result == threadsByTid_.end() ) return false;
1360 PCThread *toDelete = result->second;
1362 if( !unregisterThread(toDelete) ) return false;
1364 threadsByTid_.erase(result);
1366 if( toDelete == initialThread_ ) {
1367 initialThread_ = NULL;
1370 toDelete->markExited();
1372 // Note: don't delete the thread here, the BPatch_thread takes care of it
1373 proccontrol_printf("%s[%d]: removed thread %lu from process %d\n",
1374 FILE__, __LINE__, toDelete->getLWP(), getPid());
1377 extern Address getVarAddr(PCProcess *proc, std::string str);
1380 bool PCProcess::registerThread(PCThread *thread) {
1381 Address tid = (Address) thread->getTid();
1382 Address index = thread->getIndex();
1385 unsigned ptrsize = getAddressWidth();
1387 if (tid == (Address) -1) return true;
1388 if (index == (Address) -1) return true;
1390 if (!initializeRegisterThread()) {
1391 startup_printf("%s[%d]: initializeRegisterThread failed\n",
1396 // Must match the "hash" algorithm used in the RT lib
1397 int working = (tid % thread_hash_size);
1400 if (!readDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &tmp, false)) {
1401 startup_printf("%s[%d]: Failed to read index slot, base 0x%lx, active 0x%lx\n", FILE__, __LINE__,
1402 thread_hash_indices, thread_hash_indices + (working * ptrsize));
1405 startup_printf("%s[%d]: value of tid in slot %p is 0x%lx\n",
1406 FILE__, __LINE__, thread_hash_indices + (working * ptrsize), tmp);
1407 if (ptrsize == 4 && tmp == 0xffffffff) {
1408 int index_int = (int) index;
1409 int tid_int = (int) tid;
1410 startup_printf("%s[%d]: writing %d to %p and 0x%x to %p\n",
1411 FILE__, __LINE__, index_int, thread_hash_indices + (working * ptrsize),
1412 tid_int, thread_hash_tids + (working * ptrsize));
1413 writeDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &index_int);
1414 writeDataWord(( void *)(thread_hash_tids + (working * ptrsize)), ptrsize, &tid_int);
1417 else if (ptrsize == 8 && tmp == (Address)-1) {
1418 writeDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &index);
1419 writeDataWord(( void *)(thread_hash_tids + (working * ptrsize)), ptrsize, &tid);
1423 if (working == thread_hash_size) working = 0;
1424 if (working == (int) (tid % thread_hash_size)) {
1425 startup_printf("%s[%d]: Failed to find empty tid slot\n", FILE__, __LINE__);
1431 bool PCProcess::unregisterThread(PCThread *thread) {
1433 Address tid = (Address) thread->getTid();
1434 Address index = thread->getIndex();
1437 unsigned ptrsize = getAddressWidth();
1438 if (tid == (Address) -1) return true;
1439 if (index == (Address) -1) return true;
1441 initializeRegisterThread();
1443 // Must match the "hash" algorithm used in the RT lib
1444 int working = tid % thread_hash_size;
1447 if (!readDataWord((void *)(thread_hash_tids + (working * ptrsize)), ptrsize, &tmp, false)) return false;
1451 writeDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &tmp);
1455 if (working == thread_hash_size) working = 0;
1456 if (working == (int) (tid % thread_hash_size)) return false;
1461 bool PCProcess::initializeRegisterThread() {
1462 // if (thread_hash_tids) return true;
1464 unsigned ptrsize = getAddressWidth();
1466 Address tidPtr = getVarAddr(this, "DYNINST_thread_hash_tids");
1467 if (!tidPtr) return false;
1468 Address indexPtr = getVarAddr(this, "DYNINST_thread_hash_indices");
1469 if (!indexPtr) return false;
1470 Address sizePtr = getVarAddr(this, "DYNINST_thread_hash_size");
1471 if (!sizePtr) return false;
1473 if (!readDataWord((const void *)tidPtr, ptrsize, &thread_hash_tids, false)) return false;
1475 if (!readDataWord((const void *)indexPtr, ptrsize, &thread_hash_indices, false)) return false;
1477 if (!readDataWord((const void *)sizePtr, sizeof(int), &thread_hash_size, false)) return false;
1484 void PCProcess::addThread(PCThread *thread) {
1485 pair<map<dynthread_t, PCThread *>::iterator, bool> result;
1486 result = threadsByTid_.insert(make_pair(thread->getTid(), thread));
1488 assert( result.second && "Thread already in collection of threads" );
1489 proccontrol_printf("%s[%d]: added thread %lu to process %d\n",
1490 FILE__, __LINE__, thread->getLWP(), getPid());
1493 void PCProcess::getThreads(vector<PCThread* > &threads) const {
1494 for(map<dynthread_t, PCThread *>::const_iterator i = threadsByTid_.begin();
1495 i != threadsByTid_.end(); ++i)
1497 threads.push_back(i->second);
1501 bool PCProcess::wasRunningWhenAttached() const {
1502 return runningWhenAttached_;
1505 bool PCProcess::wasCreatedViaAttach() const {
1506 return createdViaAttach_;
1509 bool PCProcess::wasCreatedViaFork() const {
1510 return parent_ != NULL;
1513 unsigned PCProcess::getMemoryPageSize() const {
1515 return pcProc_->getMemoryPageSize();
1518 int PCProcess::getPid() const {
1522 int PCProcess::incrementThreadIndex() {
1523 int ret = curThreadIndex_;
1528 unsigned PCProcess::getAddressWidth() const {
1529 if( mapped_objects.size() > 0 ) {
1530 return mapped_objects[0]->parse_img()->codeObject()->cs()->getAddressWidth();
1533 // We can call this before we've attached...best effort guess
1534 return sizeof(Address);
1537 PCEventHandler * PCProcess::getPCEventHandler() const {
1538 return eventHandler_;
1541 bool PCProcess::walkStacks(pdvector<pdvector<Frame> > &stackWalks) {
1542 bool needToContinue = false;
1546 if( stackwalker_ == NULL ) return false;
1548 // Process needs to be stopped before doing a stackwalk
1549 if( !isStopped() ) {
1550 needToContinue = true;
1551 if( !stopProcess() ) {
1552 proccontrol_printf("%s[%d]: failed to stop process for stackwalking\n",
1558 for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
1559 i != threadsByTid_.end(); ++i)
1561 PCThread *curThr = i->second;
1563 pdvector<Frame> stackWalk;
1564 if( !curThr->walkStack(stackWalk) ) {
1566 proccontrol_printf("%s[%d]: failed to walk stack for thread 0x%lx(%d)\n",
1568 curThr->getTid(), curThr->getLWP());
1570 stackWalks.push_back(stackWalk);
1574 if( needToContinue ) {
1575 if( !continueProcess() ) {
1576 proccontrol_printf("%s[%d]: failed to continue process after performing stackwalking\n",
1585 // Return a vector (possibly with one object) of active frames in the process
1586 bool PCProcess::getAllActiveFrames(pdvector<Frame> &activeFrames) {
1588 if( threadsByTid_.size() == 0 ) return false;
1590 for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
1591 i != threadsByTid_.end(); ++i)
1593 Frame active = i->second->getActiveFrame();
1594 if( active == Frame() ) return false;
1595 activeFrames.push_back(active);
1602 // dynamic inferior heap stuff
1605 #if defined(os_vxworks)
1606 #include "vxworks.h"
1607 #define HEAP_DYN_BUF_SIZE (0x4000)
1609 #define HEAP_DYN_BUF_SIZE (0x100000)
1612 static const Address ADDRESS_LO = ((Address)0);
1613 static const Address ADDRESS_HI = ((Address)~((Address)0));
1615 Address PCProcess::inferiorMalloc(unsigned size, inferiorHeapType type,
1616 Address near_, bool *err)
1618 if(bootstrapState_ <= bs_readyToLoadRTLib) {
1622 enum MallocAttempt {
1624 DeferredFree = 1, // compact free blocks
1625 NewSegment1MBConstrained = 2, // allocate new segment (1 MB, constrained)
1626 NewSegmentSizedConstrained = 3, // allocate new segment (sized, constrained)
1627 RemoveRangeConstraints = 4,
1628 NewSegment1MBUnconstrained = 5,
1629 NewSegmentSizedUnconstrained = 6,
1630 DeferredFreeAgain = 7 // why again?
1634 if (err) *err = false;
1637 infmalloc_printf("%s[%d]: inferior malloc cannot be <= 0\n",
1639 if( err ) *err = true;
1644 Address lo = ADDRESS_LO; // Should get reset to a more reasonable value
1645 Address hi = ADDRESS_HI; // Should get reset to a more reasonable value
1647 //#if defined(cap_dynamic_heap)
1648 inferiorMallocAlign(size); // align size
1649 // Set the lo/hi constraints (if necessary)
1650 inferiorMallocConstraints(near_, lo, hi, type);
1652 /* align to cache line size (32 bytes on SPARC) */
1653 //size = (size + 0x1f) & ~0x1f;
1656 infmalloc_printf("%s[%d]: inferiorMalloc entered; size %d, type %d, near 0x%lx (0x%lx to 0x%lx)\n",
1657 FILE__, __LINE__, size, type, near_, lo, hi);
1659 // find free memory block (multiple attempts)
1662 for (ntry = 0; freeIndex == -1; ntry++) {
1666 //#if defined(cap_dynamic_heap)
1668 infmalloc_printf("%s[%d]: garbage collecting and compacting\n",
1670 inferiorFreeCompact();
1672 case NewSegment1MBConstrained:
1673 infmalloc_printf("%s[%d]: inferiorMallocDynamic for %d (0x%x) bytes between 0x%lx - 0x%lx\n",
1674 FILE__, __LINE__, HEAP_DYN_BUF_SIZE, HEAP_DYN_BUF_SIZE, lo, hi);
1675 inferiorMallocDynamic(HEAP_DYN_BUF_SIZE, lo, hi);
1677 case NewSegmentSizedConstrained:
1678 infmalloc_printf("%s[%d]: inferiorMallocDynamic for %d (0x%x) bytes between 0x%lx - 0x%lx\n",
1679 FILE__, __LINE__, size, size, lo, hi);
1680 inferiorMallocDynamic(size, lo, hi);
1682 case RemoveRangeConstraints:
1683 infmalloc_printf("%s[%d]: inferiorMalloc: removing range constraints\n",
1688 infmalloc_printf("%s[%d]: error in inferiorMalloc\n", FILE__, __LINE__);
1692 case NewSegment1MBUnconstrained:
1693 infmalloc_printf("%s[%d]: 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);
1697 case NewSegmentSizedUnconstrained:
1698 infmalloc_printf("%s[%d]: inferiorMallocDynamic for %d (0x%x) bytes between 0x%lx - 0x%lx\n",
1699 FILE__, __LINE__, size, size, lo, hi);
1700 inferiorMallocDynamic(size, lo, hi);
1702 case DeferredFreeAgain:
1703 infmalloc_printf("%s[%d]: inferiorMalloc: recompacting\n", FILE__, __LINE__);
1704 inferiorFreeCompact();
1706 //#else /* !(cap_dynamic_heap) */
1707 //case DeferredFree: // deferred free, compact free blocks
1708 //inferiorFreeCompact();
1710 //#endif /* cap_dynamic_heap */
1712 default: // error - out of memory
1713 infmalloc_printf("%s[%d]: failed to allocate memory\n", FILE__, __LINE__);
1714 if( err ) *err = true;
1718 ret = inferiorMallocInternal(size, lo, hi, type);
1721 infmalloc_printf("%s[%d]: inferiorMalloc, returning address 0x%lx\n", FILE__, __LINE__, ret);
1725 void PCProcess::inferiorFree(Dyninst::Address item) {
1726 inferiorFreeInternal(item);
1729 bool PCProcess::inferiorRealloc(Dyninst::Address item, unsigned int newSize) {
1730 if(bootstrapState_ <= bs_readyToLoadRTLib) {
1733 return inferiorReallocInternal(item, newSize);
1737 void alignUp(int &val, int align) {
1741 if (val % align != 0) {
1742 val = ((val / align) + 1) * align;
1746 bool PCProcess::inferiorMallocDynamic(int size, Address lo, Address hi) {
1747 const int MallocFailed = 0;
1748 const int UnalignedBuffer = -1;
1750 infmalloc_printf("%s[%d]: entering inferiorMallocDynamic\n", FILE__, __LINE__);
1752 // word-align buffer size
1753 // (see "DYNINSTheap_align" in rtinst/src/RTheap-<os>.c)
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);
1763 // issue RPC and wait for result
1764 bool wasRunning = !isStopped();
1766 proccontrol_printf("%s[%d]: running inferiorMalloc via iRPC on process %d\n",
1767 FILE__, __LINE__, getPid());
1771 NULL, // only care about the result
1772 wasRunning, // run when finished?
1773 NULL, // no specific thread
1774 true, // wait for completion
1776 false, // internal iRPC
1777 true) ) // is a memory allocation RPC
1779 infmalloc_printf("%s[%d]: failed to post iRPC for inferior malloc\n",
1783 proccontrol_printf("%s[%d]: inferiorMalloc via iRPC returned 0x%lx\n",
1784 FILE__, __LINE__, result);
1786 switch ((int)result) {
1788 infmalloc_printf("%s[%d]: DYNINSTos_malloc() failed\n",
1791 case UnalignedBuffer:
1792 infmalloc_printf("%s[%d]: DYNINSTos_malloc(): unaligned buffer size\n",
1796 // add new segment to buffer pool
1797 heapItem *h = new heapItem(result, size, getDynamicHeapType(),
1806 // A copy of the BPatch-level instrumentation installer
1807 void PCProcess::installInstrRequests(const pdvector<instMapping*> &requests) {
1808 if (requests.size() == 0) {
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.
1816 vector<func_instance *> instrumentedFuncs;
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());
1821 instMapping *req = requests[lcv];
1822 pdvector<miniTramp *> minis;
1824 if(!multithread_capable() && req->is_MTonly())
1827 pdvector<func_instance *> matchingFuncs;
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());
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());
1838 for (unsigned funcIter = 0; funcIter < matchingFuncs.size(); funcIter++) {
1839 func_instance *func = matchingFuncs[funcIter];
1841 inst_printf("%s[%d]: null int_func detected\n",
1843 continue; // probably should have a flag telling us whether errors
1846 inst_printf("%s[%d]: Instrumenting %s at 0x%lx, offset 0x%lx in %s\n",
1848 func->symTabName().c_str(),
1850 func->addr() - func->obj()->codeBase(),
1851 func->obj()->fullName().c_str());
1853 // should be silently handled or not
1855 if ((req->where & FUNC_ARG) && req->args.size()>0) {
1856 ast = AstNode::funcCallNode(req->inst,
1861 pdvector<AstNodePtr> def_args;
1862 def_args.push_back(AstNode::operandNode(AstNode::Constant,
1864 ast = AstNode::funcCallNode(req->inst,
1867 // We mask to strip off the FUNC_ARG bit...
1868 std::vector<Point *> points;
1869 switch ( ( req->where & 0x7) ) {
1871 mgr()->findPoints(Dyninst::PatchAPI::Scope(func),
1873 std::back_inserter(points));
1876 mgr()->findPoints(Dyninst::PatchAPI::Scope(func),
1878 std::back_inserter(points));
1881 mgr()->findPoints(Dyninst::PatchAPI::Scope(func),
1883 std::back_inserter(points));
1886 fprintf(stderr, "Unknown where: %d\n",
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);
1897 if (!req->useTrampGuard) inst->disableRecursiveGuard();
1898 req->instances.push_back(inst);
1901 fprintf(stderr, "%s[%d]: failed to addInst here\n", FILE__, __LINE__);
1903 } } // matchingFuncs
1910 static const unsigned MAX_IRPC_SIZE = 0x100000;
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)
1917 return postIRPC_internal(buffer,
1931 bool PCProcess::postIRPC(AstNodePtr action, void *userData,
1932 bool runProcessWhenDone, PCThread *thread, bool synchronous,
1933 void **result, bool userRPC, bool isMemAlloc, Address addr)
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);
1942 #if defined(bug_syscall_changepc_rewind)
1943 // Reported by SGI, during attach to a process in a system call:
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).
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);
1958 irpcTramp_->setIRPCAST(action);
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",
1967 Register resultReg = REG_NULL;
1968 if( !action->generateCode(irpcBuf, false, resultReg) ) {
1969 proccontrol_printf("%s[%d]: failed to generate code from AST\n",
1974 // Note: we should not do a corresponding baseTramp restore here:
1975 // 1) It isn't necessary because ProcControl will restore the
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
1980 // Emit the trailer for the iRPC
1982 // breakOffset: where the irpc ends
1983 unsigned breakOffset = irpcBuf.used();
1984 insnCodeGen::generateTrap(irpcBuf);
1985 insnCodeGen::generateTrap(irpcBuf);
1987 irpcBuf.endTrackRegDefs();
1989 return postIRPC_internal(irpcBuf.start_ptr(),
2004 #include "instructionAPI/h/InstructionDecoder.h"
2006 bool PCProcess::postIRPC_internal(void *buf,
2008 unsigned breakOffset,
2012 bool runProcessWhenDone,
2018 if( isTerminated() ) {
2019 proccontrol_printf("%s[%d]: cannot post RPC to exited or terminated process %d\n",
2020 FILE__, __LINE__, getpid());
2024 if( thread && !thread->isLive() ) {
2025 proccontrol_printf("%s[%d]: attempted to post RPC to dead thread %d\n",
2026 FILE__, __LINE__, thread->getLWP());
2031 inferiorRPCinProgress *newRPC = new inferiorRPCinProgress;
2032 newRPC->runProcWhenDone = runProcessWhenDone;
2033 newRPC->deliverCallbacks = userRPC;
2034 newRPC->userData = userData;
2035 newRPC->synchronous = synchronous;
2037 newRPC->resultRegister = resultReg;
2039 // Create the iRPC at the ProcControl level
2043 // This assumes that there will always be space
2044 addr = inferiorMalloc(size, lowmemHeap, 0, &err);
2046 // recursive RPCs are okay when this isn't an inferiorMalloc RPC
2047 addr = inferiorMalloc(size, anyHeap, 0, &err);
2051 proccontrol_printf("%s[%d]: failed to allocate memory for RPC\n",
2056 newRPC->memoryAllocated = true;
2060 newRPC->rpc = IRPC::createIRPC(buf, size, addr);
2062 newRPC->rpc = IRPC::createIRPC(buf, size);
2066 InstructionAPI::InstructionDecoder d(buf,size,getArch());
2068 InstructionAPI::Instruction::Ptr insn = d.decode();
2070 cerr << "\t" << hex << foo << ": " << insn->format(foo) << dec << endl;
2071 foo += insn->size();
2075 newRPC->rpc->setData(newRPC);
2077 unsigned int start_offset = 0;
2078 #if defined(bug_syscall_changepc_rewind)
2079 // Some Linux kernels have the following behavior:
2080 // Process is in a system call;
2081 // We interrupt the system call;
2082 // We say "change PC to address N"
2083 // The kernel helpfully changes it to (N - address width)
2084 // The program crashes
2085 // See a more complete comment above.
2086 // For now, we pad the start of our code with NOOPS and change to just
2087 // after those; if we hit rewind behavior, then we're executing safe code.
2089 // Matt Note: The above comment is slightly incorrect. The kernel subracts
2090 // the length of the syscall/int instruction that triggered the system call,
2091 // not the address width. Still address width is big enough, so I'm not
2092 // changing anything.
2093 start_offset = proc()->getAddressWidth();
2094 newRPC->rpcStartAddr += start_offset;
2096 newRPC->rpc->setStartOffset(start_offset);
2097 newRPC->rpcCompletionAddr = addr + breakOffset;
2102 t = thread->pcThr();
2107 proccontrol_printf("%s[%d]: Launching IRPC\n", FILE__, __LINE__);
2109 // We have an interesting problem here. ProcControl allows callbacks to specify whether the
2110 // process should stop or run; however, that allows us to stop a process in the middle of an
2111 // inferior RPC. If that happens, manually execute a continue and wait for completion ourselves.
2113 res = t->runIRPCSync(newRPC->rpc);
2115 res = pcProc_->runIRPCSync(newRPC->rpc);
2119 proccontrol_printf("%s[%d]: Iterating in loop waiting for IRPC to complete\n", FILE__, __LINE__);
2120 if (isTerminated()) {
2121 fprintf(stderr, "IRPC on terminated process, ret false!\n");
2126 if (ProcControlAPI::getLastError() != ProcControlAPI::err_notrunning) {
2127 // Something went wrong
2128 proccontrol_printf("%s[%d]: failed to post %s RPC to %s, error %s\n",
2129 FILE__, __LINE__, (synchronous ? "sync" : "async"),
2130 ((thread == NULL) ? "thread" : "process"),
2131 ProcControlAPI::getLastErrorMsg());
2136 proccontrol_printf("%s[%d]: ProcControl reported IRPC thread stopped, continuing and consuming events\n", FILE__, __LINE__);
2137 newRPC->rpc->continueStoppedIRPC();
2138 proccontrol_printf("%s[%d]: handling events in ProcControl\n", FILE__, __LINE__);
2139 res = pcProc_->handleEvents(true);
2140 PCEventMuxer::muxer().handle(NULL);
2141 if (newRPC->rpc->state() == ProcControlAPI::IRPC::Done) {
2142 proccontrol_printf("%s[%d]: IRPC complete\n", FILE__, __LINE__);
2151 res = t->runIRPCAsync(newRPC->rpc);
2153 res = pcProc_->runIRPCAsync(newRPC->rpc);
2156 proccontrol_printf("%s[%d]: failed to post %s RPC to %s\n",
2157 FILE__, __LINE__, (synchronous ? "sync" : "async"), ((thread == NULL) ? "thread" : "process"));
2163 *result = newRPC->returnValue;
2166 // Make sure Dyninst has worked everything out
2167 PCEventMuxer::muxer().wait(false);
2173 BPatch_hybridMode PCProcess::getHybridMode() {
2174 return BPatch_normalMode;
2177 bool PCProcess::isExploratoryModeOn() const {
2178 return BPatch_exploratoryMode == analysisMode_ ||
2179 BPatch_defensiveMode == analysisMode_;
2182 bool PCProcess::isRuntimeHeapAddr(Address addr) const {
2183 for (unsigned hidx=0; hidx < dyninstRT_heaps_.size(); hidx++) {
2184 if (addr >= dyninstRT_heaps_[hidx]->addr &&
2185 addr < dyninstRT_heaps_[hidx]->addr + dyninstRT_heaps_[hidx]->length) {
2192 /* returns true if blocks were overwritten, initializes overwritten
2193 * blocks and ranges by contrasting shadow pages with current memory
2195 * 1. reads shadow pages in from memory
2196 * 2. constructs overwritten region list
2197 * 3. constructs overwrittn basic block list
2198 * 4. determines if the last of the blocks has an abrupt end, in which
2199 * case it marks it as overwritten
2201 bool PCProcess::getOverwrittenBlocks
2202 ( std::map<Address, unsigned char *>& overwrittenPages,//input
2203 std::list<std::pair<Address,Address> >& overwrittenRanges,//output
2204 std::list<block_instance *> &writtenBBIs)//output
2206 const unsigned MEM_PAGE_SIZE = getMemoryPageSize();
2207 unsigned char * memVersion = (unsigned char *) ::malloc(MEM_PAGE_SIZE);
2208 Address regionStart = 0;
2209 bool foundStart = false;
2210 map<Address, unsigned char*>::iterator pIter = overwrittenPages.begin();
2211 set<mapped_object*> owObjs;
2212 for (; pIter != overwrittenPages.end(); pIter++) {
2213 Address curPageAddr = (*pIter).first / MEM_PAGE_SIZE * MEM_PAGE_SIZE;
2214 unsigned char *curShadow = (*pIter).second;
2216 // 0. check to make sure curShadow is non-null, if it is null,
2217 // that means it hasn't been written to
2218 if ( ! curShadow ) {
2219 cerr << "\t\t No current shadow, continuing" << endl;
2223 mapped_object* obj = findObject(curPageAddr);
2224 if (owObjs.end() != owObjs.find(obj)) {
2225 obj->setCodeBytesUpdated(false);
2228 // 1. Read the modified page in from memory
2229 Address readAddr = curPageAddr;
2230 if (isMemoryEmulated()) {
2232 boost::tie(valid,readAddr) = getMemEm()->translate(curPageAddr);
2233 cerr << "\t\t Reading from shadow page " << hex << readAddr << " instead of original " << curPageAddr << endl;
2236 readTextSpace((void*)readAddr, MEM_PAGE_SIZE, memVersion);
2238 // 2. build overwritten region list by comparing shadow, memory
2239 for (unsigned mIdx = 0; mIdx < MEM_PAGE_SIZE; mIdx++) {
2240 if ( ! foundStart && curShadow[mIdx] != memVersion[mIdx] ) {
2242 regionStart = curPageAddr+mIdx;
2243 } else if (foundStart && curShadow[mIdx] == memVersion[mIdx]) {
2245 cerr << "\t\t Adding overwritten range " << hex << regionStart << " -> " << curPageAddr + mIdx << dec << endl;
2247 overwrittenRanges.push_back(
2248 pair<Address,Address>(regionStart,curPageAddr+mIdx));
2254 cerr << "\t\t Adding overwritten range " << hex << regionStart << " -> " << curPageAddr + MEM_PAGE_SIZE << dec << endl;
2256 overwrittenRanges.push_back(
2257 pair<Address,Address>(regionStart,curPageAddr+MEM_PAGE_SIZE));
2261 // 3. Determine which basic blocks have been overwritten
2262 list<pair<Address,Address> >::const_iterator rIter = overwrittenRanges.begin();
2263 std::list<block_instance*> curBBIs;
2264 while (rIter != overwrittenRanges.end()) {
2265 mapped_object *curObject = findObject((*rIter).first);
2267 curObject->findBlocksByRange((*rIter).first,(*rIter).second,curBBIs);
2268 if (curBBIs.size()) {
2269 mal_printf("overwrote %d blocks in range %lx %lx \n",
2270 curBBIs.size(),(*rIter).first,(*rIter).second);
2271 writtenBBIs.splice(writtenBBIs.end(), curBBIs);
2279 if (writtenBBIs.size()) {
2286 // distribute the work to mapped_objects
2287 void PCProcess::updateCodeBytes
2288 ( const list<pair<Address, Address> > &owRanges ) // input
2290 std::map<mapped_object *,list<pair<Address,Address> >*> objRanges;
2291 list<pair<Address,Address> >::const_iterator rIter = owRanges.begin();
2292 for (; rIter != owRanges.end(); rIter++) {
2293 mapped_object *obj = findObject((*rIter).first);
2294 if (objRanges.find(obj) == objRanges.end()) {
2295 objRanges[obj] = new list<pair<Address,Address> >();
2297 objRanges[obj]->push_back(pair<Address,Address>(rIter->first, rIter->second));
2300 std::map<mapped_object *,list<pair<Address,Address> > *>::iterator oIter =
2302 for (; oIter != objRanges.end(); oIter++)
2304 oIter->first->updateCodeBytes( *(oIter->second) );
2305 delete (oIter->second);
2307 assert(objRanges.size() <= 1); //o/w analysis code may not be prepared for other cases
2311 static void otherFuncBlocks(func_instance *func,
2312 const set<block_instance*> &blks,
2313 set<block_instance*> &otherBlks)
2315 const func_instance::BlockSet &allBlocks =
2317 for (func_instance::BlockSet::const_iterator bit =
2319 bit != allBlocks.end();
2322 if (blks.end() == blks.find((*bit))) {
2323 otherBlks.insert((*bit));
2330 * Given a list of overwritten blocks, find blocks that are unreachable,
2331 * functions that have been overwritten at their entry points and can go away,
2332 * and new function entry for functions that are being overwritten while still
2336 * f: the overwritten function
2337 * ow: the set of overwritten blocks
2338 * ex: the set of blocks that are executing on the call stack that were not overwritten
2341 * R(b,s): yields set of reachable blocks for collection of blocks b, starting
2343 * B(f): the blocks pertaining to function f
2344 * EP(f): the entry point of function f
2345 * F(b): functions containing block b
2348 * Elim(f): the set of blocks to eliminate from function f.
2349 * Elim(f) = B(f) - R( B(f)-ow , EP(f) )
2350 * New(f): new function entry candidates for f's surviving blocks.
2351 * If EB(f) not in ow(f), empty set
2352 * Else, all blocks b such that ( b in ex AND e in Elim(f) )
2353 * Eliminate New(f) elements that have ancestors in New(f)
2354 * Del(f): A block can be deleted altogether if
2355 * forall f in F(b): B(F) - R( B(f) - ow , New(f) U (EP(f) \ ow(f)) U (ex(f) intersect Elim(f)) ),
2356 * b is not in the resulting set. In other words, b is not
2357 * reachable from non-overwritten blocks in the functions in
2358 * which it appears, seeded at new entry points and original
2359 * non-overwritten entry points to the function, and at f's
2360 * executing blocks if these will be deleted from the
2361 * function (they constitute an entry point into the function
2362 * even if they've been overwritten).
2363 * DeadF: the set of functions that have no executing blocks
2364 * and were overwritten in their entry blocks
2365 * EP(f) in ow(f) AND ex(f) is empty
2367 bool PCProcess::getDeadCode
2368 ( const std::list<block_instance*> & /*owBlocks*/, // input
2369 std::set<block_instance*> & /*delBlocks*/, //output: Del(for all f)
2370 std::map<func_instance*,set<block_instance*> > & /*elimMap*/, //output: elimF
2371 std::list<func_instance*> & /*deadFuncs*/, //output: DeadF
2372 std::map<func_instance*,block_instance*> & /*newFuncEntries*/) //output: newF
2374 assert(0 && "TODO");
2377 // do a stackwalk to see which functions are currently executing
2378 pdvector<pdvector<Frame> > stacks;
2379 pdvector<Address> pcs;
2380 if (!walkStacks(stacks)) {
2381 inst_printf("%s[%d]: walkStacks failed\n", FILE__, __LINE__);
2384 for (unsigned i = 0; i < stacks.size(); ++i) {
2385 pdvector<Frame> &stack = stacks[i];
2386 for (unsigned int j = 0; j < stack.size(); ++j) {
2388 vector<func_instance*> dontcare1;
2389 baseTramp *dontcare2 = NULL;
2390 getAddrInfo(stack[j].getPC(), origPC, dontcare1, dontcare2);
2391 pcs.push_back( origPC );
2395 // group blocks by function
2396 std::map<func_instance*,set<block_instance*> > deadMap;
2397 std::set<func_instance*> deadEntryFuncs;
2398 std::set<Address> owBlockAddrs;
2399 for (list<block_instance*>::const_iterator bIter=owBlocks.begin();
2400 bIter != owBlocks.end();
2403 deadMap[(*bIter)->func()].insert(*bIter);
2404 owBlockAddrs.insert((*bIter)->start());
2405 if ((*bIter)->llb() == (*bIter)->func()->ifunc()->entry()) {
2406 deadEntryFuncs.insert((*bIter)->func());
2410 // for each modified function, calculate ex, ElimF, NewF, DelF
2411 for (map<func_instance*,set<block_instance*> >::iterator fit = deadMap.begin();
2412 fit != deadMap.end();
2417 set<block_instance*> execBlocks;
2418 for (unsigned pidx=0; pidx < pcs.size(); pidx++) {
2419 std::set<block_instance *> candidateBlocks;
2420 fit->first->findBlocksByAddr(pcs[pidx], candidateBlocks);
2421 for (std::set<block_instance *>::iterator cb_iter = candidateBlocks.begin();
2422 cb_iter != candidateBlocks.end(); ++cb_iter) {
2423 block_instance *exB = *cb_iter;
2424 if (exB && owBlockAddrs.end() == owBlockAddrs.find(
2427 execBlocks.insert(exB);
2432 // calculate DeadF: EP(f) in ow and EP(f) not in ex
2433 if ( 0 == execBlocks.size() ) {
2434 set<block_instance*>::iterator eb = fit->second.find(
2435 fit->first->entryBlock());
2436 if (eb != fit->second.end()) {
2437 deadFuncs.push_back(fit->first);
2438 continue;// treated specially, don't need elimF, NewF or DelF
2443 set<block_instance*> keepF;
2444 list<block_instance*> seedBs;
2445 seedBs.push_back(fit->first->entryBlock());
2446 fit->first->getReachableBlocks(fit->second, seedBs, keepF);
2447 otherFuncBlocks(fit->first, keepF, elimMap[fit->first]);
2450 if (deadEntryFuncs.end() != deadEntryFuncs.find(fit->first)) {
2451 for (set<block_instance*>::iterator bit = execBlocks.begin();
2452 bit != execBlocks.end();
2455 if (elimMap[fit->first].end() !=
2456 elimMap[fit->first].find(*bit))
2458 newFuncEntries[fit->first] = *bit;
2459 break; // just need one candidate
2466 if (deadEntryFuncs.end() == deadEntryFuncs.find(fit->first)) {
2467 seedBs.push_back(fit->first->entryBlock());
2469 else if (newFuncEntries.end() != newFuncEntries.find(fit->first)) {
2470 seedBs.push_back(newFuncEntries[fit->first]);
2472 for (set<block_instance*>::iterator xit = execBlocks.begin();
2473 xit != execBlocks.end();
2476 if (elimMap[fit->first].end() != elimMap[fit->first].find(*xit)) {
2477 seedBs.push_back(*xit);
2481 fit->first->getReachableBlocks(fit->second, seedBs, keepF);
2482 otherFuncBlocks(fit->first, keepF, delBlocks);
2490 // will flush addresses of all addresses in the specified range, if the
2491 // range is null, flush all addresses from the cache. Also flush
2492 // rt-lib heap addrs that correspond to the range
2493 void PCProcess::flushAddressCache_RT(Address start, unsigned size)
2496 mal_printf("Flushing address cache of range [%lx %lx]\n",
2500 mal_printf("Flushing address cache of rt_lib heap addrs only \n");
2503 // Find the runtime cache's address if it hasn't been set yet
2504 if (0 == RT_address_cache_addr_) {
2505 std::string arg_str ("DYNINST_target_cache");
2506 pdvector<int_variable *> vars;
2507 if ( ! findVarsByAll(arg_str, vars) ) {
2508 fprintf(stderr, "%s[%d]: cannot find var %s\n",
2509 FILE__, __LINE__, arg_str.c_str());
2512 if (vars.size() != 1) {
2513 fprintf(stderr, "%s[%d]: ERROR: %d vars matching %s, not 1\n",
2514 FILE__, __LINE__, (int)vars.size(), arg_str.c_str());
2517 RT_address_cache_addr_ = vars[0]->getAddress();
2520 // Clear all cache entries that match the runtime library
2521 // Read in the contents of the cache
2522 Address* cacheCopy = (Address*)malloc(TARGET_CACHE_WIDTH*sizeof(Address));
2523 if ( ! readDataSpace( (void*)RT_address_cache_addr_,
2524 sizeof(Address)*TARGET_CACHE_WIDTH,(void*)cacheCopy,
2530 assert(dyninstRT_heaps_.size());
2531 bool flushedHeaps = false;
2533 while ( true ) // iterate twice, once to flush the heaps,
2534 { // and once to flush the flush range
2535 Address flushStart=0;
2537 if (!flushedHeaps) {
2538 // figure out the range of addresses we'll want to flush from
2540 flushStart = dyninstRT_heaps_[0]->addr;
2541 flushEnd = flushStart + dyninstRT_heaps_[0]->length;
2542 for (unsigned idx=1; idx < dyninstRT_heaps_.size(); idx++) {
2543 Address curAddr = dyninstRT_heaps_[idx]->addr;
2544 if (flushStart > curAddr) {
2545 flushStart = curAddr;
2547 curAddr += dyninstRT_heaps_[idx]->length;
2548 if (flushEnd < curAddr) {
2554 flushEnd = start + size;
2556 //zero out entries that lie in the runtime heaps
2557 for(int idx=0; idx < TARGET_CACHE_WIDTH; idx++) {
2558 //printf("cacheCopy[%d]=%lx\n",idx,cacheCopy[idx]);
2559 if (flushStart <= cacheCopy[idx] &&
2560 flushEnd > cacheCopy[idx]) {
2564 if ( flushedHeaps || (start == 0) ) {
2567 flushedHeaps = true;
2570 // write the modified cache back into the RT_library
2571 if ( ! writeDataSpace( (void*)RT_address_cache_addr_,
2572 sizeof(Address)*TARGET_CACHE_WIDTH,
2573 (void*)cacheCopy ) ) {
2579 /* Given an address that's on the call stack, find the function that's
2580 * actively executing that address. This makes most sense for finding the
2581 * address that's triggered a context switch back to Dyninst, either
2582 * through instrumentation or a signal
2584 func_instance *PCProcess::findActiveFuncByAddr(Address addr)
2586 std::set<func_instance *> funcs;
2587 // error checking by size...
2588 (void)findFuncsByAddr(addr, funcs, true);
2589 if (funcs.empty()) return NULL;
2591 if (funcs.size() == 1) {
2592 return *(funcs.begin());
2595 // unrelocated shared function address, do a stack walk to figure
2596 // out which of the shared functions is on the call stack
2597 bool foundFrame = false;
2598 func_instance *activeFunc = NULL;
2599 pdvector<pdvector<Frame> > stacks;
2600 if ( false == walkStacks(stacks) ) {
2601 fprintf(stderr,"ERROR: %s[%d], walkStacks failed\n",
2605 for (unsigned int i = 0; !foundFrame && i < stacks.size(); ++i) {
2606 pdvector<Frame> &stack = stacks[i];
2607 for (unsigned int j = 0; !foundFrame && j < stack.size(); ++j) {
2608 Frame *curFrame = &stack[j];
2609 Address framePC = curFrame->getPC();
2611 // if we're at a relocated address, we can translate
2612 // back to the right function, if translation fails
2613 // frameFunc will still be NULL
2615 func_instance *frameFunc = NULL;
2617 if (getRelocInfo(framePC, ri) &&
2619 frameFunc = ri.func;
2621 else if (j < (stack.size() - 1)) {
2622 // Okay, crawl original code.
2623 // Step 1: get our current function
2624 std::set<func_instance *> curFuncs;
2625 findFuncsByAddr(framePC, curFuncs);
2626 // Step 2: get return addresses one frame up and map to possible callers
2627 std::set<block_instance *> callerBlocks;
2628 findBlocksByAddr(stack[j+1].getPC() - 1, callerBlocks);
2629 for (std::set<block_instance *>::iterator cb_iter = callerBlocks.begin();
2630 cb_iter != callerBlocks.end(); ++cb_iter)
2632 if (!(*cb_iter)->containsCall()) continue;
2633 // We have a call point; now see if it called the entry of any function
2634 // that maps to a curFunc.
2635 for (std::set<func_instance *>::iterator cf_iter = curFuncs.begin();
2636 cf_iter != curFuncs.end(); ++cf_iter) {
2637 if ((*cf_iter) == (*cb_iter)->callee()) {
2638 frameFunc = *cf_iter;
2645 activeFunc = frameFunc;
2650 activeFunc = *(funcs.begin());
2656 bool PCProcess::patchPostCallArea(instPoint *callPt) {
2657 // 1) Find all the post-call patch areas that correspond to this
2659 // 2) Generate and install the branches that will be inserted into
2660 // these patch areas
2663 AddrPairSet patchAreas;
2664 if ( ! generateRequiredPatches(callPt, patchAreas) ) {
2669 generatePatchBranches(patchAreas);
2673 bool PCProcess::generateRequiredPatches(instPoint *callPoint,
2674 AddrPairSet &patchAreas)
2676 // We need to figure out where this patch should branch to.
2677 // To do that, we're going to:
2678 // 1) Forward map the entry of the ft block to
2679 // its most recent relocated version (if that exists)
2680 // 2) For each padding area, create a (padAddr,target) pair
2684 block_instance *callB = callPoint->block();
2685 block_instance *ftBlk = callB->getFallthrough()->trg();
2687 // find the block at the next address, if there's no fallthrough block
2688 ftBlk = callB->obj()->findBlockByEntry(callB->end());
2692 // ensure that we patch other callPts at the same address
2694 vector<ParseAPI::Function*> callFuncs;
2695 callPoint->block()->llb()->getFuncs(callFuncs);
2696 for (vector<ParseAPI::Function*>::iterator fit = callFuncs.begin();
2697 fit != callFuncs.end();
2700 func_instance *callF = findFunction((parse_func*)*fit);
2701 instPoint *callP = instPoint::preCall(callF, callB);
2702 Relocation::CodeTracker::RelocatedElements reloc;
2703 CodeTrackers::reverse_iterator rit;
2704 for (rit = relocatedCode_.rbegin(); rit != relocatedCode_.rend(); rit++)
2706 if ((*rit)->origToReloc(ftBlk->start(), ftBlk, callF, reloc)) {
2710 if (rit == relocatedCode_.rend()) {
2711 mal_printf("WARNING: no relocs of call-fallthrough at %lx "
2712 "in func at %lx, will not patch its post-call "
2713 "padding\n", callP->block()->last(),callF->addr());
2714 (*relocatedCode_.rbegin())->debug();
2718 Address to = reloc.instruction;
2719 if (!reloc.instrumentation.empty()) {
2720 // There could be a lot of instrumentation at this point. Bias towards the lowest,
2721 // non-edge instrumentation
2722 for (std::map<instPoint *, Address>::iterator inst_iter = reloc.instrumentation.begin();
2723 inst_iter != reloc.instrumentation.end(); ++inst_iter) {
2724 if (inst_iter->first->type() == PatchAPI::Point::EdgeDuring) continue;
2725 to = (inst_iter->second < to) ? inst_iter->second : to;
2730 Address callInsnAddr = callP->block()->last();
2731 if (forwardDefensiveMap_.end() != forwardDefensiveMap_.find(callInsnAddr)) {
2732 map<func_instance*,set<DefensivePad> >::iterator mit = forwardDefensiveMap_[callInsnAddr].begin();
2733 for (; mit != forwardDefensiveMap_[callInsnAddr].end(); ++mit) {
2734 if (callF == mit->first) {
2735 set<DefensivePad>::iterator dit = mit->second.begin();
2736 for (; dit != mit->second.end(); ++dit) {
2737 Address jumpAddr = dit->first;
2738 patchAreas.insert(std::make_pair(jumpAddr, to));
2739 mal_printf("patching post-call pad for %lx[%lx] with %lx %s[%d]\n",
2740 callB->end(), jumpAddr, to, FILE__,__LINE__);
2746 if (patchAreas.empty()) {
2747 mal_printf("WARNING: no relocs to patch for call at %lx, block end %lx\n",
2748 callPoint->addr_compat(),ftBlk->start());
2750 return ! patchAreas.empty();
2753 void PCProcess::generatePatchBranches(AddrPairSet &branchesNeeded) {
2754 for (AddrPairSet::iterator iter = branchesNeeded.begin();
2755 iter != branchesNeeded.end(); ++iter)
2757 Address from = iter->first;
2758 Address to = iter->second;
2761 insnCodeGen::generateBranch(gen, from, to);
2763 // Safety check: make sure we didn't overrun the patch area
2764 Address lb = 0, ub = 0;
2765 std::pair<func_instance*,Address> tmp;
2766 if (!reverseDefensiveMap_.find(from, lb, ub, tmp)) {
2767 // Huh? This worked before!
2770 assert((from + gen.used()) <= ub);
2771 if (!writeTextSpace((void *)from,
2779 /* debugSuicide is a kind of alternate debugging continueProc. It runs the
2780 * process until terminated in single step mode, printing each instruction as
2783 void PCProcess::debugSuicide() {
2784 if( isTerminated() ) return;
2786 isInDebugSuicide_ = true;
2788 pdvector<Frame> activeFrames;
2789 getAllActiveFrames(activeFrames);
2791 for(unsigned i=0; i < activeFrames.size(); ++i) {
2792 Address addr = activeFrames[i].getPC();
2793 fprintf(stderr, "Frame %u @ 0x%lx\n", i , addr);
2796 Thread::ptr initialThread = pcProc_->threads().getInitialThread();
2798 initialThread->setSingleStepMode(true);
2799 while( !isTerminated() && isAttached() && initialThread->isLive() ) {
2800 // Get the current PC
2801 MachRegister pcReg = MachRegister::getPC(getArch());
2802 MachRegisterVal resultVal;
2803 if( !initialThread->getRegister(pcReg, resultVal) ) {
2804 fprintf(stderr, "%s[%d]: failed to retreive register from thread %d/%d\n",
2805 FILE__, __LINE__, getPid(), initialThread->getLWP());
2811 pdvector<func_instance *> PCProcess::pcsToFuncs(pdvector<Frame> stackWalk) {
2812 pdvector <func_instance *> ret;
2815 for(i=0;i<stackWalk.size();i++) {
2816 fn = (func_instance *)findOneFuncByAddr(stackWalk[i].getPC());
2817 // no reason to add a null function to ret
2818 if (fn != 0) ret.push_back(fn);
2823 bool PCProcess::isInSignalHandler(Address addr) {
2825 if( signalHandlerLocations_.find(addr, range) ) {
2832 void PCProcess::addSignalHandler(Address addr, unsigned size) {
2833 codeRange *handlerLoc;
2834 if (signalHandlerLocations_.find(addr, handlerLoc)) {
2835 return; // we're already tracking this location
2837 handlerLoc = new signal_handler_location(addr, size);
2838 signalHandlerLocations_.insert((signal_handler_location *)handlerLoc);
2841 bool PCProcess::mappedObjIsDeleted(mapped_object *obj) {
2842 for(unsigned i = 0; i < deletedObjects_.size(); ++i) {
2843 if( obj == deletedObjects_[i] ) return true;
2849 // AddressSpace Implementation //
2850 Address PCProcess::offset() const {
2851 assert(!"This function is not implemented");
2855 Address PCProcess::length() const {
2856 assert(!"This function is not implemented");
2860 Architecture PCProcess::getArch() const {
2864 bool PCProcess::multithread_ready(bool ignoreIfMtNotSet) {
2865 // Since ProcControlAPI has taken over handling thread creation
2866 // and destruction from the RT library, as soon as the process reaches
2867 // the initialized state, the process is multithread ready if it
2868 // is multithread capable.
2870 if( !hasReachedBootstrapState(bs_initialized) ) return false;
2871 if( !multithread_capable(ignoreIfMtNotSet) ) return false;
2876 bool PCProcess::needsPIC() {
2880 bool PCProcess::isInDebugSuicide() const {
2881 return isInDebugSuicide_;
2884 PCProcess::processState_t PCProcess::getDesiredProcessState() const {
2885 return processState_;
2888 void PCProcess::setDesiredProcessState(PCProcess::processState_t pc) {
2892 bool PCProcess::walkStack(pdvector<Frame> &stackWalk,
2895 if( stackwalker_ == NULL ) return false;
2897 vector<Dyninst::Stackwalker::Frame> swWalk;
2899 if (!stackwalker_->walkStack(swWalk, thread->getLWP()))
2904 for (vector<Dyninst::Stackwalker::Frame>::iterator SWB = swWalk.begin(),
2910 stackWalk.push_back(Frame(*SWI, this, thread, (SWI == SWB)));
2916 bool PCProcess::getActiveFrame(Frame &frame, PCThread *thread)
2918 Dyninst::Stackwalker::Frame swFrame;
2919 if (!stackwalker_->getInitialFrame(swFrame, thread->getLWP()))
2924 frame = Frame(swFrame, this, thread, true);
2928 /* This is the simple version
2929 * 1. Need three pieces of information:
2930 * 1a. The instrumentation point that triggered the stopThread event (pointAddress)
2931 * 1b. The ID of the callback function given at the registration
2932 * of the stopThread snippet
2933 * 1c. The result of the snippet calculation that was given by the user,
2934 * if the point is a return instruction, read the return address
2935 * 2. If the calculation is an address that is meant to be interpreted, do that
2936 * 3. Invoke the callback
2938 bool PCProcess::triggerStopThread(Address pointAddress, int callbackID, void *calculation) {
2939 AddressSpace::RelocInfo ri;
2940 if( !getRelocInfo(pointAddress, ri) ) {
2945 // get instPoint from point address
2946 func_instance *pointfunc = ri.func;
2948 mal_printf("%s[%d]: failed to find active function at 0x%lx\n",
2949 FILE__, __LINE__, pointAddress);
2953 instPoint *intPoint = ri.bt->point();
2955 mal_printf("%s[%d]: failed to find inst point at 0x%lx\n",
2956 FILE__, __LINE__, pointAddress);
2960 mal_printf("handling stopThread %lx[%lx]=>%lx %s[%d]\n",
2961 ri.reloc, pointAddress, (long)calculation, FILE__, __LINE__);
2963 /* 2. If the callbackID is negative, the calculation is meant to be
2964 interpreted as the address of code, so we call stopThreadCtrlTransfer
2965 to translate the target to an unrelocated address */
2966 if (callbackID < 0) {
2968 calculation = (void*)
2969 stopThreadCtrlTransfer(intPoint, (Address)calculation);
2972 /* 3. Trigger the callback for the stopThread
2973 using the correct snippet instance ID & event type */
2974 ((BPatch_process*)up_ptr())->triggerStopThread
2975 (intPoint, pointfunc, callbackID, (void*)calculation);
2980 /* If calculation is a relocated address, translate it to the original addr
2981 * case 1: The point is at a return instruction
2982 * case 2: The point is a control transfer into the runtime library
2983 * Mark returning functions as returning
2984 * Save the targets of indirect control transfers (not regular returns)
2986 Address PCProcess::stopThreadCtrlTransfer (instPoint* intPoint,
2989 Address pointAddr = intPoint->addr_compat();
2991 // if the point is a real return instruction and its target is a stack
2992 // address, get the return address off of the stack
2993 if (intPoint->type() == instPoint::FuncExit &&
2994 intPoint->block()->isFuncExit() &&
2995 !intPoint->func()->isSignalHandler())
2997 mal_printf("%s[%d]: return address is %lx\n", FILE__,
3001 Address unrelocTarget = target;
3003 if ( isRuntimeHeapAddr( target ) ) {
3004 // get unrelocated target address, there are three possibilities
3005 // a. We're in post-call padding, and targBBI is the call block
3006 // b. We're in an analyzed fallthrough block
3007 // c. The stack was tampered with and we need the (mod_pc - pc)
3008 // offset to figure out where we should be
3009 malware_cerr << "Looking for matches to incoming address "
3010 << hex << target << dec << endl;
3011 std::pair<func_instance*,Address> tmp;
3013 if ( reverseDefensiveMap_.find(target,tmp) ) {
3015 std::set<block_instance*> callBs;
3016 tmp.first->getBlocks(tmp.second, callBs);
3017 block_instance *callB = (*callBs.begin());
3018 edge_instance *fallthrough = callB->getFallthrough();
3020 unrelocTarget = fallthrough->trg()->start();
3022 unrelocTarget = callB->end();
3027 // if we're in the fallthrough block, match to call block,
3028 // and if necessary, add fallthrough edge
3029 AddressSpace::RelocInfo ri;
3030 bool hasFT = getRelocInfo(target, ri);
3031 assert(hasFT); // otherwise we should be in the defensive map
3033 unrelocTarget = ri.block->end();
3035 unrelocTarget = ri.block->start();
3038 mal_printf("translated target %lx to %lx %s[%d]\n",
3039 target, unrelocTarget, FILE__, __LINE__);
3041 else { // target is not relocated, nothing to do but find the
3042 // mapped_object, creating one if necessary, for transfers
3043 // into memory regions that are allocated at runtime
3044 mapped_object *obj = findObject(target);
3048 Frame activeFrame = threads[0]->get_lwp()->getActiveFrame();
3049 for (unsigned i = 0; i < 0x100; ++i) {
3050 Address stackTOP = activeFrame.esp;
3051 Address stackTOPVAL =0;
3052 readDataSpace((void *) (stackTOP + 4*i),
3053 sizeof(getAddressWidth()),
3054 &stackTOPVAL, false);
3055 malware_cerr << "\tSTACK[" << hex << stackTOP+4*i << "]="
3056 << stackTOPVAL << dec << endl;
3060 obj = createObjectNoFile(target);
3062 fprintf(stderr,"ERROR, point %lx has target %lx that responds "
3063 "to no object %s[%d]\n", pointAddr, target,
3065 assert(0 && "stopThread snippet has an invalid target");
3072 Frame activeFrame = threads[0]->get_lwp()->getActiveFrame();
3073 Address stackTOP = activeFrame.esp;
3074 Address stackTOPVAL =0;
3075 for (unsigned i = 0;
3076 i < 0x100 && 0 != ((stackTOP + 4*i) % memoryPageSize_);
3079 readDataSpace((void *) (stackTOP + 4*i),
3080 sizeof(getAddressWidth()),
3081 &stackTOPVAL, false);
3082 malware_cerr << "\tSTACK[" << hex << stackTOP+4*i << "]="
3083 << stackTOPVAL << dec << endl;
3087 return unrelocTarget;
3090 void PCProcess::triggerNormalExit(int exitcode) {
3091 for(std::map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
3092 i != threadsByTid_.end(); ++i)
3094 if( i->second != initialThread_ )
3095 BPatch::bpatch->registerThreadExit(this, i->second);
3097 BPatch::bpatch->registerNormalExit(this, exitcode);
3099 // Let the event handler know that the process should be moved to
3105 bool PCProcess::setBreakpoint(Address addr) {
3106 Breakpoint::ptr brkPt = Breakpoint::newBreakpoint();
3107 if( !pcProc_->addBreakpoint(addr, brkPt) ) {
3108 proccontrol_printf("%s[%d]: failed to set breakpoint at 0x%lx\n",
3109 FILE__, __LINE__, addr);
3116 bool PCProcess::launchDebugger() {
3117 // Stop the process on detach
3118 pdvector<func_instance *> breakpointFuncs;
3119 if( !findFuncsByAll("DYNINSTsafeBreakPoint", breakpointFuncs) ) {
3120 fprintf(stderr, "Failed to find function DYNINSTsafeBreakPoint\n");
3124 func_instance *safeBreakpoint = breakpointFuncs[0];
3125 for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
3126 i != threadsByTid_.end(); ++i)
3128 if( !i->second->pcThr_->setRegister(MachRegister::getPC(getArch()),
3129 safeBreakpoint->addr()) )
3131 fprintf(stderr, "Failed to set PC to 0x%lx\n",
3132 safeBreakpoint->addr());
3137 // Detach the process
3138 if( !detachProcess(true) ) {
3139 fprintf(stderr, "Failed to detach from process %d\n", getPid());
3143 if( !startDebugger() ) {
3144 fprintf(stderr, "Failed to start debugger on process %d\n", getPid());
3153 Address getVarAddr(PCProcess *proc, std::string str) {
3154 Address retAddr = 0;
3156 pdvector<int_variable *> vars;
3157 if( proc->findVarsByAll(str, vars) ) {
3158 if( vars.size() != 1 ) {
3159 proccontrol_printf("%s[%d]: WARNING: multiple copies of %s found\n",
3160 FILE__, __LINE__, str.c_str());
3162 retAddr = vars[0]->getAddress();
3165 proccontrol_printf("%s[%d]: failed to find variable %s\n",
3166 FILE__, __LINE__, str.c_str());
3171 Address PCProcess::getRTEventBreakpointAddr() {
3172 if( sync_event_breakpoint_addr_ == 0 ) {
3173 sync_event_breakpoint_addr_ = getVarAddr(this, "DYNINST_break_point_event");
3176 return sync_event_breakpoint_addr_;
3179 Address PCProcess::getRTEventIdAddr() {
3180 if( sync_event_id_addr_ == 0 ) {
3181 sync_event_id_addr_ = getVarAddr(this, "DYNINST_synch_event_id");
3184 return sync_event_id_addr_;
3187 Address PCProcess::getRTEventArg1Addr() {
3188 if( sync_event_arg1_addr_ == 0 ) {
3189 sync_event_arg1_addr_ = getVarAddr(this, "DYNINST_synch_event_arg1");
3192 return sync_event_arg1_addr_;
3195 Address PCProcess::getRTEventArg2Addr() {
3196 if( sync_event_arg2_addr_ == 0 ) {
3197 sync_event_arg2_addr_ = getVarAddr(this, "DYNINST_synch_event_arg2");
3200 return sync_event_arg2_addr_;
3203 Address PCProcess::getRTEventArg3Addr() {
3204 if( sync_event_arg3_addr_ == 0 ) {
3205 sync_event_arg3_addr_ = getVarAddr(this, "DYNINST_synch_event_arg3");
3208 return sync_event_arg3_addr_;
3211 bool PCProcess::hasPendingEvents() {
3212 // Go to the muxer as a final arbiter
3213 return PCEventMuxer::muxer().hasPendingEvents(this);
3216 bool PCProcess::hasRunningSyncRPC() const {
3217 return (syncRPCThreads_.size() > 0);
3220 void PCProcess::addSyncRPCThread(Thread::ptr thr) {
3221 proccontrol_printf("%s[%d]: added sync rpc thread %d/%d\n",
3222 FILE__, __LINE__, getPid(), thr ? thr->getLWP() : 0);
3223 syncRPCThreads_.insert(thr);
3226 void PCProcess::removeSyncRPCThread(Thread::ptr thr) {
3227 proccontrol_printf("%s[%d]: removed sync rpc thread %d/%d\n",
3228 FILE__, __LINE__, getPid(), thr ? thr->getLWP() : 0);
3229 syncRPCThreads_.erase(thr);
3232 bool PCProcess::continueSyncRPCThreads() {
3233 for(set<Thread::ptr>::iterator i = syncRPCThreads_.begin();
3234 i != syncRPCThreads_.end(); ++i)
3237 if(!pcProc_->continueProc())
3239 proccontrol_printf("%s[%d]: failed to continue entire process %d for sync RPC\n",
3240 FILE__, __LINE__, getPid());
3243 } else if( !(*i)->continueThread() ) {
3244 proccontrol_printf("%s[%d]: failed to continue thread %d/%d for sync RPC\n",
3245 FILE__, __LINE__, getPid(), (*i)->getLWP());
3253 void PCProcess::addTrap(Address from, Address to, codeGen &gen) {
3254 map<Address, Breakpoint::ptr>::iterator breakIter =
3255 installedCtrlBrkpts.find(from);
3257 if( breakIter != installedCtrlBrkpts.end() ) {
3258 if( !pcProc_->rmBreakpoint(from, breakIter->second) ) {
3261 installedCtrlBrkpts.erase(breakIter);
3264 Breakpoint::ptr newBreak = Breakpoint::newTransferBreakpoint(to);
3265 newBreak->setSuppressCallbacks(true);
3267 if( !pcProc_->addBreakpoint(from, newBreak) ) {
3271 installedCtrlBrkpts.insert(make_pair(from, newBreak));
3275 void PCProcess::removeTrap(Address from) {
3276 map<Address, Breakpoint::ptr>::iterator breakIter =
3277 installedCtrlBrkpts.find(from);
3278 if( breakIter == installedCtrlBrkpts.end() ) return;
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);
3285 installedCtrlBrkpts.erase(breakIter);
3288 void PCProcess::invalidateMTCache() {
3289 mt_cache_result_ = not_cached;
3293 StackwalkSymLookup::StackwalkSymLookup(PCProcess *p)
3297 StackwalkSymLookup::~StackwalkSymLookup()
3300 bool StackwalkSymLookup::lookupAtAddr(Dyninst::Address addr, std::string &out_name, void* &out_value)
3302 func_instance *func = proc_->findOneFuncByAddr(addr);
3303 if( func == NULL ) return false;
3305 // set out_name to the name of the function at this addr
3306 // set out_value to NULL, this value is no longer used
3312 out_name = func->prettyName();
3316 out_name = string("[UNKNOWN]");
3322 StackwalkInstrumentationHelper::StackwalkInstrumentationHelper(PCProcess *p)
3326 StackwalkInstrumentationHelper::~StackwalkInstrumentationHelper()
3329 DynFrameHelper::DynFrameHelper(PCProcess *p)
3330 : FrameFuncHelper(NULL),
3334 DynFrameHelper::~DynFrameHelper()
3337 DynWandererHelper::DynWandererHelper(PCProcess *p)
3338 : WandererHelper(NULL),
3342 DynWandererHelper::~DynWandererHelper()