More cleanup in the Process lands.

develop
Petr Mrázek 2011-02-24 11:43:33 +01:00
parent 79b78673e5
commit 97bfa32a82
13 changed files with 124 additions and 210 deletions

@ -31,12 +31,12 @@ distribution.
using namespace DFHack; using namespace DFHack;
Process* DFHack::createSHMProcess(uint32_t pid, vector <VersionInfo *> & known_versions) Process* DFHack::createSHMProcess(uint32_t pid, VersionInfoFactory * factory)
{ {
return new SHMProcess(pid, known_versions); return new SHMProcess(pid, factory);
} }
SHMProcess::SHMProcess(uint32_t PID, vector <VersionInfo *> & known_versions) SHMProcess::SHMProcess(uint32_t PID, VersionInfoFactory * factory)
: d(new Private(this)) : d(new Private(this))
{ {
d->process_ID = PID; d->process_ID = PID;
@ -59,7 +59,7 @@ SHMProcess::SHMProcess(uint32_t PID, vector <VersionInfo *> & known_versions)
} }
// try to identify the DF version (md5 the binary, compare with known versions) // try to identify the DF version (md5 the binary, compare with known versions)
d->validate(known_versions); d->validate(factory);
// at this point, DF is attached and suspended, make it run // at this point, DF is attached and suspended, make it run
detach(); detach();
} }

@ -216,7 +216,7 @@ bool SHMProcess::Private::AreLocksOk()
} }
bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions) bool SHMProcess::Private::validate(VersionInfoFactory * factory)
{ {
char exe_link_name [256]; char exe_link_name [256];
char target_name[1024]; char target_name[1024];
@ -233,29 +233,19 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
// see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html // see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html
target_name[target_result] = 0; target_name[target_result] = 0;
md5wrapper md5;
// get hash of the running DF process // get hash of the running DF process
md5wrapper md5;
string hash = md5.getHashFromFile(target_name); string hash = md5.getHashFromFile(target_name);
vector<VersionInfo *>::iterator it;
// cerr << exe_file << " " << hash << endl; // create linux process, add it to the vector
// iterate over the list of memory locations VersionInfo * vinfo = factory->getVersionInfoByMD5(hash);
for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) if(vinfo)
{ {
try{ memdescriptor = vinfo;
if(hash == (*it)->getMD5()) // are the md5 hashes the same? // FIXME: BIG BAD BUG RIGHT HERE!!!!
{ memdescriptor->setParentProcess(self);
VersionInfo *m = new VersionInfo(**it); identified = true;
memdescriptor = m; return true;
m->setParentProcess(self);
identified = true;
// cerr << "identified " << m->getVersion() << endl;
return true;
}
}
catch (Error::AllMemdef&)
{
continue;
}
} }
return false; return false;
} }

@ -38,24 +38,22 @@ namespace {
private: private:
MicrosoftSTL stl; MicrosoftSTL stl;
public: public:
WineProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions); WineProcess(uint32_t pid, VersionInfoFactory * factory);
const std::string readSTLString (uint32_t offset); const std::string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
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:
bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions);
}; };
} }
Process* DFHack::createWineProcess(uint32_t pid, vector <VersionInfo *> & known_versions) Process* DFHack::createWineProcess(uint32_t pid, VersionInfoFactory * factory)
{ {
return new WineProcess(pid, known_versions); return new WineProcess(pid, factory);
} }
WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions) : LinuxProcessBase(pid) WineProcess::WineProcess(uint32_t pid, VersionInfoFactory * factory) : LinuxProcessBase(pid)
{ {
char dir_name [256]; char dir_name [256];
char exe_link_name [256]; char exe_link_name [256];
@ -71,6 +69,7 @@ WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
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);
sprintf(mem_name,"/proc/%d/mem", pid); sprintf(mem_name,"/proc/%d/mem", pid);
memFile = mem_name;
sprintf(cwd_name,"/proc/%d/cwd", pid); sprintf(cwd_name,"/proc/%d/cwd", pid);
sprintf(cmdline_name,"/proc/%d/cmdline", pid); sprintf(cmdline_name,"/proc/%d/cmdline", pid);
@ -101,51 +100,23 @@ WineProcess::WineProcess(uint32_t pid, vector <VersionInfo *> & known_versions)
// put executable name and path together // put executable name and path together
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 md5wrapper md5;
identified = validate(exe_link,pid,mem_name,known_versions); // get hash of the running DF process
return; string hash = md5.getHashFromFile(exe_link);
} // create linux process, add it to the vector
} VersionInfo * vinfo = factory->getVersionInfoByMD5(hash);
} if(vinfo)
bool WineProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions)
{
md5wrapper md5;
// get hash of the running DF process
string hash = md5.getHashFromFile(exe_file);
vector<VersionInfo *>::iterator it;
// iterate over the list of memory locations
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
try
{
if (hash == (*it)->getMD5()) // are the md5 hashes the same?
{ {
if (OS_WINDOWS == (*it)->getOS()) my_descriptor = new VersionInfo(*vinfo);
{ my_descriptor->setParentProcess(this);
// keep track of created memory_info object so we can destroy it later stl.init(this);
my_descriptor = new VersionInfo(**it); identified = true;
my_descriptor->setParentProcess(this);
// tell Process about the /proc/PID/mem file
memFile = memFile;
identified = true;
stl.init(this);
return true;
}
} }
} return;
catch (Error::AllMemdef&)
{
continue;
} }
} }
return false;
} }
size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
{ {
return stl.readSTLString(offset, buffer, bufcapacity); return stl.readSTLString(offset, buffer, bufcapacity);
@ -158,5 +129,5 @@ const string WineProcess::readSTLString (uint32_t offset)
string WineProcess::readClassName (uint32_t vptr) string WineProcess::readClassName (uint32_t vptr)
{ {
stl.readClassName(vptr); return stl.readClassName(vptr);
} }

@ -34,24 +34,22 @@ namespace {
class NormalProcess : public LinuxProcessBase class NormalProcess : public LinuxProcessBase
{ {
public: public:
NormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions); NormalProcess(uint32_t pid, VersionInfoFactory * known_versions);
const std::string readSTLString (uint32_t offset); const std::string readSTLString (uint32_t offset);
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
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:
bool validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions);
}; };
} }
Process* DFHack::createNormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions) Process* DFHack::createNormalProcess(uint32_t pid, VersionInfoFactory * known_versions)
{ {
return new NormalProcess(pid, known_versions); return new NormalProcess(pid, known_versions);
} }
NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions) : LinuxProcessBase(pid) NormalProcess::NormalProcess(uint32_t pid, VersionInfoFactory * known_versions) : LinuxProcessBase(pid)
{ {
char dir_name [256]; char dir_name [256];
char exe_link_name [256]; char exe_link_name [256];
@ -67,6 +65,7 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
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);
sprintf(mem_name,"/proc/%d/mem", pid); sprintf(mem_name,"/proc/%d/mem", pid);
memFile = mem_name;
sprintf(cwd_name,"/proc/%d/cwd", pid); sprintf(cwd_name,"/proc/%d/cwd", pid);
sprintf(cmdline_name,"/proc/%d/cmdline", pid); sprintf(cmdline_name,"/proc/%d/cmdline", pid);
@ -82,44 +81,18 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
// is this the regular linux DF? // is this the regular linux DF?
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)
{ {
md5wrapper md5;
// get hash of the running DF process
string hash = md5.getHashFromFile(target_name);
// create linux process, add it to the vector // create linux process, add it to the vector
identified = validate(target_name,pid,mem_name,known_versions); VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash);
return; if(vinfo)
}
}
bool NormalProcess::validate(char * exe_file,uint32_t pid, char * memFile, vector <VersionInfo *> & known_versions)
{
md5wrapper md5;
// get hash of the running DF process
string hash = md5.getHashFromFile(exe_file);
vector<VersionInfo *>::iterator it;
// iterate over the list of memory locations
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{
try
{
if (hash == (*it)->getMD5()) // are the md5 hashes the same?
{
if (OS_LINUX == (*it)->getOS())
{
// keep track of created memory_info object so we can destroy it later
my_descriptor = new VersionInfo(**it);
my_descriptor->setParentProcess(this);
// tell Process about the /proc/PID/mem file
memFile = memFile;
identified = true;
return true;
}
}
}
catch (Error::AllMemdef&)
{ {
continue; my_descriptor = new VersionInfo(*vinfo);
my_descriptor->setParentProcess(this);
identified = true;
} }
} }
return false;
} }
struct _Rep_base struct _Rep_base

@ -216,7 +216,7 @@ bool SHMProcess::Private::AreLocksOk()
return false; return false;
} }
bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions) bool SHMProcess::Private::validate(VersionInfoFactory * factory)
{ {
// try to identify the DF version // try to identify the DF version
IMAGE_NT_HEADERS pe_header; IMAGE_NT_HEADERS pe_header;
@ -246,30 +246,16 @@ bool SHMProcess::Private::validate(vector <VersionInfo *> & known_versions)
self->read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); self->read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
self->read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections ); self->read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)&sections );
// iterate over the list of memory locations VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(pe_header.FileHeader.TimeDateStamp);
vector<VersionInfo *>::iterator it; if(vinfo)
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{ {
uint32_t pe_timestamp; VersionInfo *m = new VersionInfo(*vinfo);
try m->RebaseAll(base);
{ memdescriptor = m;
pe_timestamp = (*it)->getPE(); m->setParentProcess(self);
} identified = true;
catch(Error::AllMemdef&) CloseHandle(hProcess);
{ return true;
continue;
}
if (pe_timestamp == pe_header.FileHeader.TimeDateStamp)
{
VersionInfo *m = new VersionInfo(**it);
m->RebaseAll(base);
memdescriptor = m;
m->setParentProcess(self);
identified = true;
cerr << "identified " << m->getVersion() << endl;
CloseHandle(hProcess);
return true;
}
} }
return false; return false;
} }

@ -47,7 +47,7 @@ namespace
uint32_t base; uint32_t base;
MicrosoftSTL stl; MicrosoftSTL stl;
public: public:
NormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions); NormalProcess(uint32_t pid, VersionInfoFactory * factory);
~NormalProcess(); ~NormalProcess();
bool attach(); bool attach();
bool detach(); bool detach();
@ -101,12 +101,12 @@ namespace
} }
Process* DFHack::createNormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions) Process* DFHack::createNormalProcess(uint32_t pid, VersionInfoFactory * factory)
{ {
return new NormalProcess(pid, known_versions); return new NormalProcess(pid, factory);
} }
NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versions) NormalProcess::NormalProcess(uint32_t pid, VersionInfoFactory * factory)
: my_pid(pid) : my_pid(pid)
{ {
my_descriptor = NULL; my_descriptor = NULL;
@ -155,56 +155,30 @@ NormalProcess::NormalProcess(uint32_t pid, vector <VersionInfo *> & known_versio
return; return;
} }
// see if there's a version entry that matches this process VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(pe_header.FileHeader.TimeDateStamp);
vector<VersionInfo*>::iterator it; if(vinfo)
for ( it=known_versions.begin() ; it < known_versions.end(); it++ )
{ {
// filter by OS identified = true;
if(OS_WINDOWS != (*it)->getOS()) // give the process a data model and memory layout fixed for the base of first module
continue; my_descriptor = new VersionInfo(*vinfo);
uint32_t pe_timestamp; my_descriptor->RebaseAll(base);
// filter by timestamp, skip entries without a timestamp // keep track of created memory_info object so we can destroy it later
try my_descriptor->setParentProcess(this);
{ // process is responsible for destroying its data model
pe_timestamp = (*it)->getPE(); my_handle = my_handle;
}
catch(Error::AllMemdef&) // TODO: detect errors in thread enumeration
{ vector<uint32_t> threads;
continue; getThreadIDs( threads );
} my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]);
if (pe_timestamp != pe_header.FileHeader.TimeDateStamp) stl.init(this);
continue;
// all went well
{
printf("Match found! Using version %s.\n", (*it)->getVersion().c_str());
identified = true;
// give the process a data model and memory layout fixed for the base of first module
my_descriptor = new VersionInfo(**it);
my_descriptor->RebaseAll(base);
// keep track of created memory_info object so we can destroy it later
my_descriptor->setParentProcess(this);
// process is responsible for destroying its data model
my_handle = my_handle;
identified = true;
// TODO: detect errors in thread enumeration
vector<uint32_t> threads;
getThreadIDs( threads );
my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]);
stl.init(this);
found = true;
break; // break the iterator loop
}
} }
// close handle of processes that aren't DF else
if(!found)
{ {
// close handles of processes that aren't DF
CloseHandle(my_handle); CloseHandle(my_handle);
} }
} }
/*
*/
NormalProcess::~NormalProcess() NormalProcess::~NormalProcess()
{ {

@ -120,19 +120,19 @@ Process * BadProcesses::operator[](uint32_t index)
Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID) Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID)
{ {
Process *p1 = createSHMProcess(ID.pid,meminfo->versions); Process *p1 = createSHMProcess(ID.pid, meminfo);
if(p1->isIdentified()) if(p1->isIdentified())
return p1; return p1;
else else
delete p1; delete p1;
Process *p2 = createNormalProcess(ID.pid,meminfo->versions); Process *p2 = createNormalProcess(ID.pid, meminfo);
if(p2->isIdentified()) if(p2->isIdentified())
return p2; return p2;
else else
delete p2; delete p2;
#ifdef LINUX_BUILD #ifdef LINUX_BUILD
Process *p3 = createWineProcess(ID.pid,meminfo->versions); Process *p3 = createWineProcess(ID.pid, meminfo);
if(p3->isIdentified()) if(p3->isIdentified())
return p3; return p3;
else else

@ -90,6 +90,12 @@ inline bool operator>=(const triple<_T1, _T2, _T3>& __x, const triple<_T1, _T2,
return !(__x < __y); return !(__x < __y);
} }
VersionInfoFactory::VersionInfoFactory(string path_to_xml)
{
error = false;
loadFile(path_to_xml);
}
VersionInfoFactory::~VersionInfoFactory() VersionInfoFactory::~VersionInfoFactory()
{ {
// for each stored version, delete // for each stored version, delete
@ -100,6 +106,35 @@ VersionInfoFactory::~VersionInfoFactory()
versions.clear(); versions.clear();
} }
VersionInfo * VersionInfoFactory::getVersionInfoByMD5(string hash)
{
VersionInfo * vinfo;
for(uint32_t i = 0; i < versions.size();i++)
{
vinfo = versions[i];
if(vinfo->getMD5() == hash)
{
return vinfo;
}
}
return NULL;
}
VersionInfo * VersionInfoFactory::getVersionInfoByPETimestamp(uint32_t timestamp)
{
VersionInfo * vinfo;
for(uint32_t i = 0; i < versions.size();i++)
{
vinfo = versions[i];
if(vinfo->getPE() == timestamp)
{
return vinfo;
}
}
return NULL;
}
void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem) void VersionInfoFactory::ParseVTable(TiXmlElement* vtable, VersionInfo* mem)
{ {
TiXmlElement* pClassEntry; TiXmlElement* pClassEntry;
@ -628,12 +663,6 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem)
} // for } // for
} // method } // method
VersionInfoFactory::VersionInfoFactory(string path_to_xml)
{
error = false;
loadFile(path_to_xml);
}
// load the XML file with offsets // load the XML file with offsets
bool VersionInfoFactory::loadFile(string path_to_xml) bool VersionInfoFactory::loadFile(string path_to_xml)
{ {

@ -41,6 +41,8 @@ namespace DFHack
// memory info entries loaded from a file // memory info entries loaded from a file
bool loadFile( std::string path_to_xml); bool loadFile( std::string path_to_xml);
bool isInErrorState() const {return error;}; bool isInErrorState() const {return error;};
VersionInfo * getVersionInfoByMD5(std::string md5string);
VersionInfo * getVersionInfoByPETimestamp(uint32_t timestamp);
std::vector<VersionInfo*> versions; std::vector<VersionInfo*> versions;
private: private:
void ParseVTable(TiXmlElement* vtable, VersionInfo* mem); void ParseVTable(TiXmlElement* vtable, VersionInfo* mem);

@ -158,15 +158,7 @@ namespace DFHack
liquid_water, liquid_water,
liquid_magma liquid_magma
}; };
/*
enum e_liquidcharacter
{
liquid_fresh,
liquid_unk1,
liquid_salt,
liquid_unk2,
};
*/
struct naked_designation struct naked_designation
{ {
unsigned int flow_size : 3; // how much liquid is here? unsigned int flow_size : 3; // how much liquid is here?

@ -25,8 +25,6 @@ distribution.
#ifndef LINUX_PROCESS_H_INCLUDED #ifndef LINUX_PROCESS_H_INCLUDED
#define LINUX_PROCESS_H_INCLUDED #define LINUX_PROCESS_H_INCLUDED
#ifdef LINUX_BUILD
#include "dfhack/DFProcess.h" #include "dfhack/DFProcess.h"
namespace DFHack namespace DFHack
@ -89,8 +87,5 @@ namespace DFHack
// set a SHM command and wait for a response // set a SHM command and wait for a response
bool SetAndWait (uint32_t state){return false;}; bool SetAndWait (uint32_t state){return false;};
}; };
} }
#endif
#endif #endif

@ -26,13 +26,14 @@ distribution.
#define PROCESS_FACTORY_H_INCLUDED #define PROCESS_FACTORY_H_INCLUDED
#include "dfhack/DFProcess.h" #include "dfhack/DFProcess.h"
#include "dfhack/VersionInfoFactory.h"
namespace DFHack namespace DFHack
{ {
Process* createNormalProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions); Process* createNormalProcess(uint32_t pid, VersionInfoFactory * factory);
Process* createSHMProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions); Process* createSHMProcess(uint32_t pid, VersionInfoFactory * factory);
#ifdef LINUX_BUILD #ifdef LINUX_BUILD
Process* createWineProcess(uint32_t pid, std::vector <VersionInfo *> & known_versions); Process* createWineProcess(uint32_t pid, VersionInfoFactory * factory);
#endif #endif
} }
#endif #endif

@ -27,6 +27,7 @@ distribution.
#include "dfhack/DFProcess.h" #include "dfhack/DFProcess.h"
#include "dfhack/DFIntegers.h" #include "dfhack/DFIntegers.h"
#include "dfhack/VersionInfoFactory.h"
namespace DFHack namespace DFHack
{ {
@ -37,7 +38,7 @@ namespace DFHack
Private * const d; Private * const d;
public: public:
SHMProcess(uint32_t PID, std::vector <VersionInfo *> & known_versions); SHMProcess(uint32_t PID, VersionInfoFactory * factory);
~SHMProcess(); ~SHMProcess();
// Set up stuff so we can read memory // Set up stuff so we can read memory
bool attach(); bool attach();
@ -121,7 +122,7 @@ namespace DFHack
HANDLE DFCLSuspendMutex; HANDLE DFCLSuspendMutex;
#endif #endif
bool validate(std::vector< VersionInfo* >& known_versions); bool validate(VersionInfoFactory * factory);
bool Aux_Core_Attach(bool & versionOK, pid_t& PID); bool Aux_Core_Attach(bool & versionOK, pid_t& PID);
bool SetAndWait (uint32_t state); bool SetAndWait (uint32_t state);