Remove handle-body idiom of DFProcess on linux.

Since the classes aren't exposed to the client, there is no reason to
split the class.
develop
Tom Prince 2011-02-23 05:49:33 -05:00
parent b3c490857c
commit 2927b08f93
4 changed files with 75 additions and 97 deletions

@ -29,55 +29,48 @@ distribution.
#include <sys/ptrace.h> #include <sys/ptrace.h>
using namespace DFHack; using namespace DFHack;
LinuxProcessBase::Private::Private(LinuxProcessBase * self_, pid_t pid) LinuxProcessBase::LinuxProcessBase(uint32_t pid)
: my_pid(pid)
{ {
my_descriptor = NULL; my_descriptor = NULL;
my_pid = pid;
attached = false; attached = false;
suspended = false; suspended = false;
memFileHandle = 0; memFileHandle = 0;
self = self_;
}
LinuxProcessBase::LinuxProcessBase(uint32_t pid)
: d(new Private(this, pid))
{
} }
bool LinuxProcessBase::isSuspended() bool LinuxProcessBase::isSuspended()
{ {
return d->suspended; return suspended;
} }
bool LinuxProcessBase::isAttached() bool LinuxProcessBase::isAttached()
{ {
return d->attached; return attached;
} }
bool LinuxProcessBase::isIdentified() bool LinuxProcessBase::isIdentified()
{ {
return d->identified; return identified;
} }
LinuxProcessBase::~LinuxProcessBase() LinuxProcessBase::~LinuxProcessBase()
{ {
if(d->attached) if(attached)
{ {
detach(); detach();
} }
// destroy our copy of the memory descriptor // destroy our copy of the memory descriptor
if(d->my_descriptor) if(my_descriptor)
delete d->my_descriptor; delete my_descriptor;
delete d;
} }
VersionInfo * LinuxProcessBase::getDescriptor() VersionInfo * LinuxProcessBase::getDescriptor()
{ {
return d->my_descriptor; return my_descriptor;
} }
int LinuxProcessBase::getPID() int LinuxProcessBase::getPID()
{ {
return d->my_pid; return my_pid;
} }
//FIXME: implement //FIXME: implement
@ -92,7 +85,7 @@ void LinuxProcessBase::getMemRanges( vector<t_memrange> & ranges )
char buffer[1024]; char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0 char permissions[5]; // r/-, w/-, x/-, p/s, 0
sprintf(buffer, "/proc/%lu/maps", d->my_pid); sprintf(buffer, "/proc/%lu/maps", my_pid);
FILE *mapFile = ::fopen(buffer, "r"); FILE *mapFile = ::fopen(buffer, "r");
uint64_t offset, device1, device2, node; uint64_t offset, device1, device2, node;
@ -122,11 +115,11 @@ bool LinuxProcessBase::asyncSuspend()
bool LinuxProcessBase::suspend() bool LinuxProcessBase::suspend()
{ {
int status; int status;
if(!d->attached) if(!attached)
return false; return false;
if(d->suspended) if(suspended)
return true; return true;
if (kill(d->my_pid, SIGSTOP) == -1) if (kill(my_pid, SIGSTOP) == -1)
{ {
// no, we got an error // no, we got an error
perror("kill SIGSTOP error"); perror("kill SIGSTOP error");
@ -135,7 +128,7 @@ bool LinuxProcessBase::suspend()
while(true) while(true)
{ {
// we wait on the pid // we wait on the pid
pid_t w = waitpid(d->my_pid, &status, 0); pid_t w = waitpid(my_pid, &status, 0);
if (w == -1) if (w == -1)
{ {
// child died // child died
@ -148,7 +141,7 @@ bool LinuxProcessBase::suspend()
break; break;
} }
} }
d->suspended = true; suspended = true;
return true; return true;
} }
@ -159,17 +152,17 @@ bool LinuxProcessBase::forceresume()
bool LinuxProcessBase::resume() bool LinuxProcessBase::resume()
{ {
if(!d->attached) if(!attached)
return false; return false;
if(!d->suspended) if(!suspended)
return true; return true;
if (ptrace(PTRACE_CONT, d->my_pid, NULL, NULL) == -1) if (ptrace(PTRACE_CONT, my_pid, NULL, NULL) == -1)
{ {
// no, we got an error // no, we got an error
perror("ptrace resume error"); perror("ptrace resume error");
return false; return false;
} }
d->suspended = false; suspended = false;
return true; return true;
} }
@ -177,24 +170,24 @@ bool LinuxProcessBase::resume()
bool LinuxProcessBase::attach() bool LinuxProcessBase::attach()
{ {
int status; int status;
if(d->attached) if(attached)
{ {
if(!d->suspended) if(!suspended)
return suspend(); return suspend();
return true; return true;
} }
// can we attach? // can we attach?
if (ptrace(PTRACE_ATTACH , d->my_pid, NULL, NULL) == -1) if (ptrace(PTRACE_ATTACH , my_pid, NULL, NULL) == -1)
{ {
// no, we got an error // no, we got an error
perror("ptrace attach error"); perror("ptrace attach error");
cerr << "attach failed on pid " << d->my_pid << endl; cerr << "attach failed on pid " << my_pid << endl;
return false; return false;
} }
while(true) while(true)
{ {
// we wait on the pid // we wait on the pid
pid_t w = waitpid(d->my_pid, &status, 0); pid_t w = waitpid(my_pid, &status, 0);
if (w == -1) if (w == -1)
{ {
// child died // child died
@ -207,52 +200,52 @@ bool LinuxProcessBase::attach()
break; break;
} }
} }
d->suspended = true; suspended = true;
int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); int proc_pid_mem = open(memFile.c_str(),O_RDONLY);
if(proc_pid_mem == -1) if(proc_pid_mem == -1)
{ {
ptrace(PTRACE_DETACH, d->my_pid, NULL, NULL); ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
cerr << d->memFile << endl; cerr << memFile << endl;
cerr << "couldn't open /proc/" << d->my_pid << "/mem" << endl; cerr << "couldn't open /proc/" << my_pid << "/mem" << endl;
perror("open(memFile.c_str(),O_RDONLY)"); perror("open(memFile.c_str(),O_RDONLY)");
return false; return false;
} }
else else
{ {
d->attached = true; attached = true;
d->memFileHandle = proc_pid_mem; memFileHandle = proc_pid_mem;
return true; // we are attached return true; // we are attached
} }
} }
bool LinuxProcessBase::detach() bool LinuxProcessBase::detach()
{ {
if(!d->attached) return true; if(!attached) return true;
if(!d->suspended) suspend(); if(!suspended) suspend();
int result = 0; int result = 0;
// close /proc/PID/mem // close /proc/PID/mem
result = close(d->memFileHandle); result = close(memFileHandle);
if(result == -1) if(result == -1)
{ {
cerr << "couldn't close /proc/"<< d->my_pid <<"/mem" << endl; cerr << "couldn't close /proc/"<< my_pid <<"/mem" << endl;
perror("mem file close"); perror("mem file close");
return false; return false;
} }
else else
{ {
// detach // detach
result = ptrace(PTRACE_DETACH, d->my_pid, NULL, NULL); result = ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
if(result == -1) if(result == -1)
{ {
cerr << "couldn't detach from process pid" << d->my_pid << endl; cerr << "couldn't detach from process pid" << my_pid << endl;
perror("ptrace detach"); perror("ptrace detach");
return false; return false;
} }
else else
{ {
d->attached = false; attached = false;
return true; return true;
} }
} }
@ -268,7 +261,7 @@ void LinuxProcessBase::read (const uint32_t offset, const uint32_t size, uint8_t
ssize_t remaining = size; ssize_t remaining = size;
while (total != size) while (total != size)
{ {
result = pread(d->memFileHandle, target + total ,remaining,offset + total); result = pread(memFileHandle, target + total ,remaining,offset + total);
if(result == -1) if(result == -1)
{ {
cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl; cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl;
@ -316,10 +309,10 @@ void LinuxProcessBase::readQuad (const uint32_t offset, uint64_t &val)
void LinuxProcessBase::writeQuad (uint32_t offset, const uint64_t data) void LinuxProcessBase::writeQuad (uint32_t offset, const uint64_t data)
{ {
#ifdef HAVE_64_BIT #ifdef HAVE_64_BIT
ptrace(PTRACE_POKEDATA,d->my_pid, offset, data); ptrace(PTRACE_POKEDATA,my_pid, offset, data);
#else #else
ptrace(PTRACE_POKEDATA,d->my_pid, offset, (uint32_t) data); ptrace(PTRACE_POKEDATA,my_pid, offset, (uint32_t) data);
ptrace(PTRACE_POKEDATA,d->my_pid, offset+4, (uint32_t) (data >> 32)); ptrace(PTRACE_POKEDATA,my_pid, offset+4, (uint32_t) (data >> 32));
#endif #endif
} }
@ -329,9 +322,9 @@ void LinuxProcessBase::writeDWord (uint32_t offset, uint32_t data)
uint64_t orig = Process::readQuad(offset); uint64_t orig = Process::readQuad(offset);
orig &= 0xFFFFFFFF00000000; orig &= 0xFFFFFFFF00000000;
orig |= data; orig |= data;
ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#else #else
ptrace(PTRACE_POKEDATA,d->my_pid, offset, data); ptrace(PTRACE_POKEDATA,my_pid, offset, data);
#endif #endif
} }
@ -342,12 +335,12 @@ void LinuxProcessBase::writeWord (uint32_t offset, uint16_t data)
uint64_t orig = Process::readQuad(offset); uint64_t orig = Process::readQuad(offset);
orig &= 0xFFFFFFFFFFFF0000; orig &= 0xFFFFFFFFFFFF0000;
orig |= data; orig |= data;
ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#else #else
uint32_t orig = readDWord(offset); uint32_t orig = readDWord(offset);
orig &= 0xFFFF0000; orig &= 0xFFFF0000;
orig |= data; orig |= data;
ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#endif #endif
} }
@ -357,12 +350,12 @@ void LinuxProcessBase::writeByte (uint32_t offset, uint8_t data)
uint64_t orig = Process::readQuad(offset); uint64_t orig = Process::readQuad(offset);
orig &= 0xFFFFFFFFFFFFFF00; orig &= 0xFFFFFFFFFFFFFF00;
orig |= data; orig |= data;
ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#else #else
uint32_t orig = readDWord(offset); uint32_t orig = readDWord(offset);
orig &= 0xFFFFFF00; orig &= 0xFFFFFF00;
orig |= data; orig |= data;
ptrace(PTRACE_POKEDATA,d->my_pid, offset, orig); ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
#endif #endif
} }

@ -30,7 +30,6 @@ distribution.
#include <stdio.h> #include <stdio.h>
using namespace DFHack; using namespace DFHack;
WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions) : LinuxProcessBase(pid) WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions) : LinuxProcessBase(pid)
{ {
char dir_name [256]; char dir_name [256];
@ -41,8 +40,8 @@ WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
char target_name[1024]; char target_name[1024];
int target_result; int target_result;
d->identified = false; identified = false;
d->my_descriptor = 0; my_descriptor = 0;
sprintf(dir_name,"/proc/%d/", pid); sprintf(dir_name,"/proc/%d/", pid);
sprintf(exe_link_name,"/proc/%d/exe", pid); sprintf(exe_link_name,"/proc/%d/exe", pid);
@ -78,7 +77,7 @@ WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
sprintf(exe_link,"%s/%s",target_name,cmdline.c_str()); sprintf(exe_link,"%s/%s",target_name,cmdline.c_str());
// create wine process, add it to the vector // create wine process, add it to the vector
d->identified = validate(exe_link,pid,mem_name,known_versions); identified = validate(exe_link,pid,mem_name,known_versions);
return; return;
} }
} }
@ -101,15 +100,14 @@ bool WineProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector
{ {
if (OS_WINDOWS == (*it)->getOS()) if (OS_WINDOWS == (*it)->getOS())
{ {
VersionInfo *m = new VersionInfo(**it);
// keep track of created memory_info object so we can destroy it later // keep track of created memory_info object so we can destroy it later
d->my_descriptor = m; my_descriptor = new VersionInfo(**it);
m->setParentProcess(this); my_descriptor->setParentProcess(this);
// tell Process about the /proc/PID/mem file // tell Process about the /proc/PID/mem file
d->memFile = memFile; memFile = memFile;
d->identified = true; identified = true;
OffsetGroup * strGrp = m->getGroup("string")->getGroup("MSVC"); OffsetGroup * strGrp = my_descriptor->getGroup("string")->getGroup("MSVC");
STLSTR_buf_off = strGrp->getOffset("buffer"); STLSTR_buf_off = strGrp->getOffset("buffer");
STLSTR_size_off = strGrp->getOffset("size"); STLSTR_size_off = strGrp->getOffset("size");
STLSTR_cap_off = strGrp->getOffset("capacity"); STLSTR_cap_off = strGrp->getOffset("capacity");

@ -39,8 +39,8 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
char target_name[1024]; char target_name[1024];
int target_result; int target_result;
d->identified = false; identified = false;
d->my_descriptor = 0; my_descriptor = 0;
sprintf(dir_name,"/proc/%d/", pid); sprintf(dir_name,"/proc/%d/", pid);
sprintf(exe_link_name,"/proc/%d/exe", pid); sprintf(exe_link_name,"/proc/%d/exe", pid);
@ -61,7 +61,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0) if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0)
{ {
// create linux process, add it to the vector // create linux process, add it to the vector
d->identified = validate(target_name,pid,mem_name,known_versions); identified = validate(target_name,pid,mem_name,known_versions);
return; return;
} }
} }
@ -82,13 +82,12 @@ bool NormalProcess::validate(char * exe_file,uint32_t pid, char * memFile, vecto
{ {
if (OS_LINUX == (*it)->getOS()) if (OS_LINUX == (*it)->getOS())
{ {
VersionInfo *m = new VersionInfo(**it);
// keep track of created memory_info object so we can destroy it later // keep track of created memory_info object so we can destroy it later
d->my_descriptor = m; my_descriptor = new VersionInfo(**it);
m->setParentProcess(this); my_descriptor->setParentProcess(this);
// tell Process about the /proc/PID/mem file // tell Process about the /proc/PID/mem file
d->memFile = memFile; memFile = memFile;
d->identified = true; identified = true;
return true; return true;
} }
} }

@ -33,11 +33,14 @@ namespace DFHack
{ {
class LinuxProcessBase : public Process class LinuxProcessBase : public Process
{ {
public:
class Private;
protected: protected:
Private * const d; VersionInfo * my_descriptor;
bool readProgramName(char *target_name, char *mem_name, char *cmdline_name); pid_t my_pid;
string memFile;
int memFileHandle;
bool attached;
bool suspended;
bool identified;
public: public:
LinuxProcessBase(uint32_t pid); LinuxProcessBase(uint32_t pid);
~LinuxProcessBase(); ~LinuxProcessBase();
@ -98,8 +101,8 @@ namespace DFHack
void writeSTLString(const uint32_t address, const std::string writeString){}; void writeSTLString(const uint32_t address, const std::string writeString){};
// get class name of an object with rtti/type info // get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr); std::string readClassName(uint32_t vptr);
private: private:
bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions); bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions);
}; };
class DFHACK_EXPORT WineProcess : public LinuxProcessBase class DFHACK_EXPORT WineProcess : public LinuxProcessBase
@ -117,23 +120,8 @@ namespace DFHack
void writeSTLString(const uint32_t address, const std::string writeString){}; void writeSTLString(const uint32_t address, const std::string writeString){};
// get class name of an object with rtti/type info // get class name of an object with rtti/type info
std::string readClassName(uint32_t vptr); std::string readClassName(uint32_t vptr);
private: private:
bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions); bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions);
};
class LinuxProcessBase::Private
{
public:
Private(LinuxProcessBase * self_, pid_t);
~Private(){};
VersionInfo * my_descriptor;
LinuxProcessBase * self;
pid_t my_pid;
string memFile;
int memFileHandle;
bool attached;
bool suspended;
bool identified;
}; };
} }