split out memory.xml reading functionality out of the processenumerator

develop
Petr Mrázek 2009-11-18 02:33:17 +00:00
parent 30d80debfb
commit 29c0932ff7
9 changed files with 332 additions and 206 deletions

@ -6,6 +6,7 @@ DFDataModel.h
DFHackAPI.h DFHackAPI.h
DFMemAccess.h DFMemAccess.h
DFMemInfo.h DFMemInfo.h
DFMemInfoManager.h
DFProcessEnumerator.h DFProcessEnumerator.h
DFProcess.h DFProcess.h
DFTileTypes.h DFTileTypes.h
@ -23,7 +24,7 @@ tinyxml/tinyxml.h
SET(PROJECT_SRCS SET(PROJECT_SRCS
DFDataModel.cpp DFDataModel.cpp
DFMemInfo.cpp DFMemInfo.cpp
DFProcessEnumerator.cpp DFMemInfoManager.cpp
DFHackAPI.cpp DFHackAPI.cpp
DFTileTypes.cpp DFTileTypes.cpp
md5/md5.cpp md5/md5.cpp
@ -35,7 +36,6 @@ tinyxml/tinyxmlparser.cpp
) )
SET(PROJECT_HDRS_LINUX SET(PROJECT_HDRS_LINUX
DFProcess-linux.h
MemAccess-linux.h MemAccess-linux.h
) )
@ -46,10 +46,12 @@ stdint_win.h
SET(PROJECT_SRCS_LINUX SET(PROJECT_SRCS_LINUX
DFProcess-linux.cpp DFProcess-linux.cpp
DFProcessEnumerator-linux.cpp
) )
SET(PROJECT_SRCS_WINDOWS SET(PROJECT_SRCS_WINDOWS
DFProcess-windows.cpp DFProcess-windows.cpp
DFProcessEnumerator-windows.cpp
) )
IF(UNIX) IF(UNIX)

@ -96,6 +96,7 @@ namespace DFHack
#include "DFDataModel.h" #include "DFDataModel.h"
#include "DFProcess.h" #include "DFProcess.h"
#include "DFProcessEnumerator.h" #include "DFProcessEnumerator.h"
#include "DFMemInfoManager.h"
#include "DFMemAccess.h" #include "DFMemAccess.h"
#include "DFVector.h" #include "DFVector.h"
#include "DFMemInfo.h" #include "DFMemInfo.h"

@ -25,143 +25,7 @@ distribution.
#include "DFCommonInternal.h" #include "DFCommonInternal.h"
using namespace DFHack; using namespace DFHack;
/// HACK: global variables (only one process can be attached at the same time.) void MemInfoManager::ParseVTable(TiXmlElement* vtable, memory_info& mem)
Process * DFHack::g_pProcess; ///< current process. non-NULL when picked
ProcessHandle DFHack::g_ProcessHandle; ///< cache of handle to current process. used for speed reasons
int DFHack::g_ProcessMemFile; ///< opened /proc/PID/mem, valid when attached
class DFHack::ProcessEnumerator::Private
{
public:
Private(){};
// memory info entries loaded from a file
std::vector<memory_info> meminfo;
Process * currentProcess;
ProcessHandle currentProcessHandle;
std::vector<Process *> processes;
bool loadDescriptors( string path_to_xml);
void ParseVTable(TiXmlElement* vtable, memory_info& mem);
void ParseEntry (TiXmlElement* entry, memory_info& mem, map <string ,TiXmlElement *>& knownEntries);
#ifdef LINUX_BUILD
Process* addProcess(const string & exe,ProcessHandle PH,const string & memFile);
#endif
};
#ifdef LINUX_BUILD
/*
* LINUX version of the process finder.
*/
bool ProcessEnumerator::findProcessess()
{
DIR *dir_p;
struct dirent *dir_entry_p;
string dir_name;
string exe_link;
string cwd_link;
string cmdline_path;
string cmdline;
// ALERT: buffer overrun potential
int errorcount;
int result;
errorcount=0;
result=0;
// Open /proc/ directory
dir_p = opendir("/proc/");
// Reading /proc/ entries
while(NULL != (dir_entry_p = readdir(dir_p)))
{
// Only PID folders (numbers)
if (strspn(dir_entry_p->d_name, "0123456789") != strlen(dir_entry_p->d_name))
{
continue;
}
Process *p = new Process(atoi(dir_entry_p->d_name),d->meminfo);
if(p->isIdentified())
{
d->processes.push_back(p);
}
else
{
delete p;
}
}
closedir(dir_p);
// return value depends on if we found some DF processes
if(d->processes.size())
{
return true;
}
return false;
}
#else
// some magic - will come in handy when we start doing debugger stuff on Windows
bool EnableDebugPriv()
{
bool bRET = FALSE;
TOKEN_PRIVILEGES tp;
HANDLE hToken;
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))
{
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
if (hToken != INVALID_HANDLE_VALUE)
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.PrivilegeCount = 1;
if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, 0, 0))
{
bRET = TRUE;
}
CloseHandle(hToken);
}
}
}
return bRET;
}
// WINDOWS version of the process finder
bool ProcessEnumerator::findProcessess()
{
// Get the list of process identifiers.
DWORD ProcArray[2048], memoryNeeded, numProccesses;
EnableDebugPriv();
if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) )
{
return false;
}
// Calculate how many process identifiers were returned.
numProccesses = memoryNeeded / sizeof(DWORD);
// iterate through processes
for ( int i = 0; i < (int)numProccesses; i++ )
{
Process *p = new Process(ProcArray[i],d->meminfo);
if(p->isIdentified())
{
d->processes.push_back(p);
}
else
{
delete p;
}
}
if(d->processes.size())
return true;
return false;
}
#endif
void ProcessEnumerator::Private::ParseVTable(TiXmlElement* vtable, memory_info& mem)
{ {
TiXmlElement* pClassEntry; TiXmlElement* pClassEntry;
TiXmlElement* pClassSubEntry; TiXmlElement* pClassSubEntry;
@ -209,7 +73,7 @@ void ProcessEnumerator::Private::ParseVTable(TiXmlElement* vtable, memory_info&
void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& mem, map <string ,TiXmlElement *>& knownEntries) void MemInfoManager::ParseEntry (TiXmlElement* entry, memory_info& mem, map <string ,TiXmlElement *>& knownEntries)
{ {
TiXmlElement* pMemEntry; TiXmlElement* pMemEntry;
const char *cstr_version = entry->Attribute("version"); const char *cstr_version = entry->Attribute("version");
@ -232,7 +96,7 @@ void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& m
string os = cstr_os; string os = cstr_os;
mem.setVersion(cstr_version); mem.setVersion(cstr_version);
mem.setOS(cstr_os); mem.setOS(cstr_os);
// offset inherited addresses by 'rebase'. // offset inherited addresses by 'rebase'.
int32_t rebase = 0; int32_t rebase = 0;
if(cstr_rebase) if(cstr_rebase)
@ -240,7 +104,7 @@ void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& m
rebase = mem.getBase() + strtol(cstr_rebase, NULL, 16); rebase = mem.getBase() + strtol(cstr_rebase, NULL, 16);
mem.RebaseAddresses(rebase); mem.RebaseAddresses(rebase);
} }
//set base to default, we're overwriting this because the previous rebase could cause havoc on Vista/7 //set base to default, we're overwriting this because the previous rebase could cause havoc on Vista/7
if(os == "windows") if(os == "windows")
{ {
@ -303,22 +167,22 @@ void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& m
{ {
mem.setString(name, value); mem.setString(name, value);
} }
else if (type == "Profession") else if (type == "Profession")
{ {
mem.setProfession(value,name); mem.setProfession(value,name);
} }
else if (type == "Job") else if (type == "Job")
{ {
mem.setJob(value,name); mem.setJob(value,name);
} }
else if (type == "Skill") else if (type == "Skill")
{ {
mem.setSkill(value,name); mem.setSkill(value,name);
} }
else if (type == "Trait") else if (type == "Trait")
{ {
mem.setTrait(value, name,pMemEntry->Attribute("level_0"),pMemEntry->Attribute("level_1"),pMemEntry->Attribute("level_2"),pMemEntry->Attribute("level_3"),pMemEntry->Attribute("level_4"),pMemEntry->Attribute("level_5")); mem.setTrait(value, name,pMemEntry->Attribute("level_0"),pMemEntry->Attribute("level_1"),pMemEntry->Attribute("level_2"),pMemEntry->Attribute("level_3"),pMemEntry->Attribute("level_4"),pMemEntry->Attribute("level_5"));
} }
else if (type == "Labor") else if (type == "Labor")
{ {
mem.setLabor(value,name); mem.setLabor(value,name);
@ -330,17 +194,22 @@ void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& m
} // for } // for
} // method } // method
MemInfoManager::MemInfoManager(string path_to_xml)
{
error = false;
loadFile(path_to_xml);
}
// load the XML file with offsets // load the XML file with offsets
bool ProcessEnumerator::Private::loadDescriptors(string path_to_xml) bool MemInfoManager::loadFile(string path_to_xml)
{ {
TiXmlDocument doc( path_to_xml.c_str() ); TiXmlDocument doc( path_to_xml.c_str() );
bool loadOkay = doc.LoadFile(); bool loadOkay = doc.LoadFile();
TiXmlHandle hDoc(&doc); TiXmlHandle hDoc(&doc);
TiXmlElement* pElem; TiXmlElement* pElem;
TiXmlHandle hRoot(0); TiXmlHandle hRoot(0);
memory_info mem; memory_info mem;
if ( loadOkay ) if ( loadOkay )
{ {
// block: name // block: name
@ -388,45 +257,14 @@ bool ProcessEnumerator::Private::loadDescriptors(string path_to_xml)
} }
// process found things here // process found things here
} }
error = false;
return true; return true;
} }
else else
{ {
// load failed // load failed
cerr << "Can't load memory offsets from memory.xml" << endl; cerr << "Can't load memory offsets from memory.xml" << endl;
error = true;
return false; return false;
} }
} }
uint32_t ProcessEnumerator::size()
{
return d->processes.size();
};
Process * ProcessEnumerator::operator[](uint32_t index)
{
assert(index < d->processes.size());
return d->processes[index];
};
ProcessEnumerator::ProcessEnumerator( string path_to_xml )
: d(new Private())
{
d->currentProcess = NULL;
d->currentProcessHandle = 0;
d->loadDescriptors( path_to_xml );
}
ProcessEnumerator::~ProcessEnumerator()
{
// delete all processes
for(uint32_t i = 0;i < d->processes.size();i++)
{
delete d->processes[i];
}
delete d;
}

@ -0,0 +1,46 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef MEMINFO_MANAGER_H_INCLUDED
#define MEMINFO_MANAGER_H_INCLUDED
namespace DFHack
{
class MemInfoManager
{
friend class ProcessEnumerator;
public:
MemInfoManager(string path_to_xml);
// memory info entries loaded from a file
bool loadFile( string path_to_xml);
bool isInErrorState() const {return error;};
private:
std::vector<memory_info> meminfo;
void ParseVTable(TiXmlElement* vtable, memory_info& mem);
void ParseEntry (TiXmlElement* entry, memory_info& mem, map <string ,TiXmlElement *>& knownEntries);
bool error;
};
}
#endif

@ -181,24 +181,18 @@ DataModel *Process::getDataModel()
return d->my_datamodel; return d->my_datamodel;
} }
memory_info * Process::getDescriptor() memory_info * Process::getDescriptor()
{ {
return d->my_descriptor; return d->my_descriptor;
} }
//FIXME: implement
/*void Process::setMemFile(const string & memf)
{
assert(!attached);
memFile = memf;
}*/
bool Process::getThreadIDs(vector<uint32_t> & threads ) bool Process::getThreadIDs(vector<uint32_t> & threads )
{ {
return false; return false;
} }
//FIXME: cross-reference with ELF segment entries?
void Process::getMemRanges( vector<t_memrange> & ranges ) void Process::getMemRanges( vector<t_memrange> & ranges )
{ {
char buffer[1024]; char buffer[1024];

@ -200,7 +200,7 @@ bool Process::resume()
bool Process::attach() bool Process::attach()
{ {
if(d->attached) if(g_pProcess != NULL)
{ {
return false; return false;
} }
@ -256,7 +256,7 @@ bool Process::getThreadIDs(vector<uint32_t> & threads )
return true; return true;
} }
//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries
void Process::getMemRanges( vector<t_memrange> & ranges ) void Process::getMemRanges( vector<t_memrange> & ranges )
{ {
// code here is taken from hexsearch by Silas Dunmore. // code here is taken from hexsearch by Silas Dunmore.

@ -0,0 +1,116 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "DFCommonInternal.h"
using namespace DFHack;
/// HACK: global variables (only one process can be attached at the same time.)
Process * DFHack::g_pProcess; ///< current process. non-NULL when picked
ProcessHandle DFHack::g_ProcessHandle; ///< cache of handle to current process. used for speed reasons
int DFHack::g_ProcessMemFile; ///< opened /proc/PID/mem, valid when attached
class DFHack::ProcessEnumerator::Private
{
public:
Private(){};
MemInfoManager *meminfo;
std::vector<Process *> processes;
};
bool ProcessEnumerator::findProcessess()
{
DIR *dir_p;
struct dirent *dir_entry_p;
string dir_name;
string exe_link;
string cwd_link;
string cmdline_path;
string cmdline;
// ALERT: buffer overrun potential
int errorcount;
int result;
errorcount=0;
result=0;
// Open /proc/ directory
dir_p = opendir("/proc/");
// Reading /proc/ entries
while(NULL != (dir_entry_p = readdir(dir_p)))
{
// Only PID folders (numbers)
if (strspn(dir_entry_p->d_name, "0123456789") != strlen(dir_entry_p->d_name))
{
continue;
}
Process *p = new Process(atoi(dir_entry_p->d_name),d->meminfo->meminfo);
if(p->isIdentified())
{
d->processes.push_back(p);
}
else
{
delete p;
}
}
closedir(dir_p);
// return value depends on if we found some DF processes
if(d->processes.size())
{
return true;
}
return false;
}
uint32_t ProcessEnumerator::size()
{
return d->processes.size();
};
Process * ProcessEnumerator::operator[](uint32_t index)
{
assert(index < d->processes.size());
return d->processes[index];
};
ProcessEnumerator::ProcessEnumerator( string path_to_xml )
: d(new Private())
{
d->meminfo = new MemInfoManager(path_to_xml);
}
ProcessEnumerator::~ProcessEnumerator()
{
// delete all processes
for(uint32_t i = 0;i < d->processes.size();i++)
{
delete d->processes[i];
}
delete d->meminfo;
delete d;
}

@ -0,0 +1,129 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "DFCommonInternal.h"
using namespace DFHack;
/// HACK: global variables (only one process can be attached at the same time.)
Process * DFHack::g_pProcess; ///< current process. non-NULL when picked
ProcessHandle DFHack::g_ProcessHandle; ///< cache of handle to current process. used for speed reasons
int DFHack::g_ProcessMemFile; ///< opened /proc/PID/mem, valid when attached
class DFHack::ProcessEnumerator::Private
{
public:
Private(){};
MemInfoManager *meminfo;
std::vector<Process *> processes;
};
// some magic - will come in handy when we start doing debugger stuff on Windows
bool EnableDebugPriv()
{
bool bRET = FALSE;
TOKEN_PRIVILEGES tp;
HANDLE hToken;
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))
{
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
if (hToken != INVALID_HANDLE_VALUE)
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.PrivilegeCount = 1;
if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, 0, 0))
{
bRET = TRUE;
}
CloseHandle(hToken);
}
}
}
return bRET;
}
// WINDOWS version of the process finder
bool ProcessEnumerator::findProcessess()
{
// Get the list of process identifiers.
DWORD ProcArray[2048], memoryNeeded, numProccesses;
EnableDebugPriv();
if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) )
{
return false;
}
// Calculate how many process identifiers were returned.
numProccesses = memoryNeeded / sizeof(DWORD);
// iterate through processes
for ( int i = 0; i < (int)numProccesses; i++ )
{
Process *p = new Process(ProcArray[i],d->meminfo->meminfo);
if(p->isIdentified())
{
d->processes.push_back(p);
}
else
{
delete p;
}
}
if(d->processes.size())
return true;
return false;
}
uint32_t ProcessEnumerator::size()
{
return d->processes.size();
};
Process * ProcessEnumerator::operator[](uint32_t index)
{
assert(index < d->processes.size());
return d->processes[index];
};
ProcessEnumerator::ProcessEnumerator( string path_to_xml )
: d(new Private())
{
d->meminfo = new MemInfoManager(path_to_xml);
}
ProcessEnumerator::~ProcessEnumerator()
{
// delete all processes
for(uint32_t i = 0;i < d->processes.size();i++)
{
delete d->processes[i];
}
delete d->meminfo;
delete d;
}

@ -42,9 +42,9 @@ void searchLoop(DFHack::API & DF, vector <DFHack::t_memrange>& ranges, int size,
while (1) while (1)
{ {
cout << ">>"; cout << ">>";
DF.Resume(); DF.Detach();
std::getline(cin, select); std::getline(cin, select);
DF.Suspend(); DF.Attach();
if(select == "p") if(select == "p")
{ {
cout << "Found addresses:" << endl; cout << "Found addresses:" << endl;