From 29c0932ff74db1fab2465b6c4d2de73a06c24109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 18 Nov 2009 02:33:17 +0000 Subject: [PATCH] split out memory.xml reading functionality out of the processenumerator --- library/CMakeLists.txt | 6 +- library/DFCommonInternal.h | 1 + ...essEnumerator.cpp => DFMemInfoManager.cpp} | 222 +++--------------- library/DFMemInfoManager.h | 46 ++++ library/DFProcess-linux.cpp | 10 +- library/DFProcess-windows.cpp | 4 +- library/DFProcessEnumerator-linux.cpp | 116 +++++++++ library/DFProcessEnumerator-windows.cpp | 129 ++++++++++ tools/incrementalsearch.cpp | 4 +- 9 files changed, 332 insertions(+), 206 deletions(-) rename library/{DFProcessEnumerator.cpp => DFMemInfoManager.cpp} (61%) create mode 100644 library/DFMemInfoManager.h create mode 100644 library/DFProcessEnumerator-linux.cpp create mode 100644 library/DFProcessEnumerator-windows.cpp diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 7c4bc5a0f..9f972e8d4 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -6,6 +6,7 @@ DFDataModel.h DFHackAPI.h DFMemAccess.h DFMemInfo.h +DFMemInfoManager.h DFProcessEnumerator.h DFProcess.h DFTileTypes.h @@ -23,7 +24,7 @@ tinyxml/tinyxml.h SET(PROJECT_SRCS DFDataModel.cpp DFMemInfo.cpp -DFProcessEnumerator.cpp +DFMemInfoManager.cpp DFHackAPI.cpp DFTileTypes.cpp md5/md5.cpp @@ -35,7 +36,6 @@ tinyxml/tinyxmlparser.cpp ) SET(PROJECT_HDRS_LINUX -DFProcess-linux.h MemAccess-linux.h ) @@ -46,10 +46,12 @@ stdint_win.h SET(PROJECT_SRCS_LINUX DFProcess-linux.cpp +DFProcessEnumerator-linux.cpp ) SET(PROJECT_SRCS_WINDOWS DFProcess-windows.cpp +DFProcessEnumerator-windows.cpp ) IF(UNIX) diff --git a/library/DFCommonInternal.h b/library/DFCommonInternal.h index e62ea52e3..bbb002a7d 100644 --- a/library/DFCommonInternal.h +++ b/library/DFCommonInternal.h @@ -96,6 +96,7 @@ namespace DFHack #include "DFDataModel.h" #include "DFProcess.h" #include "DFProcessEnumerator.h" +#include "DFMemInfoManager.h" #include "DFMemAccess.h" #include "DFVector.h" #include "DFMemInfo.h" diff --git a/library/DFProcessEnumerator.cpp b/library/DFMemInfoManager.cpp similarity index 61% rename from library/DFProcessEnumerator.cpp rename to library/DFMemInfoManager.cpp index 136071e71..a487e519b 100644 --- a/library/DFProcessEnumerator.cpp +++ b/library/DFMemInfoManager.cpp @@ -25,143 +25,7 @@ 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(){}; - // memory info entries loaded from a file - std::vector meminfo; - Process * currentProcess; - ProcessHandle currentProcessHandle; - std::vector processes; - bool loadDescriptors( string path_to_xml); - void ParseVTable(TiXmlElement* vtable, memory_info& mem); - void ParseEntry (TiXmlElement* entry, memory_info& mem, map & 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) +void MemInfoManager::ParseVTable(TiXmlElement* vtable, memory_info& mem) { TiXmlElement* pClassEntry; TiXmlElement* pClassSubEntry; @@ -209,7 +73,7 @@ void ProcessEnumerator::Private::ParseVTable(TiXmlElement* vtable, memory_info& -void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& mem, map & knownEntries) +void MemInfoManager::ParseEntry (TiXmlElement* entry, memory_info& mem, map & knownEntries) { TiXmlElement* pMemEntry; const char *cstr_version = entry->Attribute("version"); @@ -232,7 +96,7 @@ void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& m string os = cstr_os; mem.setVersion(cstr_version); mem.setOS(cstr_os); - + // offset inherited addresses by 'rebase'. int32_t rebase = 0; if(cstr_rebase) @@ -240,7 +104,7 @@ void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& m rebase = mem.getBase() + strtol(cstr_rebase, NULL, 16); mem.RebaseAddresses(rebase); } - + //set base to default, we're overwriting this because the previous rebase could cause havoc on Vista/7 if(os == "windows") { @@ -303,22 +167,22 @@ void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& m { mem.setString(name, value); } - else if (type == "Profession") - { - mem.setProfession(value,name); - } - else if (type == "Job") - { - mem.setJob(value,name); - } + else if (type == "Profession") + { + mem.setProfession(value,name); + } + else if (type == "Job") + { + mem.setJob(value,name); + } else if (type == "Skill") - { - mem.setSkill(value,name); - } - 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.setSkill(value,name); + } + 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")); + } else if (type == "Labor") { mem.setLabor(value,name); @@ -330,17 +194,22 @@ void ProcessEnumerator::Private::ParseEntry (TiXmlElement* entry, memory_info& m } // for } // method +MemInfoManager::MemInfoManager(string path_to_xml) +{ + error = false; + loadFile(path_to_xml); +} // 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() ); bool loadOkay = doc.LoadFile(); - TiXmlHandle hDoc(&doc); + TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(0); memory_info mem; - + if ( loadOkay ) { // block: name @@ -388,45 +257,14 @@ bool ProcessEnumerator::Private::loadDescriptors(string path_to_xml) } // process found things here } + error = false; return true; } else { // load failed cerr << "Can't load memory offsets from memory.xml" << endl; + error = 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->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; -} +} \ No newline at end of file diff --git a/library/DFMemInfoManager.h b/library/DFMemInfoManager.h new file mode 100644 index 000000000..535757dac --- /dev/null +++ b/library/DFMemInfoManager.h @@ -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 meminfo; + void ParseVTable(TiXmlElement* vtable, memory_info& mem); + void ParseEntry (TiXmlElement* entry, memory_info& mem, map & knownEntries); + bool error; + }; +} + +#endif \ No newline at end of file diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 68c40c351..693105d92 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -181,24 +181,18 @@ DataModel *Process::getDataModel() return d->my_datamodel; } - memory_info * Process::getDescriptor() { return d->my_descriptor; } - -/*void Process::setMemFile(const string & memf) -{ - assert(!attached); - memFile = memf; -}*/ - +//FIXME: implement bool Process::getThreadIDs(vector & threads ) { return false; } +//FIXME: cross-reference with ELF segment entries? void Process::getMemRanges( vector & ranges ) { char buffer[1024]; diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index e4dc0f866..6c90998e0 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -200,7 +200,7 @@ bool Process::resume() bool Process::attach() { - if(d->attached) + if(g_pProcess != NULL) { return false; } @@ -256,7 +256,7 @@ bool Process::getThreadIDs(vector & threads ) return true; } - +//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries void Process::getMemRanges( vector & ranges ) { // code here is taken from hexsearch by Silas Dunmore. diff --git a/library/DFProcessEnumerator-linux.cpp b/library/DFProcessEnumerator-linux.cpp new file mode 100644 index 000000000..e386a1a6e --- /dev/null +++ b/library/DFProcessEnumerator-linux.cpp @@ -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 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; +} diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp new file mode 100644 index 000000000..ace2cfada --- /dev/null +++ b/library/DFProcessEnumerator-windows.cpp @@ -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 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; +} diff --git a/tools/incrementalsearch.cpp b/tools/incrementalsearch.cpp index be4484ec3..39f148a9c 100644 --- a/tools/incrementalsearch.cpp +++ b/tools/incrementalsearch.cpp @@ -42,9 +42,9 @@ void searchLoop(DFHack::API & DF, vector & ranges, int size, while (1) { cout << ">>"; - DF.Resume(); + DF.Detach(); std::getline(cin, select); - DF.Suspend(); + DF.Attach(); if(select == "p") { cout << "Found addresses:" << endl;