|
Packit |
ce96f2 |
/*
|
|
Packit |
ce96f2 |
* See the dyninst/COPYRIGHT file for copyright information.
|
|
Packit |
ce96f2 |
*
|
|
Packit |
ce96f2 |
* We provide the Paradyn Tools (below described as "Paradyn")
|
|
Packit |
ce96f2 |
* on an AS IS basis, and do not warrant its validity or performance.
|
|
Packit |
ce96f2 |
* We reserve the right to update, modify, or discontinue this
|
|
Packit |
ce96f2 |
* software at any time. We shall have no obligation to supply such
|
|
Packit |
ce96f2 |
* updates or modifications or any other form of support to you.
|
|
Packit |
ce96f2 |
*
|
|
Packit |
ce96f2 |
* By your use of Paradyn, you understand and agree that we (or any
|
|
Packit |
ce96f2 |
* other person or entity with proprietary rights in Paradyn) are
|
|
Packit |
ce96f2 |
* under no obligation to provide either maintenance services,
|
|
Packit |
ce96f2 |
* update services, notices of latent defects, or correction of
|
|
Packit |
ce96f2 |
* defects for Paradyn.
|
|
Packit |
ce96f2 |
*
|
|
Packit |
ce96f2 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
ce96f2 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
ce96f2 |
* License as published by the Free Software Foundation; either
|
|
Packit |
ce96f2 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
ce96f2 |
*
|
|
Packit |
ce96f2 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
ce96f2 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
ce96f2 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
ce96f2 |
* Lesser General Public License for more details.
|
|
Packit |
ce96f2 |
*
|
|
Packit |
ce96f2 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
ce96f2 |
* License along with this library; if not, write to the Free Software
|
|
Packit |
ce96f2 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#include "dynProcess.h"
|
|
Packit |
ce96f2 |
#include "dynThread.h"
|
|
Packit |
ce96f2 |
#include "pcEventHandler.h"
|
|
Packit |
ce96f2 |
#include "pcEventMuxer.h"
|
|
Packit |
ce96f2 |
#include "function.h"
|
|
Packit |
ce96f2 |
#include "os.h"
|
|
Packit |
ce96f2 |
#include "debug.h"
|
|
Packit |
ce96f2 |
#include "instPoint.h"
|
|
Packit |
ce96f2 |
#include "BPatch.h"
|
|
Packit |
ce96f2 |
#include "mapped_module.h"
|
|
Packit |
ce96f2 |
#include "baseTramp.h"
|
|
Packit |
ce96f2 |
#include "registerSpace.h"
|
|
Packit |
ce96f2 |
#include "mapped_object.h"
|
|
Packit |
ce96f2 |
#include "image.h"
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#include "common/src/pathName.h"
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#include "PCErrors.h"
|
|
Packit |
ce96f2 |
#include "MemoryEmulator/memEmulator.h"
|
|
Packit |
ce96f2 |
#include <boost/tuple/tuple.hpp>
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#include "symtabAPI/h/SymtabReader.h"
|
|
Packit |
ce96f2 |
#include "patchAPI/h/PatchMgr.h"
|
|
Packit |
ce96f2 |
#include "patchAPI/h/Point.h"
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#include <sstream>
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
using namespace Dyninst::ProcControlAPI;
|
|
Packit |
ce96f2 |
using std::map;
|
|
Packit |
ce96f2 |
using std::vector;
|
|
Packit |
ce96f2 |
using std::string;
|
|
Packit |
ce96f2 |
using std::stringstream;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Dyninst::SymtabAPI::SymtabReaderFactory *PCProcess::symReaderFactory_;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess *PCProcess::createProcess(const string file, pdvector<string> &argv,
|
|
Packit |
ce96f2 |
BPatch_hybridMode analysisMode,
|
|
Packit |
ce96f2 |
pdvector<string> &envp,
|
|
Packit |
ce96f2 |
const string dir, int stdin_fd, int stdout_fd,
|
|
Packit |
ce96f2 |
int stderr_fd)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
// Debugging information
|
|
Packit |
ce96f2 |
startup_cerr << "Creating process " << file << " in directory " << dir << endl;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_cerr << "Arguments: (" << argv.size() << ")" << endl;
|
|
Packit |
ce96f2 |
for (unsigned a = 0; a < argv.size(); a++)
|
|
Packit |
ce96f2 |
startup_cerr << " " << a << ": " << argv[a] << endl;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_cerr << "Environment: (" << envp.size() << ")" << endl;
|
|
Packit |
ce96f2 |
for (unsigned e = 0; e < envp.size(); e++)
|
|
Packit |
ce96f2 |
startup_cerr << " " << e << ": " << envp[e] << endl;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: stdin: %d, stdout: %d, stderr: %d\n", FILE__, __LINE__,
|
|
Packit |
ce96f2 |
stdin_fd, stdout_fd, stderr_fd);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
initSymtabReader();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create a full path to the executable
|
|
Packit |
ce96f2 |
string path = createExecPath(file, dir);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
std::map<int, int> fdMap;
|
|
Packit |
ce96f2 |
redirectFds(stdin_fd, stdout_fd, stderr_fd, fdMap);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !setEnvPreload(envp, path) ) {
|
|
Packit |
ce96f2 |
startup_cerr << "Failed to set environment var to preload RT library" << endl;
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create the ProcControl process
|
|
Packit |
ce96f2 |
Process::ptr tmpPcProc = Process::createProcess(path, argv, envp, fdMap);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !tmpPcProc ) {
|
|
Packit |
ce96f2 |
cerr << "Failed to create process " << path << endl;
|
|
Packit |
ce96f2 |
const char *lastErrMsg = getLastErrorMsg();
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to create process for %s: %s\n", __FILE__,
|
|
Packit |
ce96f2 |
__LINE__, file.c_str(), lastErrMsg);
|
|
Packit |
ce96f2 |
string msg = string("Failed to create process for ") + file +
|
|
Packit |
ce96f2 |
string(": ") + lastErrMsg;
|
|
Packit |
ce96f2 |
showErrorCallback(68, msg.c_str());
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_cerr << "Created process " << tmpPcProc->getPid() << endl;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess *ret = new PCProcess(tmpPcProc, file, analysisMode);
|
|
Packit |
ce96f2 |
assert(ret);
|
|
Packit |
ce96f2 |
tmpPcProc->setData(ret);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !ret->bootstrapProcess() ) {
|
|
Packit |
ce96f2 |
startup_cerr << "Failed to bootstrap process " << ret->getPid()
|
|
Packit |
ce96f2 |
<< ": terminating..." << endl;
|
|
Packit |
ce96f2 |
ret->terminateProcess();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
delete ret;
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return ret;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess *PCProcess::attachProcess(const string &progpath, int pid,
|
|
Packit |
ce96f2 |
BPatch_hybridMode analysisMode)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
initSymtabReader();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_cerr << "Attaching to process " << pid << endl;
|
|
Packit |
ce96f2 |
Process::ptr tmpPcProc = Process::attachProcess(pid, progpath);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !tmpPcProc ) {
|
|
Packit |
ce96f2 |
const char *lastErrMsg = getLastErrorMsg();
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: Failed to attach process %d: %s\n",
|
|
Packit |
ce96f2 |
__FILE__, __LINE__, pid, lastErrMsg);
|
|
Packit |
ce96f2 |
stringstream msg;
|
|
Packit |
ce96f2 |
msg << "Failed to attach to process " << pid << ": " << lastErrMsg;
|
|
Packit |
ce96f2 |
showErrorCallback(26, msg.str());
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
startup_cerr << "Attached to process " << tmpPcProc->getPid() << endl;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess *ret = new PCProcess(tmpPcProc, analysisMode);
|
|
Packit |
ce96f2 |
assert(ret);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
tmpPcProc->setData(ret);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
ret->runningWhenAttached_ = tmpPcProc->allThreadsRunningWhenAttached();
|
|
Packit |
ce96f2 |
ret->file_ = tmpPcProc->libraries().getExecutable()->getAbsoluteName();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !ret->bootstrapProcess() ) {
|
|
Packit |
ce96f2 |
startup_cerr << "Failed to bootstrap process " << pid
|
|
Packit |
ce96f2 |
<< ": terminating..." << endl;
|
|
Packit |
ce96f2 |
ret->terminateProcess();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
delete ret;
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return ret;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess *PCProcess::setupForkedProcess(PCProcess *parent, Process::ptr pcProc) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: setting up forked process %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, pcProc->getPid());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess *ret = new PCProcess(parent, pcProc);
|
|
Packit |
ce96f2 |
assert(ret);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
pcProc->setData(ret);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
ret->copyAddressSpace(parent);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// This requires the AddressSpace be copied from the parent
|
|
Packit |
ce96f2 |
if (parent->tracedSyscalls_)
|
|
Packit |
ce96f2 |
ret->tracedSyscalls_ = new syscallNotification(parent->tracedSyscalls_, ret);
|
|
Packit |
ce96f2 |
else
|
|
Packit |
ce96f2 |
ret->tracedSyscalls_ = NULL;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Check if RT library exists in child
|
|
Packit |
ce96f2 |
if( ret->runtime_lib.size() == 0 ) {
|
|
Packit |
ce96f2 |
// Set the RT library name
|
|
Packit |
ce96f2 |
if( !ret->getDyninstRTLibName() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to get Dyninst RT lib name\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
delete ret;
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: Got Dyninst RT libname: %s\n", FILE__, __LINE__,
|
|
Packit |
ce96f2 |
ret->dyninstRT_name.c_str());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for(unsigned i = 0; i < ret->mapped_objects.size(); ++i) {
|
|
Packit |
ce96f2 |
const fileDescriptor &desc = ret->mapped_objects[i]->getFileDesc();
|
|
Packit |
ce96f2 |
fileDescriptor tmpDesc(ret->dyninstRT_name,
|
|
Packit |
ce96f2 |
desc.code(), desc.data(), true);
|
|
Packit |
ce96f2 |
if( desc == tmpDesc ) {
|
|
Packit |
ce96f2 |
ret->runtime_lib.insert(ret->mapped_objects[i]);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// TODO hybrid mode stuff
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Copy signal handlers
|
|
Packit |
ce96f2 |
pdvector<codeRange *> sigHandlers;
|
|
Packit |
ce96f2 |
parent->signalHandlerLocations_.elements(sigHandlers);
|
|
Packit |
ce96f2 |
for(unsigned i = 0; i < sigHandlers.size(); ++i) {
|
|
Packit |
ce96f2 |
signal_handler_location *oldSig = dynamic_cast<signal_handler_location *>(sigHandlers[i]);
|
|
Packit |
ce96f2 |
assert(oldSig);
|
|
Packit |
ce96f2 |
signal_handler_location *newSig = new signal_handler_location(*oldSig);
|
|
Packit |
ce96f2 |
ret->signalHandlerLocations_.insert(newSig);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// If required
|
|
Packit |
ce96f2 |
if( !ret->copyDanglingMemory(parent) ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to copy dangling memory from parent %d to child %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, parent->getPid(), ret->getPid());
|
|
Packit |
ce96f2 |
ret->terminateProcess();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
delete ret;
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
ret->setInEventHandling(true);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !ret->bootstrapProcess() ) {
|
|
Packit |
ce96f2 |
startup_cerr << "Failed to bootstrap process " << ret->getPid()
|
|
Packit |
ce96f2 |
<< ": terminating..." << endl;
|
|
Packit |
ce96f2 |
ret->terminateProcess();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
delete ret;
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
ret->setDesiredProcessState(parent->getDesiredProcessState());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return ret;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess *PCProcess::setupExecedProcess(PCProcess *oldProc, std::string execPath) {
|
|
Packit |
ce96f2 |
BPatch::bpatch->registerExecCleanup(oldProc, NULL);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess *newProc = new PCProcess(oldProc->pcProc_, execPath, oldProc->analysisMode_);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
oldProc->pcProc_->setData(newProc);
|
|
Packit |
ce96f2 |
newProc->setExecing(true);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !newProc->bootstrapProcess() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to bootstrap execed process %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, newProc->getPid());
|
|
Packit |
ce96f2 |
delete newProc;
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
delete oldProc;
|
|
Packit |
ce96f2 |
oldProc = NULL;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
newProc->setInEventHandling(true);
|
|
Packit |
ce96f2 |
//newProc->incPendingEvents();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
BPatch::bpatch->registerExecExit(newProc);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
newProc->setExecing(false);
|
|
Packit |
ce96f2 |
newProc->setDesiredProcessState(ps_running);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return newProc;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess::~PCProcess() {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: destructing PCProcess %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( tracedSyscalls_ ) delete tracedSyscalls_;
|
|
Packit |
ce96f2 |
tracedSyscalls_ = NULL;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( irpcTramp_ ) delete irpcTramp_;
|
|
Packit |
ce96f2 |
irpcTramp_ = NULL;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
signalHandlerLocations_.clear();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
trapMapping.clearTrapMappings();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if(pcProc_ && pcProc_->getData() == this) pcProc_->setData(NULL);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::initSymtabReader()
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
//Set SymbolReaderFactory in Stackwalker before create/attach
|
|
Packit |
ce96f2 |
if (!symReaderFactory_) {
|
|
Packit |
ce96f2 |
symReaderFactory_ = new Dyninst::SymtabAPI::SymtabReaderFactory();
|
|
Packit |
ce96f2 |
Dyninst::Stackwalker::Walker::setSymbolReader(symReaderFactory_);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/***************************************************************************
|
|
Packit |
ce96f2 |
**** Runtime library initialization code (Dyninst) ****
|
|
Packit |
ce96f2 |
***************************************************************************/
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/*
|
|
Packit |
ce96f2 |
*
|
|
Packit |
ce96f2 |
* Gratuitously large comment. This diagrams the startup flow of
|
|
Packit |
ce96f2 |
* messages between the mutator and mutatee. Entry points
|
|
Packit |
ce96f2 |
* for create and attach process are both given.
|
|
Packit |
ce96f2 |
* Mutator Signal Mutatee
|
|
Packit |
ce96f2 |
* Create:
|
|
Packit |
ce96f2 |
* Fork/Exec
|
|
Packit |
ce96f2 |
* <-- Trap Halted in exec (handled by ProcControlAPI)
|
|
Packit |
ce96f2 |
* Install trap in main
|
|
Packit |
ce96f2 |
* <-- Trap Halted in main
|
|
Packit |
ce96f2 |
* Attach: (also paused, not in main)
|
|
Packit |
ce96f2 |
* Install call to dlopen/
|
|
Packit |
ce96f2 |
* LoadLibrary
|
|
Packit |
ce96f2 |
* <-- Trap In library load
|
|
Packit |
ce96f2 |
* Set parameters in library
|
|
Packit |
ce96f2 |
* <-- Trap Finished loading
|
|
Packit |
ce96f2 |
* Restore code and leave paused
|
|
Packit |
ce96f2 |
* Finalize library
|
|
Packit |
ce96f2 |
* If finalizing fails, init via iRPC
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/*
|
|
Packit |
ce96f2 |
* In all cases, the process is left paused at the entry of main
|
|
Packit |
ce96f2 |
* (create) or where it was (attach). No permanent instrumentation
|
|
Packit |
ce96f2 |
* is inserted.
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::hasReachedBootstrapState(bootstrapState_t state) const {
|
|
Packit |
ce96f2 |
return state <= bootstrapState_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::setBootstrapState(bootstrapState_t newState) {
|
|
Packit |
ce96f2 |
bootstrapState_ = newState;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::bootstrapProcess() {
|
|
Packit |
ce96f2 |
assert( pcProc_->allThreadsStopped() );
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: attempting to bootstrap process %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !wasCreatedViaFork() ) {
|
|
Packit |
ce96f2 |
// Initialize the inferior heaps
|
|
Packit |
ce96f2 |
initializeHeap();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for(unsigned i = 0; i < mapped_objects.size(); ++i) {
|
|
Packit |
ce96f2 |
addInferiorHeap(mapped_objects[i]);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create the mapped_objects for the executable and shared libraries
|
|
Packit |
ce96f2 |
if( !createInitialMappedObjects() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: bootstrap failed while creating mapped objects\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create the initial threads
|
|
Packit |
ce96f2 |
createInitialThreads();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Initialize StackwalkerAPI
|
|
Packit |
ce96f2 |
if ( !createStackwalker() )
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
startup_printf("Bootstrap failed while initializing Stackwalker\n");
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Insert a breakpoint at the entry point of main (and possibly __libc_start_main)
|
|
Packit |
ce96f2 |
if( !hasPassedMain() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: inserting breakpoint at main\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
if( !insertBreakpointAtMain() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: bootstrap failed while setting a breakpoint at main\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: continuing process to breakpoint\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
if( !continueProcess() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: bootstrap failed while continuing the process\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
while( !hasReachedBootstrapState(bs_readyToLoadRTLib) ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: waiting for main() loop\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
if( isStopped() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: We think the process is stopped, continuing\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
if( !continueProcess() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: bootstrap failed while continuing the process\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( isTerminated() ) {
|
|
Packit |
ce96f2 |
bperr("The process exited during startup. This is likely due to one "
|
|
Packit |
ce96f2 |
"of two reasons:\n"
|
|
Packit |
ce96f2 |
"A). The application is mis-built and unable to load. Try "
|
|
Packit |
ce96f2 |
"running the application outside of Dyninst and see if it "
|
|
Packit |
ce96f2 |
"loads properly.\n"
|
|
Packit |
ce96f2 |
"B). libdyninstAPI_RT is mis-built. Try loading the library "
|
|
Packit |
ce96f2 |
"into another application and see if it reports any errors. "
|
|
Packit |
ce96f2 |
"Ubuntu users - You may need to rebuild the RT library "
|
|
Packit |
ce96f2 |
"with the DISABLE_STACK_PROT line enabled in "
|
|
Packit |
ce96f2 |
"core/make.config.local");
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: program exited early, never reached "
|
|
Packit |
ce96f2 |
"initialized state\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
startup_printf("Error is likely due to the application or RT "
|
|
Packit |
ce96f2 |
"library having missing symbols or dependencies\n");
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: bootstrap waiting for process to initialize\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
if( PCEventMuxer::wait(true) == PCEventMuxer::Error) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: bootstrap failed to wait for events\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}else{
|
|
Packit |
ce96f2 |
bootstrapState_ = bs_readyToLoadRTLib;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: process initialized, loading the RT library\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Load the RT library
|
|
Packit |
ce96f2 |
if( !loadRTLib() ) {
|
|
Packit |
ce96f2 |
bperr("Dyninst was unable to load the dyninst runtime library "
|
|
Packit |
ce96f2 |
"into the application. This may be caused by statically "
|
|
Packit |
ce96f2 |
"linked executables, or by having dyninst linked against a "
|
|
Packit |
ce96f2 |
"different version of libelf than it was built with.");
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: bootstrap failed to load RT library\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
pdvector<int_variable *> obsCostVec;
|
|
Packit |
ce96f2 |
if( !findVarsByAll("DYNINSTobsCostLow", obsCostVec) ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to find DYNINSTobsCostLow\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
costAddr_ = obsCostVec[0]->getAddress();
|
|
Packit |
ce96f2 |
assert(costAddr_);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !wasCreatedViaFork() ) {
|
|
Packit |
ce96f2 |
// Install system call tracing
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: installing default Dyninst instrumentation into process %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
tracedSyscalls_ = new syscallNotification(this);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// TODO
|
|
Packit |
ce96f2 |
// pre-fork and pre-exit should depend on whether a callback is defined
|
|
Packit |
ce96f2 |
//
|
|
Packit |
ce96f2 |
// This will require checking whether BPatch holds a defined callback and also
|
|
Packit |
ce96f2 |
// adding a way for BPatch enable this instrumentation in all processes when
|
|
Packit |
ce96f2 |
// a callback is registered
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!tracedSyscalls_->installPreFork()) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed pre-fork notification setup\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!tracedSyscalls_->installPostFork()) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed post-fork notification setup\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!tracedSyscalls_->installPreExec()) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed pre-exec notification setup\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!tracedSyscalls_->installPostExec()) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed post-exec notification setup\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!tracedSyscalls_->installPreExit()) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed pre-exit notification setup\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!tracedSyscalls_->installPreLwpExit()) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed pre-lwp-exit notification setup\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Initialize the MT stuff
|
|
Packit |
ce96f2 |
if (multithread_capable()) {
|
|
Packit |
ce96f2 |
if( !instrumentMTFuncs() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: Failed to instrument MT funcs\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// use heuristics to set hybrid analysis mode
|
|
Packit |
ce96f2 |
if (BPatch_heuristicMode == analysisMode_) {
|
|
Packit |
ce96f2 |
if (getAOut()->parse_img()->codeObject()->defensiveMode()) {
|
|
Packit |
ce96f2 |
analysisMode_ = BPatch_defensiveMode;
|
|
Packit |
ce96f2 |
} else {
|
|
Packit |
ce96f2 |
analysisMode_ = BPatch_normalMode;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bootstrapState_ = bs_initialized;
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: finished bootstrapping process %d\n", FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::createStackwalker()
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
using namespace Stackwalker;
|
|
Packit |
ce96f2 |
ProcDebug *procDebug = NULL;
|
|
Packit |
ce96f2 |
StackwalkSymLookup *symLookup = NULL;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create ProcessState
|
|
Packit |
ce96f2 |
if (NULL == (procDebug = ProcDebug::newProcDebug(pcProc_)))
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
startup_printf("Could not create Stackwalker process state\n");
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create SymbolLookup
|
|
Packit |
ce96f2 |
symLookup = new StackwalkSymLookup(this);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create Walker without default steppers
|
|
Packit |
ce96f2 |
if (NULL == (stackwalker_ = Walker::newWalker(procDebug,
|
|
Packit |
ce96f2 |
NULL,
|
|
Packit |
ce96f2 |
symLookup,
|
|
Packit |
ce96f2 |
false)))
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
startup_printf("Could not create Stackwalker\n");
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return createStackwalkerSteppers();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::createInitialThreads() {
|
|
Packit |
ce96f2 |
ThreadPool &pcThreads = pcProc_->threads();
|
|
Packit |
ce96f2 |
initialThread_ = PCThread::createPCThread(this, pcThreads.getInitialThread());
|
|
Packit |
ce96f2 |
addThread(initialThread_);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for(ThreadPool::iterator i = pcThreads.begin(); i != pcThreads.end(); ++i) {
|
|
Packit |
ce96f2 |
if( *i == pcThreads.getInitialThread() ) continue;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Wait to create threads until they have user thread information available
|
|
Packit |
ce96f2 |
if( !(*i)->haveUserThreadInfo() ) continue;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCThread *newThr = PCThread::createPCThread(this, *i);
|
|
Packit |
ce96f2 |
addThread(newThr);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::createInitialMappedObjects() {
|
|
Packit |
ce96f2 |
if( file_.empty() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to determine executable for process %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("Processing initial shared objects\n");
|
|
Packit |
ce96f2 |
startup_printf("----\n");
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
initPatchAPI();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Do the a.out first...
|
|
Packit |
ce96f2 |
mapped_object *aout = mapped_object::createMappedObject(pcProc_->libraries().getExecutable(), this, analysisMode_);
|
|
Packit |
ce96f2 |
addASharedObject(aout);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Set the RT library name
|
|
Packit |
ce96f2 |
if( !getDyninstRTLibName() ) {
|
|
Packit |
ce96f2 |
bperr("Dyninst was unable to find the dyninst runtime library.");
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to get Dyninst RT lib name\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Find main
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: leave setAOut/setting main\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
setMainFunction();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create mapped objects for any loaded shared libraries
|
|
Packit |
ce96f2 |
const LibraryPool &libraries = pcProc_->libraries();
|
|
Packit |
ce96f2 |
for(LibraryPool::const_iterator i = libraries.begin(); i != libraries.end(); ++i) {
|
|
Packit |
ce96f2 |
// Some platforms don't use the data load address field
|
|
Packit |
ce96f2 |
if ((*i) == libraries.getExecutable()) continue;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_cerr << "Library: " << (*i)->getAbsoluteName()
|
|
Packit |
ce96f2 |
<< hex << " / " << (*i)->getLoadAddress()
|
|
Packit |
ce96f2 |
<< ", " << ((*i)->isSharedLib() ? "<lib>" : "<aout>") << dec << endl;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
mapped_object *newObj = mapped_object::createMappedObject(*i,
|
|
Packit |
ce96f2 |
this, analysisMode_);
|
|
Packit |
ce96f2 |
if( newObj == NULL ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to create mapped object for library %s\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, (*i)->getAbsoluteName().c_str());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
const fileDescriptor &desc = newObj->getFileDesc();
|
|
Packit |
ce96f2 |
fileDescriptor tmpDesc(dyninstRT_name, desc.code(), desc.data(), true);
|
|
Packit |
ce96f2 |
if( desc == tmpDesc ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: RT library already loaded, manual loading not necessary\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
runtime_lib.insert(newObj);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (analysisMode_ == BPatch_defensiveMode) {
|
|
Packit |
ce96f2 |
std::string lib_name = newObj->fileName();
|
|
Packit |
ce96f2 |
if (lib_name == "dyninstAPI_RT.dll" ||
|
|
Packit |
ce96f2 |
lib_name == "ntdll.dll" ||
|
|
Packit |
ce96f2 |
lib_name == "kernel32.dll" ||
|
|
Packit |
ce96f2 |
lib_name == "user32.dll" ||
|
|
Packit |
ce96f2 |
lib_name == "KERNELBASE.dll" ||
|
|
Packit |
ce96f2 |
lib_name == "msvcrt.dll" ||
|
|
Packit |
ce96f2 |
lib_name == "msvcr80.dll" ||
|
|
Packit |
ce96f2 |
lib_name == "msvcr100d.dll" ||
|
|
Packit |
ce96f2 |
lib_name == "msvcp100d.dll" ||
|
|
Packit |
ce96f2 |
lib_name == "MSVCR100.dll") {
|
|
Packit |
ce96f2 |
startup_cerr << "Running library " << lib_name
|
|
Packit |
ce96f2 |
<< " in normal mode because it is trusted.\n";
|
|
Packit |
ce96f2 |
newObj->enableDefensiveMode(false);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
addASharedObject(newObj);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("----\n");
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// creates an image, creates new resources for a new shared object
|
|
Packit |
ce96f2 |
// adds it to the collection of mapped_objects
|
|
Packit |
ce96f2 |
void PCProcess::addASharedObject(mapped_object *newObj) {
|
|
Packit |
ce96f2 |
assert(newObj);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
addMappedObject(newObj);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
findSignalHandler(newObj);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: adding shared object %s, addr range 0x%lx to 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__,
|
|
Packit |
ce96f2 |
newObj->fileName().c_str(),
|
|
Packit |
ce96f2 |
newObj->getBaseAddress(),
|
|
Packit |
ce96f2 |
newObj->getBaseAddress() + newObj->get_size());
|
|
Packit |
ce96f2 |
parsing_printf("Adding shared object %s, addr range 0x%x to 0x%x\n",
|
|
Packit |
ce96f2 |
newObj->fileName().c_str(),
|
|
Packit |
ce96f2 |
newObj->getBaseAddress(),
|
|
Packit |
ce96f2 |
newObj->getBaseAddress() + newObj->get_size());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( heapInitialized_ ) {
|
|
Packit |
ce96f2 |
addInferiorHeap(newObj);
|
|
Packit |
ce96f2 |
}else{
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: skipping check for new inferior heaps, heap uninitialized\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::removeASharedObject(mapped_object *obj) {
|
|
Packit |
ce96f2 |
// Remove from mapped_objects list
|
|
Packit |
ce96f2 |
for (unsigned j = 0; j < mapped_objects.size(); j++) {
|
|
Packit |
ce96f2 |
if (obj == mapped_objects[j]) {
|
|
Packit |
ce96f2 |
mapped_objects[j] = mapped_objects.back();
|
|
Packit |
ce96f2 |
mapped_objects.pop_back();
|
|
Packit |
ce96f2 |
deletedObjects_.push_back(obj);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (runtime_lib.end() != runtime_lib.find(obj)) {
|
|
Packit |
ce96f2 |
runtime_lib.erase( runtime_lib.find(obj) );
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
proccontrol_printf("Removing shared object %s, addr range 0x%x to 0x%x\n",
|
|
Packit |
ce96f2 |
obj->fileName().c_str(),
|
|
Packit |
ce96f2 |
obj->getBaseAddress(),
|
|
Packit |
ce96f2 |
obj->get_size());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// TODO Signal handler...
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::setAOut(fileDescriptor &desc) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: enter setAOut\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
assert(mapped_objects.size() == 0);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
mapped_object *aout = mapped_object::createMappedObject
|
|
Packit |
ce96f2 |
(desc, this, getHybridMode());
|
|
Packit |
ce96f2 |
if (!aout) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: fail setAOut\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// We keep a vector of all signal handler locations
|
|
Packit |
ce96f2 |
void PCProcess::findSignalHandler(mapped_object *obj) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: findSignalhandler(%p)\n", FILE__, __LINE__, obj);
|
|
Packit |
ce96f2 |
assert(obj);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
int_symbol sigSym;
|
|
Packit |
ce96f2 |
string signame(SIGNAL_HANDLER);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: findSignalhandler(%p): gettingSymbolInfo\n", FILE__, __LINE__, obj);
|
|
Packit |
ce96f2 |
if (obj->getSymbolInfo(signame, sigSym)) {
|
|
Packit |
ce96f2 |
// Symbols often have a size of 0. This b0rks the codeRange code,
|
|
Packit |
ce96f2 |
// so override to 1 if this is true...
|
|
Packit |
ce96f2 |
unsigned size_to_use = sigSym.getSize();
|
|
Packit |
ce96f2 |
if (!size_to_use) size_to_use = 1;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: findSignalhandler(%p): addingSignalHandler(%p, %d)\n", FILE__, __LINE__, obj, (void *) sigSym.getAddr(), size_to_use);
|
|
Packit |
ce96f2 |
addSignalHandler(sigSym.getAddr(), size_to_use);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: leaving findSignalhandler(%p)\n", FILE__, __LINE__, obj);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// NUMBER_OF_MAIN_POSSIBILITIES is defined in image.h
|
|
Packit |
ce96f2 |
void PCProcess::setMainFunction() {
|
|
Packit |
ce96f2 |
assert(!main_function_);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for (unsigned i = 0; i < NUMBER_OF_MAIN_POSSIBILITIES; i++) {
|
|
Packit |
ce96f2 |
main_function_ = findOnlyOneFunction(main_function_names[i]);
|
|
Packit |
ce96f2 |
if (main_function_) {
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/*
|
|
Packit |
ce96f2 |
* Given an image, add all static heaps inside it
|
|
Packit |
ce96f2 |
* (DYNINSTstaticHeap...) to the buffer pool.
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
void PCProcess::addInferiorHeap(mapped_object *obj) {
|
|
Packit |
ce96f2 |
pdvector<heapDescriptor> infHeaps;
|
|
Packit |
ce96f2 |
/* Get a list of inferior heaps in the new image */
|
|
Packit |
ce96f2 |
if (obj->getInfHeapList(infHeaps)) {
|
|
Packit |
ce96f2 |
/* Add the vector to the inferior heap structure */
|
|
Packit |
ce96f2 |
for (u_int j=0; j < infHeaps.size(); j++) {
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: adding heap at 0x%lx to 0x%lx, name %s\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__,
|
|
Packit |
ce96f2 |
infHeaps[j].addr(),
|
|
Packit |
ce96f2 |
infHeaps[j].addr() + infHeaps[j].size(),
|
|
Packit |
ce96f2 |
infHeaps[j].name().c_str());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// platform-specific check to ignore this heap
|
|
Packit |
ce96f2 |
if( skipHeap(infHeaps[j]) ) continue;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
heapItem *h = new heapItem (infHeaps[j].addr(), infHeaps[j].size(),
|
|
Packit |
ce96f2 |
infHeaps[j].type(), false);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: Adding heap from 0x%lx - 0x%lx (%d bytes, type %d) from mapped object %s\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__,
|
|
Packit |
ce96f2 |
infHeaps[j].addr(),
|
|
Packit |
ce96f2 |
infHeaps[j].addr() + infHeaps[j].size(),
|
|
Packit |
ce96f2 |
infHeaps[j].size(),
|
|
Packit |
ce96f2 |
infHeaps[j].type(),
|
|
Packit |
ce96f2 |
obj->fileName().c_str());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
addHeap(h);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// set rtlib heaps (runtime_lib hasn't been set yet)
|
|
Packit |
ce96f2 |
if ( ! obj->fullName().compare( dyninstRT_name ) ) {
|
|
Packit |
ce96f2 |
dyninstRT_heaps_.push_back(h);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
static const unsigned MAX_THREADS = 32; // Should match MAX_THREADS in RTcommon.c
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::loadRTLib() {
|
|
Packit |
ce96f2 |
// Check if the RT library has already been loaded
|
|
Packit |
ce96f2 |
if( runtime_lib.size() != 0 ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: RT library already loaded\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bootstrapState_ = bs_loadedRTLib;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else {
|
|
Packit |
ce96f2 |
if (!pcProc_->addLibrary(dyninstRT_name)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to start loading RT lib\n", FILE__,
|
|
Packit |
ce96f2 |
__LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
bootstrapState_ = bs_loadedRTLib;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Process the library load (we hope)
|
|
Packit |
ce96f2 |
PCEventMuxer::handle(this);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( runtime_lib.size() == 0 ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to load RT lib\n", FILE__,
|
|
Packit |
ce96f2 |
__LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bootstrapState_ = bs_loadedRTLib;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
int loaded_ok = 0;
|
|
Packit |
ce96f2 |
pdvector<int_variable *> vars;
|
|
Packit |
ce96f2 |
if (!findVarsByAll("DYNINSThasInitialized", vars)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: no DYNINSThasInitialized variable\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if (!readDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *)&loaded_ok, false)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: readDataWord failed\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if(!loaded_ok)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: DYNINSTinit not called automatically\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: DYNINSTinit succeeded\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return setRTLibInitParams();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Set up the parameters for DYNINSTinit in the RT lib
|
|
Packit |
ce96f2 |
bool PCProcess::setRTLibInitParams() {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: welcome to PCProcess::setRTLibInitParams\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
int pid = P_getpid();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Now we write these variables into the following global vrbles
|
|
Packit |
ce96f2 |
// in the dyninst library:
|
|
Packit |
ce96f2 |
// libdyninstAPI_RT_init_localCause
|
|
Packit |
ce96f2 |
// libdyninstAPI_RT_init_localPid
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
pdvector<int_variable *> vars;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!findVarsByAll("libdyninstAPI_RT_init_localPid", vars)) {
|
|
Packit |
ce96f2 |
if (!findVarsByAll("_libdyninstAPI_RT_init_localPid", vars)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: could not find necessary internal variable\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
assert(vars.size() >= 1);
|
|
Packit |
ce96f2 |
if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *)&pid)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
vars.clear();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!findVarsByAll("libdyninstAPI_RT_init_maxthreads", vars)) {
|
|
Packit |
ce96f2 |
if (!findVarsByAll("_libdyninstAPI_RT_init_maxthreads", vars)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: could not find necessary internal variable\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
unsigned numThreads = MAX_THREADS;
|
|
Packit |
ce96f2 |
if( !multithread_capable() ) numThreads = 1;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
assert(vars.size() >= 1);
|
|
Packit |
ce96f2 |
if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *) &numThreads)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
vars.clear();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!findVarsByAll("libdyninstAPI_RT_init_debug_flag", vars)) {
|
|
Packit |
ce96f2 |
if (!findVarsByAll("_libdyninstAPI_RT_init_debug_flag", vars)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: could not find necessary internal variable\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
assert(vars.size() >= 1);
|
|
Packit |
ce96f2 |
if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *) &dyn_debug_rtlib)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
vars.clear();
|
|
Packit |
ce96f2 |
if (dyn_debug_rtlib) {
|
|
Packit |
ce96f2 |
fprintf(stderr, "%s[%d]: set var in RTlib for debug...\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
int static_mode = 0;
|
|
Packit |
ce96f2 |
if (!findVarsByAll("DYNINSTstaticMode", vars)) {
|
|
Packit |
ce96f2 |
if (!findVarsByAll("DYNINSTstaticMode", vars)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: could not find necessary internal variable\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
assert(vars.size() >= 1);
|
|
Packit |
ce96f2 |
if (!writeDataWord((void*)vars[0]->getAddress(), sizeof(int), (void *) &static_mode)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: writeDataWord failed\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
vars.clear();
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#if defined(os_vxworks)
|
|
Packit |
ce96f2 |
bool PCProcess::insertBreakpointAtMain() {
|
|
Packit |
ce96f2 |
// We don't need any extra processing of the RTlib.
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
#else
|
|
Packit |
ce96f2 |
bool PCProcess::insertBreakpointAtMain() {
|
|
Packit |
ce96f2 |
if( main_function_ == NULL ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: main function not yet found, cannot insert breakpoint\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
Address addr = main_function_->addr();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create the breakpoint
|
|
Packit |
ce96f2 |
mainBrkPt_ = Breakpoint::newBreakpoint();
|
|
Packit |
ce96f2 |
if( !pcProc_->addBreakpoint(addr, mainBrkPt_) ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to insert a breakpoint at main entry: 0x%x\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, addr);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: added trap to entry of main, address 0x%x\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, addr);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::removeBreakpointAtMain() {
|
|
Packit |
ce96f2 |
if( main_function_ == NULL || mainBrkPt_ == Breakpoint::ptr() ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: no breakpoint set at main function, not removing\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address addr = main_function_->addr();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !pcProc_->rmBreakpoint(addr, mainBrkPt_) ) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: failed to remove breakpoint at main entry: 0x%x\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, addr);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
mainBrkPt_ = Breakpoint::ptr();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Breakpoint::ptr PCProcess::getBreakpointAtMain() const {
|
|
Packit |
ce96f2 |
return mainBrkPt_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// End Runtime library initialization code
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::continueProcess() {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: Continuing process %d\n", FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !isAttached() || isTerminated() ) {
|
|
Packit |
ce96f2 |
bpwarn("Warning: continue attempted on non-attached process\n");
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// If the process is in event handling, the process should not be continued,
|
|
Packit |
ce96f2 |
// the processState_t value will be used after event handling to determine the
|
|
Packit |
ce96f2 |
// state of the process
|
|
Packit |
ce96f2 |
if( isInEventHandling() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: process currently in event handling, not continuing\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
|
|
Packit |
ce96f2 |
i != threadsByTid_.end(); ++i)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
i->second->clearStackwalk();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return pcProc_->continueProc();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::stopProcess() {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: Stopping process %d\n", FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !isAttached() || isTerminated() ) {
|
|
Packit |
ce96f2 |
bpwarn("Warning: stop attempted on non-attached process\n");
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// See comment in continueProcess about this
|
|
Packit |
ce96f2 |
if( isInEventHandling() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: process currently in event handling, not stopping\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return pcProc_->stopProc();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::terminateProcess() {
|
|
Packit |
ce96f2 |
if( isTerminated() ) return true;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !isAttached() ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
forcedTerminating_ = true;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: Terminating process %d\n", FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
if( !pcProc_->terminate() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: Failed to terminate process %d\n", FILE__, __LINE__,
|
|
Packit |
ce96f2 |
getPid());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
PCEventMuxer::handle();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: finished terminating process %d\n", FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::detachProcess(bool cont = true) {
|
|
Packit |
ce96f2 |
if( isTerminated() ) return true;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !isAttached() ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (tracedSyscalls_) {
|
|
Packit |
ce96f2 |
// Process needs to be stopped to change instrumentation
|
|
Packit |
ce96f2 |
bool needToContinue = false;
|
|
Packit |
ce96f2 |
if( !isStopped() ) {
|
|
Packit |
ce96f2 |
needToContinue = true;
|
|
Packit |
ce96f2 |
if( !stopProcess() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to stop process for removing syscalls\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
tracedSyscalls_->removePreFork();
|
|
Packit |
ce96f2 |
tracedSyscalls_->removePostFork();
|
|
Packit |
ce96f2 |
tracedSyscalls_->removePreExec();
|
|
Packit |
ce96f2 |
tracedSyscalls_->removePostExec();
|
|
Packit |
ce96f2 |
tracedSyscalls_->removePreExit();
|
|
Packit |
ce96f2 |
tracedSyscalls_->removePreLwpExit();
|
|
Packit |
ce96f2 |
if (cont) {
|
|
Packit |
ce96f2 |
if( needToContinue ) {
|
|
Packit |
ce96f2 |
if( !continueProcess() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to continue process after removing syscalls\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// TODO figure out if ProcControl should care about continuing a process
|
|
Packit |
ce96f2 |
// after detach
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// NB: it's possible to get markExited() while handling events for the
|
|
Packit |
ce96f2 |
// tracedSyscalls_->remove* calls above, clearing pcProc_.
|
|
Packit |
ce96f2 |
if( isTerminated() || pcProc_->detach(!cont) ) {
|
|
Packit |
ce96f2 |
attached_ = false;
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isBootstrapped() const {
|
|
Packit |
ce96f2 |
return bootstrapState_ == bs_initialized;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isAttached() const {
|
|
Packit |
ce96f2 |
return attached_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isStopped() const {
|
|
Packit |
ce96f2 |
if( pcProc_ == Process::ptr() ) return true;
|
|
Packit |
ce96f2 |
return pcProc_->allThreadsStopped();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isTerminated() const {
|
|
Packit |
ce96f2 |
if( pcProc_ == Process::ptr() ) return true;
|
|
Packit |
ce96f2 |
return pcProc_->isTerminated();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::hasExitedNormally() const {
|
|
Packit |
ce96f2 |
if( pcProc_ == Process::ptr() ) return true;
|
|
Packit |
ce96f2 |
return pcProc_->isExited();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isExecing() const {
|
|
Packit |
ce96f2 |
return execing_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::setExecing(bool b) {
|
|
Packit |
ce96f2 |
execing_ = b;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isExiting() const {
|
|
Packit |
ce96f2 |
return exiting_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::setExiting(bool b) {
|
|
Packit |
ce96f2 |
exiting_ = b;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isInEventHandling() const {
|
|
Packit |
ce96f2 |
return inEventHandling_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::setInEventHandling(bool b) {
|
|
Packit |
ce96f2 |
inEventHandling_ = b;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::hasReportedEvent() const {
|
|
Packit |
ce96f2 |
return reportedEvent_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::setReportingEvent(bool b) {
|
|
Packit |
ce96f2 |
reportedEvent_ = b;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::markExited() {
|
|
Packit |
ce96f2 |
pcProc_.reset();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::writeDebugDataSpace(void *inTracedProcess, u_int amount,
|
|
Packit |
ce96f2 |
const void *inSelf)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
static unsigned write_no = 0;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !dyn_debug_write ) return;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
write_printf("const unsigned char ");
|
|
Packit |
ce96f2 |
switch(getArch()) {
|
|
Packit |
ce96f2 |
case Arch_x86:
|
|
Packit |
ce96f2 |
write_printf("x86_");
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case Arch_x86_64:
|
|
Packit |
ce96f2 |
write_printf("amd64_");
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case Arch_ppc32:
|
|
Packit |
ce96f2 |
case Arch_ppc64:
|
|
Packit |
ce96f2 |
write_printf("power_");
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
default:
|
|
Packit |
ce96f2 |
write_printf("unknown_");
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
write_printf("%lx_%d_%u[] = {", inTracedProcess, getPid(), write_no++);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( amount > 0 ) {
|
|
Packit |
ce96f2 |
const unsigned char *buffer = (const unsigned char *)inSelf;
|
|
Packit |
ce96f2 |
for(unsigned i = 0; i < amount-1; ++i) {
|
|
Packit |
ce96f2 |
if( i % 10 == 0 ) write_printf("\n");
|
|
Packit |
ce96f2 |
write_printf("0x%02hhx, ", buffer[i]);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
write_printf("0x%02hhx", buffer[amount-1]);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
write_printf("\n};\n");
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::writeDataSpace(void *inTracedProcess, u_int amount,
|
|
Packit |
ce96f2 |
const void *inSelf) {
|
|
Packit |
ce96f2 |
if( isTerminated() ) {
|
|
Packit |
ce96f2 |
cerr << "Writing to terminated process!" << endl;
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf,
|
|
Packit |
ce96f2 |
amount);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( BPatch_defensiveMode == proc()->getHybridMode() && !result ) {
|
|
Packit |
ce96f2 |
// the write may have failed because we've removed write permissions
|
|
Packit |
ce96f2 |
// from the page, remove them and try again
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCMemPerm origRights, rights(true, true, true);
|
|
Packit |
ce96f2 |
if (!pcProc_->setMemoryAccessRights((Address)inTracedProcess,
|
|
Packit |
ce96f2 |
amount, rights, origRights)) {
|
|
Packit |
ce96f2 |
cerr << "Fail to set memory permissions!" << endl;
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/*
|
|
Packit |
ce96f2 |
int oldRights = pcProc_->setMemoryAccessRights((Address)inTracedProcess,
|
|
Packit |
ce96f2 |
amount,
|
|
Packit |
ce96f2 |
PAGE_EXECUTE_READWRITE);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( oldRights == PAGE_EXECUTE_READ || oldRights == PAGE_READONLY ) {
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( origRights.isRX() || origRights.isR() ) {
|
|
Packit |
ce96f2 |
result = pcProc_->writeMemory((Address)inTracedProcess, inSelf,
|
|
Packit |
ce96f2 |
amount);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/*
|
|
Packit |
ce96f2 |
if( pcProc_->setMemoryAccessRights((Address)inTracedProcess,
|
|
Packit |
ce96f2 |
amount, oldRights) == false ) {
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCMemPerm tmpRights;
|
|
Packit |
ce96f2 |
if( !pcProc_->setMemoryAccessRights((Address)inTracedProcess,
|
|
Packit |
ce96f2 |
amount, origRights, tmpRights)) {
|
|
Packit |
ce96f2 |
result = false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
} else {
|
|
Packit |
ce96f2 |
result = false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return result;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::writeDataWord(void *inTracedProcess,
|
|
Packit |
ce96f2 |
u_int amount, const void *inSelf)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( isTerminated() ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// XXX ProcControlAPI should support word writes in the future
|
|
Packit |
ce96f2 |
bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf, amount);
|
|
Packit |
ce96f2 |
if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
|
|
Packit |
ce96f2 |
return result;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::readDataSpace(const void *inTracedProcess, u_int amount,
|
|
Packit |
ce96f2 |
void *inSelf, bool displayErrMsg)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( isTerminated() ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool result = pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
|
|
Packit |
ce96f2 |
if( !result && displayErrMsg ) {
|
|
Packit |
ce96f2 |
stringstream msg;
|
|
Packit |
ce96f2 |
msg << "System error: unable to read " << amount << "@"
|
|
Packit |
ce96f2 |
<< Address_str((Address)inTracedProcess) << " from process data space: "
|
|
Packit |
ce96f2 |
<< getLastErrorMsg() << "(pid = " << getPid() << ")";
|
|
Packit |
ce96f2 |
showErrorCallback(38, msg.str());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
return result;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::readDataWord(const void *inTracedProcess, u_int amount,
|
|
Packit |
ce96f2 |
void *inSelf, bool displayErrMsg)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( isTerminated() ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// XXX see writeDataWord above
|
|
Packit |
ce96f2 |
bool result = pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
|
|
Packit |
ce96f2 |
if( !result && displayErrMsg ) {
|
|
Packit |
ce96f2 |
stringstream msg;
|
|
Packit |
ce96f2 |
msg << "System error: unable to read " << amount << "@"
|
|
Packit |
ce96f2 |
<< Address_str((Address)inTracedProcess) << " from process data space: "
|
|
Packit |
ce96f2 |
<< getLastErrorMsg() << "(pid = " << getPid() << ")";
|
|
Packit |
ce96f2 |
showErrorCallback(38, msg.str());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return result;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::writeTextSpace(void *inTracedProcess, u_int amount, const void *inSelf)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( isTerminated() ) return false;
|
|
Packit |
ce96f2 |
bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf, amount);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return result;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::writeTextWord(void *inTracedProcess, u_int amount, const void *inSelf)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( isTerminated() ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// XXX see writeDataWord above
|
|
Packit |
ce96f2 |
bool result = pcProc_->writeMemory((Address)inTracedProcess, inSelf, amount);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( result && dyn_debug_write ) writeDebugDataSpace(inTracedProcess, amount, inSelf);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return result;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::readTextSpace(const void *inTracedProcess, u_int amount,
|
|
Packit |
ce96f2 |
void *inSelf)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( isTerminated() ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::readTextWord(const void *inTracedProcess, u_int amount,
|
|
Packit |
ce96f2 |
void *inSelf)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( isTerminated() ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// XXX see writeDataWord above
|
|
Packit |
ce96f2 |
return pcProc_->readMemory(inSelf, (Address)inTracedProcess, amount);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCThread *PCProcess::getInitialThread() const {
|
|
Packit |
ce96f2 |
return initialThread_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCThread *PCProcess::getThread(dynthread_t tid) const {
|
|
Packit |
ce96f2 |
map<dynthread_t, PCThread *>::const_iterator findIter;
|
|
Packit |
ce96f2 |
findIter = threadsByTid_.find(tid);
|
|
Packit |
ce96f2 |
if( findIter == threadsByTid_.end() ) {
|
|
Packit |
ce96f2 |
return NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return findIter->second;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::removeThread(dynthread_t tid) {
|
|
Packit |
ce96f2 |
map<dynthread_t, PCThread *>::iterator result;
|
|
Packit |
ce96f2 |
result = threadsByTid_.find(tid);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( result == threadsByTid_.end() ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCThread *toDelete = result->second;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
//if( !unregisterThread(toDelete) ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
threadsByTid_.erase(result);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( toDelete == initialThread_ ) {
|
|
Packit |
ce96f2 |
initialThread_ = NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
toDelete->markExited();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Note: don't delete the thread here, the BPatch_thread takes care of it
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: removed thread %lu from process %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, toDelete->getLWP(), getPid());
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
extern Address getVarAddr(PCProcess *proc, std::string str);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#if 0
|
|
Packit |
ce96f2 |
bool PCProcess::registerThread(PCThread *thread) {
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address tid = (Address) thread->getTid();
|
|
Packit |
ce96f2 |
Address index = thread->getIndex();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address tmp = 0;
|
|
Packit |
ce96f2 |
unsigned ptrsize = getAddressWidth();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (tid == (Address) -1) return true;
|
|
Packit |
ce96f2 |
if (index == (Address) -1) return true;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!initializeRegisterThread()) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: initializeRegisterThread failed\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
// Must match the "hash" algorithm used in the RT lib
|
|
Packit |
ce96f2 |
int working = (tid % thread_hash_size);
|
|
Packit |
ce96f2 |
while(1) {
|
|
Packit |
ce96f2 |
tmp = 0;
|
|
Packit |
ce96f2 |
if (!readDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &tmp, false)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: Failed to read index slot, base 0x%lx, active 0x%lx\n", FILE__, __LINE__,
|
|
Packit |
ce96f2 |
thread_hash_indices, thread_hash_indices + (working * ptrsize));
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: value of tid in slot %p is 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, thread_hash_indices + (working * ptrsize), tmp);
|
|
Packit |
ce96f2 |
if (ptrsize == 4 && tmp == 0xffffffff) {
|
|
Packit |
ce96f2 |
int index_int = (int) index;
|
|
Packit |
ce96f2 |
int tid_int = (int) tid;
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: writing %d to %p and 0x%x to %p\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, index_int, thread_hash_indices + (working * ptrsize),
|
|
Packit |
ce96f2 |
tid_int, thread_hash_tids + (working * ptrsize));
|
|
Packit |
ce96f2 |
writeDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &index_int);
|
|
Packit |
ce96f2 |
writeDataWord(( void *)(thread_hash_tids + (working * ptrsize)), ptrsize, &tid_int);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else if (ptrsize == 8 && tmp == (Address)-1) {
|
|
Packit |
ce96f2 |
writeDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &index);
|
|
Packit |
ce96f2 |
writeDataWord(( void *)(thread_hash_tids + (working * ptrsize)), ptrsize, &tid;;
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
working++;
|
|
Packit |
ce96f2 |
if (working == thread_hash_size) working = 0;
|
|
Packit |
ce96f2 |
if (working == (int) (tid % thread_hash_size)) {
|
|
Packit |
ce96f2 |
startup_printf("%s[%d]: Failed to find empty tid slot\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
bool PCProcess::unregisterThread(PCThread *thread) {
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
Address tid = (Address) thread->getTid();
|
|
Packit |
ce96f2 |
Address index = thread->getIndex();
|
|
Packit |
ce96f2 |
Address tmp = 0;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
unsigned ptrsize = getAddressWidth();
|
|
Packit |
ce96f2 |
if (tid == (Address) -1) return true;
|
|
Packit |
ce96f2 |
if (index == (Address) -1) return true;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
initializeRegisterThread();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Must match the "hash" algorithm used in the RT lib
|
|
Packit |
ce96f2 |
int working = tid % thread_hash_size;
|
|
Packit |
ce96f2 |
while(1) {
|
|
Packit |
ce96f2 |
tmp = 0;
|
|
Packit |
ce96f2 |
if (!readDataWord((void *)(thread_hash_tids + (working * ptrsize)), ptrsize, &tmp, false)) return false;
|
|
Packit |
ce96f2 |
if (tmp == tid) {
|
|
Packit |
ce96f2 |
// Zero it out
|
|
Packit |
ce96f2 |
tmp = (Address) -1;
|
|
Packit |
ce96f2 |
writeDataWord(( void *)(thread_hash_indices + (working * ptrsize)), ptrsize, &tmp);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
working++;
|
|
Packit |
ce96f2 |
if (working == thread_hash_size) working = 0;
|
|
Packit |
ce96f2 |
if (working == (int) (tid % thread_hash_size)) return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::initializeRegisterThread() {
|
|
Packit |
ce96f2 |
// if (thread_hash_tids) return true;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
unsigned ptrsize = getAddressWidth();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address tidPtr = getVarAddr(this, "DYNINST_thread_hash_tids");
|
|
Packit |
ce96f2 |
if (!tidPtr) return false;
|
|
Packit |
ce96f2 |
Address indexPtr = getVarAddr(this, "DYNINST_thread_hash_indices");
|
|
Packit |
ce96f2 |
if (!indexPtr) return false;
|
|
Packit |
ce96f2 |
Address sizePtr = getVarAddr(this, "DYNINST_thread_hash_size");
|
|
Packit |
ce96f2 |
if (!sizePtr) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!readDataWord((const void *)tidPtr, ptrsize, &thread_hash_tids, false)) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!readDataWord((const void *)indexPtr, ptrsize, &thread_hash_indices, false)) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!readDataWord((const void *)sizePtr, sizeof(int), &thread_hash_size, false)) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::addThread(PCThread *thread) {
|
|
Packit |
ce96f2 |
pair<map<dynthread_t, PCThread *>::iterator, bool> result;
|
|
Packit |
ce96f2 |
result = threadsByTid_.insert(make_pair(thread->getTid(), thread));
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
assert( result.second && "Thread already in collection of threads" );
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: added thread %lu to process %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, thread->getLWP(), getPid());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::getThreads(vector<PCThread* > &threads) const {
|
|
Packit |
ce96f2 |
for(map<dynthread_t, PCThread *>::const_iterator i = threadsByTid_.begin();
|
|
Packit |
ce96f2 |
i != threadsByTid_.end(); ++i)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
threads.push_back(i->second);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::wasRunningWhenAttached() const {
|
|
Packit |
ce96f2 |
return runningWhenAttached_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::wasCreatedViaAttach() const {
|
|
Packit |
ce96f2 |
return createdViaAttach_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::wasCreatedViaFork() const {
|
|
Packit |
ce96f2 |
return parent_ != NULL;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
unsigned PCProcess::getMemoryPageSize() const {
|
|
Packit |
ce96f2 |
assert(pcProc_);
|
|
Packit |
ce96f2 |
return pcProc_->getMemoryPageSize();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
int PCProcess::getPid() const {
|
|
Packit |
ce96f2 |
return savedPid_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
int PCProcess::incrementThreadIndex() {
|
|
Packit |
ce96f2 |
int ret = curThreadIndex_;
|
|
Packit |
ce96f2 |
curThreadIndex_++;
|
|
Packit |
ce96f2 |
return ret;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
unsigned PCProcess::getAddressWidth() const {
|
|
Packit |
ce96f2 |
if( mapped_objects.size() > 0 ) {
|
|
Packit |
ce96f2 |
return mapped_objects[0]->parse_img()->codeObject()->cs()->getAddressWidth();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// We can call this before we've attached...best effort guess
|
|
Packit |
ce96f2 |
return sizeof(Address);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCEventHandler * PCProcess::getPCEventHandler() const {
|
|
Packit |
ce96f2 |
return eventHandler_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::walkStacks(pdvector<pdvector<Frame> > &stackWalks) {
|
|
Packit |
ce96f2 |
bool needToContinue = false;
|
|
Packit |
ce96f2 |
bool retval = true;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// sanity check
|
|
Packit |
ce96f2 |
if( stackwalker_ == NULL ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Process needs to be stopped before doing a stackwalk
|
|
Packit |
ce96f2 |
if( !isStopped() ) {
|
|
Packit |
ce96f2 |
needToContinue = true;
|
|
Packit |
ce96f2 |
if( !stopProcess() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to stop process for stackwalking\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
|
|
Packit |
ce96f2 |
i != threadsByTid_.end(); ++i)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
PCThread *curThr = i->second;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
pdvector<Frame> stackWalk;
|
|
Packit |
ce96f2 |
if( !curThr->walkStack(stackWalk) ) {
|
|
Packit |
ce96f2 |
retval = false;
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to walk stack for thread 0x%lx(%d)\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__,
|
|
Packit |
ce96f2 |
curThr->getTid(), curThr->getLWP());
|
|
Packit |
ce96f2 |
}else{
|
|
Packit |
ce96f2 |
stackWalks.push_back(stackWalk);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( needToContinue ) {
|
|
Packit |
ce96f2 |
if( !continueProcess() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to continue process after performing stackwalking\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return retval;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Return a vector (possibly with one object) of active frames in the process
|
|
Packit |
ce96f2 |
bool PCProcess::getAllActiveFrames(pdvector<Frame> &activeFrames) {
|
|
Packit |
ce96f2 |
Frame active;
|
|
Packit |
ce96f2 |
if( threadsByTid_.size() == 0 ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
|
|
Packit |
ce96f2 |
i != threadsByTid_.end(); ++i)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
Frame active = i->second->getActiveFrame();
|
|
Packit |
ce96f2 |
if( active == Frame() ) return false;
|
|
Packit |
ce96f2 |
activeFrames.push_back(active);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
//
|
|
Packit |
ce96f2 |
// dynamic inferior heap stuff
|
|
Packit |
ce96f2 |
//
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#if defined(os_vxworks)
|
|
Packit |
ce96f2 |
#include "vxworks.h"
|
|
Packit |
ce96f2 |
#define HEAP_DYN_BUF_SIZE (0x4000)
|
|
Packit |
ce96f2 |
#else
|
|
Packit |
ce96f2 |
#define HEAP_DYN_BUF_SIZE (0x100000)
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
static const Address ADDRESS_LO = ((Address)0x10000);
|
|
Packit |
ce96f2 |
static const Address ADDRESS_HI = ((Address)~((Address)0));
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address PCProcess::inferiorMalloc(unsigned size, inferiorHeapType type,
|
|
Packit |
ce96f2 |
Address near_, bool *err)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if(bootstrapState_ <= bs_readyToLoadRTLib) {
|
|
Packit |
ce96f2 |
return 0;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
enum MallocAttempt {
|
|
Packit |
ce96f2 |
AsIs = 0,
|
|
Packit |
ce96f2 |
DeferredFree = 1, // compact free blocks
|
|
Packit |
ce96f2 |
NewSegment1MBConstrained = 2, // allocate new segment (1 MB, constrained)
|
|
Packit |
ce96f2 |
NewSegmentSizedConstrained = 3, // allocate new segment (sized, constrained)
|
|
Packit |
ce96f2 |
RemoveRangeConstraints = 4,
|
|
Packit |
ce96f2 |
NewSegment1MBUnconstrained = 5,
|
|
Packit |
ce96f2 |
NewSegmentSizedUnconstrained = 6,
|
|
Packit |
ce96f2 |
DeferredFreeAgain = 7 // why again?
|
|
Packit |
ce96f2 |
};
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address ret = 0;
|
|
Packit |
ce96f2 |
if (err) *err = false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( size <= 0 ) {
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: inferior malloc cannot be <= 0\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
if( err ) *err = true;
|
|
Packit |
ce96f2 |
return 0;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// allocation range
|
|
Packit |
ce96f2 |
Address lo = ADDRESS_LO; // Should get reset to a more reasonable value
|
|
Packit |
ce96f2 |
Address hi = ADDRESS_HI; // Should get reset to a more reasonable value
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
//#if defined(cap_dynamic_heap)
|
|
Packit |
ce96f2 |
inferiorMallocAlign(size); // align size
|
|
Packit |
ce96f2 |
// Set the lo/hi constraints (if necessary)
|
|
Packit |
ce96f2 |
inferiorMallocConstraints(near_, lo, hi, type);
|
|
Packit |
ce96f2 |
//#else
|
|
Packit |
ce96f2 |
/* align to cache line size (32 bytes on SPARC) */
|
|
Packit |
ce96f2 |
//size = (size + 0x1f) & ~0x1f;
|
|
Packit |
ce96f2 |
//#endif
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: inferiorMalloc entered; size %d, type %d, near 0x%lx (0x%lx to 0x%lx)\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, size, type, near_, lo, hi);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// find free memory block (multiple attempts)
|
|
Packit |
ce96f2 |
int freeIndex = -1;
|
|
Packit |
ce96f2 |
int ntry = 0;
|
|
Packit |
ce96f2 |
for (ntry = 0; freeIndex == -1; ntry++) {
|
|
Packit |
ce96f2 |
switch(ntry) {
|
|
Packit |
ce96f2 |
case AsIs:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: (1) AsIs\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
//#if defined(cap_dynamic_heap)
|
|
Packit |
ce96f2 |
case DeferredFree:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: (2) garbage collecting and compacting\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
inferiorFreeCompact();
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case NewSegment1MBConstrained:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: (3) inferiorMallocDynamic "
|
|
Packit |
ce96f2 |
"for %d (0x%x) bytes between 0x%lx - 0x%lx\n", FILE__, __LINE__,
|
|
Packit |
ce96f2 |
HEAP_DYN_BUF_SIZE, HEAP_DYN_BUF_SIZE, lo, hi);
|
|
Packit |
ce96f2 |
inferiorMallocDynamic(HEAP_DYN_BUF_SIZE, lo, hi);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case NewSegmentSizedConstrained:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: (4) inferiorMallocDynamic "
|
|
Packit |
ce96f2 |
"for %d (0x%x) bytes between 0x%lx - 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, size, size, lo, hi);
|
|
Packit |
ce96f2 |
inferiorMallocDynamic(size, lo, hi);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case RemoveRangeConstraints:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: (5) inferiorMalloc: removing range constraints\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
lo = ADDRESS_LO;
|
|
Packit |
ce96f2 |
hi = ADDRESS_HI;
|
|
Packit |
ce96f2 |
if (err) {
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: error in inferiorMalloc\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
*err = true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case NewSegment1MBUnconstrained:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: (6) inferiorMallocDynamic for %d (0x%x) bytes between 0x%lx - 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, HEAP_DYN_BUF_SIZE, HEAP_DYN_BUF_SIZE, lo, hi);
|
|
Packit |
ce96f2 |
inferiorMallocDynamic(HEAP_DYN_BUF_SIZE, lo, hi);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case NewSegmentSizedUnconstrained:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: (7) inferiorMallocDynamic for %d (0x%x) bytes between 0x%lx - 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, size, size, lo, hi);
|
|
Packit |
ce96f2 |
inferiorMallocDynamic(size, lo, hi);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case DeferredFreeAgain:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: inferiorMalloc: recompacting\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
inferiorFreeCompact();
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
//#else /* !(cap_dynamic_heap) */
|
|
Packit |
ce96f2 |
//case DeferredFree: // deferred free, compact free blocks
|
|
Packit |
ce96f2 |
//inferiorFreeCompact();
|
|
Packit |
ce96f2 |
//break;
|
|
Packit |
ce96f2 |
//#endif /* cap_dynamic_heap */
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
default: // error - out of memory
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: failed to allocate memory\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
if( err ) *err = true;
|
|
Packit |
ce96f2 |
return 0;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
ret = inferiorMallocInternal(size, lo, hi, type);
|
|
Packit |
ce96f2 |
if (ret) break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: inferiorMalloc, returning address 0x%lx\n", FILE__, __LINE__, ret);
|
|
Packit |
ce96f2 |
return ret;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::inferiorFree(Dyninst::Address item) {
|
|
Packit |
ce96f2 |
inferiorFreeInternal(item);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::inferiorRealloc(Dyninst::Address item, unsigned int newSize) {
|
|
Packit |
ce96f2 |
if(bootstrapState_ <= bs_readyToLoadRTLib) {
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
return inferiorReallocInternal(item, newSize);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
static
|
|
Packit |
ce96f2 |
void alignUp(int &val, int align) {
|
|
Packit |
ce96f2 |
assert(val >= 0);
|
|
Packit |
ce96f2 |
assert(align >= 0);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (val % align != 0) {
|
|
Packit |
ce96f2 |
val = ((val / align) + 1) * align;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::inferiorMallocDynamic(int size, Address lo, Address hi) {
|
|
Packit |
ce96f2 |
const int MallocFailed = 0;
|
|
Packit |
ce96f2 |
const int UnalignedBuffer = -1;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: entering inferiorMallocDynamic\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// word-align buffer size
|
|
Packit |
ce96f2 |
// (see "DYNINSTheap_align" in rtinst/src/RTheap-<os>.c)
|
|
Packit |
ce96f2 |
alignUp(size, 4);
|
|
Packit |
ce96f2 |
// build AstNode for "DYNINSTos_malloc" call
|
|
Packit |
ce96f2 |
std::string callee = "DYNINSTos_malloc";
|
|
Packit |
ce96f2 |
pdvector<AstNodePtr> args(3);
|
|
Packit |
ce96f2 |
args[0] = AstNode::operandNode(AstNode::Constant, (void *)(Address)size);
|
|
Packit |
ce96f2 |
args[1] = AstNode::operandNode(AstNode::Constant, (void *)lo);
|
|
Packit |
ce96f2 |
args[2] = AstNode::operandNode(AstNode::Constant, (void *)hi);
|
|
Packit |
ce96f2 |
AstNodePtr code = AstNode::funcCallNode(callee, args);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// issue RPC and wait for result
|
|
Packit |
ce96f2 |
bool wasRunning = !isStopped();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: running inferiorMalloc via iRPC on process %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address result = 0;
|
|
Packit |
ce96f2 |
if( !postIRPC(code,
|
|
Packit |
ce96f2 |
NULL, // only care about the result
|
|
Packit |
ce96f2 |
wasRunning, // run when finished?
|
|
Packit |
ce96f2 |
NULL, // no specific thread
|
|
Packit |
ce96f2 |
true, // wait for completion
|
|
Packit |
ce96f2 |
(void **)&result,
|
|
Packit |
ce96f2 |
false, // internal iRPC
|
|
Packit |
ce96f2 |
true) ) // is a memory allocation RPC
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: failed to post iRPC for inferior malloc\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: inferiorMalloc via iRPC returned 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, result);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
switch ((int)result) {
|
|
Packit |
ce96f2 |
case MallocFailed:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: DYNINSTos_malloc() failed\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
case UnalignedBuffer:
|
|
Packit |
ce96f2 |
infmalloc_printf("%s[%d]: DYNINSTos_malloc(): unaligned buffer size\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
default:
|
|
Packit |
ce96f2 |
// add new segment to buffer pool
|
|
Packit |
ce96f2 |
heapItem *h = new heapItem(result, size, getDynamicHeapType(),
|
|
Packit |
ce96f2 |
true, HEAPfree);
|
|
Packit |
ce96f2 |
addHeap(h);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// A copy of the BPatch-level instrumentation installer
|
|
Packit |
ce96f2 |
void PCProcess::installInstrRequests(const pdvector<instMapping*> &requests) {
|
|
Packit |
ce96f2 |
if (requests.size() == 0) {
|
|
Packit |
ce96f2 |
return;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Instrumentation is now generated on a per-function basis, while
|
|
Packit |
ce96f2 |
// the requests are per-inst, not per-function. So
|
|
Packit |
ce96f2 |
// accumulate functions, then generate afterwards.
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
vector<func_instance *> instrumentedFuncs;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for (unsigned lcv=0; lcv < requests.size(); lcv++) {
|
|
Packit |
ce96f2 |
inst_printf("%s[%d]: handling request %d of %d\n", FILE__, __LINE__, lcv+1, requests.size());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
instMapping *req = requests[lcv];
|
|
Packit |
ce96f2 |
pdvector<miniTramp *> minis;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if(!multithread_capable() && req->is_MTonly())
|
|
Packit |
ce96f2 |
continue;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
pdvector<func_instance *> matchingFuncs;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!findFuncsByAll(req->func, matchingFuncs, req->lib)) {
|
|
Packit |
ce96f2 |
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());
|
|
Packit |
ce96f2 |
return;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else {
|
|
Packit |
ce96f2 |
inst_printf("%s[%d]: found %d functions matching %s (lib %s), instrumenting...\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, matchingFuncs.size(), req->func.c_str(), req->lib.c_str());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for (unsigned funcIter = 0; funcIter < matchingFuncs.size(); funcIter++) {
|
|
Packit |
ce96f2 |
func_instance *func = matchingFuncs[funcIter];
|
|
Packit |
ce96f2 |
if (!func) {
|
|
Packit |
ce96f2 |
inst_printf("%s[%d]: null int_func detected\n",
|
|
Packit |
ce96f2 |
FILE__,__LINE__);
|
|
Packit |
ce96f2 |
continue; // probably should have a flag telling us whether errors
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
inst_printf("%s[%d]: Instrumenting %s at 0x%lx, offset 0x%lx in %s\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__,
|
|
Packit |
ce96f2 |
func->symTabName().c_str(),
|
|
Packit |
ce96f2 |
func->addr(),
|
|
Packit |
ce96f2 |
func->addr() - func->obj()->codeBase(),
|
|
Packit |
ce96f2 |
func->obj()->fullName().c_str());
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// should be silently handled or not
|
|
Packit |
ce96f2 |
AstNodePtr ast;
|
|
Packit |
ce96f2 |
if ((req->where & FUNC_ARG) && req->args.size()>0) {
|
|
Packit |
ce96f2 |
ast = AstNode::funcCallNode(req->inst,
|
|
Packit |
ce96f2 |
req->args,
|
|
Packit |
ce96f2 |
this);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else {
|
|
Packit |
ce96f2 |
pdvector<AstNodePtr> def_args;
|
|
Packit |
ce96f2 |
def_args.push_back(AstNode::operandNode(AstNode::Constant,
|
|
Packit |
ce96f2 |
(void *)0));
|
|
Packit |
ce96f2 |
ast = AstNode::funcCallNode(req->inst,
|
|
Packit |
ce96f2 |
def_args);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
// We mask to strip off the FUNC_ARG bit...
|
|
Packit |
ce96f2 |
std::vector<Point *> points;
|
|
Packit |
ce96f2 |
switch ( ( req->where & 0x7) ) {
|
|
Packit |
ce96f2 |
case FUNC_EXIT:
|
|
Packit |
ce96f2 |
mgr()->findPoints(Dyninst::PatchAPI::Scope(func),
|
|
Packit |
ce96f2 |
Point::FuncExit,
|
|
Packit |
ce96f2 |
std::back_inserter(points));
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case FUNC_ENTRY:
|
|
Packit |
ce96f2 |
mgr()->findPoints(Dyninst::PatchAPI::Scope(func),
|
|
Packit |
ce96f2 |
Point::FuncEntry,
|
|
Packit |
ce96f2 |
std::back_inserter(points));
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
case FUNC_CALL:
|
|
Packit |
ce96f2 |
mgr()->findPoints(Dyninst::PatchAPI::Scope(func),
|
|
Packit |
ce96f2 |
Point::PreCall,
|
|
Packit |
ce96f2 |
std::back_inserter(points));
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
default:
|
|
Packit |
ce96f2 |
fprintf(stderr, "Unknown where: %d\n",
|
|
Packit |
ce96f2 |
req->where);
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
} // switch
|
|
Packit |
ce96f2 |
inst_printf("%s[%d]: found %d points to instrument\n", FILE__, __LINE__, points.size());
|
|
Packit |
ce96f2 |
for (std::vector<Point *>::iterator iter = points.begin();
|
|
Packit |
ce96f2 |
iter != points.end(); ++iter) {
|
|
Packit |
ce96f2 |
Dyninst::PatchAPI::Instance::Ptr inst = (req->order == orderFirstAtPoint) ?
|
|
Packit |
ce96f2 |
(*iter)->pushFront(ast) :
|
|
Packit |
ce96f2 |
(*iter)->pushBack(ast);
|
|
Packit |
ce96f2 |
if (inst) {
|
|
Packit |
ce96f2 |
if (!req->useTrampGuard) inst->disableRecursiveGuard();
|
|
Packit |
ce96f2 |
req->instances.push_back(inst);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else {
|
|
Packit |
ce96f2 |
fprintf(stderr, "%s[%d]: failed to addInst here\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
} } // matchingFuncs
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
} // requests
|
|
Packit |
ce96f2 |
relocate();
|
|
Packit |
ce96f2 |
return;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
static const unsigned MAX_IRPC_SIZE = 0x100000;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::postIRPC(void* buffer, int size, void* userData, bool runProcessWhenDone,
|
|
Packit |
ce96f2 |
PCThread* thread, bool synchronous, void** result,
|
|
Packit |
ce96f2 |
bool userRPC, bool isMemAlloc, Address addr)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
return postIRPC_internal(buffer,
|
|
Packit |
ce96f2 |
size,
|
|
Packit |
ce96f2 |
size,
|
|
Packit |
ce96f2 |
REG_NULL,
|
|
Packit |
ce96f2 |
addr,
|
|
Packit |
ce96f2 |
userData,
|
|
Packit |
ce96f2 |
runProcessWhenDone,
|
|
Packit |
ce96f2 |
thread,
|
|
Packit |
ce96f2 |
synchronous,
|
|
Packit |
ce96f2 |
userRPC,
|
|
Packit |
ce96f2 |
isMemAlloc,
|
|
Packit |
ce96f2 |
result);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::postIRPC(AstNodePtr action, void *userData,
|
|
Packit |
ce96f2 |
bool runProcessWhenDone, PCThread *thread, bool synchronous,
|
|
Packit |
ce96f2 |
void **result, bool userRPC, bool isMemAlloc, Address addr)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
// Generate the code for the iRPC
|
|
Packit |
ce96f2 |
codeGen irpcBuf(MAX_IRPC_SIZE);
|
|
Packit |
ce96f2 |
irpcBuf.setAddrSpace(this);
|
|
Packit |
ce96f2 |
irpcBuf.setRegisterSpace(registerSpace::irpcRegSpace(proc()));
|
|
Packit |
ce96f2 |
irpcBuf.beginTrackRegDefs();
|
|
Packit |
ce96f2 |
irpcBuf.setThread(thread);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#if defined(bug_syscall_changepc_rewind)
|
|
Packit |
ce96f2 |
// Reported by SGI, during attach to a process in a system call:
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Insert eight NOP instructions before the actual call to dlopen(). Loading
|
|
Packit |
ce96f2 |
// the runtime library when the mutatee was in a system call will sometimes
|
|
Packit |
ce96f2 |
// cause the process to (on IA32 anyway) execute the instruction four bytes
|
|
Packit |
ce96f2 |
// PREVIOUS to the PC we actually set here. No idea why. Prepending the
|
|
Packit |
ce96f2 |
// actual dlopen() call with eight NOP instructions insures this doesn't
|
|
Packit |
ce96f2 |
// really matter. Eight was selected rather than four because I don't know
|
|
Packit |
ce96f2 |
// if x86-64 does the same thing (and jumps eight bytes instead of four).
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// We will put in <addr width> rather than always 8; this will be 4 on x86 and
|
|
Packit |
ce96f2 |
// 32-bit AMD64, and 8 on 64-bit AMD64.
|
|
Packit |
ce96f2 |
irpcBuf.fill(proc()->getAddressWidth(), codeGen::cgNOP);
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
irpcTramp_->setIRPCAST(action);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create a stack frame for the RPC
|
|
Packit |
ce96f2 |
if( !irpcTramp_->generateSaves(irpcBuf, irpcBuf.rs()) ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to generate saves via baseTramp\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Register resultReg = REG_NULL;
|
|
Packit |
ce96f2 |
if( !action->generateCode(irpcBuf, false, resultReg) ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to generate code from AST\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Note: we should not do a corresponding baseTramp restore here:
|
|
Packit |
ce96f2 |
// 1) It isn't necessary because ProcControl will restore the
|
|
Packit |
ce96f2 |
// registers
|
|
Packit |
ce96f2 |
// 2) We need to be able to read registers to get the result of the iRPC
|
|
Packit |
ce96f2 |
// If we restore, we can't do that
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Emit the trailer for the iRPC
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// breakOffset: where the irpc ends
|
|
Packit |
ce96f2 |
unsigned breakOffset = irpcBuf.used();
|
|
Packit |
ce96f2 |
insnCodeGen::generateTrap(irpcBuf);
|
|
Packit |
ce96f2 |
insnCodeGen::generateTrap(irpcBuf);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
irpcBuf.endTrackRegDefs();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
//#sasha printing code patch for DYNINSTos_malloc
|
|
Packit |
ce96f2 |
//cerr << "BUFFER for IRPC" << endl;
|
|
Packit |
ce96f2 |
//cerr << irpcBuf.format() << endl;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return postIRPC_internal(irpcBuf.start_ptr(),
|
|
Packit |
ce96f2 |
irpcBuf.used(),
|
|
Packit |
ce96f2 |
breakOffset,
|
|
Packit |
ce96f2 |
resultReg,
|
|
Packit |
ce96f2 |
addr,
|
|
Packit |
ce96f2 |
userData,
|
|
Packit |
ce96f2 |
runProcessWhenDone,
|
|
Packit |
ce96f2 |
thread,
|
|
Packit |
ce96f2 |
synchronous,
|
|
Packit |
ce96f2 |
userRPC,
|
|
Packit |
ce96f2 |
isMemAlloc,
|
|
Packit |
ce96f2 |
result);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// DEBUG
|
|
Packit |
ce96f2 |
#include "instructionAPI/h/InstructionDecoder.h"
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::postIRPC_internal(void *buf,
|
|
Packit |
ce96f2 |
unsigned size,
|
|
Packit |
ce96f2 |
unsigned breakOffset,
|
|
Packit |
ce96f2 |
Register resultReg,
|
|
Packit |
ce96f2 |
Address addr,
|
|
Packit |
ce96f2 |
void *userData,
|
|
Packit |
ce96f2 |
bool runProcessWhenDone,
|
|
Packit |
ce96f2 |
PCThread *thread,
|
|
Packit |
ce96f2 |
bool synchronous,
|
|
Packit |
ce96f2 |
bool userRPC,
|
|
Packit |
ce96f2 |
bool isMemAlloc,
|
|
Packit |
ce96f2 |
void **result) {
|
|
Packit |
ce96f2 |
if( isTerminated() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: cannot post RPC to exited or terminated process %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getpid());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( thread && !thread->isLive() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: attempted to post RPC to dead thread %d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, thread->getLWP());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
inferiorRPCinProgress *newRPC = new inferiorRPCinProgress;
|
|
Packit |
ce96f2 |
newRPC->runProcWhenDone = runProcessWhenDone;
|
|
Packit |
ce96f2 |
newRPC->deliverCallbacks = userRPC;
|
|
Packit |
ce96f2 |
newRPC->userData = userData;
|
|
Packit |
ce96f2 |
newRPC->synchronous = synchronous;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
newRPC->resultRegister = resultReg;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Create the iRPC at the ProcControl level
|
|
Packit |
ce96f2 |
if( addr == 0 ) {
|
|
Packit |
ce96f2 |
bool err = false;
|
|
Packit |
ce96f2 |
if( isMemAlloc ) {
|
|
Packit |
ce96f2 |
// This assumes that there will always be space
|
|
Packit |
ce96f2 |
addr = inferiorMalloc(size, lowmemHeap, 0, &err;;
|
|
Packit |
ce96f2 |
}else{
|
|
Packit |
ce96f2 |
// recursive RPCs are okay when this isn't an inferiorMalloc RPC
|
|
Packit |
ce96f2 |
addr = inferiorMalloc(size, anyHeap, 0, &err;;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( err ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to allocate memory for RPC\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
delete newRPC;
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
newRPC->memoryAllocated = true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (addr)
|
|
Packit |
ce96f2 |
newRPC->rpc = IRPC::createIRPC(buf, size, addr);
|
|
Packit |
ce96f2 |
else
|
|
Packit |
ce96f2 |
newRPC->rpc = IRPC::createIRPC(buf, size);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#if 0
|
|
Packit |
ce96f2 |
// DEBUG
|
|
Packit |
ce96f2 |
InstructionAPI::InstructionDecoder d(buf,size,getArch());
|
|
Packit |
ce96f2 |
Address foo = addr;
|
|
Packit |
ce96f2 |
InstructionAPI::Instruction::Ptr insn = d.decode();
|
|
Packit |
ce96f2 |
while(insn) {
|
|
Packit |
ce96f2 |
cerr << "\t" << hex << foo << ": " << insn->format(foo) << dec << endl;
|
|
Packit |
ce96f2 |
foo += insn->size();
|
|
Packit |
ce96f2 |
insn = d.decode();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
newRPC->rpc->setData(newRPC);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
unsigned int start_offset = 0;
|
|
Packit |
ce96f2 |
#if defined(bug_syscall_changepc_rewind)
|
|
Packit |
ce96f2 |
// Some Linux kernels have the following behavior:
|
|
Packit |
ce96f2 |
// Process is in a system call;
|
|
Packit |
ce96f2 |
// We interrupt the system call;
|
|
Packit |
ce96f2 |
// We say "change PC to address N"
|
|
Packit |
ce96f2 |
// The kernel helpfully changes it to (N - address width)
|
|
Packit |
ce96f2 |
// The program crashes
|
|
Packit |
ce96f2 |
// See a more complete comment above.
|
|
Packit |
ce96f2 |
// For now, we pad the start of our code with NOOPS and change to just
|
|
Packit |
ce96f2 |
// after those; if we hit rewind behavior, then we're executing safe code.
|
|
Packit |
ce96f2 |
//
|
|
Packit |
ce96f2 |
// Matt Note: The above comment is slightly incorrect. The kernel subracts
|
|
Packit |
ce96f2 |
// the length of the syscall/int instruction that triggered the system call,
|
|
Packit |
ce96f2 |
// not the address width. Still address width is big enough, so I'm not
|
|
Packit |
ce96f2 |
// changing anything.
|
|
Packit |
ce96f2 |
start_offset = proc()->getAddressWidth();
|
|
Packit |
ce96f2 |
newRPC->rpcStartAddr += start_offset;
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
newRPC->rpc->setStartOffset(start_offset);
|
|
Packit |
ce96f2 |
newRPC->rpcCompletionAddr = addr + breakOffset;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Post the iRPC
|
|
Packit |
ce96f2 |
Thread::ptr t;
|
|
Packit |
ce96f2 |
if (thread) {
|
|
Packit |
ce96f2 |
t = thread->pcThr();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
newRPC->thread = t;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool res = false;
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: Launching IRPC\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
if (synchronous) {
|
|
Packit |
ce96f2 |
// We have an interesting problem here. ProcControl allows callbacks to specify whether the
|
|
Packit |
ce96f2 |
// process should stop or run; however, that allows us to stop a process in the middle of an
|
|
Packit |
ce96f2 |
// inferior RPC. If that happens, manually execute a continue and wait for completion ourselves.
|
|
Packit |
ce96f2 |
if (t)
|
|
Packit |
ce96f2 |
res = t->runIRPCSync(newRPC->rpc);
|
|
Packit |
ce96f2 |
else
|
|
Packit |
ce96f2 |
res = pcProc_->runIRPCSync(newRPC->rpc);
|
|
Packit |
ce96f2 |
if (!res) {
|
|
Packit |
ce96f2 |
bool done = false;
|
|
Packit |
ce96f2 |
while (!done) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: Iterating in loop waiting for IRPC to complete\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
if (isTerminated()) {
|
|
Packit |
ce96f2 |
fprintf(stderr, "IRPC on terminated process, ret false!\n");
|
|
Packit |
ce96f2 |
delete newRPC;
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (ProcControlAPI::getLastError() != ProcControlAPI::err_notrunning) {
|
|
Packit |
ce96f2 |
// Something went wrong
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to post %s RPC to %s, error %s\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, (synchronous ? "sync" : "async"),
|
|
Packit |
ce96f2 |
((thread == NULL) ? "thread" : "process"),
|
|
Packit |
ce96f2 |
ProcControlAPI::getLastErrorMsg());
|
|
Packit |
ce96f2 |
delete newRPC;
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: ProcControl reported IRPC thread stopped, continuing and consuming events\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
newRPC->rpc->continueStoppedIRPC();
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: handling events in ProcControl\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
res = pcProc_->handleEvents(true);
|
|
Packit |
ce96f2 |
PCEventMuxer::muxer().handle(NULL);
|
|
Packit |
ce96f2 |
if (newRPC->rpc->state() == ProcControlAPI::IRPC::Done) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: IRPC complete\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
done = true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else {
|
|
Packit |
ce96f2 |
if (t)
|
|
Packit |
ce96f2 |
res = t->runIRPCAsync(newRPC->rpc);
|
|
Packit |
ce96f2 |
else
|
|
Packit |
ce96f2 |
res = pcProc_->runIRPCAsync(newRPC->rpc);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if(!res) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to post %s RPC to %s\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, (synchronous ? "sync" : "async"), ((thread == NULL) ? "thread" : "process"));
|
|
Packit |
ce96f2 |
delete newRPC;
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( result ) {
|
|
Packit |
ce96f2 |
*result = newRPC->returnValue;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Make sure Dyninst has worked everything out
|
|
Packit |
ce96f2 |
PCEventMuxer::muxer().wait(false);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
BPatch_hybridMode PCProcess::getHybridMode() {
|
|
Packit |
ce96f2 |
return analysisMode_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isExploratoryModeOn() const {
|
|
Packit |
ce96f2 |
return BPatch_exploratoryMode == analysisMode_ ||
|
|
Packit |
ce96f2 |
BPatch_defensiveMode == analysisMode_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isRuntimeHeapAddr(Address addr) const {
|
|
Packit |
ce96f2 |
for (unsigned hidx=0; hidx < dyninstRT_heaps_.size(); hidx++) {
|
|
Packit |
ce96f2 |
if (addr >= dyninstRT_heaps_[hidx]->addr &&
|
|
Packit |
ce96f2 |
addr < dyninstRT_heaps_[hidx]->addr + dyninstRT_heaps_[hidx]->length) {
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/* returns true if blocks were overwritten, initializes overwritten
|
|
Packit |
ce96f2 |
* blocks and ranges by contrasting shadow pages with current memory
|
|
Packit |
ce96f2 |
* contents
|
|
Packit |
ce96f2 |
* 1. reads shadow pages in from memory
|
|
Packit |
ce96f2 |
* 2. constructs overwritten region list
|
|
Packit |
ce96f2 |
* 3. constructs overwrittn basic block list
|
|
Packit |
ce96f2 |
* 4. determines if the last of the blocks has an abrupt end, in which
|
|
Packit |
ce96f2 |
* case it marks it as overwritten
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
bool PCProcess::getOverwrittenBlocks
|
|
Packit |
ce96f2 |
( std::map<Address, unsigned char *>& overwrittenPages,//input
|
|
Packit |
ce96f2 |
std::list<std::pair<Address,Address> >& overwrittenRanges,//output
|
|
Packit |
ce96f2 |
std::list<block_instance *> &writtenBBIs)//output
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
const unsigned MEM_PAGE_SIZE = getMemoryPageSize();
|
|
Packit |
ce96f2 |
unsigned char * memVersion = (unsigned char *) ::malloc(MEM_PAGE_SIZE);
|
|
Packit |
ce96f2 |
Address regionStart = 0;
|
|
Packit |
ce96f2 |
bool foundStart = false;
|
|
Packit |
ce96f2 |
map<Address, unsigned char*>::iterator pIter = overwrittenPages.begin();
|
|
Packit |
ce96f2 |
set<mapped_object*> owObjs;
|
|
Packit |
ce96f2 |
for (; pIter != overwrittenPages.end(); pIter++) {
|
|
Packit |
ce96f2 |
Address curPageAddr = (*pIter).first / MEM_PAGE_SIZE * MEM_PAGE_SIZE;
|
|
Packit |
ce96f2 |
unsigned char *curShadow = (*pIter).second;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// 0. check to make sure curShadow is non-null, if it is null,
|
|
Packit |
ce96f2 |
// that means it hasn't been written to
|
|
Packit |
ce96f2 |
if ( ! curShadow ) {
|
|
Packit |
ce96f2 |
cerr << "\t\t No current shadow, continuing" << endl;
|
|
Packit |
ce96f2 |
continue;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
mapped_object* obj = findObject(curPageAddr);
|
|
Packit |
ce96f2 |
if (owObjs.end() != owObjs.find(obj)) {
|
|
Packit |
ce96f2 |
obj->setCodeBytesUpdated(false);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// 1. Read the modified page in from memory
|
|
Packit |
ce96f2 |
Address readAddr = curPageAddr;
|
|
Packit |
ce96f2 |
if (isMemoryEmulated()) {
|
|
Packit |
ce96f2 |
bool valid = false;
|
|
Packit |
ce96f2 |
boost::tie(valid,readAddr) = getMemEm()->translate(curPageAddr);
|
|
Packit |
ce96f2 |
cerr << "\t\t Reading from shadow page " << hex << readAddr << " instead of original " << curPageAddr << endl;
|
|
Packit |
ce96f2 |
assert(valid);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
readTextSpace((void*)readAddr, MEM_PAGE_SIZE, memVersion);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// 2. build overwritten region list by comparing shadow, memory
|
|
Packit |
ce96f2 |
for (unsigned mIdx = 0; mIdx < MEM_PAGE_SIZE; mIdx++) {
|
|
Packit |
ce96f2 |
if ( ! foundStart && curShadow[mIdx] != memVersion[mIdx] ) {
|
|
Packit |
ce96f2 |
foundStart = true;
|
|
Packit |
ce96f2 |
regionStart = curPageAddr+mIdx;
|
|
Packit |
ce96f2 |
} else if (foundStart && curShadow[mIdx] == memVersion[mIdx]) {
|
|
Packit |
ce96f2 |
foundStart = false;
|
|
Packit |
ce96f2 |
cerr << "\t\t Adding overwritten range " << hex << regionStart << " -> " << curPageAddr + mIdx << dec << endl;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
overwrittenRanges.push_back(
|
|
Packit |
ce96f2 |
pair<Address,Address>(regionStart,curPageAddr+mIdx));
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if (foundStart) {
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
foundStart = false;
|
|
Packit |
ce96f2 |
cerr << "\t\t Adding overwritten range " << hex << regionStart << " -> " << curPageAddr + MEM_PAGE_SIZE << dec << endl;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
overwrittenRanges.push_back(
|
|
Packit |
ce96f2 |
pair<Address,Address>(regionStart,curPageAddr+MEM_PAGE_SIZE));
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// 3. Determine which basic blocks have been overwritten
|
|
Packit |
ce96f2 |
list<pair<Address,Address> >::const_iterator rIter = overwrittenRanges.begin();
|
|
Packit |
ce96f2 |
std::list<block_instance*> curBBIs;
|
|
Packit |
ce96f2 |
while (rIter != overwrittenRanges.end()) {
|
|
Packit |
ce96f2 |
mapped_object *curObject = findObject((*rIter).first);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
curObject->findBlocksByRange((*rIter).first,(*rIter).second,curBBIs);
|
|
Packit |
ce96f2 |
if (curBBIs.size()) {
|
|
Packit |
ce96f2 |
mal_printf("overwrote %d blocks in range %lx %lx \n",
|
|
Packit |
ce96f2 |
curBBIs.size(),(*rIter).first,(*rIter).second);
|
|
Packit |
ce96f2 |
writtenBBIs.splice(writtenBBIs.end(), curBBIs);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
curBBIs.clear();
|
|
Packit |
ce96f2 |
rIter++;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
free(memVersion);
|
|
Packit |
ce96f2 |
if (writtenBBIs.size()) {
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
} else {
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// distribute the work to mapped_objects
|
|
Packit |
ce96f2 |
void PCProcess::updateCodeBytes
|
|
Packit |
ce96f2 |
( const list<pair<Address, Address> > &owRanges ) // input
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
std::map<mapped_object *,list<pair<Address,Address> >*> objRanges;
|
|
Packit |
ce96f2 |
list<pair<Address,Address> >::const_iterator rIter = owRanges.begin();
|
|
Packit |
ce96f2 |
for (; rIter != owRanges.end(); rIter++) {
|
|
Packit |
ce96f2 |
mapped_object *obj = findObject((*rIter).first);
|
|
Packit |
ce96f2 |
if (objRanges.find(obj) == objRanges.end()) {
|
|
Packit |
ce96f2 |
objRanges[obj] = new list<pair<Address,Address> >();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
objRanges[obj]->push_back(pair<Address,Address>(rIter->first, rIter->second));
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
std::map<mapped_object *,list<pair<Address,Address> > *>::iterator oIter =
|
|
Packit |
ce96f2 |
objRanges.begin();
|
|
Packit |
ce96f2 |
for (; oIter != objRanges.end(); oIter++)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
oIter->first->updateCodeBytes( *(oIter->second) );
|
|
Packit |
ce96f2 |
delete (oIter->second);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
assert(objRanges.size() <= 1); //o/w analysis code may not be prepared for other cases
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#if 0
|
|
Packit |
ce96f2 |
static void otherFuncBlocks(func_instance *func,
|
|
Packit |
ce96f2 |
const set<block_instance*> &blks,
|
|
Packit |
ce96f2 |
set<block_instance*> &otherBlks)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
const func_instance::BlockSet &allBlocks =
|
|
Packit |
ce96f2 |
func->blocks();
|
|
Packit |
ce96f2 |
for (func_instance::BlockSet::const_iterator bit =
|
|
Packit |
ce96f2 |
allBlocks.begin();
|
|
Packit |
ce96f2 |
bit != allBlocks.end();
|
|
Packit |
ce96f2 |
bit++)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if (blks.end() == blks.find((*bit))) {
|
|
Packit |
ce96f2 |
otherBlks.insert((*bit));
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/* Summary
|
|
Packit |
ce96f2 |
* Given a list of overwritten blocks, find blocks that are unreachable,
|
|
Packit |
ce96f2 |
* functions that have been overwritten at their entry points and can go away,
|
|
Packit |
ce96f2 |
* and new function entry for functions that are being overwritten while still
|
|
Packit |
ce96f2 |
* executing
|
|
Packit |
ce96f2 |
*
|
|
Packit |
ce96f2 |
* variables
|
|
Packit |
ce96f2 |
* f: the overwritten function
|
|
Packit |
ce96f2 |
* ow: the set of overwritten blocks
|
|
Packit |
ce96f2 |
* ex: the set of blocks that are executing on the call stack that were not overwritten
|
|
Packit |
ce96f2 |
*
|
|
Packit |
ce96f2 |
* primitives
|
|
Packit |
ce96f2 |
* R(b,s): yields set of reachable blocks for collection of blocks b, starting
|
|
Packit |
ce96f2 |
* at seed blocks s.
|
|
Packit |
ce96f2 |
* B(f): the blocks pertaining to function f
|
|
Packit |
ce96f2 |
* EP(f): the entry point of function f
|
|
Packit |
ce96f2 |
* F(b): functions containing block b
|
|
Packit |
ce96f2 |
*
|
|
Packit |
ce96f2 |
* calculations
|
|
Packit |
ce96f2 |
* Elim(f): the set of blocks to eliminate from function f.
|
|
Packit |
ce96f2 |
* Elim(f) = B(f) - R( B(f)-ow , EP(f) )
|
|
Packit |
ce96f2 |
* New(f): new function entry candidates for f's surviving blocks.
|
|
Packit |
ce96f2 |
* If EB(f) not in ow(f), empty set
|
|
Packit |
ce96f2 |
* Else, all blocks b such that ( b in ex AND e in Elim(f) )
|
|
Packit |
ce96f2 |
* Eliminate New(f) elements that have ancestors in New(f)
|
|
Packit |
ce96f2 |
* Del(f): A block can be deleted altogether if
|
|
Packit |
ce96f2 |
* forall f in F(b): B(F) - R( B(f) - ow , New(f) U (EP(f) \ ow(f)) U (ex(f) intersect Elim(f)) ),
|
|
Packit |
ce96f2 |
* b is not in the resulting set. In other words, b is not
|
|
Packit |
ce96f2 |
* reachable from non-overwritten blocks in the functions in
|
|
Packit |
ce96f2 |
* which it appears, seeded at new entry points and original
|
|
Packit |
ce96f2 |
* non-overwritten entry points to the function, and at f's
|
|
Packit |
ce96f2 |
* executing blocks if these will be deleted from the
|
|
Packit |
ce96f2 |
* function (they constitute an entry point into the function
|
|
Packit |
ce96f2 |
* even if they've been overwritten).
|
|
Packit |
ce96f2 |
* DeadF: the set of functions that have no executing blocks
|
|
Packit |
ce96f2 |
* and were overwritten in their entry blocks
|
|
Packit |
ce96f2 |
* EP(f) in ow(f) AND ex(f) is empty
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
bool PCProcess::getDeadCode
|
|
Packit |
ce96f2 |
( const std::list<block_instance*> & /*owBlocks*/, // input
|
|
Packit |
ce96f2 |
std::set<block_instance*> & /*delBlocks*/, //output: Del(for all f)
|
|
Packit |
ce96f2 |
std::map<func_instance*,set<block_instance*> > & /*elimMap*/, //output: elimF
|
|
Packit |
ce96f2 |
std::list<func_instance*> & /*deadFuncs*/, //output: DeadF
|
|
Packit |
ce96f2 |
std::map<func_instance*,block_instance*> & /*newFuncEntries*/) //output: newF
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
assert(0 && "TODO");
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
#if 0
|
|
Packit |
ce96f2 |
// do a stackwalk to see which functions are currently executing
|
|
Packit |
ce96f2 |
pdvector<pdvector<Frame> > stacks;
|
|
Packit |
ce96f2 |
pdvector<Address> pcs;
|
|
Packit |
ce96f2 |
if (!walkStacks(stacks)) {
|
|
Packit |
ce96f2 |
inst_printf("%s[%d]: walkStacks failed\n", FILE__, __LINE__);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
for (unsigned i = 0; i < stacks.size(); ++i) {
|
|
Packit |
ce96f2 |
pdvector<Frame> &stack = stacks[i];
|
|
Packit |
ce96f2 |
for (unsigned int j = 0; j < stack.size(); ++j) {
|
|
Packit |
ce96f2 |
Address origPC = 0;
|
|
Packit |
ce96f2 |
vector<func_instance*> dontcare1;
|
|
Packit |
ce96f2 |
baseTramp *dontcare2 = NULL;
|
|
Packit |
ce96f2 |
getAddrInfo(stack[j].getPC(), origPC, dontcare1, dontcare2);
|
|
Packit |
ce96f2 |
pcs.push_back( origPC );
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// group blocks by function
|
|
Packit |
ce96f2 |
std::map<func_instance*,set<block_instance*> > deadMap;
|
|
Packit |
ce96f2 |
std::set<func_instance*> deadEntryFuncs;
|
|
Packit |
ce96f2 |
std::set<Address> owBlockAddrs;
|
|
Packit |
ce96f2 |
for (list<block_instance*>::const_iterator bIter=owBlocks.begin();
|
|
Packit |
ce96f2 |
bIter != owBlocks.end();
|
|
Packit |
ce96f2 |
bIter++)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
deadMap[(*bIter)->func()].insert(*bIter);
|
|
Packit |
ce96f2 |
owBlockAddrs.insert((*bIter)->start());
|
|
Packit |
ce96f2 |
if ((*bIter)->llb() == (*bIter)->func()->ifunc()->entry()) {
|
|
Packit |
ce96f2 |
deadEntryFuncs.insert((*bIter)->func());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// for each modified function, calculate ex, ElimF, NewF, DelF
|
|
Packit |
ce96f2 |
for (map<func_instance*,set<block_instance*> >::iterator fit = deadMap.begin();
|
|
Packit |
ce96f2 |
fit != deadMap.end();
|
|
Packit |
ce96f2 |
fit++)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// calculate ex(f)
|
|
Packit |
ce96f2 |
set<block_instance*> execBlocks;
|
|
Packit |
ce96f2 |
for (unsigned pidx=0; pidx < pcs.size(); pidx++) {
|
|
Packit |
ce96f2 |
std::set<block_instance *> candidateBlocks;
|
|
Packit |
ce96f2 |
fit->first->findBlocksByAddr(pcs[pidx], candidateBlocks);
|
|
Packit |
ce96f2 |
for (std::set<block_instance *>::iterator cb_iter = candidateBlocks.begin();
|
|
Packit |
ce96f2 |
cb_iter != candidateBlocks.end(); ++cb_iter) {
|
|
Packit |
ce96f2 |
block_instance *exB = *cb_iter;
|
|
Packit |
ce96f2 |
if (exB && owBlockAddrs.end() == owBlockAddrs.find(
|
|
Packit |
ce96f2 |
exB->start()))
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
execBlocks.insert(exB);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// calculate DeadF: EP(f) in ow and EP(f) not in ex
|
|
Packit |
ce96f2 |
if ( 0 == execBlocks.size() ) {
|
|
Packit |
ce96f2 |
set<block_instance*>::iterator eb = fit->second.find(
|
|
Packit |
ce96f2 |
fit->first->entryBlock());
|
|
Packit |
ce96f2 |
if (eb != fit->second.end()) {
|
|
Packit |
ce96f2 |
deadFuncs.push_back(fit->first);
|
|
Packit |
ce96f2 |
continue;// treated specially, don't need elimF, NewF or DelF
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// calculate elimF
|
|
Packit |
ce96f2 |
set<block_instance*> keepF;
|
|
Packit |
ce96f2 |
list<block_instance*> seedBs;
|
|
Packit |
ce96f2 |
seedBs.push_back(fit->first->entryBlock());
|
|
Packit |
ce96f2 |
fit->first->getReachableBlocks(fit->second, seedBs, keepF);
|
|
Packit |
ce96f2 |
otherFuncBlocks(fit->first, keepF, elimMap[fit->first]);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// calculate NewF
|
|
Packit |
ce96f2 |
if (deadEntryFuncs.end() != deadEntryFuncs.find(fit->first)) {
|
|
Packit |
ce96f2 |
for (set<block_instance*>::iterator bit = execBlocks.begin();
|
|
Packit |
ce96f2 |
bit != execBlocks.end();
|
|
Packit |
ce96f2 |
bit++)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if (elimMap[fit->first].end() !=
|
|
Packit |
ce96f2 |
elimMap[fit->first].find(*bit))
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
newFuncEntries[fit->first] = *bit;
|
|
Packit |
ce96f2 |
break; // just need one candidate
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// calculate Del(f)
|
|
Packit |
ce96f2 |
seedBs.clear();
|
|
Packit |
ce96f2 |
if (deadEntryFuncs.end() == deadEntryFuncs.find(fit->first)) {
|
|
Packit |
ce96f2 |
seedBs.push_back(fit->first->entryBlock());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else if (newFuncEntries.end() != newFuncEntries.find(fit->first)) {
|
|
Packit |
ce96f2 |
seedBs.push_back(newFuncEntries[fit->first]);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
for (set<block_instance*>::iterator xit = execBlocks.begin();
|
|
Packit |
ce96f2 |
xit != execBlocks.end();
|
|
Packit |
ce96f2 |
xit++)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if (elimMap[fit->first].end() != elimMap[fit->first].find(*xit)) {
|
|
Packit |
ce96f2 |
seedBs.push_back(*xit);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
keepF.clear();
|
|
Packit |
ce96f2 |
fit->first->getReachableBlocks(fit->second, seedBs, keepF);
|
|
Packit |
ce96f2 |
otherFuncBlocks(fit->first, keepF, delBlocks);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// will flush addresses of all addresses in the specified range, if the
|
|
Packit |
ce96f2 |
// range is null, flush all addresses from the cache. Also flush
|
|
Packit |
ce96f2 |
// rt-lib heap addrs that correspond to the range
|
|
Packit |
ce96f2 |
void PCProcess::flushAddressCache_RT(Address start, unsigned size)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if (start != 0) {
|
|
Packit |
ce96f2 |
mal_printf("Flushing address cache of range [%lx %lx]\n",
|
|
Packit |
ce96f2 |
start,
|
|
Packit |
ce96f2 |
start + size);
|
|
Packit |
ce96f2 |
} else {
|
|
Packit |
ce96f2 |
mal_printf("Flushing address cache of rt_lib heap addrs only \n");
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Find the runtime cache's address if it hasn't been set yet
|
|
Packit |
ce96f2 |
if (0 == RT_address_cache_addr_) {
|
|
Packit |
ce96f2 |
std::string arg_str ("DYNINST_target_cache");
|
|
Packit |
ce96f2 |
pdvector<int_variable *> vars;
|
|
Packit |
ce96f2 |
if ( ! findVarsByAll(arg_str, vars) ) {
|
|
Packit |
ce96f2 |
fprintf(stderr, "%s[%d]: cannot find var %s\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, arg_str.c_str());
|
|
Packit |
ce96f2 |
assert(0);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if (vars.size() != 1) {
|
|
Packit |
ce96f2 |
fprintf(stderr, "%s[%d]: ERROR: %d vars matching %s, not 1\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, (int)vars.size(), arg_str.c_str());
|
|
Packit |
ce96f2 |
assert(0);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
RT_address_cache_addr_ = vars[0]->getAddress();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Clear all cache entries that match the runtime library
|
|
Packit |
ce96f2 |
// Read in the contents of the cache
|
|
Packit |
ce96f2 |
Address* cacheCopy = (Address*)malloc(TARGET_CACHE_WIDTH*sizeof(Address));
|
|
Packit |
ce96f2 |
if ( ! readDataSpace( (void*)RT_address_cache_addr_,
|
|
Packit |
ce96f2 |
sizeof(Address)*TARGET_CACHE_WIDTH,(void*)cacheCopy,
|
|
Packit |
ce96f2 |
false ) )
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
assert(0);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
assert(dyninstRT_heaps_.size());
|
|
Packit |
ce96f2 |
bool flushedHeaps = false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
while ( true ) // iterate twice, once to flush the heaps,
|
|
Packit |
ce96f2 |
{ // and once to flush the flush range
|
|
Packit |
ce96f2 |
Address flushStart=0;
|
|
Packit |
ce96f2 |
Address flushEnd=0;
|
|
Packit |
ce96f2 |
if (!flushedHeaps) {
|
|
Packit |
ce96f2 |
// figure out the range of addresses we'll want to flush from
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
flushStart = dyninstRT_heaps_[0]->addr;
|
|
Packit |
ce96f2 |
flushEnd = flushStart + dyninstRT_heaps_[0]->length;
|
|
Packit |
ce96f2 |
for (unsigned idx=1; idx < dyninstRT_heaps_.size(); idx++) {
|
|
Packit |
ce96f2 |
Address curAddr = dyninstRT_heaps_[idx]->addr;
|
|
Packit |
ce96f2 |
if (flushStart > curAddr) {
|
|
Packit |
ce96f2 |
flushStart = curAddr;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
curAddr += dyninstRT_heaps_[idx]->length;
|
|
Packit |
ce96f2 |
if (flushEnd < curAddr) {
|
|
Packit |
ce96f2 |
flushEnd = curAddr;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
} else {
|
|
Packit |
ce96f2 |
flushStart = start;
|
|
Packit |
ce96f2 |
flushEnd = start + size;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
//zero out entries that lie in the runtime heaps
|
|
Packit |
ce96f2 |
for(int idx=0; idx < TARGET_CACHE_WIDTH; idx++) {
|
|
Packit |
ce96f2 |
//printf("cacheCopy[%d]=%lx\n",idx,cacheCopy[idx]);
|
|
Packit |
ce96f2 |
if (flushStart <= cacheCopy[idx] &&
|
|
Packit |
ce96f2 |
flushEnd > cacheCopy[idx]) {
|
|
Packit |
ce96f2 |
cacheCopy[idx] = 0;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if ( flushedHeaps || (start == 0) ) {
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
flushedHeaps = true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// write the modified cache back into the RT_library
|
|
Packit |
ce96f2 |
if ( ! writeDataSpace( (void*)RT_address_cache_addr_,
|
|
Packit |
ce96f2 |
sizeof(Address)*TARGET_CACHE_WIDTH,
|
|
Packit |
ce96f2 |
(void*)cacheCopy ) ) {
|
|
Packit |
ce96f2 |
assert(0);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
free(cacheCopy);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/* Given an address that's on the call stack, find the function that's
|
|
Packit |
ce96f2 |
* actively executing that address. This makes most sense for finding the
|
|
Packit |
ce96f2 |
* address that's triggered a context switch back to Dyninst, either
|
|
Packit |
ce96f2 |
* through instrumentation or a signal
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
func_instance *PCProcess::findActiveFuncByAddr(Address addr)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
std::set<func_instance *> funcs;
|
|
Packit |
ce96f2 |
// error checking by size...
|
|
Packit |
ce96f2 |
(void)findFuncsByAddr(addr, funcs, true);
|
|
Packit |
ce96f2 |
if (funcs.empty()) return NULL;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (funcs.size() == 1) {
|
|
Packit |
ce96f2 |
return *(funcs.begin());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// unrelocated shared function address, do a stack walk to figure
|
|
Packit |
ce96f2 |
// out which of the shared functions is on the call stack
|
|
Packit |
ce96f2 |
bool foundFrame = false;
|
|
Packit |
ce96f2 |
func_instance *activeFunc = NULL;
|
|
Packit |
ce96f2 |
pdvector<pdvector<Frame> > stacks;
|
|
Packit |
ce96f2 |
if ( false == walkStacks(stacks) ) {
|
|
Packit |
ce96f2 |
fprintf(stderr,"ERROR: %s[%d], walkStacks failed\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__);
|
|
Packit |
ce96f2 |
assert(0);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
for (unsigned int i = 0; !foundFrame && i < stacks.size(); ++i) {
|
|
Packit |
ce96f2 |
pdvector<Frame> &stack = stacks[i];
|
|
Packit |
ce96f2 |
for (unsigned int j = 0; !foundFrame && j < stack.size(); ++j) {
|
|
Packit |
ce96f2 |
Frame *curFrame = &stack[j];
|
|
Packit |
ce96f2 |
Address framePC = curFrame->getPC();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// if we're at a relocated address, we can translate
|
|
Packit |
ce96f2 |
// back to the right function, if translation fails
|
|
Packit |
ce96f2 |
// frameFunc will still be NULL
|
|
Packit |
ce96f2 |
RelocInfo ri;
|
|
Packit |
ce96f2 |
func_instance *frameFunc = NULL;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (getRelocInfo(framePC, ri) &&
|
|
Packit |
ce96f2 |
ri.func) {
|
|
Packit |
ce96f2 |
frameFunc = ri.func;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else if (j < (stack.size() - 1)) {
|
|
Packit |
ce96f2 |
// Okay, crawl original code.
|
|
Packit |
ce96f2 |
// Step 1: get our current function
|
|
Packit |
ce96f2 |
std::set<func_instance *> curFuncs;
|
|
Packit |
ce96f2 |
findFuncsByAddr(framePC, curFuncs);
|
|
Packit |
ce96f2 |
// Step 2: get return addresses one frame up and map to possible callers
|
|
Packit |
ce96f2 |
std::set<block_instance *> callerBlocks;
|
|
Packit |
ce96f2 |
findBlocksByAddr(stack[j+1].getPC() - 1, callerBlocks);
|
|
Packit |
ce96f2 |
for (std::set<block_instance *>::iterator cb_iter = callerBlocks.begin();
|
|
Packit |
ce96f2 |
cb_iter != callerBlocks.end(); ++cb_iter)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if (!(*cb_iter)->containsCall()) continue;
|
|
Packit |
ce96f2 |
// We have a call point; now see if it called the entry of any function
|
|
Packit |
ce96f2 |
// that maps to a curFunc.
|
|
Packit |
ce96f2 |
for (std::set<func_instance *>::iterator cf_iter = curFuncs.begin();
|
|
Packit |
ce96f2 |
cf_iter != curFuncs.end(); ++cf_iter) {
|
|
Packit |
ce96f2 |
if ((*cf_iter) == (*cb_iter)->callee()) {
|
|
Packit |
ce96f2 |
frameFunc = *cf_iter;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if (frameFunc) {
|
|
Packit |
ce96f2 |
foundFrame = true;
|
|
Packit |
ce96f2 |
activeFunc = frameFunc;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if (!foundFrame) {
|
|
Packit |
ce96f2 |
activeFunc = *(funcs.begin());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return activeFunc;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::patchPostCallArea(instPoint *callPt) {
|
|
Packit |
ce96f2 |
// 1) Find all the post-call patch areas that correspond to this
|
|
Packit |
ce96f2 |
// call point
|
|
Packit |
ce96f2 |
// 2) Generate and install the branches that will be inserted into
|
|
Packit |
ce96f2 |
// these patch areas
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// 1...
|
|
Packit |
ce96f2 |
AddrPairSet patchAreas;
|
|
Packit |
ce96f2 |
if ( ! generateRequiredPatches(callPt, patchAreas) ) {
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// 2...
|
|
Packit |
ce96f2 |
generatePatchBranches(patchAreas);
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::generateRequiredPatches(instPoint *callPoint,
|
|
Packit |
ce96f2 |
AddrPairSet &patchAreas)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
// We need to figure out where this patch should branch to.
|
|
Packit |
ce96f2 |
// To do that, we're going to:
|
|
Packit |
ce96f2 |
// 1) Forward map the entry of the ft block to
|
|
Packit |
ce96f2 |
// its most recent relocated version (if that exists)
|
|
Packit |
ce96f2 |
// 2) For each padding area, create a (padAddr,target) pair
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// 3)
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
block_instance *callB = callPoint->block();
|
|
Packit |
ce96f2 |
block_instance *ftBlk = callB->getFallthrough()->trg();
|
|
Packit |
ce96f2 |
if (!ftBlk) {
|
|
Packit |
ce96f2 |
// find the block at the next address, if there's no fallthrough block
|
|
Packit |
ce96f2 |
ftBlk = callB->obj()->findBlockByEntry(callB->end());
|
|
Packit |
ce96f2 |
assert(ftBlk);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// ensure that we patch other callPts at the same address
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
vector<ParseAPI::Function*> callFuncs;
|
|
Packit |
ce96f2 |
callPoint->block()->llb()->getFuncs(callFuncs);
|
|
Packit |
ce96f2 |
for (vector<ParseAPI::Function*>::iterator fit = callFuncs.begin();
|
|
Packit |
ce96f2 |
fit != callFuncs.end();
|
|
Packit |
ce96f2 |
fit++)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
func_instance *callF = findFunction((parse_func*)*fit);
|
|
Packit |
ce96f2 |
instPoint *callP = instPoint::preCall(callF, callB);
|
|
Packit |
ce96f2 |
Relocation::CodeTracker::RelocatedElements reloc;
|
|
Packit |
ce96f2 |
CodeTrackers::reverse_iterator rit;
|
|
Packit |
ce96f2 |
for (rit = relocatedCode_.rbegin(); rit != relocatedCode_.rend(); rit++)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if ((*rit)->origToReloc(ftBlk->start(), ftBlk, callF, reloc)) {
|
|
Packit |
ce96f2 |
break;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if (rit == relocatedCode_.rend()) {
|
|
Packit |
ce96f2 |
mal_printf("WARNING: no relocs of call-fallthrough at %lx "
|
|
Packit |
ce96f2 |
"in func at %lx, will not patch its post-call "
|
|
Packit |
ce96f2 |
"padding\n", callP->block()->last(),callF->addr());
|
|
Packit |
ce96f2 |
(*relocatedCode_.rbegin())->debug();
|
|
Packit |
ce96f2 |
continue;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address to = reloc.instruction;
|
|
Packit |
ce96f2 |
if (!reloc.instrumentation.empty()) {
|
|
Packit |
ce96f2 |
// There could be a lot of instrumentation at this point. Bias towards the lowest,
|
|
Packit |
ce96f2 |
// non-edge instrumentation
|
|
Packit |
ce96f2 |
for (std::map<instPoint *, Address>::iterator inst_iter = reloc.instrumentation.begin();
|
|
Packit |
ce96f2 |
inst_iter != reloc.instrumentation.end(); ++inst_iter) {
|
|
Packit |
ce96f2 |
if (inst_iter->first->type() == PatchAPI::Point::EdgeDuring) continue;
|
|
Packit |
ce96f2 |
to = (inst_iter->second < to) ? inst_iter->second : to;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// 2)
|
|
Packit |
ce96f2 |
Address callInsnAddr = callP->block()->last();
|
|
Packit |
ce96f2 |
if (forwardDefensiveMap_.end() != forwardDefensiveMap_.find(callInsnAddr)) {
|
|
Packit |
ce96f2 |
map<func_instance*,set<DefensivePad> >::iterator mit = forwardDefensiveMap_[callInsnAddr].begin();
|
|
Packit |
ce96f2 |
for (; mit != forwardDefensiveMap_[callInsnAddr].end(); ++mit) {
|
|
Packit |
ce96f2 |
if (callF == mit->first) {
|
|
Packit |
ce96f2 |
set<DefensivePad>::iterator dit = mit->second.begin();
|
|
Packit |
ce96f2 |
for (; dit != mit->second.end(); ++dit) {
|
|
Packit |
ce96f2 |
Address jumpAddr = dit->first;
|
|
Packit |
ce96f2 |
patchAreas.insert(std::make_pair(jumpAddr, to));
|
|
Packit |
ce96f2 |
mal_printf("patching post-call pad for %lx[%lx] with %lx %s[%d]\n",
|
|
Packit |
ce96f2 |
callB->end(), jumpAddr, to, FILE__,__LINE__);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
if (patchAreas.empty()) {
|
|
Packit |
ce96f2 |
mal_printf("WARNING: no relocs to patch for call at %lx, block end %lx\n",
|
|
Packit |
ce96f2 |
callPoint->addr_compat(),ftBlk->start());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
return ! patchAreas.empty();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::generatePatchBranches(AddrPairSet &branchesNeeded) {
|
|
Packit |
ce96f2 |
for (AddrPairSet::iterator iter = branchesNeeded.begin();
|
|
Packit |
ce96f2 |
iter != branchesNeeded.end(); ++iter)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
Address from = iter->first;
|
|
Packit |
ce96f2 |
Address to = iter->second;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
codeGen gen(64);
|
|
Packit |
ce96f2 |
insnCodeGen::generateBranch(gen, from, to);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Safety check: make sure we didn't overrun the patch area
|
|
Packit |
ce96f2 |
Address lb = 0, ub = 0;
|
|
Packit |
ce96f2 |
std::pair<func_instance*,Address> tmp;
|
|
Packit |
ce96f2 |
if (!reverseDefensiveMap_.find(from, lb, ub, tmp)) {
|
|
Packit |
ce96f2 |
// Huh? This worked before!
|
|
Packit |
ce96f2 |
assert(0);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
assert((from + gen.used()) <= ub);
|
|
Packit |
ce96f2 |
if (!writeTextSpace((void *)from,
|
|
Packit |
ce96f2 |
gen.used(),
|
|
Packit |
ce96f2 |
gen.start_ptr())) {
|
|
Packit |
ce96f2 |
assert(0);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/* debugSuicide is a kind of alternate debugging continueProc. It runs the
|
|
Packit |
ce96f2 |
* process until terminated in single step mode, printing each instruction as
|
|
Packit |
ce96f2 |
* it executes.
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
void PCProcess::debugSuicide() {
|
|
Packit |
ce96f2 |
if( isTerminated() ) return;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
isInDebugSuicide_ = true;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
pdvector<Frame> activeFrames;
|
|
Packit |
ce96f2 |
getAllActiveFrames(activeFrames);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for(unsigned i=0; i < activeFrames.size(); ++i) {
|
|
Packit |
ce96f2 |
Address addr = activeFrames[i].getPC();
|
|
Packit |
ce96f2 |
fprintf(stderr, "Frame %u @ 0x%lx\n", i , addr);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Thread::ptr initialThread = pcProc_->threads().getInitialThread();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
initialThread->setSingleStepMode(true);
|
|
Packit |
ce96f2 |
while( !isTerminated() && isAttached() && initialThread->isLive() ) {
|
|
Packit |
ce96f2 |
// Get the current PC
|
|
Packit |
ce96f2 |
MachRegister pcReg = MachRegister::getPC(getArch());
|
|
Packit |
ce96f2 |
MachRegisterVal resultVal;
|
|
Packit |
ce96f2 |
if( !initialThread->getRegister(pcReg, resultVal) ) {
|
|
Packit |
ce96f2 |
fprintf(stderr, "%s[%d]: failed to retreive register from thread %d/%d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid(), initialThread->getLWP());
|
|
Packit |
ce96f2 |
return;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
pdvector<func_instance *> PCProcess::pcsToFuncs(pdvector<Frame> stackWalk) {
|
|
Packit |
ce96f2 |
pdvector <func_instance *> ret;
|
|
Packit |
ce96f2 |
unsigned i;
|
|
Packit |
ce96f2 |
func_instance *fn;
|
|
Packit |
ce96f2 |
for(i=0;i
|
|
Packit |
ce96f2 |
fn = (func_instance *)findOneFuncByAddr(stackWalk[i].getPC());
|
|
Packit |
ce96f2 |
// no reason to add a null function to ret
|
|
Packit |
ce96f2 |
if (fn != 0) ret.push_back(fn);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
return ret;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isInSignalHandler(Address addr) {
|
|
Packit |
ce96f2 |
codeRange *range;
|
|
Packit |
ce96f2 |
if( signalHandlerLocations_.find(addr, range) ) {
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::addSignalHandler(Address addr, unsigned size) {
|
|
Packit |
ce96f2 |
codeRange *handlerLoc;
|
|
Packit |
ce96f2 |
if (signalHandlerLocations_.find(addr, handlerLoc)) {
|
|
Packit |
ce96f2 |
return; // we're already tracking this location
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
handlerLoc = new signal_handler_location(addr, size);
|
|
Packit |
ce96f2 |
signalHandlerLocations_.insert((signal_handler_location *)handlerLoc);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::mappedObjIsDeleted(mapped_object *obj) {
|
|
Packit |
ce96f2 |
for(unsigned i = 0; i < deletedObjects_.size(); ++i) {
|
|
Packit |
ce96f2 |
if( obj == deletedObjects_[i] ) return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// AddressSpace Implementation //
|
|
Packit |
ce96f2 |
Address PCProcess::offset() const {
|
|
Packit |
ce96f2 |
assert(!"This function is not implemented");
|
|
Packit |
ce96f2 |
return 0;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address PCProcess::length() const {
|
|
Packit |
ce96f2 |
assert(!"This function is not implemented");
|
|
Packit |
ce96f2 |
return 0;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Architecture PCProcess::getArch() const {
|
|
Packit |
ce96f2 |
return savedArch_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::multithread_ready(bool ignoreIfMtNotSet) {
|
|
Packit |
ce96f2 |
// Since ProcControlAPI has taken over handling thread creation
|
|
Packit |
ce96f2 |
// and destruction from the RT library, as soon as the process reaches
|
|
Packit |
ce96f2 |
// the initialized state, the process is multithread ready if it
|
|
Packit |
ce96f2 |
// is multithread capable.
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !hasReachedBootstrapState(bs_initialized) ) return false;
|
|
Packit |
ce96f2 |
if( !multithread_capable(ignoreIfMtNotSet) ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::needsPIC() {
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::isInDebugSuicide() const {
|
|
Packit |
ce96f2 |
return isInDebugSuicide_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
PCProcess::processState_t PCProcess::getDesiredProcessState() const {
|
|
Packit |
ce96f2 |
return processState_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::setDesiredProcessState(PCProcess::processState_t pc) {
|
|
Packit |
ce96f2 |
processState_ = pc;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::walkStack(pdvector<Frame> &stackWalk,
|
|
Packit |
ce96f2 |
PCThread *thread)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( stackwalker_ == NULL ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
vector<Dyninst::Stackwalker::Frame> swWalk;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (!stackwalker_->walkStack(swWalk, thread->getLWP()))
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
for (vector<Dyninst::Stackwalker::Frame>::iterator SWB = swWalk.begin(),
|
|
Packit |
ce96f2 |
SWI = SWB,
|
|
Packit |
ce96f2 |
SWE = swWalk.end();
|
|
Packit |
ce96f2 |
SWI != SWE;
|
|
Packit |
ce96f2 |
++SWI)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
stackWalk.push_back(Frame(*SWI, this, thread, (SWI == SWB)));
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::getActiveFrame(Frame &frame, PCThread *thread)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
Dyninst::Stackwalker::Frame swFrame;
|
|
Packit |
ce96f2 |
if (!stackwalker_->getInitialFrame(swFrame, thread->getLWP()))
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
frame = Frame(swFrame, this, thread, true);
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/* This is the simple version
|
|
Packit |
ce96f2 |
* 1. Need three pieces of information:
|
|
Packit |
ce96f2 |
* 1a. The instrumentation point that triggered the stopThread event (pointAddress)
|
|
Packit |
ce96f2 |
* 1b. The ID of the callback function given at the registration
|
|
Packit |
ce96f2 |
* of the stopThread snippet
|
|
Packit |
ce96f2 |
* 1c. The result of the snippet calculation that was given by the user,
|
|
Packit |
ce96f2 |
* if the point is a return instruction, read the return address
|
|
Packit |
ce96f2 |
* 2. If the calculation is an address that is meant to be interpreted, do that
|
|
Packit |
ce96f2 |
* 3. Invoke the callback
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
bool PCProcess::triggerStopThread(Address pointAddress, int callbackID, void *calculation) {
|
|
Packit |
ce96f2 |
AddressSpace::RelocInfo ri;
|
|
Packit |
ce96f2 |
if( !getRelocInfo(pointAddress, ri) ) {
|
|
Packit |
ce96f2 |
assert(0);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// get instPoint from point address
|
|
Packit |
ce96f2 |
func_instance *pointfunc = ri.func;
|
|
Packit |
ce96f2 |
if (!pointfunc) {
|
|
Packit |
ce96f2 |
mal_printf("%s[%d]: failed to find active function at 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, pointAddress);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
instPoint *intPoint = ri.bt->point();
|
|
Packit |
ce96f2 |
if (!intPoint) {
|
|
Packit |
ce96f2 |
mal_printf("%s[%d]: failed to find inst point at 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, pointAddress);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
mal_printf("handling stopThread %lx[%lx]=>%lx %s[%d]\n",
|
|
Packit |
ce96f2 |
ri.reloc, pointAddress, (long)calculation, FILE__, __LINE__);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/* 2. If the callbackID is negative, the calculation is meant to be
|
|
Packit |
ce96f2 |
interpreted as the address of code, so we call stopThreadCtrlTransfer
|
|
Packit |
ce96f2 |
to translate the target to an unrelocated address */
|
|
Packit |
ce96f2 |
if (callbackID < 0) {
|
|
Packit |
ce96f2 |
callbackID *= -1;
|
|
Packit |
ce96f2 |
calculation = (void*)
|
|
Packit |
ce96f2 |
stopThreadCtrlTransfer(intPoint, (Address)calculation);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/* 3. Trigger the callback for the stopThread
|
|
Packit |
ce96f2 |
using the correct snippet instance ID & event type */
|
|
Packit |
ce96f2 |
((BPatch_process*)up_ptr())->triggerStopThread
|
|
Packit |
ce96f2 |
(intPoint, pointfunc, callbackID, (void*)calculation);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
/* If calculation is a relocated address, translate it to the original addr
|
|
Packit |
ce96f2 |
* case 1: The point is at a return instruction
|
|
Packit |
ce96f2 |
* case 2: The point is a control transfer into the runtime library
|
|
Packit |
ce96f2 |
* Mark returning functions as returning
|
|
Packit |
ce96f2 |
* Save the targets of indirect control transfers (not regular returns)
|
|
Packit |
ce96f2 |
*/
|
|
Packit |
ce96f2 |
Address PCProcess::stopThreadCtrlTransfer (instPoint* intPoint,
|
|
Packit |
ce96f2 |
Address target)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
Address pointAddr = intPoint->addr_compat();
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// if the point is a real return instruction and its target is a stack
|
|
Packit |
ce96f2 |
// address, get the return address off of the stack
|
|
Packit |
ce96f2 |
if (intPoint->type() == instPoint::FuncExit &&
|
|
Packit |
ce96f2 |
intPoint->block()->isFuncExit() &&
|
|
Packit |
ce96f2 |
!intPoint->func()->isSignalHandler())
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
mal_printf("%s[%d]: return address is %lx\n", FILE__,
|
|
Packit |
ce96f2 |
__LINE__,target);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address unrelocTarget = target;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if ( isRuntimeHeapAddr( target ) ) {
|
|
Packit |
ce96f2 |
// get unrelocated target address, there are three possibilities
|
|
Packit |
ce96f2 |
// a. We're in post-call padding, and targBBI is the call block
|
|
Packit |
ce96f2 |
// b. We're in an analyzed fallthrough block
|
|
Packit |
ce96f2 |
// c. The stack was tampered with and we need the (mod_pc - pc)
|
|
Packit |
ce96f2 |
// offset to figure out where we should be
|
|
Packit |
ce96f2 |
malware_cerr << "Looking for matches to incoming address "
|
|
Packit |
ce96f2 |
<< hex << target << dec << endl;
|
|
Packit |
ce96f2 |
std::pair<func_instance*,Address> tmp;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if ( reverseDefensiveMap_.find(target,tmp) ) {
|
|
Packit |
ce96f2 |
// a.
|
|
Packit |
ce96f2 |
std::set<block_instance*> callBs;
|
|
Packit |
ce96f2 |
tmp.first->getBlocks(tmp.second, callBs);
|
|
Packit |
ce96f2 |
block_instance *callB = (*callBs.begin());
|
|
Packit |
ce96f2 |
edge_instance *fallthrough = callB->getFallthrough();
|
|
Packit |
ce96f2 |
if (fallthrough) {
|
|
Packit |
ce96f2 |
unrelocTarget = fallthrough->trg()->start();
|
|
Packit |
ce96f2 |
} else {
|
|
Packit |
ce96f2 |
unrelocTarget = callB->end();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else {
|
|
Packit |
ce96f2 |
// b.
|
|
Packit |
ce96f2 |
// if we're in the fallthrough block, match to call block,
|
|
Packit |
ce96f2 |
// and if necessary, add fallthrough edge
|
|
Packit |
ce96f2 |
AddressSpace::RelocInfo ri;
|
|
Packit |
ce96f2 |
bool hasFT = getRelocInfo(target, ri);
|
|
Packit |
ce96f2 |
assert(hasFT); // otherwise we should be in the defensive map
|
|
Packit |
ce96f2 |
if (ri.pad) {
|
|
Packit |
ce96f2 |
unrelocTarget = ri.block->end();
|
|
Packit |
ce96f2 |
} else {
|
|
Packit |
ce96f2 |
unrelocTarget = ri.block->start();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
mal_printf("translated target %lx to %lx %s[%d]\n",
|
|
Packit |
ce96f2 |
target, unrelocTarget, FILE__, __LINE__);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else { // target is not relocated, nothing to do but find the
|
|
Packit |
ce96f2 |
// mapped_object, creating one if necessary, for transfers
|
|
Packit |
ce96f2 |
// into memory regions that are allocated at runtime
|
|
Packit |
ce96f2 |
mapped_object *obj = findObject(target);
|
|
Packit |
ce96f2 |
if (!obj) {
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#if 0
|
|
Packit |
ce96f2 |
Frame activeFrame = threads[0]->get_lwp()->getActiveFrame();
|
|
Packit |
ce96f2 |
for (unsigned i = 0; i < 0x100; ++i) {
|
|
Packit |
ce96f2 |
Address stackTOP = activeFrame.esp;
|
|
Packit |
ce96f2 |
Address stackTOPVAL =0;
|
|
Packit |
ce96f2 |
readDataSpace((void *) (stackTOP + 4*i),
|
|
Packit |
ce96f2 |
sizeof(getAddressWidth()),
|
|
Packit |
ce96f2 |
&stackTOPVAL, false);
|
|
Packit |
ce96f2 |
malware_cerr << "\tSTACK[" << hex << stackTOP+4*i << "]="
|
|
Packit |
ce96f2 |
<< stackTOPVAL << dec << endl;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
obj = createObjectNoFile(target);
|
|
Packit |
ce96f2 |
if (!obj) {
|
|
Packit |
ce96f2 |
fprintf(stderr,"ERROR, point %lx has target %lx that responds "
|
|
Packit |
ce96f2 |
"to no object %s[%d]\n", pointAddr, target,
|
|
Packit |
ce96f2 |
FILE__,__LINE__);
|
|
Packit |
ce96f2 |
assert(0 && "stopThread snippet has an invalid target");
|
|
Packit |
ce96f2 |
return 0;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
#if 0
|
|
Packit |
ce96f2 |
Frame activeFrame = threads[0]->get_lwp()->getActiveFrame();
|
|
Packit |
ce96f2 |
Address stackTOP = activeFrame.esp;
|
|
Packit |
ce96f2 |
Address stackTOPVAL =0;
|
|
Packit |
ce96f2 |
for (unsigned i = 0;
|
|
Packit |
ce96f2 |
i < 0x100 && 0 != ((stackTOP + 4*i) % memoryPageSize_);
|
|
Packit |
ce96f2 |
++i)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
readDataSpace((void *) (stackTOP + 4*i),
|
|
Packit |
ce96f2 |
sizeof(getAddressWidth()),
|
|
Packit |
ce96f2 |
&stackTOPVAL, false);
|
|
Packit |
ce96f2 |
malware_cerr << "\tSTACK[" << hex << stackTOP+4*i << "]="
|
|
Packit |
ce96f2 |
<< stackTOPVAL << dec << endl;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
#endif
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return unrelocTarget;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::triggerNormalExit(int exitcode) {
|
|
Packit |
ce96f2 |
for(std::map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
|
|
Packit |
ce96f2 |
i != threadsByTid_.end(); ++i)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( i->second != initialThread_ )
|
|
Packit |
ce96f2 |
BPatch::bpatch->registerThreadExit(this, i->second);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
BPatch::bpatch->registerNormalExit(this, exitcode);
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Let the event handler know that the process should be moved to
|
|
Packit |
ce96f2 |
// an exited state
|
|
Packit |
ce96f2 |
setExiting(true);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Debugging only
|
|
Packit |
ce96f2 |
bool PCProcess::setBreakpoint(Address addr) {
|
|
Packit |
ce96f2 |
Breakpoint::ptr brkPt = Breakpoint::newBreakpoint();
|
|
Packit |
ce96f2 |
if( !pcProc_->addBreakpoint(addr, brkPt) ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to set breakpoint at 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, addr);
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::launchDebugger() {
|
|
Packit |
ce96f2 |
// Stop the process on detach
|
|
Packit |
ce96f2 |
pdvector<func_instance *> breakpointFuncs;
|
|
Packit |
ce96f2 |
if( !findFuncsByAll("DYNINSTsafeBreakPoint", breakpointFuncs) ) {
|
|
Packit |
ce96f2 |
fprintf(stderr, "Failed to find function DYNINSTsafeBreakPoint\n");
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
func_instance *safeBreakpoint = breakpointFuncs[0];
|
|
Packit |
ce96f2 |
for(map<dynthread_t, PCThread *>::iterator i = threadsByTid_.begin();
|
|
Packit |
ce96f2 |
i != threadsByTid_.end(); ++i)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if( !i->second->pcThr_->setRegister(MachRegister::getPC(getArch()),
|
|
Packit |
ce96f2 |
safeBreakpoint->addr()) )
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
fprintf(stderr, "Failed to set PC to 0x%lx\n",
|
|
Packit |
ce96f2 |
safeBreakpoint->addr());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// Detach the process
|
|
Packit |
ce96f2 |
if( !detachProcess(true) ) {
|
|
Packit |
ce96f2 |
fprintf(stderr, "Failed to detach from process %d\n", getPid());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !startDebugger() ) {
|
|
Packit |
ce96f2 |
fprintf(stderr, "Failed to start debugger on process %d\n", getPid());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// End debugging
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address getVarAddr(PCProcess *proc, std::string str) {
|
|
Packit |
ce96f2 |
Address retAddr = 0;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
pdvector<int_variable *> vars;
|
|
Packit |
ce96f2 |
if( proc->findVarsByAll(str, vars) ) {
|
|
Packit |
ce96f2 |
if( vars.size() != 1 ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: WARNING: multiple copies of %s found\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, str.c_str());
|
|
Packit |
ce96f2 |
}else{
|
|
Packit |
ce96f2 |
retAddr = vars[0]->getAddress();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}else{
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to find variable %s\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, str.c_str());
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
return retAddr;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address PCProcess::getRTEventBreakpointAddr() {
|
|
Packit |
ce96f2 |
if( sync_event_breakpoint_addr_ == 0 ) {
|
|
Packit |
ce96f2 |
sync_event_breakpoint_addr_ = getVarAddr(this, "DYNINST_break_point_event");
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return sync_event_breakpoint_addr_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address PCProcess::getRTEventIdAddr() {
|
|
Packit |
ce96f2 |
if( sync_event_id_addr_ == 0 ) {
|
|
Packit |
ce96f2 |
sync_event_id_addr_ = getVarAddr(this, "DYNINST_synch_event_id");
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return sync_event_id_addr_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address PCProcess::getRTEventArg1Addr() {
|
|
Packit |
ce96f2 |
if( sync_event_arg1_addr_ == 0 ) {
|
|
Packit |
ce96f2 |
sync_event_arg1_addr_ = getVarAddr(this, "DYNINST_synch_event_arg1");
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return sync_event_arg1_addr_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address PCProcess::getRTEventArg2Addr() {
|
|
Packit |
ce96f2 |
if( sync_event_arg2_addr_ == 0 ) {
|
|
Packit |
ce96f2 |
sync_event_arg2_addr_ = getVarAddr(this, "DYNINST_synch_event_arg2");
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return sync_event_arg2_addr_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
Address PCProcess::getRTEventArg3Addr() {
|
|
Packit |
ce96f2 |
if( sync_event_arg3_addr_ == 0 ) {
|
|
Packit |
ce96f2 |
sync_event_arg3_addr_ = getVarAddr(this, "DYNINST_synch_event_arg3");
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return sync_event_arg3_addr_;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::hasPendingEvents() {
|
|
Packit |
ce96f2 |
// Go to the muxer as a final arbiter
|
|
Packit |
ce96f2 |
return PCEventMuxer::muxer().hasPendingEvents(this);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::hasRunningSyncRPC() const {
|
|
Packit |
ce96f2 |
return (syncRPCThreads_.size() > 0);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::addSyncRPCThread(Thread::ptr thr) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: added sync rpc thread %d/%d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid(), thr ? thr->getLWP() : 0);
|
|
Packit |
ce96f2 |
syncRPCThreads_.insert(thr);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::removeSyncRPCThread(Thread::ptr thr) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: removed sync rpc thread %d/%d\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid(), thr ? thr->getLWP() : 0);
|
|
Packit |
ce96f2 |
syncRPCThreads_.erase(thr);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool PCProcess::continueSyncRPCThreads() {
|
|
Packit |
ce96f2 |
for(set<Thread::ptr>::iterator i = syncRPCThreads_.begin();
|
|
Packit |
ce96f2 |
i != syncRPCThreads_.end(); ++i)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
if(!(*i)) {
|
|
Packit |
ce96f2 |
if(!pcProc_->continueProc())
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to continue entire process %d for sync RPC\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
} else if( !(*i)->continueThread() ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to continue thread %d/%d for sync RPC\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, getPid(), (*i)->getLWP());
|
|
Packit |
ce96f2 |
return false;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::addTrap(Address from, Address to, codeGen &gen) {
|
|
Packit Service |
71288b |
gen.invalidate();
|
|
Packit Service |
71288b |
gen.allocate(4);
|
|
Packit Service |
71288b |
gen.setAddrSpace(this);
|
|
Packit Service |
71288b |
gen.setAddr(from);
|
|
Packit Service |
71288b |
insnCodeGen::generateTrap(gen);
|
|
Packit Service |
71288b |
trapMapping.addTrapMapping(from, to, true);
|
|
Packit Service |
71288b |
springboard_cerr << "Generated springboard trap " << hex << from << "->" << to << dec << endl;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::removeTrap(Address from) {
|
|
Packit |
ce96f2 |
map<Address, Breakpoint::ptr>::iterator breakIter =
|
|
Packit |
ce96f2 |
installedCtrlBrkpts.find(from);
|
|
Packit |
ce96f2 |
if( breakIter == installedCtrlBrkpts.end() ) return;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if( !pcProc_->rmBreakpoint(from, breakIter->second) ) {
|
|
Packit |
ce96f2 |
proccontrol_printf("%s[%d]: failed to remove ctrl transfer breakpoint from 0x%lx\n",
|
|
Packit |
ce96f2 |
FILE__, __LINE__, from);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
installedCtrlBrkpts.erase(breakIter);
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
void PCProcess::invalidateMTCache() {
|
|
Packit |
ce96f2 |
mt_cache_result_ = not_cached;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
StackwalkSymLookup::StackwalkSymLookup(PCProcess *p)
|
|
Packit |
ce96f2 |
: proc_(p)
|
|
Packit |
ce96f2 |
{}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
StackwalkSymLookup::~StackwalkSymLookup()
|
|
Packit |
ce96f2 |
{}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
bool StackwalkSymLookup::lookupAtAddr(Dyninst::Address addr, std::string &out_name, void* &out_value)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
func_instance *func = proc_->findOneFuncByAddr(addr);
|
|
Packit |
ce96f2 |
if( func == NULL ) return false;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
// set out_name to the name of the function at this addr
|
|
Packit |
ce96f2 |
// set out_value to NULL, this value is no longer used
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
out_value = NULL;
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
if (func)
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
out_name = func->prettyName();
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
else
|
|
Packit |
ce96f2 |
{
|
|
Packit |
ce96f2 |
out_name = string("[UNKNOWN]");
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
return true;
|
|
Packit |
ce96f2 |
}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
StackwalkInstrumentationHelper::StackwalkInstrumentationHelper(PCProcess *p)
|
|
Packit |
ce96f2 |
: proc_(p)
|
|
Packit |
ce96f2 |
{}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
StackwalkInstrumentationHelper::~StackwalkInstrumentationHelper()
|
|
Packit |
ce96f2 |
{}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
DynFrameHelper::DynFrameHelper(PCProcess *p)
|
|
Packit |
ce96f2 |
: FrameFuncHelper(NULL),
|
|
Packit |
ce96f2 |
proc_(p)
|
|
Packit |
ce96f2 |
{}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
DynFrameHelper::~DynFrameHelper()
|
|
Packit |
ce96f2 |
{}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
DynWandererHelper::DynWandererHelper(PCProcess *p)
|
|
Packit |
ce96f2 |
: WandererHelper(NULL),
|
|
Packit |
ce96f2 |
proc_(p)
|
|
Packit |
ce96f2 |
{}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
DynWandererHelper::~DynWandererHelper()
|
|
Packit |
ce96f2 |
{}
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|
|
Packit |
ce96f2 |
|