From b3424418e6a046e0da8f3e6f7bfe9d4d6dd77602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 2 Mar 2010 01:18:34 +0100 Subject: [PATCH 01/16] Nuked many Process classes. Only SHM remains. We'll see how it goes :) --- library/CMakeLists.txt | 6 +- library/DFProcess-linux-SHM.cpp | 76 +-- library/DFProcess-linux-wine.cpp | 595 ------------------------ library/DFProcess-linux.cpp | 546 ---------------------- library/DFProcess-windows-SHM.cpp | 76 +-- library/DFProcess-windows.cpp | 482 ------------------- library/DFProcess.h | 191 +------- library/DFProcessEnumerator-linux.cpp | 5 +- library/DFProcessEnumerator-windows.cpp | 32 +- 9 files changed, 102 insertions(+), 1907 deletions(-) delete mode 100644 library/DFProcess-linux-wine.cpp delete mode 100644 library/DFProcess-linux.cpp delete mode 100644 library/DFProcess-windows.cpp diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 321ef5b3b..9df32d6d6 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -47,15 +47,15 @@ stdint_win.h ) SET(PROJECT_SRCS_LINUX -DFProcess-linux.cpp +#DFProcess-linux.cpp DFProcess-linux-SHM.cpp -DFProcess-linux-wine.cpp +#DFProcess-linux-wine.cpp DFWindow-linux.cpp DFProcessEnumerator-linux.cpp ) SET(PROJECT_SRCS_WINDOWS -DFProcess-windows.cpp +#DFProcess-windows.cpp DFProcess-windows-SHM.cpp DFWindow-windows.cpp DFProcessEnumerator-windows.cpp diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 9bcda4ff2..1c1254989 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -37,7 +37,7 @@ using namespace DFHack; // a full memory barrier! better be safe than sorry. #define gcc_barrier asm volatile("" ::: "memory"); __sync_synchronize(); -class SHMProcess::Private +class Process::Private { public: Private() @@ -68,7 +68,7 @@ class SHMProcess::Private bool DF_GetPID(pid_t & ret); }; -bool SHMProcess::Private::waitWhile (DF_PINGPONG state) +bool Process::Private::waitWhile (DF_PINGPONG state) { uint32_t cnt = 0; struct shmid_ds descriptor; @@ -104,7 +104,7 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state) return true; } -bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret) +bool Process::Private::DF_TestBridgeVersion(bool & ret) { ((shm_cmd *)my_shm)->pingpong = DFPP_VERSION; gcc_barrier @@ -116,7 +116,7 @@ bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret) return true; } -bool SHMProcess::Private::DF_GetPID(pid_t & ret) +bool Process::Private::DF_GetPID(pid_t & ret) { ((shm_cmd *)my_shm)->pingpong = DFPP_PID; gcc_barrier @@ -128,7 +128,7 @@ bool SHMProcess::Private::DF_GetPID(pid_t & ret) return true; } -SHMProcess::SHMProcess(vector & known_versions) +Process::Process(vector & known_versions) : d(new Private()) { char exe_link_name [256]; @@ -204,21 +204,21 @@ SHMProcess::SHMProcess(vector & known_versions) shmdt(d->my_shm); // detach so we don't attach twice when attach() is called } -bool SHMProcess::isSuspended() +bool Process::isSuspended() { return d->suspended; } -bool SHMProcess::isAttached() +bool Process::isAttached() { return d->attached; } -bool SHMProcess::isIdentified() +bool Process::isIdentified() { return d->identified; } -bool SHMProcess::Private::validate(char * exe_file, uint32_t pid, vector & known_versions) +bool Process::Private::validate(char * exe_file, uint32_t pid, vector & known_versions) { md5wrapper md5; // get hash of the running DF process @@ -247,7 +247,7 @@ bool SHMProcess::Private::validate(char * exe_file, uint32_t pid, vector attached) { @@ -261,29 +261,29 @@ SHMProcess::~SHMProcess() delete d; } -memory_info * SHMProcess::getDescriptor() +memory_info * Process::getDescriptor() { return d->my_descriptor; } -DFWindow * SHMProcess::getWindow() +DFWindow * Process::getWindow() { return d->my_window; } -int SHMProcess::getPID() +int Process::getPID() { return d->my_pid; } //FIXME: implement -bool SHMProcess::getThreadIDs(vector & threads ) +bool Process::getThreadIDs(vector & threads ) { return false; } //FIXME: cross-reference with ELF segment entries? -void SHMProcess::getMemRanges( vector & ranges ) +void Process::getMemRanges( vector & ranges ) { char buffer[1024]; char permissions[5]; // r/-, w/-, x/-, p/s, 0 @@ -309,7 +309,7 @@ void SHMProcess::getMemRanges( vector & ranges ) } } -bool SHMProcess::suspend() +bool Process::suspend() { if(!d->attached) { @@ -328,7 +328,7 @@ bool SHMProcess::suspend() return true; } -bool SHMProcess::asyncSuspend() +bool Process::asyncSuspend() { if(!d->attached) { @@ -350,12 +350,12 @@ bool SHMProcess::asyncSuspend() } } -bool SHMProcess::forceresume() +bool Process::forceresume() { return resume(); } -bool SHMProcess::resume() +bool Process::resume() { if(!d->attached) return false; @@ -367,7 +367,7 @@ bool SHMProcess::resume() } -bool SHMProcess::attach() +bool Process::attach() { int status; if(g_pProcess != 0) @@ -396,7 +396,7 @@ bool SHMProcess::attach() return false; } -bool SHMProcess::detach() +bool Process::detach() { if(!d->attached) { @@ -420,7 +420,7 @@ bool SHMProcess::detach() return false; } -void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) +void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) { // normal read under 1MB if(size <= SHM_BODY) @@ -457,7 +457,7 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff } } -uint8_t SHMProcess::readByte (const uint32_t offset) +uint8_t Process::readByte (const uint32_t offset) { ((shm_read_small *)d->my_shm)->address = offset; gcc_barrier @@ -466,7 +466,7 @@ uint8_t SHMProcess::readByte (const uint32_t offset) return ((shm_retval *)d->my_shm)->value; } -void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) +void Process::readByte (const uint32_t offset, uint8_t &val ) { ((shm_read_small *)d->my_shm)->address = offset; gcc_barrier @@ -475,7 +475,7 @@ void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) val = ((shm_retval *)d->my_shm)->value; } -uint16_t SHMProcess::readWord (const uint32_t offset) +uint16_t Process::readWord (const uint32_t offset) { ((shm_read_small *)d->my_shm)->address = offset; gcc_barrier @@ -484,7 +484,7 @@ uint16_t SHMProcess::readWord (const uint32_t offset) return ((shm_retval *)d->my_shm)->value; } -void SHMProcess::readWord (const uint32_t offset, uint16_t &val) +void Process::readWord (const uint32_t offset, uint16_t &val) { ((shm_read_small *)d->my_shm)->address = offset; gcc_barrier @@ -493,7 +493,7 @@ void SHMProcess::readWord (const uint32_t offset, uint16_t &val) val = ((shm_retval *)d->my_shm)->value; } -uint32_t SHMProcess::readDWord (const uint32_t offset) +uint32_t Process::readDWord (const uint32_t offset) { ((shm_read_small *)d->my_shm)->address = offset; gcc_barrier @@ -501,7 +501,7 @@ uint32_t SHMProcess::readDWord (const uint32_t offset) d->waitWhile(DFPP_READ_DWORD); return ((shm_retval *)d->my_shm)->value; } -void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) +void Process::readDWord (const uint32_t offset, uint32_t &val) { ((shm_read_small *)d->my_shm)->address = offset; gcc_barrier @@ -514,7 +514,7 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) * WRITING */ -void SHMProcess::writeDWord (uint32_t offset, uint32_t data) +void Process::writeDWord (uint32_t offset, uint32_t data) { ((shm_write_small *)d->my_shm)->address = offset; ((shm_write_small *)d->my_shm)->value = data; @@ -524,7 +524,7 @@ void SHMProcess::writeDWord (uint32_t offset, uint32_t data) } // using these is expensive. -void SHMProcess::writeWord (uint32_t offset, uint16_t data) +void Process::writeWord (uint32_t offset, uint16_t data) { ((shm_write_small *)d->my_shm)->address = offset; ((shm_write_small *)d->my_shm)->value = data; @@ -533,7 +533,7 @@ void SHMProcess::writeWord (uint32_t offset, uint16_t data) d->waitWhile(DFPP_WRITE_WORD); } -void SHMProcess::writeByte (uint32_t offset, uint8_t data) +void Process::writeByte (uint32_t offset, uint8_t data) { ((shm_write_small *)d->my_shm)->address = offset; ((shm_write_small *)d->my_shm)->value = data; @@ -542,7 +542,7 @@ void SHMProcess::writeByte (uint32_t offset, uint8_t data) d->waitWhile(DFPP_WRITE_BYTE); } -void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) +void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) { // normal write under 1MB if(size <= SHM_BODY) @@ -580,7 +580,7 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf } // FIXME: butt-fugly -const std::string SHMProcess::readCString (uint32_t offset) +const std::string Process::readCString (uint32_t offset) { std::string temp; char temp_c[256]; @@ -597,7 +597,7 @@ const std::string SHMProcess::readCString (uint32_t offset) return temp; } -DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size) +DfVector Process::readVector (uint32_t offset, uint32_t item_size) { /* GNU libstdc++ vector is three pointers long @@ -613,7 +613,7 @@ DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size) return DfVector(start,size,item_size); } -const std::string SHMProcess::readSTLString(uint32_t offset) +const std::string Process::readSTLString(uint32_t offset) { ((shm_read_small *)d->my_shm)->address = offset; full_barrier @@ -623,7 +623,7 @@ const std::string SHMProcess::readSTLString(uint32_t offset) return(string( (char *)d->my_shm+SHM_HEADER)); } -size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) +size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { ((shm_read_small *)d->my_shm)->address = offset; full_barrier @@ -636,7 +636,7 @@ size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapa return fit; } -void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) +void Process::writeSTLString(const uint32_t address, const std::string writeString) { ((shm_write_small *)d->my_shm)->address = address; strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator @@ -645,7 +645,7 @@ void SHMProcess::writeSTLString(const uint32_t address, const std::string writeS d->waitWhile(DFPP_WRITE_STL_STRING); } -string SHMProcess::readClassName (uint32_t vptr) +string Process::readClassName (uint32_t vptr) { int typeinfo = readDWord(vptr - 0x4); int typestring = readDWord(typeinfo + 0x4); diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp deleted file mode 100644 index 880a9a06a..000000000 --- a/library/DFProcess-linux-wine.cpp +++ /dev/null @@ -1,595 +0,0 @@ -/* -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" -#include -#include -#include -using namespace DFHack; - -class WineProcess::Private -{ - public: - Private() - { - my_descriptor = NULL; - my_handle = NULL; - my_window = NULL; - my_pid = 0; - attached = false; - suspended = false; - memFileHandle = 0; - }; - ~Private(){}; - DFWindow* my_window; - memory_info * my_descriptor; - ProcessHandle my_handle; - uint32_t my_pid; - string memFile; - int memFileHandle; - bool attached; - bool suspended; - bool identified; - bool validate(char * exe_file, uint32_t pid, char * mem_file, vector & known_versions); -}; - -WineProcess::WineProcess(uint32_t pid, vector & known_versions) -: d(new Private()) -{ - char dir_name [256]; - char exe_link_name [256]; - char mem_name [256]; - char cwd_name [256]; - char cmdline_name [256]; - char target_name[1024]; - int target_result; - - d->identified = false; - - sprintf(dir_name,"/proc/%d/", pid); - sprintf(exe_link_name,"/proc/%d/exe", pid); - sprintf(mem_name,"/proc/%d/mem", pid); - sprintf(cwd_name,"/proc/%d/cwd", pid); - sprintf(cmdline_name,"/proc/%d/cmdline", pid); - - // resolve /proc/PID/exe link - target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); - if (target_result == -1) - { - return; - } - // make sure we have a null terminated string... - target_name[target_result] = 0; - - // FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline - // is this windows version of Df running in wine? - if(strstr(target_name, "wine-preloader")!= NULL) - { - // get working directory - target_result = readlink(cwd_name, target_name, sizeof(target_name)-1); - target_name[target_result] = 0; - - // got path to executable, do the same for its name - ifstream ifs ( cmdline_name , ifstream::in ); - string cmdline; - getline(ifs,cmdline); - if (cmdline.find("dwarfort-w.exe") != string::npos || cmdline.find("dwarfort.exe") != string::npos || cmdline.find("Dwarf Fortress.exe") != string::npos) - { - char exe_link[1024]; - // put executable name and path together - sprintf(exe_link,"%s/%s",target_name,cmdline.c_str()); - - // create wine process, add it to the vector - d->identified = d->validate(exe_link,pid,mem_name,known_versions); - d->my_window = new DFWindow(this); - return; - } - } -} - -bool WineProcess::isSuspended() -{ - return d->suspended; -} -bool WineProcess::isAttached() -{ - return d->attached; -} - -bool WineProcess::isIdentified() -{ - return d->identified; -} - -bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file, std::vector< memory_info* >& known_versions) -{ - md5wrapper md5; - // get hash of the running DF process - string hash = md5.getHashFromFile(exe_file); - vector::iterator it; - - // iterate over the list of memory locations - for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) - { - string thishash; - try - { - thishash = (*it)->getString("md5"); - } - catch (Error::MissingMemoryDefinition& e) - { - continue; - } - // are the md5 hashes the same? - if(memory_info::OS_WINDOWS == (*it)->getOS() && hash == thishash) - { - memory_info * m = *it; - my_descriptor = m; - my_handle = my_pid = pid; - // tell WineProcess about the /proc/PID/mem file - memFile = mem_file; - identified = true; - return true; - } - } - return false; -} - -WineProcess::~WineProcess() -{ - if(d->attached) - { - detach(); - } - if(d->my_window) - delete d->my_window; - delete d; -} - -memory_info * WineProcess::getDescriptor() -{ - return d->my_descriptor; -} - -DFWindow * WineProcess::getWindow() -{ - return d->my_window; -} - -int WineProcess::getPID() -{ - return d->my_pid; -} - -//FIXME: implement -bool WineProcess::getThreadIDs(vector & threads ) -{ - return false; -} - -//FIXME: cross-reference with ELF segment entries? -void WineProcess::getMemRanges( vector & ranges ) -{ - char buffer[1024]; - char permissions[5]; // r/-, w/-, x/-, p/s, 0 - - sprintf(buffer, "/proc/%lu/maps", d->my_pid); - FILE *mapFile = ::fopen(buffer, "r"); - uint64_t offset, device1, device2, node; - - while (fgets(buffer, 1024, mapFile)) - { - t_memrange temp; - temp.name[0] = 0; - sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s", - &temp.start, - &temp.end, - (char*)&permissions, - &offset, &device1, &device2, &node, - (char*)&temp.name); - temp.read = permissions[0] == 'r'; - temp.write = permissions[1] == 'w'; - temp.execute = permissions[2] == 'x'; - ranges.push_back(temp); - } -} - -bool WineProcess::asyncSuspend() -{ - return suspend(); -} - -bool WineProcess::suspend() -{ - int status; - if(!d->attached) - return false; - if(d->suspended) - return true; - if (kill(d->my_handle, SIGSTOP) == -1) - { - // no, we got an error - perror("kill SIGSTOP error"); - return false; - } - while(true) - { - // we wait on the pid - pid_t w = waitpid(d->my_handle, &status, 0); - if (w == -1) - { - // child died - perror("DF exited during suspend call"); - return false; - } - // stopped -> let's continue - if (WIFSTOPPED(status)) - { - break; - } - } - d->suspended = true; - return true; -} - -bool WineProcess::forceresume() -{ - return resume(); -} - -bool WineProcess::resume() -{ - if(!d->attached) - return false; - if(!d->suspended) - return true; - if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1) - { - // no, we got an error - perror("ptrace resume error"); - return false; - } - d->suspended = false; - return true; -} - - -bool WineProcess::attach() -{ - int status; - if(g_pProcess != NULL) - { - return false; - } - // can we attach? - if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1) - { - // no, we got an error - perror("ptrace attach error"); - cerr << "attach failed on pid " << d->my_handle << endl; - return false; - } - while(true) - { - // we wait on the pid - pid_t w = waitpid(d->my_handle, &status, 0); - if (w == -1) - { - // child died - perror("wait inside attach()"); - return false; - } - // stopped -> let's continue - if (WIFSTOPPED(status)) - { - break; - } - } - d->suspended = true; - - int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); - if(proc_pid_mem == -1) - { - ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); - cerr << d->memFile << endl; - cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl; - perror("open(memFile.c_str(),O_RDONLY)"); - return false; - } - else - { - d->attached = true; - g_pProcess = this; - - d->memFileHandle = proc_pid_mem; - return true; // we are attached - } -} - -bool WineProcess::detach() -{ - if(!d->attached) return false; - if(!d->suspended) suspend(); - int result = 0; - // close /proc/PID/mem - result = close(d->memFileHandle); - if(result == -1) - { - cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl; - perror("mem file close"); - return false; - } - else - { - // detach - result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); - if(result == -1) - { - cerr << "couldn't detach from process pid" << d->my_handle << endl; - perror("ptrace detach"); - return false; - } - else - { - d->attached = false; - g_pProcess = NULL; - return true; - } - } -} - - -// danger: uses recursion! -void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target) -{ - if(size == 0) return; - - ssize_t result; - result = pread(d->memFileHandle, target,size,offset); - if(result != size) - { - if(result == -1) - { - cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl; - cerr << "errno: " << errno << endl; - errno = 0; - } - else - { - read(offset + result, size - result, target + result); - } - } -} - -uint8_t WineProcess::readByte (const uint32_t offset) -{ - uint8_t val; - read(offset, 1, &val); - return val; -} - -void WineProcess::readByte (const uint32_t offset, uint8_t &val ) -{ - read(offset, 1, &val); -} - -uint16_t WineProcess::readWord (const uint32_t offset) -{ - uint16_t val; - read(offset, 2, (uint8_t *) &val); - return val; -} - -void WineProcess::readWord (const uint32_t offset, uint16_t &val) -{ - read(offset, 2, (uint8_t *) &val); -} - -uint32_t WineProcess::readDWord (const uint32_t offset) -{ - uint32_t val; - read(offset, 4, (uint8_t *) &val); - return val; -} -void WineProcess::readDWord (const uint32_t offset, uint32_t &val) -{ - read(offset, 4, (uint8_t *) &val); -} - -/* - * WRITING - */ - -void WineProcess::writeDWord (uint32_t offset, uint32_t data) -{ - ptrace(PTRACE_POKEDATA,d->my_handle, offset, data); -} - -// using these is expensive. -void WineProcess::writeWord (uint32_t offset, uint16_t data) -{ - uint32_t orig = readDWord(offset); - orig &= 0xFFFF0000; - orig |= data; - /* - orig |= 0x0000FFFF; - orig &= data; - */ - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); -} - -void WineProcess::writeByte (uint32_t offset, uint8_t data) -{ - uint32_t orig = readDWord(offset); - orig &= 0xFFFFFF00; - orig |= data; - /* - orig |= 0x000000FF; - orig &= data; - */ - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); -} - -// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS -void WineProcess::write (uint32_t offset, uint32_t size, uint8_t *source) -{ - uint32_t indexptr = 0; - while (size > 0) - { - // default: we push 4 bytes - if(size >= 4) - { - writeDWord(offset, *(uint32_t *) (source + indexptr)); - offset +=4; - indexptr +=4; - size -=4; - } - // last is either three or 2 bytes - else if(size >= 2) - { - writeWord(offset, *(uint16_t *) (source + indexptr)); - offset +=2; - indexptr +=2; - size -=2; - } - // finishing move - else if(size == 1) - { - writeByte(offset, *(uint8_t *) (source + indexptr)); - return; - } - } -} - -const std::string WineProcess::readCString (uint32_t offset) -{ - std::string temp; - char temp_c[256]; - int counter = 0; - char r; - do - { - r = readByte(offset+counter); - temp_c[counter] = r; - counter++; - } while (r && counter < 255); - temp_c[counter] = 0; - temp = temp_c; - return temp; -} - -DfVector WineProcess::readVector (uint32_t offset, uint32_t item_size) -{ - /* - MSVC++ vector is four pointers long - ptr allocator - ptr start - ptr end - ptr alloc_end - - we don't care about alloc_end because we don't try to add stuff - we also don't care about the allocator thing in front - */ - uint32_t start = g_pProcess->readDWord(offset+4); - uint32_t end = g_pProcess->readDWord(offset+8); - uint32_t size = (end - start) /4; - return DfVector(start,size,item_size); -} - -size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) -{ - /* - MSVC++ string - ptr allocator - union - { - char[16] start; - char * start_ptr - } - Uint32 length - Uint32 capacity - */ - uint32_t start_offset = offset + 4; - size_t length = g_pProcess->readDWord(offset + 20); - - size_t capacity = g_pProcess->readDWord(offset + 24); - size_t read_real = min(length, bufcapacity-1);// keep space for null termination - - // read data from inside the string structure - if(capacity < 16) - { - g_pProcess->read(start_offset, read_real , (uint8_t *)buffer); - } - else // read data from what the offset + 4 dword points to - { - start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset - g_pProcess->read(start_offset, read_real, (uint8_t *)buffer); - } - - buffer[read_real] = 0; - return read_real; -} - -const string WineProcess::readSTLString (uint32_t offset) -{ - /* - MSVC++ string - ptr allocator - union - { - char[16] start; - char * start_ptr - } - Uint32 length - Uint32 capacity - */ - uint32_t start_offset = offset + 4; - uint32_t length = g_pProcess->readDWord(offset + 20); - uint32_t capacity = g_pProcess->readDWord(offset + 24); - char * temp = new char[capacity+1]; - - // read data from inside the string structure - if(capacity < 16) - { - g_pProcess->read(start_offset, capacity, (uint8_t *)temp); - } - else // read data from what the offset + 4 dword points to - { - start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset - g_pProcess->read(start_offset, capacity, (uint8_t *)temp); - } - - temp[length] = 0; - string ret = temp; - delete temp; - return ret; -} - -string WineProcess::readClassName (uint32_t vptr) -{ - int rtti = readDWord(vptr - 0x4); - int typeinfo = readDWord(rtti + 0xC); - string raw = readCString(typeinfo + 0xC); // skips the .?AV - raw.resize(raw.length() - 4);// trim st@@ from end - return raw; -} \ No newline at end of file diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp deleted file mode 100644 index 3294cbaf2..000000000 --- a/library/DFProcess-linux.cpp +++ /dev/null @@ -1,546 +0,0 @@ -/* -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" -#include -#include -using namespace DFHack; - -class NormalProcess::Private -{ - public: - Private() - { - my_descriptor = NULL; - my_handle = NULL; - my_window = NULL; - my_pid = 0; - attached = false; - suspended = false; - memFileHandle = 0; - }; - ~Private(){}; - DFWindow* my_window; - memory_info * my_descriptor; - ProcessHandle my_handle; - uint32_t my_pid; - string memFile; - int memFileHandle; - bool attached; - bool suspended; - bool identified; - bool validate(char * exe_file, uint32_t pid, char * mem_file, vector & known_versions); -}; - -NormalProcess::NormalProcess(uint32_t pid, vector< memory_info* >& known_versions) -: d(new Private()) -{ - char dir_name [256]; - char exe_link_name [256]; - char mem_name [256]; - char cwd_name [256]; - char cmdline_name [256]; - char target_name[1024]; - int target_result; - - d->identified = false; - - sprintf(dir_name,"/proc/%d/", pid); - sprintf(exe_link_name,"/proc/%d/exe", pid); - sprintf(mem_name,"/proc/%d/mem", pid); - sprintf(cwd_name,"/proc/%d/cwd", pid); - sprintf(cmdline_name,"/proc/%d/cmdline", pid); - - // resolve /proc/PID/exe link - target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); - if (target_result == -1) - { - return; - } - // make sure we have a null terminated string... - target_name[target_result] = 0; - - // is this the regular linux DF? - if (strstr(target_name, "dwarfort.exe") != NULL) - { - // create linux process, add it to the vector - d->identified = d->validate(target_name,pid,mem_name,known_versions ); - d->my_window = new DFWindow(this); - return; - } -} - -bool NormalProcess::isSuspended() -{ - return d->suspended; -} -bool NormalProcess::isAttached() -{ - return d->attached; -} - -bool NormalProcess::isIdentified() -{ - return d->identified; -} - -bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions) -{ - md5wrapper md5; - // get hash of the running DF process - string hash = md5.getHashFromFile(exe_file); - vector::iterator it; - - // iterate over the list of memory locations - for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) - { - try - { - if(hash == (*it)->getString("md5")) // are the md5 hashes the same? - { - memory_info * m = *it; - if (memory_info::OS_LINUX == m->getOS()) - { - my_descriptor = m; - my_handle = my_pid = pid; - } - else - { - // some error happened, continue with next process - continue; - } - // tell NormalProcess about the /proc/PID/mem file - this->memFile = memFile; - identified = true; - return true; - } - } - catch (Error::MissingMemoryDefinition&) - { - continue; - } - } - return false; -} - -NormalProcess::~NormalProcess() -{ - if(d->attached) - { - detach(); - } - // destroy data model. this is assigned by processmanager - if(d->my_window) - delete d->my_window; - delete d; -} - -memory_info * NormalProcess::getDescriptor() -{ - return d->my_descriptor; -} - -DFWindow * NormalProcess::getWindow() -{ - return d->my_window; -} - -int NormalProcess::getPID() -{ - return d->my_pid; -} - -//FIXME: implement -bool NormalProcess::getThreadIDs(vector & threads ) -{ - return false; -} - -//FIXME: cross-reference with ELF segment entries? -void NormalProcess::getMemRanges( vector & ranges ) -{ - char buffer[1024]; - char permissions[5]; // r/-, w/-, x/-, p/s, 0 - - sprintf(buffer, "/proc/%lu/maps", d->my_pid); - FILE *mapFile = ::fopen(buffer, "r"); - uint64_t offset, device1, device2, node; - - while (fgets(buffer, 1024, mapFile)) - { - t_memrange temp; - temp.name[0] = 0; - sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s", - &temp.start, - &temp.end, - (char*)&permissions, - &offset, &device1, &device2, &node, - (char*)&temp.name); - temp.read = permissions[0] == 'r'; - temp.write = permissions[1] == 'w'; - temp.execute = permissions[2] == 'x'; - ranges.push_back(temp); - } -} - -bool NormalProcess::asyncSuspend() -{ - return suspend(); -} - -bool NormalProcess::suspend() -{ - int status; - if(!d->attached) - return false; - if(d->suspended) - return true; - if (kill(d->my_handle, SIGSTOP) == -1) - { - // no, we got an error - perror("kill SIGSTOP error"); - return false; - } - while(true) - { - // we wait on the pid - pid_t w = waitpid(d->my_handle, &status, 0); - if (w == -1) - { - // child died - perror("DF exited during suspend call"); - return false; - } - // stopped -> let's continue - if (WIFSTOPPED(status)) - { - break; - } - } - d->suspended = true; - return true; -} - -bool NormalProcess::forceresume() -{ - return resume(); -} - -bool NormalProcess::resume() -{ - if(!d->attached) - return false; - if(!d->suspended) - return true; - if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1) - { - // no, we got an error - perror("ptrace resume error"); - return false; - } - d->suspended = false; - return true; -} - - -bool NormalProcess::attach() -{ - int status; - if(g_pProcess != NULL) - { - return false; - } - // can we attach? - if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1) - { - // no, we got an error - perror("ptrace attach error"); - cerr << "attach failed on pid " << d->my_handle << endl; - return false; - } - while(true) - { - // we wait on the pid - pid_t w = waitpid(d->my_handle, &status, 0); - if (w == -1) - { - // child died - perror("wait inside attach()"); - return false; - } - // stopped -> let's continue - if (WIFSTOPPED(status)) - { - break; - } - } - d->suspended = true; - - int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); - if(proc_pid_mem == -1) - { - ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); - cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl; - perror("open(memFile.c_str(),O_RDONLY)"); - return false; - } - else - { - d->attached = true; - g_pProcess = this; - - d->memFileHandle = proc_pid_mem; - return true; // we are attached - } -} - -bool NormalProcess::detach() -{ - if(!d->attached) return false; - if(!d->suspended) suspend(); - int result = 0; - // close /proc/PID/mem - result = close(d->memFileHandle); - if(result == -1) - { - cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl; - perror("mem file close"); - return false; - } - else - { - // detach - result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); - if(result == -1) - { - cerr << "couldn't detach from process pid" << d->my_handle << endl; - perror("ptrace detach"); - return false; - } - else - { - d->attached = false; - g_pProcess = NULL; - return true; - } - } -} - - -// danger: uses recursion! -void NormalProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target) -{ - if(size == 0) return; - - ssize_t result; - result = pread(d->memFileHandle, target,size,offset); - if(result != size) - { - if(result == -1) - { - cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl; - cerr << "errno: " << errno << endl; - errno = 0; - } - else - { - read(offset + result, size - result, target + result); - } - } -} - -uint8_t NormalProcess::readByte (const uint32_t offset) -{ - uint8_t val; - read(offset, 1, &val); - return val; -} - -void NormalProcess::readByte (const uint32_t offset, uint8_t &val ) -{ - read(offset, 1, &val); -} - -uint16_t NormalProcess::readWord (const uint32_t offset) -{ - uint16_t val; - read(offset, 2, (uint8_t *) &val); - return val; -} - -void NormalProcess::readWord (const uint32_t offset, uint16_t &val) -{ - read(offset, 2, (uint8_t *) &val); -} - -uint32_t NormalProcess::readDWord (const uint32_t offset) -{ - uint32_t val; - read(offset, 4, (uint8_t *) &val); - return val; -} -void NormalProcess::readDWord (const uint32_t offset, uint32_t &val) -{ - read(offset, 4, (uint8_t *) &val); -} - -/* - * WRITING - */ - -void NormalProcess::writeDWord (uint32_t offset, uint32_t data) -{ - ptrace(PTRACE_POKEDATA,d->my_handle, offset, data); -} - -// using these is expensive. -void NormalProcess::writeWord (uint32_t offset, uint16_t data) -{ - uint32_t orig = readDWord(offset); - orig &= 0xFFFF0000; - orig |= data; - /* - orig |= 0x0000FFFF; - orig &= data; - */ - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); -} - -void NormalProcess::writeByte (uint32_t offset, uint8_t data) -{ - uint32_t orig = readDWord(offset); - orig &= 0xFFFFFF00; - orig |= data; - /* - orig |= 0x000000FF; - orig &= data; - */ - ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); -} - -// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS -void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) -{ - uint32_t indexptr = 0; - while (size > 0) - { - // default: we push 4 bytes - if(size >= 4) - { - writeDWord(offset, *(uint32_t *) (source + indexptr)); - offset +=4; - indexptr +=4; - size -=4; - } - // last is either three or 2 bytes - else if(size >= 2) - { - writeWord(offset, *(uint16_t *) (source + indexptr)); - offset +=2; - indexptr +=2; - size -=2; - } - // finishing move - else if(size == 1) - { - writeByte(offset, *(uint8_t *) (source + indexptr)); - return; - } - } -} - -const std::string NormalProcess::readCString (uint32_t offset) -{ - std::string temp; - char temp_c[256]; - int counter = 0; - char r; - do - { - r = readByte(offset+counter); - temp_c[counter] = r; - counter++; - } while (r && counter < 255); - temp_c[counter] = 0; - temp = temp_c; - return temp; -} - -DfVector NormalProcess::readVector (uint32_t offset, uint32_t item_size) -{ - /* - GNU libstdc++ vector is three pointers long - ptr start - ptr end - ptr alloc_end - - we don't care about alloc_end because we don't try to add stuff - */ - uint32_t start = g_pProcess->readDWord(offset); - uint32_t end = g_pProcess->readDWord(offset+4); - uint32_t size = (end - start) /4; - return DfVector(start,size,item_size); -} - -struct _Rep_base -{ - uint32_t _M_length; - uint32_t _M_capacity; - uint32_t _M_refcount; -}; - -size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) -{ - _Rep_base header; - offset = g_pProcess->readDWord(offset); - g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header); - size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination - g_pProcess->read(offset,read_real,(uint8_t * )buffer); - buffer[read_real] = 0; - return read_real; -} - -const string NormalProcess::readSTLString (uint32_t offset) -{ - _Rep_base header; - - offset = g_pProcess->readDWord(offset); - g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header); - - // FIXME: use char* everywhere, avoid string - char * temp = new char[header._M_length+1]; - g_pProcess->read(offset,header._M_length+1,(uint8_t * )temp); - string ret(temp); - delete temp; - return ret; -} - -string NormalProcess::readClassName (uint32_t vptr) -{ - int typeinfo = readDWord(vptr - 0x4); - int typestring = readDWord(typeinfo + 0x4); - string raw = readCString(typestring); - size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers - size_t end = raw.length(); - return raw.substr(start,end-start - 2); // trim the 'st' from the end -} \ No newline at end of file diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index fcdee360b..e31ff1185 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -26,7 +26,7 @@ distribution. using namespace DFHack; // a full memory barrier! better be safe than sorry. -class SHMProcess::Private +class Process::Private { public: Private() @@ -60,7 +60,7 @@ class SHMProcess::Private }; // is the other side still there? -bool SHMProcess::Private::isValidSV() +bool Process::Private::isValidSV() { // try if CL mutex is free uint32_t result = WaitForSingleObject(DFSVMutex,0); @@ -87,7 +87,7 @@ bool SHMProcess::Private::isValidSV() } } -bool SHMProcess::Private::waitWhile (DF_PINGPONG state) +bool Process::Private::waitWhile (DF_PINGPONG state) { uint32_t cnt = 0; SCHED_YIELD // yield the CPU, valid only on single-core CPUs @@ -121,7 +121,7 @@ bool SHMProcess::Private::waitWhile (DF_PINGPONG state) return true; } -bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret) +bool Process::Private::DF_TestBridgeVersion(bool & ret) { ((shm_cmd *)my_shm)->pingpong = DFPP_VERSION; full_barrier @@ -133,7 +133,7 @@ bool SHMProcess::Private::DF_TestBridgeVersion(bool & ret) return true; } -bool SHMProcess::Private::DF_GetPID(uint32_t & ret) +bool Process::Private::DF_GetPID(uint32_t & ret) { ((shm_cmd *)my_shm)->pingpong = DFPP_PID; full_barrier @@ -145,7 +145,7 @@ bool SHMProcess::Private::DF_GetPID(uint32_t & ret) return true; } -SHMProcess::SHMProcess(vector & known_versions) +Process::Process(vector & known_versions) : d(new Private()) { // get server and client mutex @@ -274,21 +274,21 @@ SHMProcess::SHMProcess(vector & known_versions) detach(); } -bool SHMProcess::isSuspended() +bool Process::isSuspended() { return d->suspended; } -bool SHMProcess::isAttached() +bool Process::isAttached() { return d->attached; } -bool SHMProcess::isIdentified() +bool Process::isIdentified() { return d->identified; } -SHMProcess::~SHMProcess() +Process::~Process() { if(d->attached) { @@ -315,29 +315,29 @@ SHMProcess::~SHMProcess() delete d; } -memory_info * SHMProcess::getDescriptor() +memory_info * Process::getDescriptor() { return d->my_descriptor; } -DFWindow * SHMProcess::getWindow() +DFWindow * Process::getWindow() { return d->my_window; } -int SHMProcess::getPID() +int Process::getPID() { return d->my_pid; } //FIXME: implement -bool SHMProcess::getThreadIDs(vector & threads ) +bool Process::getThreadIDs(vector & threads ) { return false; } //FIXME: cross-reference with ELF segment entries? -void SHMProcess::getMemRanges( vector & ranges ) +void Process::getMemRanges( vector & ranges ) { char buffer[1024]; char permissions[5]; // r/-, w/-, x/-, p/s, 0 @@ -363,7 +363,7 @@ void SHMProcess::getMemRanges( vector & ranges ) } } -bool SHMProcess::suspend() +bool Process::suspend() { if(!d->attached) { @@ -385,7 +385,7 @@ bool SHMProcess::suspend() return true; } -bool SHMProcess::asyncSuspend() +bool Process::asyncSuspend() { if(!d->attached) { @@ -407,12 +407,12 @@ bool SHMProcess::asyncSuspend() } } -bool SHMProcess::forceresume() +bool Process::forceresume() { return resume(); } -bool SHMProcess::resume() +bool Process::resume() { if(!d->attached) { @@ -430,7 +430,7 @@ bool SHMProcess::resume() } -bool SHMProcess::attach() +bool Process::attach() { if(g_pProcess != 0) { @@ -478,7 +478,7 @@ bool SHMProcess::attach() return true; } -bool SHMProcess::detach() +bool Process::detach() { if(!d->attached) { @@ -494,7 +494,7 @@ bool SHMProcess::detach() return true; } -void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) +void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) { // normal read under 1MB if(size <= SHM_BODY) @@ -531,7 +531,7 @@ void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buff } } -uint8_t SHMProcess::readByte (const uint32_t offset) +uint8_t Process::readByte (const uint32_t offset) { ((shm_read_small *)d->my_shm)->address = offset; full_barrier @@ -540,7 +540,7 @@ uint8_t SHMProcess::readByte (const uint32_t offset) return ((shm_retval *)d->my_shm)->value; } -void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) +void Process::readByte (const uint32_t offset, uint8_t &val ) { ((shm_read_small *)d->my_shm)->address = offset; full_barrier @@ -549,7 +549,7 @@ void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) val = ((shm_retval *)d->my_shm)->value; } -uint16_t SHMProcess::readWord (const uint32_t offset) +uint16_t Process::readWord (const uint32_t offset) { ((shm_read_small *)d->my_shm)->address = offset; full_barrier @@ -558,7 +558,7 @@ uint16_t SHMProcess::readWord (const uint32_t offset) return ((shm_retval *)d->my_shm)->value; } -void SHMProcess::readWord (const uint32_t offset, uint16_t &val) +void Process::readWord (const uint32_t offset, uint16_t &val) { ((shm_read_small *)d->my_shm)->address = offset; full_barrier @@ -567,7 +567,7 @@ void SHMProcess::readWord (const uint32_t offset, uint16_t &val) val = ((shm_retval *)d->my_shm)->value; } -uint32_t SHMProcess::readDWord (const uint32_t offset) +uint32_t Process::readDWord (const uint32_t offset) { ((shm_read_small *)d->my_shm)->address = offset; full_barrier @@ -575,7 +575,7 @@ uint32_t SHMProcess::readDWord (const uint32_t offset) d->waitWhile(DFPP_READ_DWORD); return ((shm_retval *)d->my_shm)->value; } -void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) +void Process::readDWord (const uint32_t offset, uint32_t &val) { ((shm_read_small *)d->my_shm)->address = offset; full_barrier @@ -588,7 +588,7 @@ void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) * WRITING */ -void SHMProcess::writeDWord (uint32_t offset, uint32_t data) +void Process::writeDWord (uint32_t offset, uint32_t data) { ((shm_write_small *)d->my_shm)->address = offset; ((shm_write_small *)d->my_shm)->value = data; @@ -598,7 +598,7 @@ void SHMProcess::writeDWord (uint32_t offset, uint32_t data) } // using these is expensive. -void SHMProcess::writeWord (uint32_t offset, uint16_t data) +void Process::writeWord (uint32_t offset, uint16_t data) { ((shm_write_small *)d->my_shm)->address = offset; ((shm_write_small *)d->my_shm)->value = data; @@ -607,7 +607,7 @@ void SHMProcess::writeWord (uint32_t offset, uint16_t data) d->waitWhile(DFPP_WRITE_WORD); } -void SHMProcess::writeByte (uint32_t offset, uint8_t data) +void Process::writeByte (uint32_t offset, uint8_t data) { ((shm_write_small *)d->my_shm)->address = offset; ((shm_write_small *)d->my_shm)->value = data; @@ -616,7 +616,7 @@ void SHMProcess::writeByte (uint32_t offset, uint8_t data) d->waitWhile(DFPP_WRITE_BYTE); } -void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) +void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) { // normal write under 1MB if(size <= SHM_BODY) @@ -654,7 +654,7 @@ void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buf } // FIXME: butt-fugly -const std::string SHMProcess::readCString (uint32_t offset) +const std::string Process::readCString (uint32_t offset) { std::string temp; char temp_c[256]; @@ -671,7 +671,7 @@ const std::string SHMProcess::readCString (uint32_t offset) return temp; } -DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size) +DfVector Process::readVector (uint32_t offset, uint32_t item_size) { /* MSVC++ vector is four pointers long @@ -689,7 +689,7 @@ DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size) return DfVector(start,size,item_size); } -const std::string SHMProcess::readSTLString(uint32_t offset) +const std::string Process::readSTLString(uint32_t offset) { //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 ((shm_read_small *)d->my_shm)->address = offset; @@ -702,7 +702,7 @@ const std::string SHMProcess::readSTLString(uint32_t offset) return(string(d->my_shm+SHM_HEADER)); } -size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) +size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 ((shm_read_small *)d->my_shm)->address = offset; @@ -716,7 +716,7 @@ size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapa return real; } -void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) +void Process::writeSTLString(const uint32_t address, const std::string writeString) { ((shm_write_small *)d->my_shm)->address = address/*-4*/; strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator @@ -725,7 +725,7 @@ void SHMProcess::writeSTLString(const uint32_t address, const std::string writeS d->waitWhile(DFPP_WRITE_STL_STRING); } -string SHMProcess::readClassName (uint32_t vptr) +string Process::readClassName (uint32_t vptr) { int rtti = readDWord(vptr - 0x4); int typeinfo = readDWord(rtti + 0xC); diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp deleted file mode 100644 index eaba63abd..000000000 --- a/library/DFProcess-windows.cpp +++ /dev/null @@ -1,482 +0,0 @@ -/* -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; - -class NormalProcess::Private -{ - public: - Private() - { - my_descriptor = NULL; - my_handle = NULL; - my_main_thread = NULL; - my_window = NULL; - my_pid = 0; - attached = false; - suspended = false; - }; - ~Private(){}; - memory_info * my_descriptor; - DFWindow * my_window; - ProcessHandle my_handle; - HANDLE my_main_thread; - uint32_t my_pid; - string memFile; - bool attached; - bool suspended; - bool identified; -}; - -NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) -: d(new Private()) -{ - HMODULE hmod = NULL; - DWORD junk; - HANDLE hProcess; - bool found = false; - - IMAGE_NT_HEADERS32 pe_header; - IMAGE_SECTION_HEADER sections[16]; - d->identified = false; - // open process - hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ); - if (NULL == hProcess) - return; - - // try getting the first module of the process - if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) - { - CloseHandle(hProcess); - cout << "EnumProcessModules fail'd" << endl; - return; //if enumprocessModules fails, give up - } - - // got base ;) - uint32_t base = (uint32_t)hmod; - - // temporarily assign this to allow some checks - d->my_handle = hProcess; - // read from this process - uint32_t pe_offset = readDWord(base+0x3C); - read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); - read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)§ions ); - d->my_handle = 0; - - // see if there's a version entry that matches this process - vector::iterator it; - for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) - { - // filter by OS - if(memory_info::OS_WINDOWS != (*it)->getOS()) - continue; - uint32_t pe_timestamp; - // filter by timestamp, skip entries without a timestamp - try - { - pe_timestamp = (*it)->getHexValue("pe_timestamp"); - } - catch(Error::MissingMemoryDefinition& e) - { - continue; - } - if (pe_timestamp != pe_header.FileHeader.TimeDateStamp) - continue; - - // all went well - { - printf("Match found! Using version %s.\n", (*it)->getVersion().c_str()); - d->identified = true; - // give the process a data model and memory layout fixed for the base of first module - memory_info *m = new memory_info(**it); - m->RebaseAll(base); - // keep track of created memory_info object so we can destroy it later - d->my_descriptor = m; - // process is responsible for destroying its data model - d->my_pid = pid; - d->my_handle = hProcess; - d->identified = true; - - // TODO: detect errors in thread enumeration - vector threads; - getThreadIDs( threads ); - d->my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]); - - found = true; - break; // break the iterator loop - } - } - // close handle of processes that aren't DF - if(!found) - { - CloseHandle(hProcess); - } - else - { - d->my_window = new DFWindow(this); - } -} -/* -*/ - -NormalProcess::~NormalProcess() -{ - if(d->attached) - { - detach(); - } - // destroy our rebased copy of the memory descriptor - delete d->my_descriptor; - if(d->my_handle != NULL) - { - CloseHandle(d->my_handle); - } - if(d->my_main_thread != NULL) - { - CloseHandle(d->my_main_thread); - } - if(d->my_window) - { - delete d->my_window; - } - delete d; -} - -memory_info * NormalProcess::getDescriptor() -{ - return d->my_descriptor; -} - -DFWindow * NormalProcess::getWindow() -{ - return d->my_window; -} - -int NormalProcess::getPID() -{ - return d->my_pid; -} - -bool NormalProcess::isSuspended() -{ - return d->suspended; -} -bool NormalProcess::isAttached() -{ - return d->attached; -} - -bool NormalProcess::isIdentified() -{ - return d->identified; -} - -bool NormalProcess::asyncSuspend() -{ - return suspend(); -} - -bool NormalProcess::suspend() -{ - if(!d->attached) - return false; - if(d->suspended) - { - return true; - } - SuspendThread(d->my_main_thread); - d->suspended = true; - return true; -} - -bool NormalProcess::forceresume() -{ - if(!d->attached) - return false; - while (ResumeThread(d->my_main_thread) > 1); - d->suspended = false; - return true; -} - - -bool NormalProcess::resume() -{ - if(!d->attached) - return false; - if(!d->suspended) - { - return true; - } - ResumeThread(d->my_main_thread); - d->suspended = false; - return true; -} - -bool NormalProcess::attach() -{ - if(g_pProcess != NULL) - { - return false; - } - d->attached = true; - g_pProcess = this; - suspend(); - - return true; -} - - -bool NormalProcess::detach() -{ - if(!d->attached) - { - return false; - } - resume(); - d->attached = false; - g_pProcess = NULL; - return true; -} - -bool NormalProcess::getThreadIDs(vector & threads ) -{ - HANDLE AllThreads = INVALID_HANDLE_VALUE; - THREADENTRY32 te32; - - AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); - if( AllThreads == INVALID_HANDLE_VALUE ) - { - return false; - } - te32.dwSize = sizeof(THREADENTRY32 ); - - if( !Thread32First( AllThreads, &te32 ) ) - { - CloseHandle( AllThreads ); - return false; - } - - do - { - if( te32.th32OwnerProcessID == d->my_pid ) - { - threads.push_back(te32.th32ThreadID); - } - } while( Thread32Next(AllThreads, &te32 ) ); - - CloseHandle( AllThreads ); - return true; -} - -//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries -void NormalProcess::getMemRanges( vector & ranges ) -{ - // code here is taken from hexsearch by Silas Dunmore. - // As this IMHO isn't a 'sunstantial portion' of anything, I'm not including the MIT license here - - // I'm faking this, because there's no way I'm using VirtualQuery - - t_memrange temp; - uint32_t base = d->my_descriptor->getBase(); - temp.start = base + 0x1000; // more fakery. - temp.end = base + readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic. - temp.read = 1; - temp.write = 1; - temp.execute = 0; // fake - strcpy(temp.name,"pants");// that's right. I'm calling it pants. Windows can go to HELL - ranges.push_back(temp); -} - -uint8_t NormalProcess::readByte (const uint32_t offset) -{ - uint8_t result; - ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL); - return result; -} - -void NormalProcess::readByte (const uint32_t offset,uint8_t &result) -{ - ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL); -} - -uint16_t NormalProcess::readWord (const uint32_t offset) -{ - uint16_t result; - ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL); - return result; -} - -void NormalProcess::readWord (const uint32_t offset, uint16_t &result) -{ - ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL); -} - -uint32_t NormalProcess::readDWord (const uint32_t offset) -{ - uint32_t result; - ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL); - return result; -} - -void NormalProcess::readDWord (const uint32_t offset, uint32_t &result) -{ - ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL); -} - -void NormalProcess::read (const uint32_t offset, uint32_t size, uint8_t *target) -{ - ReadProcessMemory(d->my_handle, (int*) offset, target, size, NULL); -} - -// WRITING -void NormalProcess::writeDWord (const uint32_t offset, uint32_t data) -{ - WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(uint32_t), NULL); -} - -// using these is expensive. -void NormalProcess::writeWord (uint32_t offset, uint16_t data) -{ - WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(uint16_t), NULL); -} - -void NormalProcess::writeByte (uint32_t offset, uint8_t data) -{ - WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(uint8_t), NULL); -} - -void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) -{ - WriteProcessMemory(d->my_handle, (int*) offset, source, size, NULL); -} - - - -///FIXME: reduce use of temporary objects -const string NormalProcess::readCString (const uint32_t offset) -{ - string temp; - char temp_c[256]; - DWORD read; - ReadProcessMemory(d->my_handle, (int *) offset, temp_c, 255, &read); - temp_c[read+1] = 0; - temp = temp_c; - return temp; -} - -DfVector NormalProcess::readVector (uint32_t offset, uint32_t item_size) -{ - /* - MSVC++ vector is four pointers long - ptr allocator - ptr start - ptr end - ptr alloc_end - - we don't care about alloc_end because we don't try to add stuff - we also don't care about the allocator thing in front - */ - uint32_t start = g_pProcess->readDWord(offset+4); - uint32_t end = g_pProcess->readDWord(offset+8); - uint32_t size = (end - start) /4; - return DfVector(start,size,item_size); -} - -size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) -{ - /* - MSVC++ string - ptr allocator - union - { - char[16] start; - char * start_ptr -} -Uint32 length -Uint32 capacity -*/ - uint32_t start_offset = offset + 4; - size_t length = g_pProcess->readDWord(offset + 20); - - size_t capacity = g_pProcess->readDWord(offset + 24); - size_t read_real = min(length, bufcapacity-1);// keep space for null termination - - // read data from inside the string structure - if(capacity < 16) - { - g_pProcess->read(start_offset, read_real , (uint8_t *)buffer); - } - else // read data from what the offset + 4 dword points to - { - start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset - g_pProcess->read(start_offset, read_real, (uint8_t *)buffer); - } - - buffer[read_real] = 0; - return read_real; -} - -const string NormalProcess::readSTLString (uint32_t offset) -{ - /* - MSVC++ string - ptr allocator - union - { - char[16] start; - char * start_ptr - } - Uint32 length - Uint32 capacity - */ - uint32_t start_offset = offset + 4; - uint32_t length = g_pProcess->readDWord(offset + 20); - uint32_t capacity = g_pProcess->readDWord(offset + 24); - char * temp = new char[capacity+1]; - - // read data from inside the string structure - if(capacity < 16) - { - g_pProcess->read(start_offset, capacity, (uint8_t *)temp); - } - else // read data from what the offset + 4 dword points to - { - start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset - g_pProcess->read(start_offset, capacity, (uint8_t *)temp); - } - - temp[length] = 0; - string ret = temp; - delete temp; - return ret; -} - -string NormalProcess::readClassName (uint32_t vptr) -{ - int rtti = readDWord(vptr - 0x4); - int typeinfo = readDWord(rtti + 0xC); - string raw = readCString(typeinfo + 0xC); // skips the .?AV - raw.resize(raw.length() - 4);// trim st@@ from end - return raw; -} \ No newline at end of file diff --git a/library/DFProcess.h b/library/DFProcess.h index 7eac5fe18..28525daec 100644 --- a/library/DFProcess.h +++ b/library/DFProcess.h @@ -61,135 +61,28 @@ namespace DFHack class DFHACK_EXPORT Process { - public: - // this is the single most important destructor ever. ~px - virtual ~Process(){}; - // Set up stuff so we can read memory, suspends synchronously - virtual bool attach() = 0; - // detach from DF, resume its execution if it's suspended - virtual bool detach() = 0; - - // synchronous suspend - // waits for DF to be actually suspended, - // this might take a while depending on implementation - virtual bool suspend() = 0; - // asynchronous suspend to use together with polling and timers - virtual bool asyncSuspend() = 0; - // resume DF execution - virtual bool resume() = 0; - // force-resume DF execution - virtual bool forceresume() = 0; - - virtual uint32_t readDWord(const uint32_t address) = 0; - virtual void readDWord(const uint32_t address, uint32_t & value) = 0; - virtual uint16_t readWord(const uint32_t address) = 0; - virtual void readWord(const uint32_t address, uint16_t & value) = 0; - virtual uint8_t readByte(const uint32_t address) = 0; - virtual void readByte(const uint32_t address, uint8_t & value) = 0; - virtual void read( uint32_t address, uint32_t length, uint8_t* buffer) = 0; - - virtual void writeDWord(const uint32_t address, const uint32_t value) = 0; - virtual void writeWord(const uint32_t address, const uint16_t value) = 0; - virtual void writeByte(const uint32_t address, const uint8_t value) = 0; - virtual void write(uint32_t address, uint32_t length, uint8_t* buffer) = 0; - - // read a string - virtual const string readSTLString (uint32_t offset) = 0; - virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) = 0; - virtual void writeSTLString(const uint32_t address, const std::string writeString) = 0; - // read a vector from memory - virtual DfVector readVector (uint32_t offset, uint32_t item_size) = 0; - // get class name of an object with rtti/type info - virtual string readClassName(uint32_t vptr) = 0; - - virtual const std::string readCString (uint32_t offset) = 0; - - virtual bool isSuspended() = 0; - virtual bool isAttached() = 0; - virtual bool isIdentified() = 0; - - // find the thread IDs of the process - virtual bool getThreadIDs(vector & threads ) = 0; - // get virtual memory ranges of the process (what is mapped where) - virtual void getMemRanges( vector & ranges ) = 0; - - // get the flattened Memory.xml entry of this process - virtual memory_info *getDescriptor() = 0; - // get the DF's window (first that can be found ~_~) - virtual DFWindow * getWindow() = 0; - // get the DF Process ID - virtual int getPID() = 0; - }; - - class DFHACK_EXPORT NormalProcess : virtual public Process - { - friend class ProcessEnumerator; - class Private; private: - Private * const d; - + class Private; + Private *d; public: - NormalProcess(uint32_t pid, vector & known_versions); - ~NormalProcess(); - bool attach(); - bool detach(); - - bool suspend(); - bool asyncSuspend(); - bool resume(); - bool forceresume(); - - uint32_t readDWord(const uint32_t address); - void readDWord(const uint32_t address, uint32_t & value); - uint16_t readWord(const uint32_t address); - void readWord(const uint32_t address, uint16_t & value); - uint8_t readByte(const uint32_t address); - void readByte(const uint32_t address, uint8_t & value); - void read( uint32_t address, uint32_t length, uint8_t* buffer); - - void writeDWord(const uint32_t address, const uint32_t value); - void writeWord(const uint32_t address, const uint16_t value); - void writeByte(const uint32_t address, const uint8_t value); - void write(uint32_t address, uint32_t length, uint8_t* buffer); + // this is the single most important destructor ever. ~px + Process(vector & known_versions); + ~Process(); - const string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString){}; - // read a vector from memory - DfVector readVector (uint32_t offset, uint32_t item_size); - // get class name of an object with rtti/type info - string readClassName(uint32_t vptr); - - const std::string readCString (uint32_t offset); - - bool isSuspended(); - bool isAttached(); - bool isIdentified(); - - bool getThreadIDs(vector & threads ); - void getMemRanges( vector & ranges ); - memory_info *getDescriptor(); - DFWindow * getWindow(); - int getPID(); - }; - - class DFHACK_EXPORT SHMProcess : virtual public Process - { - friend class ProcessEnumerator; - class Private; - private: - Private * const d; - - public: - SHMProcess(vector & known_versions); - ~SHMProcess(); // Set up stuff so we can read memory bool attach(); + // detach from DF, resume its execution if it's suspended bool detach(); + // synchronous suspend + // waits for DF to be actually suspended, + // this might take a while depending on implementation bool suspend(); + // asynchronous suspend to use together with polling and timers bool asyncSuspend(); + // resume DF execution bool resume(); + // force-resume DF execution - maybe nonsense in this branch? :P bool forceresume(); uint32_t readDWord(const uint32_t address); @@ -212,72 +105,22 @@ namespace DFHack DfVector readVector (uint32_t offset, uint32_t item_size); // get class name of an object with rtti/type info string readClassName(uint32_t vptr); - const std::string readCString (uint32_t offset); bool isSuspended(); bool isAttached(); bool isIdentified(); + // find the thread IDs of the process bool getThreadIDs(vector & threads ); + // get virtual memory ranges of the process (what is mapped where) void getMemRanges( vector & ranges ); + // get the flattened Memory.xml entry of this process memory_info *getDescriptor(); + // get the DF's window (first that can be found ~_~) DFWindow * getWindow(); + // get the DF Process ID int getPID(); }; - -#ifdef LINUX_BUILD - class DFHACK_EXPORT WineProcess : virtual public Process - { - friend class ProcessEnumerator; - class Private; - private: - Private * const d; - - public: - WineProcess(uint32_t pid, vector & known_versions); - ~WineProcess(); - bool attach(); - bool detach(); - - bool suspend(); - bool asyncSuspend(); - bool resume(); - bool forceresume(); - - uint32_t readDWord(const uint32_t address); - void readDWord(const uint32_t address, uint32_t & value); - uint16_t readWord(const uint32_t address); - void readWord(const uint32_t address, uint16_t & value); - uint8_t readByte(const uint32_t address); - void readByte(const uint32_t address, uint8_t & value); - void read( uint32_t address, uint32_t length, uint8_t* buffer); - - void writeDWord(const uint32_t address, const uint32_t value); - void writeWord(const uint32_t address, const uint16_t value); - void writeByte(const uint32_t address, const uint8_t value); - void write(uint32_t address, uint32_t length, uint8_t* buffer); - - const string readSTLString (uint32_t offset); - size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); - void writeSTLString(const uint32_t address, const std::string writeString){}; - // read a vector from memory - DfVector readVector (uint32_t offset, uint32_t item_size); - // get class name of an object with rtti/type info - string readClassName(uint32_t vptr); - - const std::string readCString (uint32_t offset); - - bool isSuspended(); - bool isAttached(); - bool isIdentified(); - - bool getThreadIDs(vector & threads ); - void getMemRanges( vector & ranges ); - memory_info *getDescriptor(); - DFWindow * getWindow(); - int getPID(); - }; -#endif } #endif diff --git a/library/DFProcessEnumerator-linux.cpp b/library/DFProcessEnumerator-linux.cpp index f4d02e2a1..783bff27c 100644 --- a/library/DFProcessEnumerator-linux.cpp +++ b/library/DFProcessEnumerator-linux.cpp @@ -48,7 +48,7 @@ bool ProcessEnumerator::findProcessess() struct dirent *dir_entry_p; Process *p = 0; - p = new SHMProcess(d->meminfo->meminfo); + p = new Process(d->meminfo->meminfo); if(p->isIdentified()) { d->processes.push_back(p); @@ -58,7 +58,7 @@ bool ProcessEnumerator::findProcessess() delete p; p = 0; } - + /* // Open /proc/ directory dir_p = opendir("/proc/"); // Reading /proc/ entries @@ -91,6 +91,7 @@ bool ProcessEnumerator::findProcessess() } } closedir(dir_p); + */ // return value depends on if we found some DF processes if(d->processes.size()) { diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp index f77aabb2d..f263e6380 100644 --- a/library/DFProcessEnumerator-windows.cpp +++ b/library/DFProcessEnumerator-windows.cpp @@ -36,39 +36,13 @@ class DFHack::ProcessEnumerator::Private 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; { - Process * p = new SHMProcess(d->meminfo->meminfo); + Process * p = new Process(d->meminfo->meminfo); if(p->isIdentified()) { d->processes.push_back(p); @@ -80,7 +54,7 @@ bool ProcessEnumerator::findProcessess() p = 0; } } - + /* EnableDebugPriv(); if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) ) { @@ -104,7 +78,7 @@ bool ProcessEnumerator::findProcessess() delete q; q = 0; } - } + }*/ if(d->processes.size()) return true; return false; From 0192520d43b131535bed34ba2ba9fa3916463d44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Wed, 3 Mar 2010 05:43:38 +0100 Subject: [PATCH 02/16] SHM rework, stage 1 --- Compile.txt | 138 --- Readme.txt | 174 --- library/DFProcess-linux-SHM.cpp | 174 +-- library/DFProcess-windows-SHM.cpp | 166 +-- library/argstream/argstream.h | 1630 ++++++++++++++--------------- shmserver/CMakeLists.txt | 2 +- shmserver/shms-core.cpp | 274 +++++ shmserver/shms-linux.cpp | 13 +- shmserver/shms-proto.cpp | 187 ---- shmserver/shms-windows.cpp | 14 +- shmserver/shms.h | 127 +-- 11 files changed, 1328 insertions(+), 1571 deletions(-) delete mode 100644 Compile.txt delete mode 100644 Readme.txt create mode 100644 shmserver/shms-core.cpp delete mode 100644 shmserver/shms-proto.cpp diff --git a/Compile.txt b/Compile.txt deleted file mode 100644 index 92e0164ef..000000000 --- a/Compile.txt +++ /dev/null @@ -1,138 +0,0 @@ -Here's how you build dfhack! ----------------------------- - -First, there is one dependency, regardless of the OS you use: - cmake - it's the build system - - -Building on Linux: --------------------- - -* To run in the output folder (without installing): - -building the library is simple. Enter the build folder, run the tools. Like this: - -cd build -cmake .. -DCMAKE_BUILD_TYPE:string=Release -make - -This will build the library and its tools and place them in /output. -You can also use a cmake-friendly IDE like KDevelop 4 or the cmake GUI program. - -* To be installed into the system or packaged - -cd build -cmake -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/usr -DMEMXML_DATA_PATH:path=/usr/share/dfhack .. -make -make install - -With this dfhack installs: -library to $CMAKE_INSTALL_PREFIX/lib -executables to $CMAKE_INSTALL_PREFIX/bin -The Memory.xml file to /usr/share/dfhack - -See the section on the shared memory hook library (SHM). - -Building on Windows: --------------------- - -You need cmake. Get the win32 installer version from the official site: http://www.cmake.org/cmake/resources/software.html -It has the usual installer wizard thing. - -* Using mingw: - -You also need a compiler. I build dfhack using mingw. You can get it from the mingw site: -Get the automated installer, it will download newest version of mingw and set things up nicely. -You'll have to add C:\MinGW\ to your PATH variable. - - - Building: - open up cmd and navigate to the dfhack\build folder, run cmake and the mingw version of make: - cd build - cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release - mingw32-make - -* Using MSVC - -open up cmd and navigate to the dfhack\build folder, run cmake: -cd build -cmake .. - -This will generate MSVC solution and project files. Note that: you are working in the /build folder. -Files added to projects will end up there! (and that's wrong). Any changes to the build system should -be done by changing cmake configs and running cmake on them! - -* Using some other compiler: - -I'm afraid you are on your own. dfhack wasn't tested with any other compiler. -Try using a different cmake generator that's intended for your tools. - - -Building the shared memory hook library (SHM) ---------------------------------------------- - -Unlike the rest of DFHack, The SHM needs special treatment when it comes to compilation. -Because it shares the memory space with DF itself, it has to be built with the same tools as DF -and use the same C and C++/STL libraries. - -For DF 40d15 - 40d17 on Windows, use MSVC 2008. You can get the Express edition for free from Microsoft. - -Windows dependencies can be determined by a tool like depends.exe (google it). Both the fake SDL.dll -and DF have to use the same version of the C runtime (MSVCRT). -The SHM can't be debugged, because debug builds in MSVC use a different CRT! - -Linux dependencies can be determined by setting the LD_DEBUG variable and running ./df: -export LD_DEBUG=versions -./df - -Example of (a part of a) relevant output from a working SHM installation: - 24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libpthread.so.0 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GCC_3.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.1' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBCXX_3.4.9' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0] - 24472: checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBC_2.2' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0] - 24472: checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0] - -libdfconnect is the SHM. Both are compiled against the same C++ library and share the same CXXABI version. - -Precompiled SHM libraries are provided in binary releases. - -* Checking strings support - -Strings are one of the important C++ types and a great indicator that the SHM works. Tools like Dwarf Therapist depend -on string support. Reading of strings can be checked by running any of the tools that deal with materials. - -String writing is best tested with a fresh throw-away fort and dfrenamer. Embark, give one dwarf a very long name using dfrenamer -and save/exit. If DF crashes during the save sequence, your SHM is not compatible with DF and the throw-away fort is lost. - - -Build targets -------------- - -dfhack has a few build targets. If you're only after the library run 'make dfhack'. -'make' will build everything. -'make expbench' will build the expbench throughput testing program and the library. - - -Build types ------------ - -cmake allows you to pick a build type by changing this variable: CMAKE_BUILD_TYPE - -cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE - -Without specifying a build type or 'None', cmake uses the CMAKE_CXX_FLAGS variable for building. -Valid build types include 'Release' and 'Debug'. There are others, but they aren't really that useful. - -Have fun. diff --git a/Readme.txt b/Readme.txt deleted file mode 100644 index 8600bc63b..000000000 --- a/Readme.txt +++ /dev/null @@ -1,174 +0,0 @@ -Introduction ------------- - -DFHack is a Dwarf Fortress memory access library and a set of basic tools using -this library. The library is a work in progress, so things might change as more -tools are written for it. - -It is an attempt to unite the various ways tools access DF memory and allow for -easier development of new tools. - - -Getting DFHack ----------------- -The project is currently hosted on github: - http://github.com/peterix/dfhack - -There's an SVN repository at sourceforge, but will only be updated for major releases: - https://sourceforge.net/projects/dfhack/ -* subversion access: - svn co https://dfhack.svn.sourceforge.net/svnroot/dfhack/trunk dfhack - -Compatibility -------------- - -DFHack works on Windows XP, Vista, 7 or any modern Linux distribution. - -Windows 2000 is currently *not supported* due to missing OS functionality. -If you know how to easily suspend processes, you can fix it :) - -OSX is also not supported due to lack of developers with a Mac. - -Currently supported Dwarf Fortress versions: -* Windows - 40d - 40d9 - 40d18 - -* Linux - 40d9 - 40d18 - - -Using the library ------------------ - -The library is compilable under Linux with GCC and under Windows with MinGW32 -and MSVC compilers. It is using the cmake build system. See COMPILE for details. - -DFHack is using the zlib/libpng license. This makes it easy to link to it, use -it in-source or add your own extensions. Contributing back to the dfhack -repository is welcome and the right thing to do :) - -At the time of writing there's no API reference or documentation. The code does -have a lot of comments though. - - -Using DFHack Tools ------------------- - -The project comes with a special extra library you should add to your DF -installation. It's used to boost the transfer speed between DF and DFHack, and -provide data consistency and synchronization. DFHack will work without the -library, but at suboptimal speeds and the consistency of data written back -to DF is questionable. - -!!! on Windows this currently only works with DF 40d15 - 40d18 !!! - On Linux, it works with the whole range of supported DF versions. - -!!! use the pre-compiled library intended for your OS and version of DF !!! - You can find them in the 'precompiled' folder. - - - ** Installing on Windows - - Open your DF folder, locate SDL.dll and rename it to SDLreal.dll (making - a backup of it is a good idea) - - Copy the right DFHack SDL.dll into your DF folder. - - Restart DF if it is running - - ** Unistalling on Windows - - Open your DF folder, locate SDL.dll and delete it - - Rename SDLreal.dll to SDL.dll - - Restart DF if it is running - - - ** Installing on Linux - - Open your DF folder and the libs folder within it - - copy DFHack libdfconnect.so to the libs folder - - copy the df startup script, name it dfhacked - - open the new dfhacked startup script and add this line: - export LD_PRELOAD="./libs/libdfconnect.so" # Hack DF! - just before the line that launches DF - - Here's an example how the file can look after the change: -#!/bin/sh -DF_DIR=$(dirname "$0") -cd "${DF_DIR}" -export SDL_DISABLE_LOCK_KEYS=1 # Work around for bug in Debian/Ubuntu SDL patch. -#export SDL_VIDEO_CENTERED=1 # Centre the screen. Messes up resizing. -ldd dwarfort.exe | grep SDL_image | grep -qv "not found$" -if [ $? -eq 0 ]; then - mkdir unused_libs - mv libs/libSDL* unused_libs/ -fi -export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"./libs" # Update library search path. -export LD_PRELOAD="./libs/libdfconnect.so" # Hack DF! -./dwarfort.exe $* # Go, go, go! :) - - - Use this new startup script to start DF - - ** Uninstalling on Linux - - Open your DF and DF/libs folders - - Delete libdfconnect.so and the dfhacked startup script - - Go back to using the df startup script - - -Tools ------ - -All the DFHack tools are terminal programs. This might seem strange to Windows -users, but these are meant mostly as examples for developers. Still, they can -be useful and are cross-platform just like the library itself. - -If the tool writes back to DF's memory, make sure you are using the shared -memory interface mentioned in the previous section! - -* reveal - plain old reveal tool. It reveals all the map blocks already - initialized by DF. - -* prospector - scans the map for minerals. by default it only scans only visible - veins. You can make it show hidden things with '-a' and base rock - and soil layers with '-b'. These can be combined ('-ab') - -* cleanmap - cleans mud, vomit, snow and all kinds of mess from the map. - It will clean your irrigated farms too, so consider yourself - warned. - -* incremental - incremental search utility. - -* bauxite - converts all mechanisms into bauxite mechanisms. - -* itemdesignator - Allows mass-designating items by type and material - dump, - forbid, melt and set on fire ;) -* digger - allows designating tiles for digging/cutting/ramp removal - - A list of accepted tile classes: - 1 = WALL - 2 = PILLAR - 3 = FORTIFICATION - - 4 = STAIR_UP - 5 = STAIR_DOWN - 6 = STAIR_UPDOWN - - 7 = RAMP - - 8 = FLOOR - 9 = TREE_DEAD - 10 = TREE_OK - 11 = SAPLING_DEAD - 12 = SAPLING_OK - 13 = SHRUB_DEAD - 14 = SHRUB_OK - 15 = BOULDER - 16 = PEBBLES - - Example : dfdigger -o 100,100,15 -t 9,10 -m 10 - This will start looking for trees at coords 100,100,15 and designate ten of them for cutting. - - -Memory offset definitions -------------------------- - -The file with memory offset definitions used by dfhack can be found in the -output folder. - -~ EOF ~ diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 1c1254989..7a6331e73 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -50,6 +50,7 @@ class Process::Private attached = false; suspended = false; identified = false; + useYield = false; }; ~Private(){}; memory_info * my_descriptor; @@ -61,18 +62,26 @@ class Process::Private bool attached; bool suspended; bool identified; + bool useYield; bool validate(char* exe_file, uint32_t pid, std::vector< memory_info* >& known_versions); - bool waitWhile (DF_PINGPONG state); + bool waitWhile (CORE_COMMAND state); bool DF_TestBridgeVersion(bool & ret); bool DF_GetPID(pid_t & ret); }; -bool Process::Private::waitWhile (DF_PINGPONG state) +// some helpful macros to keep the code bloat in check +#define SHMCMD ((shm_cmd *)my_shm)->pingpong +#define D_SHMCMD ((shm_cmd *)d->my_shm)->pingpong + +#define SHMHDR ((shm_header *)my_shm) +#define D_SHMHDR ((shm_header *)d->my_shm) + +bool Process::Private::waitWhile (CORE_COMMAND state) { uint32_t cnt = 0; struct shmid_ds descriptor; - while (((shm_cmd *)my_shm)->pingpong == state) + while (SHMCMD == state) { if(cnt == 10000) { @@ -80,8 +89,7 @@ bool Process::Private::waitWhile (DF_PINGPONG state) shmctl(my_shmid, IPC_STAT, &descriptor); if(descriptor.shm_nattch == 1)// DF crashed? { - gcc_barrier - ((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; + SHMCMD = CORE_RUNNING; attached = suspended = false; return false; } @@ -93,9 +101,9 @@ bool Process::Private::waitWhile (DF_PINGPONG state) SCHED_YIELD cnt++; } - if(((shm_cmd *)my_shm)->pingpong == DFPP_SV_ERROR) + if(SHMCMD == CORE_SV_ERROR) { - ((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; + SHMCMD = CORE_RUNNING; attached = suspended = false; cerr << "shm server error!" << endl; assert (false); @@ -106,25 +114,25 @@ bool Process::Private::waitWhile (DF_PINGPONG state) bool Process::Private::DF_TestBridgeVersion(bool & ret) { - ((shm_cmd *)my_shm)->pingpong = DFPP_VERSION; + SHMCMD = CORE_GET_VERSION; gcc_barrier - if(!waitWhile(DFPP_VERSION)) + if(!waitWhile(CORE_GET_VERSION)) return false; gcc_barrier - ((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED; - ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION ); + SHMCMD = CORE_SUSPENDED; + ret =( SHMHDR->value == CORE_VERSION ); return true; } bool Process::Private::DF_GetPID(pid_t & ret) { - ((shm_cmd *)my_shm)->pingpong = DFPP_PID; + SHMCMD = CORE_GET_PID; gcc_barrier - if(!waitWhile(DFPP_PID)) + if(!waitWhile(CORE_GET_PID)) return false; gcc_barrier - ((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED; - ret = ((shm_retval *)my_shm)->value; + SHMCMD = CORE_SUSPENDED; + ret = SHMHDR->value; return true; } @@ -200,7 +208,7 @@ Process::Process(vector & known_versions) } gcc_barrier // at this point, DF is stopped and waiting for commands. make it run again - ((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; + D_SHMCMD = CORE_RUNNING; shmdt(d->my_shm); // detach so we don't attach twice when attach() is called } @@ -319,8 +327,8 @@ bool Process::suspend() { return true; } - ((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; - if(!d->waitWhile(DFPP_SUSPEND)) + D_SHMCMD = CORE_SUSPEND; + if(!d->waitWhile(CORE_SUSPEND)) { return false; } @@ -338,14 +346,14 @@ bool Process::asyncSuspend() { return true; } - if(((shm_cmd *)d->my_shm)->pingpong == DFPP_SUSPENDED) + if(D_SHMCMD == CORE_SUSPENDED) { d->suspended = true; return true; } else { - ((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; + D_SHMCMD = CORE_SUSPEND; return false; } } @@ -361,7 +369,7 @@ bool Process::resume() return false; if(!d->suspended) return true; - ((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; + D_SHMCMD = CORE_RUNNING; d->suspended = false; return true; } @@ -425,11 +433,11 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) // normal read under 1MB if(size <= SHM_BODY) { - ((shm_read *)d->my_shm)->address = src_address; - ((shm_read *)d->my_shm)->length = size; + D_SHMHDR->address = src_address; + D_SHMHDR->length = size; gcc_barrier - ((shm_read *)d->my_shm)->pingpong = DFPP_READ; - d->waitWhile(DFPP_READ); + D_SHMCMD = CORE_DFPP_READ; + d->waitWhile(CORE_DFPP_READ); memcpy (target_buffer, d->my_shm + SHM_HEADER,size); } // a big read, we pull data over the shm in iterations @@ -440,11 +448,11 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) while (size) { // read to_read bytes from src_cursor - ((shm_read *)d->my_shm)->address = src_address; - ((shm_read *)d->my_shm)->length = to_read; + D_SHMHDR->address = src_address; + D_SHMHDR->length = to_read; gcc_barrier - ((shm_read *)d->my_shm)->pingpong = DFPP_READ; - d->waitWhile(DFPP_READ); + D_SHMCMD = CORE_DFPP_READ; + d->waitWhile(CORE_DFPP_READ); memcpy (target_buffer, d->my_shm + SHM_HEADER,size); // decrease size by bytes read size -= to_read; @@ -459,55 +467,55 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) uint8_t Process::readByte (const uint32_t offset) { - ((shm_read_small *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; gcc_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; - d->waitWhile(DFPP_READ_BYTE); - return ((shm_retval *)d->my_shm)->value; + D_SHMCMD = CORE_READ_BYTE; + d->waitWhile(CORE_READ_BYTE); + return D_SHMHDR->value; } void Process::readByte (const uint32_t offset, uint8_t &val ) { - ((shm_read_small *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; gcc_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; - d->waitWhile(DFPP_READ_BYTE); - val = ((shm_retval *)d->my_shm)->value; + D_SHMCMD = CORE_READ_BYTE; + d->waitWhile(CORE_READ_BYTE); + val = D_SHMHDR->value; } uint16_t Process::readWord (const uint32_t offset) { - ((shm_read_small *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; gcc_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; - d->waitWhile(DFPP_READ_WORD); - return ((shm_retval *)d->my_shm)->value; + D_SHMCMD = CORE_READ_WORD; + d->waitWhile(CORE_READ_WORD); + return D_SHMHDR->value; } void Process::readWord (const uint32_t offset, uint16_t &val) { - ((shm_read_small *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; gcc_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; - d->waitWhile(DFPP_READ_WORD); - val = ((shm_retval *)d->my_shm)->value; + D_SHMCMD = CORE_READ_WORD; + d->waitWhile(CORE_READ_WORD); + val = D_SHMHDR->value; } uint32_t Process::readDWord (const uint32_t offset) { - ((shm_read_small *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; gcc_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; - d->waitWhile(DFPP_READ_DWORD); - return ((shm_retval *)d->my_shm)->value; + D_SHMCMD = CORE_READ_DWORD; + d->waitWhile(CORE_READ_DWORD); + return D_SHMHDR->value; } void Process::readDWord (const uint32_t offset, uint32_t &val) { - ((shm_read_small *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; gcc_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; - d->waitWhile(DFPP_READ_DWORD); - val = ((shm_retval *)d->my_shm)->value; + D_SHMCMD = CORE_READ_DWORD; + d->waitWhile(CORE_READ_DWORD); + val = D_SHMHDR->value; } /* @@ -516,30 +524,30 @@ void Process::readDWord (const uint32_t offset, uint32_t &val) void Process::writeDWord (uint32_t offset, uint32_t data) { - ((shm_write_small *)d->my_shm)->address = offset; - ((shm_write_small *)d->my_shm)->value = data; + D_SHMHDR->address = offset; + D_SHMHDR->value = data; gcc_barrier - ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD; - d->waitWhile(DFPP_WRITE_DWORD); + D_SHMCMD = CORE_WRITE_DWORD; + d->waitWhile(CORE_WRITE_DWORD); } // using these is expensive. void Process::writeWord (uint32_t offset, uint16_t data) { - ((shm_write_small *)d->my_shm)->address = offset; - ((shm_write_small *)d->my_shm)->value = data; + D_SHMHDR->address = offset; + D_SHMHDR->value = data; gcc_barrier - ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD; - d->waitWhile(DFPP_WRITE_WORD); + D_SHMCMD = CORE_WRITE_WORD; + d->waitWhile(CORE_WRITE_WORD); } void Process::writeByte (uint32_t offset, uint8_t data) { - ((shm_write_small *)d->my_shm)->address = offset; - ((shm_write_small *)d->my_shm)->value = data; + D_SHMHDR->address = offset; + D_SHMHDR->value = data; gcc_barrier - ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE; - d->waitWhile(DFPP_WRITE_BYTE); + D_SHMCMD = CORE_WRITE_BYTE; + d->waitWhile(CORE_WRITE_BYTE); } void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) @@ -547,12 +555,12 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer // normal write under 1MB if(size <= SHM_BODY) { - ((shm_write *)d->my_shm)->address = dst_address; - ((shm_write *)d->my_shm)->length = size; + D_SHMHDR->address = dst_address; + D_SHMHDR->length = size; memcpy(d->my_shm+SHM_HEADER,source_buffer, size); gcc_barrier - ((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; - d->waitWhile(DFPP_WRITE); + D_SHMCMD = CORE_WRITE; + d->waitWhile(CORE_WRITE); } // a big write, we push this over the shm in iterations else @@ -562,12 +570,12 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer while (size) { // write to_write bytes to dst_cursor - ((shm_write *)d->my_shm)->address = dst_address; - ((shm_write *)d->my_shm)->length = to_write; + D_SHMHDR->address = dst_address; + D_SHMHDR->length = to_write; memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write); gcc_barrier - ((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; - d->waitWhile(DFPP_WRITE); + D_SHMCMD = CORE_WRITE; + d->waitWhile(CORE_WRITE); // decrease size by bytes written size -= to_write; // move the cursors @@ -615,21 +623,21 @@ DfVector Process::readVector (uint32_t offset, uint32_t item_size) const std::string Process::readSTLString(uint32_t offset) { - ((shm_read_small *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING; - d->waitWhile(DFPP_READ_STL_STRING); + D_SHMCMD = CORE_READ_STL_STRING; + d->waitWhile(CORE_READ_STL_STRING); //int length = ((shm_retval *)d->my_shm)->value; return(string( (char *)d->my_shm+SHM_HEADER)); } size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { - ((shm_read_small *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING; - d->waitWhile(DFPP_READ_STL_STRING); - size_t length = ((shm_retval *)d->my_shm)->value; + D_SHMCMD = CORE_READ_STL_STRING; + d->waitWhile(CORE_READ_STL_STRING); + size_t length = D_SHMHDR->value; size_t fit = min(bufcapacity - 1, length); strncpy(buffer,(char *)d->my_shm+SHM_HEADER,fit); buffer[fit] = 0; @@ -638,11 +646,11 @@ size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacit void Process::writeSTLString(const uint32_t address, const std::string writeString) { - ((shm_write_small *)d->my_shm)->address = address; + D_SHMHDR->address = address; strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator full_barrier - ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING; - d->waitWhile(DFPP_WRITE_STL_STRING); + D_SHMCMD = CORE_WRITE_STL_STRING; + d->waitWhile(CORE_WRITE_STL_STRING); } string Process::readClassName (uint32_t vptr) diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index e31ff1185..fe23cb9bf 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -53,7 +53,7 @@ class Process::Private bool suspended; bool identified; - bool waitWhile (DF_PINGPONG state); + bool waitWhile (CORE_COMMAND state); bool isValidSV(); bool DF_TestBridgeVersion(bool & ret); bool DF_GetPID(uint32_t & ret); @@ -87,7 +87,7 @@ bool Process::Private::isValidSV() } } -bool Process::Private::waitWhile (DF_PINGPONG state) +bool Process::Private::waitWhile (CORE_COMMAND state) { uint32_t cnt = 0; SCHED_YIELD // yield the CPU, valid only on single-core CPUs @@ -98,7 +98,7 @@ bool Process::Private::waitWhile (DF_PINGPONG state) if(!isValidSV())// DF not there anymore? { full_barrier - ((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; + ((shm_cmd *)my_shm)->pingpong = CORE_RUNNING; attached = suspended = false; ReleaseMutex(DFCLMutex); return false; @@ -110,9 +110,9 @@ bool Process::Private::waitWhile (DF_PINGPONG state) } cnt++; } - if(((shm_cmd *)my_shm)->pingpong == DFPP_SV_ERROR) + if(((shm_cmd *)my_shm)->pingpong == CORE_SV_ERROR) { - ((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; + ((shm_cmd *)my_shm)->pingpong = CORE_RUNNING; attached = suspended = false; cerr << "shm server error!" << endl; assert (false); @@ -123,25 +123,25 @@ bool Process::Private::waitWhile (DF_PINGPONG state) bool Process::Private::DF_TestBridgeVersion(bool & ret) { - ((shm_cmd *)my_shm)->pingpong = DFPP_VERSION; + ((shm_cmd *)my_shm)->pingpong = CORE_GET_VERSION; full_barrier - if(!waitWhile(DFPP_VERSION)) + if(!waitWhile(CORE_GET_VERSION)) return false; full_barrier - ((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED; - ret =( ((shm_retval *)my_shm)->value == PINGPONG_VERSION ); + ((shm_cmd *)my_shm)->pingpong = CORE_SUSPENDED; + ret =( ((shm_val *)my_shm)->value == CORE_VERSION ); return true; } bool Process::Private::DF_GetPID(uint32_t & ret) { - ((shm_cmd *)my_shm)->pingpong = DFPP_PID; + ((shm_cmd *)my_shm)->pingpong = CORE_GET_PID; full_barrier - if(!waitWhile(DFPP_PID)) + if(!waitWhile(CORE_GET_PID)) return false; full_barrier - ((shm_cmd *)my_shm)->pingpong = DFPP_SUSPENDED; - ret = ((shm_retval *)my_shm)->value; + ((shm_cmd *)my_shm)->pingpong = CORE_SUSPENDED; + ret = ((shm_val *)my_shm)->value; return true; } @@ -182,7 +182,7 @@ Process::Process(vector & known_versions) if(!bridgeOK) { fprintf(stderr,"SHM bridge version mismatch\n"); - ((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; + ((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING; UnmapViewOfFile(d->my_shm); ReleaseMutex(d->DFCLMutex); CloseHandle(d->DFSVMutex); @@ -258,7 +258,7 @@ Process::Process(vector & known_versions) } else { - ((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; + ((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING; UnmapViewOfFile(d->my_shm); d->my_shm = 0; ReleaseMutex(d->DFCLMutex); @@ -375,8 +375,8 @@ bool Process::suspend() cerr << "couldn't suspend, already suspended" << endl; return true; } - ((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; - if(!d->waitWhile(DFPP_SUSPEND)) + ((shm_cmd *)d->my_shm)->pingpong = CORE_SUSPEND; + if(!d->waitWhile(CORE_SUSPEND)) { cerr << "couldn't suspend, DF not responding to commands" << endl; return false; @@ -395,14 +395,14 @@ bool Process::asyncSuspend() { return true; } - if(((shm_cmd *)d->my_shm)->pingpong == DFPP_SUSPENDED) + if(((shm_cmd *)d->my_shm)->pingpong == CORE_SUSPENDED) { d->suspended = true; return true; } else { - ((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; + ((shm_cmd *)d->my_shm)->pingpong = CORE_SUSPEND; return false; } } @@ -424,7 +424,7 @@ bool Process::resume() cerr << "couldn't resume because of not being suspended" << endl; return true; } - ((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; + ((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING; d->suspended = false; return true; } @@ -499,11 +499,11 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) // normal read under 1MB if(size <= SHM_BODY) { - ((shm_read *)d->my_shm)->address = src_address; - ((shm_read *)d->my_shm)->length = size; + ((shm_addrlen *)d->my_shm)->address = src_address; + ((shm_addrlen *)d->my_shm)->length = size; full_barrier - ((shm_read *)d->my_shm)->pingpong = DFPP_READ; - d->waitWhile(DFPP_READ); + ((shm_cmd *)d->my_shm)->pingpong = CORE_DFPP_READ; + d->waitWhile(CORE_DFPP_READ); memcpy (target_buffer, d->my_shm + SHM_HEADER,size); } // a big read, we pull data over the shm in iterations @@ -514,11 +514,11 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) while (size) { // read to_read bytes from src_cursor - ((shm_read *)d->my_shm)->address = src_address; - ((shm_read *)d->my_shm)->length = to_read; + ((shm_addrlen *)d->my_shm)->address = src_address; + ((shm_addrlen *)d->my_shm)->length = to_read; full_barrier - ((shm_read *)d->my_shm)->pingpong = DFPP_READ; - d->waitWhile(DFPP_READ); + ((shm_cmd *)d->my_shm)->pingpong = CORE_DFPP_READ; + d->waitWhile(CORE_DFPP_READ); memcpy (target_buffer, d->my_shm + SHM_HEADER,size); // decrease size by bytes read size -= to_read; @@ -533,55 +533,55 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) uint8_t Process::readByte (const uint32_t offset) { - ((shm_read_small *)d->my_shm)->address = offset; + ((shm_addr *)d->my_shm)->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; - d->waitWhile(DFPP_READ_BYTE); - return ((shm_retval *)d->my_shm)->value; + ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_BYTE; + d->waitWhile(CORE_READ_BYTE); + return ((shm_val *)d->my_shm)->value; } void Process::readByte (const uint32_t offset, uint8_t &val ) { - ((shm_read_small *)d->my_shm)->address = offset; + ((shm_addr *)d->my_shm)->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; - d->waitWhile(DFPP_READ_BYTE); - val = ((shm_retval *)d->my_shm)->value; + ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_BYTE; + d->waitWhile(CORE_READ_BYTE); + val = ((shm_val *)d->my_shm)->value; } uint16_t Process::readWord (const uint32_t offset) { - ((shm_read_small *)d->my_shm)->address = offset; + ((shm_addr *)d->my_shm)->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; - d->waitWhile(DFPP_READ_WORD); - return ((shm_retval *)d->my_shm)->value; + ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_WORD; + d->waitWhile(CORE_READ_WORD); + return ((shm_val *)d->my_shm)->value; } void Process::readWord (const uint32_t offset, uint16_t &val) { - ((shm_read_small *)d->my_shm)->address = offset; + ((shm_addr *)d->my_shm)->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; - d->waitWhile(DFPP_READ_WORD); - val = ((shm_retval *)d->my_shm)->value; + ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_WORD; + d->waitWhile(CORE_READ_WORD); + val = ((shm_val *)d->my_shm)->value; } uint32_t Process::readDWord (const uint32_t offset) { - ((shm_read_small *)d->my_shm)->address = offset; + ((shm_addr *)d->my_shm)->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; - d->waitWhile(DFPP_READ_DWORD); - return ((shm_retval *)d->my_shm)->value; + ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_DWORD; + d->waitWhile(CORE_READ_DWORD); + return ((shm_val *)d->my_shm)->value; } void Process::readDWord (const uint32_t offset, uint32_t &val) { - ((shm_read_small *)d->my_shm)->address = offset; + ((shm_addr *)d->my_shm)->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; - d->waitWhile(DFPP_READ_DWORD); - val = ((shm_retval *)d->my_shm)->value; + ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_DWORD; + d->waitWhile(CORE_READ_DWORD); + val = ((shm_val *)d->my_shm)->value; } /* @@ -590,30 +590,30 @@ void Process::readDWord (const uint32_t offset, uint32_t &val) void Process::writeDWord (uint32_t offset, uint32_t data) { - ((shm_write_small *)d->my_shm)->address = offset; - ((shm_write_small *)d->my_shm)->value = data; + ((shm_addrval *)d->my_shm)->address = offset; + ((shm_addrval *)d->my_shm)->value = data; full_barrier - ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD; - d->waitWhile(DFPP_WRITE_DWORD); + ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_DWORD; + d->waitWhile(CORE_WRITE_DWORD); } // using these is expensive. void Process::writeWord (uint32_t offset, uint16_t data) { - ((shm_write_small *)d->my_shm)->address = offset; - ((shm_write_small *)d->my_shm)->value = data; + ((shm_addrval *)d->my_shm)->address = offset; + ((shm_addrval *)d->my_shm)->value = data; full_barrier - ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD; - d->waitWhile(DFPP_WRITE_WORD); + ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_WORD; + d->waitWhile(CORE_WRITE_WORD); } void Process::writeByte (uint32_t offset, uint8_t data) { - ((shm_write_small *)d->my_shm)->address = offset; - ((shm_write_small *)d->my_shm)->value = data; + ((shm_addrval *)d->my_shm)->address = offset; + ((shm_addrval *)d->my_shm)->value = data; full_barrier - ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE; - d->waitWhile(DFPP_WRITE_BYTE); + ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_BYTE; + d->waitWhile(CORE_WRITE_BYTE); } void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) @@ -621,12 +621,12 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer // normal write under 1MB if(size <= SHM_BODY) { - ((shm_write *)d->my_shm)->address = dst_address; - ((shm_write *)d->my_shm)->length = size; + ((shm_addrlen *)d->my_shm)->address = dst_address; + ((shm_addrlen *)d->my_shm)->length = size; memcpy(d->my_shm+SHM_HEADER,source_buffer, size); full_barrier - ((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; - d->waitWhile(DFPP_WRITE); + ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE; + d->waitWhile(CORE_WRITE); } // a big write, we push this over the shm in iterations else @@ -636,12 +636,12 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer while (size) { // write to_write bytes to dst_cursor - ((shm_write *)d->my_shm)->address = dst_address; - ((shm_write *)d->my_shm)->length = to_write; + ((shm_addrlen *)d->my_shm)->address = dst_address; + ((shm_addrlen *)d->my_shm)->length = to_write; memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write); full_barrier - ((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; - d->waitWhile(DFPP_WRITE); + ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE; + d->waitWhile(CORE_WRITE); // decrease size by bytes written size -= to_write; // move the cursors @@ -692,11 +692,11 @@ DfVector Process::readVector (uint32_t offset, uint32_t item_size) const std::string Process::readSTLString(uint32_t offset) { //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 - ((shm_read_small *)d->my_shm)->address = offset; + ((shm_addr *)d->my_shm)->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING; - d->waitWhile(DFPP_READ_STL_STRING); - int length = ((shm_retval *)d->my_shm)->value; + ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_STL_STRING; + d->waitWhile(CORE_READ_STL_STRING); + int length = ((shm_val *)d->my_shm)->value; // char temp_c[256]; // strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator return(string(d->my_shm+SHM_HEADER)); @@ -705,11 +705,11 @@ const std::string Process::readSTLString(uint32_t offset) size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 - ((shm_read_small *)d->my_shm)->address = offset; + ((shm_addr *)d->my_shm)->address = offset; full_barrier - ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_STL_STRING; - d->waitWhile(DFPP_READ_STL_STRING); - size_t length = ((shm_retval *)d->my_shm)->value; + ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_STL_STRING; + d->waitWhile(CORE_READ_STL_STRING); + size_t length = ((shm_val *)d->my_shm)->value; size_t real = min(length, bufcapacity - 1); strncpy(buffer, d->my_shm+SHM_HEADER,real); // length + 1 for the null terminator buffer[real] = 0; @@ -718,11 +718,11 @@ size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacit void Process::writeSTLString(const uint32_t address, const std::string writeString) { - ((shm_write_small *)d->my_shm)->address = address/*-4*/; + ((shm_addr *)d->my_shm)->address = address/*-4*/; strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator full_barrier - ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_STL_STRING; - d->waitWhile(DFPP_WRITE_STL_STRING); + ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_STL_STRING; + d->waitWhile(CORE_WRITE_STL_STRING); } string Process::readClassName (uint32_t vptr) diff --git a/library/argstream/argstream.h b/library/argstream/argstream.h index cdc8e4600..9e2761493 100644 --- a/library/argstream/argstream.h +++ b/library/argstream/argstream.h @@ -1,815 +1,815 @@ -/* Copyright (C) 2004 Xavier Décoret -* -* argsteam is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* Foobar is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Foobar; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef ARGSTREAM_H -#define ARGSTREAM_H - - -#include -#include -#include -#include -#include -#include -#include - -namespace -{ - class argstream; - - template - class ValueHolder; - - template - argstream& operator>> (argstream&, const ValueHolder&); - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of ValueHolder - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - template - class ValueHolder - { - public: - ValueHolder(char s, - const char* l, - T& b, - const char* desc, - bool mandatory); - ValueHolder(const char* l, - T& b, - const char* desc, - bool mandatory); - ValueHolder(char s, - T& b, - const char* desc, - bool mandatory); - friend argstream& operator>><>(argstream& s,const ValueHolder& v); - std::string name() const; - std::string description() const; - private: - std::string shortName_; - std::string longName_; - T* value_; - T initialValue_; - std::string description_; - bool mandatory_; - }; - template - inline ValueHolder - parameter(char s, - const char* l, - T& b, - const char* desc="", - bool mandatory = true) - { - return ValueHolder(s,l,b,desc,mandatory); - } - template - inline ValueHolder - parameter(char s, - T& b, - const char* desc="", - bool mandatory = true) - { - return ValueHolder(s,b,desc,mandatory); - } - template - inline ValueHolder - parameter(const char* l, - T& b, - const char* desc="", - bool mandatory = true) - { - return ValueHolder(l,b,desc,mandatory); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of OptionHolder - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - class OptionHolder - { - public: - inline OptionHolder(char s, - const char* l, - bool& b, - const char* desc); - inline OptionHolder(const char* l, - bool& b, - const char* desc); - inline OptionHolder(char s, - bool& b, - const char* desc); - friend argstream& operator>>(argstream& s,const OptionHolder& v); - inline std::string name() const; - inline std::string description() const; - protected: - inline OptionHolder(char s, - const char* l, - const char* desc); - friend OptionHolder help(char s='h', - const char* l="help", - const char* desc="Display this help"); - private: - std::string shortName_; - std::string longName_; - bool* value_; - std::string description_; - }; - inline OptionHolder - option(char s, - const char* l, - bool& b, - const char* desc="") - { - return OptionHolder(s,l,b,desc); - } - inline OptionHolder - option(char s, - bool& b, - const char* desc="") - { - return OptionHolder(s,b,desc); - } - inline OptionHolder - option(const char* l, - bool& b, - const char* desc="") - { - return OptionHolder(l,b,desc); - } - inline OptionHolder - help(char s, - const char* l, - const char* desc) - { - return OptionHolder(s,l,desc); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of ValuesHolder - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - template - class ValuesHolder - { - public: - ValuesHolder(const O& o, - const char* desc, - int len); - friend argstream& operator>><>(argstream& s,const ValuesHolder& v); - std::string name() const; - std::string description() const; - typedef T value_type; - private: - mutable O value_; - std::string description_; - int len_; - char letter_; - }; - template - inline ValuesHolder - values(const O& o, - const char* desc="", - int len=-1) - { - return ValuesHolder(o,desc,len); - } - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of ValueParser - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - template - class ValueParser - { - public: - inline T operator()(const std::string& s) const - { - std::istringstream is(s); - T t; - is>>t; - return t; - } - }; - // We need to specialize for string otherwise parsing of a value that - // contains space (for example a string with space passed in quotes on the - // command line) would parse only the first element of the value!!! - template <> - class ValueParser - { - public: - inline std::string operator()(const std::string& s) const - { - return s; - } - }; - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // Interface of argstream - //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - class argstream - { - public: - inline argstream(int argc,char** argv); - //inline argstream(const char* c); - template - friend argstream& operator>>(argstream& s,const ValueHolder& v); - friend inline argstream& operator>>(argstream& s,const OptionHolder& v); - template - friend argstream& operator>>(argstream& s,const ValuesHolder& v); - - inline bool helpRequested() const; - inline bool isOk() const; - inline std::string errorLog() const; - inline std::string usage() const; - inline void defaultErrorHandling(bool ignoreUnused=false) const; - static inline char uniqueLetter(); - protected: - void parse(int argc,char** argv); - private: - typedef std::list::iterator value_iterator; - typedef std::pair help_entry; - std::string progName_; - std::map options_; - std::list values_; - bool minusActive_; - bool isOk_; - std::deque argHelps_; - std::string cmdLine_; - std::deque errors_; - bool helpRequested_; - }; - //************************************************************ - // Implementation of ValueHolder - //************************************************************ - template - ValueHolder::ValueHolder(char s, - const char* l, - T& v, - const char* desc, - bool mandatory) - : shortName_(1,s), - longName_(l), - value_(&v), - initialValue_(v), - description_(desc), - mandatory_(mandatory) - { - } - template - ValueHolder::ValueHolder(const char* l, - T& v, - const char* desc, - bool mandatory) - : longName_(l), - value_(&v), - initialValue_(v), - description_(desc), - mandatory_(mandatory) - { - } - template - ValueHolder::ValueHolder(char s, - T& v, - const char* desc, - bool mandatory) - : shortName_(1,s), - value_(&v), - initialValue_(v), - description_(desc), - mandatory_(mandatory) - { - } - template - std::string - ValueHolder::name() const - { - std::ostringstream os; - if (!shortName_.empty()) os<<'-'< - std::string - ValueHolder::description() const - { - std::ostringstream os; - os< - //************************************************************ - template - ValuesHolder::ValuesHolder(const O& o, - const char* desc, - int len) - : value_(o), - description_(desc), - len_(len) - { - letter_ = argstream::uniqueLetter(); - } - template - std::string - ValuesHolder::name() const - { - std::ostringstream os; - os< - std::string - ValuesHolder::description() const - { - return description_; - } - //************************************************************ - // Implementation of argstream - //************************************************************ - inline - argstream::argstream(int argc,char** argv) - : progName_(argv[0]), - minusActive_(true), - isOk_(true) - { - parse(argc,argv); - } - //inline - // argstream::argstream(const char* c) - // : progName_(""), - // minusActive_(true), - // isOk_(true) - //{ - // std::string s(c); - // // Build argc, argv from s. We must add a dummy first element for - // // progName because parse() expects it!! - // std::deque args; - // args.push_back(""); - // std::istringstream is(s); - // while (is.good()) - // { - // std::string t; - // is>>t; - // args.push_back(t); - // } - // char* pargs[args.size()]; - // char** p = pargs; - // for (std::deque::const_iterator - // iter = args.begin(); - // iter != args.end();++iter) - // { - // *p++ = const_cast(iter->c_str()); - // } - // parse(args.size(),pargs); - //} - inline void - argstream::parse(int argc,char** argv) - { - // Run thru all arguments. - // * it has -- in front : it is a long name option, if remainder is empty, - // it is an error - // * it has - in front : it is a sequence of short name options, if - // remainder is empty, deactivates option (- will - // now be considered a char). - // * if any other char, or if option was deactivated - // : it is a value. Values are split in parameters - // (immediately follow an option) and pure values. - // Each time a value is parsed, if the previously parsed argument was an - // option, then the option is linked to the value in case of it is a - // option with parameter. The subtle point is that when several options - // are given with short names (ex: -abc equivalent to -a -b -c), the last - // parsed option is -c). - // Since we use map for option, any successive call overides the previous - // one: foo -a -b -a hello is equivalent to foo -b -a hello - // For values it is not true since we might have several times the same - // value. - value_iterator* lastOption = NULL; - for (char** a = argv,**astop=a+argc;++a!=astop;) - { - std::string s(*a); - if (minusActive_ && s[0] == '-') - { - if (s.size() > 1 && s[1] == '-') - { - if (s.size() == 2) - { - minusActive_ = false; - continue; - } - lastOption = &(options_[s.substr(2)] = values_.end()); - } - else - { - if (s.size() > 1) - { - // Parse all chars, if it is a minus we have an error - for (std::string::const_iterator cter = s.begin(); - ++cter != s.end();) - { - if (*cter == '-') - { - isOk_ = false; - std::ostringstream os; - os<<"- in the middle of a switch "<::const_iterator - iter = options_.begin();iter != options_.end();++iter) - { - std::cout<<"DEBUG: option "<first; - if (iter->second != values_.end()) - { - std::cout<<" -> "<<*(iter->second); - } - std::cout<::const_iterator - iter = values_.begin();iter != values_.end();++iter) - { - std::cout<<"DEBUG: value "<<*iter<::const_iterator - iter = argHelps_.begin();iter != argHelps_.end();++iter) - { - if (lmaxfirst.size()) lmax = iter->first.size(); - } - for (std::deque::const_iterator - iter = argHelps_.begin();iter != argHelps_.end();++iter) - { - os<<'\t'<first<first.size(),' ') - <<" : "<second<<'\n'; - } - return os.str(); - } - inline std::string - argstream::errorLog() const - { - std::string s; - for(std::deque::const_iterator iter = errors_.begin(); - iter != errors_.end();++iter) - { - s += *iter; - s += '\n'; - } - return s; - } - inline char - argstream::uniqueLetter() - { - static unsigned int c = 'a'; - return c++; - } - template - argstream& - operator>>(argstream& s,const ValueHolder& v) - { - // Search in the options if there is any such option defined either with a - // short name or a long name. If both are found, only the last one is - // used. -#ifdef ARGSTREAM_DEBUG - std::cout<<"DEBUG: searching "<::iterator iter = - s.options_.find(v.shortName_); - if (iter == s.options_.end()) - { - iter = s.options_.find(v.longName_); - } - if (iter != s.options_.end()) - { - // If we find counterpart for value holder on command line, either it - // has an associated value in which case we assign it, or it has not, in - // which case we have an error. - if (iter->second != s.values_.end()) - { -#ifdef ARGSTREAM_DEBUG - std::cout<<"DEBUG: found value "<<*(iter->second)< p; - *(v.value_) = p(*(iter->second)); - // The option and its associated value are removed, the subtle thing - // is that someother options might have this associated value too, - // which we must invalidate. - s.values_.erase(iter->second); - - // FIXME this loop seems to crash if a std::string is used as the value - //for (std::map::iterator - // jter = s.options_.begin();jter != s.options_.end();++jter) - //{ - // if (jter->second == iter->second) - // { - // jter->second = s.values_.end(); - // } - //} - s.options_.erase(iter); - } - else - { - s.isOk_ = false; - std::ostringstream os; - os<<"No value following switch "<first - <<" on command line"; - s.errors_.push_back(os.str()); - } - } - else - { - if (v.mandatory_) - { - s.isOk_ = false; - std::ostringstream os; - os<<"Mandatory parameter "; - if (!v.shortName_.empty()) os<<'-'<>(argstream& s,const OptionHolder& v) - { - // Search in the options if there is any such option defined either with a - // short name or a long name. If both are found, only the last one is - // used. -#ifdef ARGSTREAM_DEBUG - std::cout<<"DEBUG: searching "<::iterator iter = - s.options_.find(v.shortName_); - if (iter == s.options_.end()) - { - iter = s.options_.find(v.longName_); - } - if (iter != s.options_.end()) - { - // If we find counterpart for value holder on command line then the - // option is true and if an associated value was found, it is ignored - if (v.value_ != NULL) - { - *(v.value_) = true; - } - else - { - s.helpRequested_ = true; - } - // The option only is removed - s.options_.erase(iter); - } - else - { - if (v.value_ != NULL) - { - *(v.value_) = false; - } - else - { - s.helpRequested_ = false; - } - } - return s; - } - template - argstream& - operator>>(argstream& s,const ValuesHolder& v) - { - s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); - { - std::ostringstream os; - os<<' '<::iterator first = s.values_.begin(); - // We add to the iterator as much values as we can, limited to the length - // specified (if different of -1) - int n = v.len_ != -1?v.len_:s.values_.size(); - while (first != s.values_.end() && n-->0) - { - // Read the value from the string *first - ValueParser p; - *(v.value_++) = p(*first ); - s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); - // The value we just removed was maybe "remembered" by an option so we - // remove it now. - for (std::map::iterator - jter = s.options_.begin();jter != s.options_.end();++jter) - { - if (jter->second == first) - { - jter->second = s.values_.end(); - } - } - ++first; - } - // Check if we have enough values - if (n != 0) - { - s.isOk_ = false; - std::ostringstream os; - os<<"Expecting "< +* +* argsteam is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* Foobar is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with Foobar; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef ARGSTREAM_H +#define ARGSTREAM_H + + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + class argstream; + + template + class ValueHolder; + + template + argstream& operator>> (argstream&, const ValueHolder&); + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValueHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValueHolder + { + public: + ValueHolder(char s, + const char* l, + T& b, + const char* desc, + bool mandatory); + ValueHolder(const char* l, + T& b, + const char* desc, + bool mandatory); + ValueHolder(char s, + T& b, + const char* desc, + bool mandatory); + friend argstream& operator>><>(argstream& s,const ValueHolder& v); + std::string name() const; + std::string description() const; + private: + std::string shortName_; + std::string longName_; + T* value_; + T initialValue_; + std::string description_; + bool mandatory_; + }; + template + inline ValueHolder + parameter(char s, + const char* l, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(s,l,b,desc,mandatory); + } + template + inline ValueHolder + parameter(char s, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(s,b,desc,mandatory); + } + template + inline ValueHolder + parameter(const char* l, + T& b, + const char* desc="", + bool mandatory = true) + { + return ValueHolder(l,b,desc,mandatory); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of OptionHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + class OptionHolder + { + public: + inline OptionHolder(char s, + const char* l, + bool& b, + const char* desc); + inline OptionHolder(const char* l, + bool& b, + const char* desc); + inline OptionHolder(char s, + bool& b, + const char* desc); + friend argstream& operator>>(argstream& s,const OptionHolder& v); + inline std::string name() const; + inline std::string description() const; + protected: + inline OptionHolder(char s, + const char* l, + const char* desc); + friend OptionHolder help(char s='h', + const char* l="help", + const char* desc="Display this help"); + private: + std::string shortName_; + std::string longName_; + bool* value_; + std::string description_; + }; + inline OptionHolder + option(char s, + const char* l, + bool& b, + const char* desc="") + { + return OptionHolder(s,l,b,desc); + } + inline OptionHolder + option(char s, + bool& b, + const char* desc="") + { + return OptionHolder(s,b,desc); + } + inline OptionHolder + option(const char* l, + bool& b, + const char* desc="") + { + return OptionHolder(l,b,desc); + } + inline OptionHolder + help(char s, + const char* l, + const char* desc) + { + return OptionHolder(s,l,desc); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValuesHolder + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValuesHolder + { + public: + ValuesHolder(const O& o, + const char* desc, + int len); + friend argstream& operator>><>(argstream& s,const ValuesHolder& v); + std::string name() const; + std::string description() const; + typedef T value_type; + private: + mutable O value_; + std::string description_; + int len_; + char letter_; + }; + template + inline ValuesHolder + values(const O& o, + const char* desc="", + int len=-1) + { + return ValuesHolder(o,desc,len); + } + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of ValueParser + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + template + class ValueParser + { + public: + inline T operator()(const std::string& s) const + { + std::istringstream is(s); + T t; + is>>t; + return t; + } + }; + // We need to specialize for string otherwise parsing of a value that + // contains space (for example a string with space passed in quotes on the + // command line) would parse only the first element of the value!!! + template <> + class ValueParser + { + public: + inline std::string operator()(const std::string& s) const + { + return s; + } + }; + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Interface of argstream + //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + class argstream + { + public: + inline argstream(int argc,char** argv); + //inline argstream(const char* c); + template + friend argstream& operator>>(argstream& s,const ValueHolder& v); + friend inline argstream& operator>>(argstream& s,const OptionHolder& v); + template + friend argstream& operator>>(argstream& s,const ValuesHolder& v); + + inline bool helpRequested() const; + inline bool isOk() const; + inline std::string errorLog() const; + inline std::string usage() const; + inline void defaultErrorHandling(bool ignoreUnused=false) const; + static inline char uniqueLetter(); + protected: + void parse(int argc,char** argv); + private: + typedef std::list::iterator value_iterator; + typedef std::pair help_entry; + std::string progName_; + std::map options_; + std::list values_; + bool minusActive_; + bool isOk_; + std::deque argHelps_; + std::string cmdLine_; + std::deque errors_; + bool helpRequested_; + }; + //************************************************************ + // Implementation of ValueHolder + //************************************************************ + template + ValueHolder::ValueHolder(char s, + const char* l, + T& v, + const char* desc, + bool mandatory) + : shortName_(1,s), + longName_(l), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + ValueHolder::ValueHolder(const char* l, + T& v, + const char* desc, + bool mandatory) + : longName_(l), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + ValueHolder::ValueHolder(char s, + T& v, + const char* desc, + bool mandatory) + : shortName_(1,s), + value_(&v), + initialValue_(v), + description_(desc), + mandatory_(mandatory) + { + } + template + std::string + ValueHolder::name() const + { + std::ostringstream os; + if (!shortName_.empty()) os<<'-'< + std::string + ValueHolder::description() const + { + std::ostringstream os; + os< + //************************************************************ + template + ValuesHolder::ValuesHolder(const O& o, + const char* desc, + int len) + : value_(o), + description_(desc), + len_(len) + { + letter_ = argstream::uniqueLetter(); + } + template + std::string + ValuesHolder::name() const + { + std::ostringstream os; + os< + std::string + ValuesHolder::description() const + { + return description_; + } + //************************************************************ + // Implementation of argstream + //************************************************************ + inline + argstream::argstream(int argc,char** argv) + : progName_(argv[0]), + minusActive_(true), + isOk_(true) + { + parse(argc,argv); + } + //inline + // argstream::argstream(const char* c) + // : progName_(""), + // minusActive_(true), + // isOk_(true) + //{ + // std::string s(c); + // // Build argc, argv from s. We must add a dummy first element for + // // progName because parse() expects it!! + // std::deque args; + // args.push_back(""); + // std::istringstream is(s); + // while (is.good()) + // { + // std::string t; + // is>>t; + // args.push_back(t); + // } + // char* pargs[args.size()]; + // char** p = pargs; + // for (std::deque::const_iterator + // iter = args.begin(); + // iter != args.end();++iter) + // { + // *p++ = const_cast(iter->c_str()); + // } + // parse(args.size(),pargs); + //} + inline void + argstream::parse(int argc,char** argv) + { + // Run thru all arguments. + // * it has -- in front : it is a long name option, if remainder is empty, + // it is an error + // * it has - in front : it is a sequence of short name options, if + // remainder is empty, deactivates option (- will + // now be considered a char). + // * if any other char, or if option was deactivated + // : it is a value. Values are split in parameters + // (immediately follow an option) and pure values. + // Each time a value is parsed, if the previously parsed argument was an + // option, then the option is linked to the value in case of it is a + // option with parameter. The subtle point is that when several options + // are given with short names (ex: -abc equivalent to -a -b -c), the last + // parsed option is -c). + // Since we use map for option, any successive call overides the previous + // one: foo -a -b -a hello is equivalent to foo -b -a hello + // For values it is not true since we might have several times the same + // value. + value_iterator* lastOption = NULL; + for (char** a = argv,**astop=a+argc;++a!=astop;) + { + std::string s(*a); + if (minusActive_ && s[0] == '-') + { + if (s.size() > 1 && s[1] == '-') + { + if (s.size() == 2) + { + minusActive_ = false; + continue; + } + lastOption = &(options_[s.substr(2)] = values_.end()); + } + else + { + if (s.size() > 1) + { + // Parse all chars, if it is a minus we have an error + for (std::string::const_iterator cter = s.begin(); + ++cter != s.end();) + { + if (*cter == '-') + { + isOk_ = false; + std::ostringstream os; + os<<"- in the middle of a switch "<::const_iterator + iter = options_.begin();iter != options_.end();++iter) + { + std::cout<<"DEBUG: option "<first; + if (iter->second != values_.end()) + { + std::cout<<" -> "<<*(iter->second); + } + std::cout<::const_iterator + iter = values_.begin();iter != values_.end();++iter) + { + std::cout<<"DEBUG: value "<<*iter<::const_iterator + iter = argHelps_.begin();iter != argHelps_.end();++iter) + { + if (lmaxfirst.size()) lmax = iter->first.size(); + } + for (std::deque::const_iterator + iter = argHelps_.begin();iter != argHelps_.end();++iter) + { + os<<'\t'<first<first.size(),' ') + <<" : "<second<<'\n'; + } + return os.str(); + } + inline std::string + argstream::errorLog() const + { + std::string s; + for(std::deque::const_iterator iter = errors_.begin(); + iter != errors_.end();++iter) + { + s += *iter; + s += '\n'; + } + return s; + } + inline char + argstream::uniqueLetter() + { + static unsigned int c = 'a'; + return c++; + } + template + argstream& + operator>>(argstream& s,const ValueHolder& v) + { + // Search in the options if there is any such option defined either with a + // short name or a long name. If both are found, only the last one is + // used. +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: searching "<::iterator iter = + s.options_.find(v.shortName_); + if (iter == s.options_.end()) + { + iter = s.options_.find(v.longName_); + } + if (iter != s.options_.end()) + { + // If we find counterpart for value holder on command line, either it + // has an associated value in which case we assign it, or it has not, in + // which case we have an error. + if (iter->second != s.values_.end()) + { +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: found value "<<*(iter->second)< p; + *(v.value_) = p(*(iter->second)); + // The option and its associated value are removed, the subtle thing + // is that someother options might have this associated value too, + // which we must invalidate. + s.values_.erase(iter->second); + + // FIXME this loop seems to crash if a std::string is used as the value + //for (std::map::iterator + // jter = s.options_.begin();jter != s.options_.end();++jter) + //{ + // if (jter->second == iter->second) + // { + // jter->second = s.values_.end(); + // } + //} + s.options_.erase(iter); + } + else + { + s.isOk_ = false; + std::ostringstream os; + os<<"No value following switch "<first + <<" on command line"; + s.errors_.push_back(os.str()); + } + } + else + { + if (v.mandatory_) + { + s.isOk_ = false; + std::ostringstream os; + os<<"Mandatory parameter "; + if (!v.shortName_.empty()) os<<'-'<>(argstream& s,const OptionHolder& v) + { + // Search in the options if there is any such option defined either with a + // short name or a long name. If both are found, only the last one is + // used. +#ifdef ARGSTREAM_DEBUG + std::cout<<"DEBUG: searching "<::iterator iter = + s.options_.find(v.shortName_); + if (iter == s.options_.end()) + { + iter = s.options_.find(v.longName_); + } + if (iter != s.options_.end()) + { + // If we find counterpart for value holder on command line then the + // option is true and if an associated value was found, it is ignored + if (v.value_ != NULL) + { + *(v.value_) = true; + } + else + { + s.helpRequested_ = true; + } + // The option only is removed + s.options_.erase(iter); + } + else + { + if (v.value_ != NULL) + { + *(v.value_) = false; + } + else + { + s.helpRequested_ = false; + } + } + return s; + } + template + argstream& + operator>>(argstream& s,const ValuesHolder& v) + { + s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); + { + std::ostringstream os; + os<<' '<::iterator first = s.values_.begin(); + // We add to the iterator as much values as we can, limited to the length + // specified (if different of -1) + int n = v.len_ != -1?v.len_:s.values_.size(); + while (first != s.values_.end() && n-->0) + { + // Read the value from the string *first + ValueParser p; + *(v.value_++) = p(*first ); + s.argHelps_.push_back(argstream::help_entry(v.name(),v.description())); + // The value we just removed was maybe "remembered" by an option so we + // remove it now. + for (std::map::iterator + jter = s.options_.begin();jter != s.options_.end();++jter) + { + if (jter->second == first) + { + jter->second = s.values_.end(); + } + } + ++first; + } + // Check if we have enough values + if (n != 0) + { + s.isOk_ = false; + std::ostringstream os; + os<<"Expecting "< dfhack shm bridge's core module. + */ + +#include +#include "../library/integers.h" +#include +#include +#include +#include +#include "shms.h" + +enum DFPP_CmdType +{ + CANCELLATION, // we should jump out of the Act() + CLIENT_WAIT, // we are waiting for the client + FUNCTION, // we call a function as a result of the command +}; + +struct DFPP_command +{ + DFPP_CmdType type:32; // force the enum to 32 bits for compatibility reasons + std::string name; + void (*_function)(void); +}; + +struct DFPP_module +{ + inline void push_command(DFPP_CmdType type, const char * name, void (*_function)(void)) + { + DFPP_command cmd; + cmd.type = type; + cmd.name = name; + cmd._function = _function; + commands.push_back(cmd); + } + inline void set_command(unsigned int index, DFPP_CmdType type, const char * name, void (*_function)(void)) + { + DFPP_command cmd; + cmd.type = type; + cmd.name = name; + cmd._function = _function; + commands[index] = cmd; + } + inline void reserve (unsigned int numcommands) + { + commands.clear(); + DFPP_command cmd = {CANCELLATION,"",0}; + commands.resize(numcommands,cmd); + } + std::string name; + uint32_t version; // version + std::vector commands; + void * modulestate; +}; + +std::vector module_registry; + +// various crud +extern int errorstate; +extern char *shm; +extern int shmid; + +#define SHMHDR ((shm_header *)shm) +#define SHMCMD ((shm_cmd *)shm)->pingpong + +void GetCoreVersion (void) +{ + SHMHDR->value = module_registry[0].version; + full_barrier + SHMCMD = CORE_RET_VERSION; +} + +void GetPID (void) +{ + SHMHDR->value = OS_getPID(); + full_barrier + SHMCMD = CORE_RET_PID; +} + +void ReadRaw (void) +{ + memcpy(shm + SHM_HEADER, (void *) SHMHDR->address,SHMHDR->length); + full_barrier + SHMCMD = CORE_RET_DATA; +} + +void ReadDWord (void) +{ + SHMHDR->value = *((uint32_t*) SHMHDR->address); + full_barrier + SHMCMD = CORE_RET_DWORD; +} + +void ReadWord (void) +{ + SHMHDR->value = *((uint16_t*) SHMHDR->address); + full_barrier + SHMCMD = CORE_RET_WORD; +} + +void ReadByte (void) +{ + SHMHDR->value = *((uint8_t*) SHMHDR->address); + full_barrier + SHMCMD = CORE_RET_BYTE; +} + +void WriteRaw (void) +{ + memcpy((void *)SHMHDR->address, shm + SHM_HEADER,SHMHDR->length); + full_barrier + SHMCMD = CORE_SUSPENDED; +} + +void WriteDWord (void) +{ + (*(uint32_t*)SHMHDR->address) = SHMHDR->value; + full_barrier + SHMCMD = CORE_SUSPENDED; +} + +void WriteWord (void) +{ + (*(uint16_t*)SHMHDR->address) = SHMHDR->value; + full_barrier + SHMCMD = CORE_SUSPENDED; +} + +void WriteByte (void) +{ + (*(uint8_t*)SHMHDR->address) = SHMHDR->value; + full_barrier + SHMCMD = CORE_SUSPENDED; +} + +void ReadSTLString (void) +{ + std::string * myStringPtr = (std::string *) SHMHDR->address; + unsigned int l = myStringPtr->length(); + SHMHDR->value = l; + // there doesn't have to be a null terminator! + strncpy(shm+SHM_HEADER,myStringPtr->c_str(),l+1); + full_barrier + SHMCMD = CORE_RET_STRING; +} + +void WriteSTLString (void) +{ + std::string * myStringPtr = (std::string *) SHMHDR->address; + // here we DO expect a 0 terminator + myStringPtr->assign((const char *) (shm + SHM_HEADER)); + full_barrier + SHMCMD = CORE_SUSPENDED; +} + +void Suspend (void) +{ + SHMCMD = CORE_SUSPENDED; +} + +void InitCore(void) +{ + DFPP_module core; + core.name = "Core"; + core.version = CORE_VERSION; + core.modulestate = 0; // this one is dumb and has no real state + + core.reserve(NUM_CORE_CMDS); + core.set_command(CORE_RUNNING, CANCELLATION, "Running", NULL); + + core.set_command(CORE_GET_VERSION, FUNCTION,"Get core version",GetCoreVersion); + core.set_command(CORE_RET_VERSION, CLIENT_WAIT,"Core version return",0); + + core.set_command(CORE_GET_PID, FUNCTION, "Get PID", GetPID); + core.set_command(CORE_RET_PID, CLIENT_WAIT, "PID return", 0); + + core.set_command(CORE_DFPP_READ, FUNCTION,"Raw read",ReadRaw); + core.set_command(CORE_RET_DATA, CLIENT_WAIT,"Raw read return",0); + + core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord); + core.set_command(CORE_RET_DWORD, CLIENT_WAIT,"Read DWORD return",0); + + core.set_command(CORE_READ_WORD, FUNCTION,"Read WORD",ReadWord); + core.set_command(CORE_RET_WORD, CLIENT_WAIT,"Read WORD return",0); + + core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte); + core.set_command(CORE_RET_BYTE, CLIENT_WAIT,"Read BYTE return",0); + + core.set_command(CORE_SV_ERROR, CANCELLATION, "Server error", 0); + core.set_command(CORE_CL_ERROR, CANCELLATION, "Client error", 0); + + core.set_command(CORE_WRITE, FUNCTION, "Raw write", WriteRaw); + core.set_command(CORE_WRITE_DWORD, FUNCTION, "Write DWORD", WriteDWord); + core.set_command(CORE_WRITE_WORD, FUNCTION, "Write WORD", WriteWord); + core.set_command(CORE_WRITE_BYTE, FUNCTION, "Write BYTE", WriteByte); + + core.set_command(CORE_SUSPEND, FUNCTION, "Suspend", Suspend); + core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended", 0); + + core.set_command(CORE_READ_STL_STRING, FUNCTION, "Read STL string", ReadSTLString); + core.set_command(CORE_READ_C_STRING, CLIENT_WAIT, "RESERVED", 0); + core.set_command(CORE_RET_STRING, CLIENT_WAIT, "Return string", 0); + core.set_command(CORE_WRITE_STL_STRING, FUNCTION, "Write STL string", WriteSTLString); + module_registry.push_back(core); +} + +void InitModules (void) +{ + // create the core module + InitCore(); +} + +void SHM_Act (void) +{ + if(errorstate) + { + return; + } + uint32_t numwaits = 0; + check_again: // goto target!!! + if(numwaits == 10000) + { + // this tests if there's a process on the other side + if(isValidSHM()) + { + numwaits = 0; + } + else + { + full_barrier + SHMCMD = CORE_RUNNING; + fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n"); + } + } + DFPP_module & mod = module_registry[((shm_cmd *)shm)->parts.module]; + DFPP_command & cmd = mod.commands[((shm_cmd *)shm)->parts.command]; + //fprintf(stderr, "Client invoked %s\n", cmd.name.c_str() ); + if(cmd._function) + { + cmd._function(); + } + if(cmd.type != CANCELLATION) + { + SCHED_YIELD + numwaits ++; // watchdog timeout + goto check_again; + } +} + diff --git a/shmserver/shms-linux.cpp b/shmserver/shms-linux.cpp index f78bf7419..59b2ea120 100644 --- a/shmserver/shms-linux.cpp +++ b/shmserver/shms-linux.cpp @@ -34,6 +34,8 @@ distribution. #include #include #include +#include +#include #include "shms.h" #include #include @@ -62,7 +64,7 @@ bool isValidSHM() //fprintf(stderr,"ID %d, attached: %d\n",shmid, descriptor.shm_nattch); return (descriptor.shm_nattch == 2); } -uint32_t getPID() +uint32_t OS_getPID() { return getpid(); } @@ -109,7 +111,8 @@ void SHM_Init ( void ) } full_barrier // make sure we don't stall or do crazy stuff - ((shm_cmd *)shm)->pingpong = DFPP_RUNNING; + ((shm_cmd *)shm)->pingpong = CORE_RUNNING; + InitModules(); } void SHM_Destroy ( void ) @@ -144,7 +147,7 @@ DFhackCExport void SDL_GL_SwapBuffers(void) { if(_SDL_GL_SwapBuffers) { - if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) + if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING) { SHM_Act(); } @@ -158,7 +161,7 @@ DFhackCExport int SDL_Flip(void * some_ptr) { if(_SDL_Flip) { - if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) + if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING) { SHM_Act(); } @@ -216,7 +219,7 @@ DFhackCExport int refresh (void) { if(_refresh) { - if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) + if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING) { SHM_Act(); } diff --git a/shmserver/shms-proto.cpp b/shmserver/shms-proto.cpp deleted file mode 100644 index ded5a4959..000000000 --- a/shmserver/shms-proto.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* -www.sourceforge.net/projects/dfhack -Copyright (c) 2009 Petr Mrázek (peterix) - -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. -*/ - -/** - * This is the source for the DF <-> dfhack shm bridge, server protocol part - */ -#include -#include "../library/integers.h" -#include -#include -#include -//#include -#include "shms.h" -// various crud -extern int errorstate; -extern char *shm; -extern int shmid; - -void SHM_Act (void) -{ - if(errorstate) - { - return; - } - uint32_t numwaits = 0; - uint32_t length; - uint32_t address; - std::string * myStringPtr; - check_again: // goto target!!! - SCHED_YIELD // yield the CPU, valid only on single-core CPUs - if(numwaits == 10000) - { - // this tests if there's a process on the other side - if(isValidSHM()) - { - numwaits = 0; - } - else - { - full_barrier - ((shm_cmd *)shm)->pingpong = DFPP_RUNNING; - fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n"); - //MessageBox(0,"Broke out of loop, other process disappeared.","FUN", MB_OK); - } - } - switch (((shm_cmd *)shm)->pingpong) - { - case DFPP_RET_VERSION: - case DFPP_RET_DATA: - case DFPP_RET_DWORD: - case DFPP_RET_WORD: - case DFPP_RET_BYTE: - case DFPP_RET_STRING: - case DFPP_SUSPENDED: - case DFPP_RET_PID: - case DFPP_SV_ERROR: - numwaits++; - goto check_again; - case DFPP_SUSPEND: - full_barrier - ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; - goto check_again; - /* - case DFPP_BOUNCE: - length = ((shm_bounce *)shm)->length; - memcpy(BigFat,shm + SHM_HEADER,length); - memcpy(shm + SHM_HEADER,BigFat,length); - ((shm_cmd *)shm)->pingpong = DFPP_RET_DATA; - goto check_again; - */ - case DFPP_PID: - ((shm_retval *)shm)->value = getPID(); - full_barrier - ((shm_retval *)shm)->pingpong = DFPP_RET_PID; - goto check_again; - - case DFPP_VERSION: - ((shm_retval *)shm)->value = PINGPONG_VERSION; - full_barrier - ((shm_retval *)shm)->pingpong = DFPP_RET_VERSION; - goto check_again; - - case DFPP_READ: - length = ((shm_read *)shm)->length; - address = ((shm_read *)shm)->address; - memcpy(shm + SHM_HEADER, (void *) address,length); - full_barrier - ((shm_cmd *)shm)->pingpong = DFPP_RET_DATA; - goto check_again; - - case DFPP_READ_DWORD: - address = ((shm_read_small *)shm)->address; - ((shm_retval *)shm)->value = *((uint32_t*) address); - full_barrier - ((shm_retval *)shm)->pingpong = DFPP_RET_DWORD; - goto check_again; - - case DFPP_READ_WORD: - address = ((shm_read_small *)shm)->address; - ((shm_retval *)shm)->value = *((uint16_t*) address); - full_barrier - ((shm_retval *)shm)->pingpong = DFPP_RET_WORD; - goto check_again; - - case DFPP_READ_BYTE: - address = ((shm_read_small *)shm)->address; - ((shm_retval *)shm)->value = *((uint8_t*) address); - full_barrier - ((shm_retval *)shm)->pingpong = DFPP_RET_BYTE; - goto check_again; - - case DFPP_WRITE: - address = ((shm_write *)shm)->address; - length = ((shm_write *)shm)->length; - memcpy((void *)address, shm + SHM_HEADER,length); - full_barrier - ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; - goto check_again; - - case DFPP_WRITE_DWORD: - (*(uint32_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value; - full_barrier - ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; - goto check_again; - - case DFPP_WRITE_WORD: - (*(uint16_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value; - full_barrier - ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; - goto check_again; - - case DFPP_WRITE_BYTE: - (*(uint8_t*)((shm_write_small *)shm)->address) = ((shm_write_small *)shm)->value; - full_barrier - ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; - goto check_again; - - case DFPP_CL_ERROR: - case DFPP_RUNNING: - //fprintf(stderr, "no. of waits: %d\n", numwaits); - //MessageBox(0,"Broke out of loop properly","FUN", MB_OK); - break; - - case DFPP_READ_STL_STRING: - myStringPtr = (std::string *) ((shm_read_small *)shm)->address; - ((shm_retval *)shm)->value = myStringPtr->length(); - strncpy(shm+SHM_HEADER,myStringPtr->c_str(),myStringPtr->length()+1);// length + 1 for the null terminator - full_barrier - ((shm_retval *)shm)->pingpong = DFPP_RET_STRING; - goto check_again; - - case DFPP_WRITE_STL_STRING: - myStringPtr = (std::string *) ((shm_write *)shm)->address; - myStringPtr->assign((const char *) (shm + SHM_HEADER)); - full_barrier - ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; - goto check_again; - - - default: - ((shm_retval *)shm)->value = DFEE_INVALID_COMMAND; - full_barrier - ((shm_retval *)shm)->pingpong = DFPP_SV_ERROR; - break; - } -} diff --git a/shmserver/shms-windows.cpp b/shmserver/shms-windows.cpp index 5a43f885e..19c22548b 100644 --- a/shmserver/shms-windows.cpp +++ b/shmserver/shms-windows.cpp @@ -34,8 +34,10 @@ distribution. #define DFhackCExport extern "C" __declspec(dllexport) #include "../library/integers.h" +#include +#include #include "shms.h" -#include +#include int errorstate = 0; char *shm = 0; int shmid = 0; @@ -131,8 +133,7 @@ void SHM_Init ( void ) shm = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE); if(shm) { - ((shm_cmd *)shm)->pingpong = DFPP_RUNNING; - //MessageBox(0,"Sucessfully mapped SHM","FUN", MB_OK); + ((shm_cmd *)shm)->pingpong = CORE_RUNNING; } else { @@ -142,6 +143,7 @@ void SHM_Init ( void ) CloseHandle(DFSVMutex); CloseHandle(DFCLMutex); } + InitModules(); } void SHM_Destroy ( void ) @@ -153,7 +155,7 @@ void SHM_Destroy ( void ) CloseHandle(DFCLMutex); } -uint32_t getPID() +uint32_t OS_getPID() { return GetCurrentProcessId(); } @@ -665,7 +667,7 @@ DFhackCExport void SDL_Quit(void) static void (*_SDL_GL_SwapBuffers)(void) = 0; DFhackCExport void SDL_GL_SwapBuffers(void) { - if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) + if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING) { SHM_Act(); } @@ -678,7 +680,7 @@ DFhackCExport int SDL_Flip(void * some_ptr) { if(_SDL_Flip) { - if(!errorstate && ((shm_cmd *)shm)->pingpong != DFPP_RUNNING) + if(!errorstate && ((shm_cmd *)shm)->pingpong != CORE_RUNNING) { SHM_Act(); } diff --git a/shmserver/shms.h b/shmserver/shms.h index a056c8a41..f80a6a6c1 100644 --- a/shmserver/shms.h +++ b/shmserver/shms.h @@ -1,10 +1,10 @@ #ifndef DFCONNECT_H #define DFCONNECT_H -#define PINGPONG_VERSION 2 +#define CORE_VERSION 3 #define SHM_KEY 123466 -#define SHM_HEADER 1024 -#define SHM_BODY 1024*1024 +#define SHM_HEADER 1024 // 1kB reserved for a header +#define SHM_BODY 1024*1024 // 1MB reserved for bulk data transfer #define SHM_SIZE SHM_HEADER+SHM_BODY @@ -32,14 +32,6 @@ #endif #endif - -/* - * read - parameters are address and length - * write - parameters are address, length and the actual data to write - * wait - sent to DF so that it waits for more commands - * end - sent to DF for breaking out of the wait -*/ - enum DF_SHM_ERRORSTATE { SHM_OK, // all OK @@ -48,51 +40,51 @@ enum DF_SHM_ERRORSTATE SHM_SECOND_DF // we are a second DF process, can't use SHM at all }; -enum DF_PINGPONG +enum CORE_COMMAND { - DFPP_RUNNING = 0, // no command, normal server execution + CORE_RUNNING = 0, // no command, normal server execution - DFPP_VERSION, // protocol version query - DFPP_RET_VERSION, // return the protocol version + CORE_GET_VERSION, // protocol version query + CORE_RET_VERSION, // return the protocol version - DFPP_PID, // query for the process ID - DFPP_RET_PID, // return process ID + CORE_GET_PID, // query for the process ID + CORE_RET_PID, // return process ID // version 1 stuff below - DFPP_READ, // cl -> sv, read some data - DFPP_RET_DATA, // sv -> cl, returned data + CORE_DFPP_READ, // cl -> sv, read some data + CORE_RET_DATA, // sv -> cl, returned data - DFPP_READ_DWORD, // cl -> sv, read a dword - DFPP_RET_DWORD, // sv -> cl, returned dword + CORE_READ_DWORD, // cl -> sv, read a dword + CORE_RET_DWORD, // sv -> cl, returned dword - DFPP_READ_WORD, // cl -> sv, read a word - DFPP_RET_WORD, // sv -> cl, returned word + CORE_READ_WORD, // cl -> sv, read a word + CORE_RET_WORD, // sv -> cl, returned word - DFPP_READ_BYTE, // cl -> sv, read a byte - DFPP_RET_BYTE, // sv -> cl, returned byte + CORE_READ_BYTE, // cl -> sv, read a byte + CORE_RET_BYTE, // sv -> cl, returned byte - DFPP_SV_ERROR, // there was a server error - DFPP_CL_ERROR, // there was a client error + CORE_SV_ERROR, // there was a server error + CORE_CL_ERROR, // there was a client error - DFPP_WRITE,// client writes to server - DFPP_WRITE_DWORD,// client writes a DWORD to server - DFPP_WRITE_WORD,// client writes a WORD to server - DFPP_WRITE_BYTE,// client writes a BYTE to server + CORE_WRITE,// client writes to server + CORE_WRITE_DWORD,// client writes a DWORD to server + CORE_WRITE_WORD,// client writes a WORD to server + CORE_WRITE_BYTE,// client writes a BYTE to server - DFPP_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait) - DFPP_SUSPENDED, // response to WAIT, server is stalled in busy wait + CORE_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait) + CORE_SUSPENDED, // response to WAIT, server is stalled in busy wait // all strings capped at 1MB - DFPP_READ_STL_STRING,// client requests contents of STL string at address - DFPP_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated) - DFPP_RET_STRING, // sv -> cl length + string contents - DFPP_WRITE_STL_STRING,// client wants to set STL string at address to something + CORE_READ_STL_STRING,// client requests contents of STL string at address + CORE_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated) + CORE_RET_STRING, // sv -> cl length + string contents + CORE_WRITE_STL_STRING,// client wants to set STL string at address to something - // vector elements > 1MB are not supported because they don't fit into the shared memory - DFPP_READ_ENTIRE_VECTOR, // read an entire vector (parameters are address of vector object and size of items) - DFPP_RET_VECTOR_BODY, // a part of a vector is returned - no. of elements returned, no. of elements total, elements + // compare affinity and determine if using yield is required + CORE_SYNC_YIELD,// cl sends affinity to sv, sv sets yield + CORE_SYNC_YIELD_RET,// sv returns yield bool - NUM_DFPP + NUM_CORE_CMDS }; @@ -102,54 +94,31 @@ enum DF_ERROR DFEE_BUFFER_OVERFLOW }; -typedef struct -{ - volatile uint32_t pingpong; // = 0 -} shm_cmd; - -typedef struct -{ - volatile uint32_t pingpong; - uint32_t address; - uint32_t length; -} shm_read; - -typedef shm_read shm_write; -typedef shm_read shm_bounce; - -typedef struct +typedef union { + struct + { + volatile uint16_t command; + volatile uint16_t module; + } parts; volatile uint32_t pingpong; -} shm_ret_data; - -typedef struct -{ - volatile uint32_t pingpong; - uint32_t address; -} shm_read_small; + inline void set(uint16_t module, uint16_t command) + { + pingpong = module + command << 16; + } +} shm_cmd; typedef struct { - volatile uint32_t pingpong; + shm_cmd cmd; uint32_t address; uint32_t value; -} shm_write_small; - -typedef struct -{ - volatile uint32_t pingpong; - uint32_t value; -} shm_retval; - -typedef struct -{ - volatile uint32_t pingpong; uint32_t length; -} shm_retstr; - +} shm_header; void SHM_Act (void); +void InitModules (void); bool isValidSHM(); -uint32_t getPID(); +uint32_t OS_getPID(); #endif From 6e69dcdeed1fabd8c3bfa5c220ee4e847fdca01c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 4 Mar 2010 04:40:06 +0100 Subject: [PATCH 03/16] Use sched_yield depending on CPU affinity --- library/DFProcess-linux-SHM.cpp | 43 +++++++- library/DFProcess-windows-SHM.cpp | 50 +++++++++- shmserver/shms-core.cpp | 161 ++++++++++++------------------ shmserver/shms-linux.cpp | 16 ++- shmserver/shms.h | 96 ++++++------------ 5 files changed, 188 insertions(+), 178 deletions(-) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 7a6331e73..15c6a0c9e 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -28,6 +28,7 @@ distribution. #include #include #include "../shmserver/shms.h" +#include "../shmserver/shms-core.h" #include #include #include @@ -68,22 +69,27 @@ class Process::Private bool waitWhile (CORE_COMMAND state); bool DF_TestBridgeVersion(bool & ret); bool DF_GetPID(pid_t & ret); + void DF_SyncAffinity(void); }; // some helpful macros to keep the code bloat in check #define SHMCMD ((shm_cmd *)my_shm)->pingpong #define D_SHMCMD ((shm_cmd *)d->my_shm)->pingpong -#define SHMHDR ((shm_header *)my_shm) -#define D_SHMHDR ((shm_header *)d->my_shm) +#define SHMHDR ((shm_core_hdr *)my_shm) +#define D_SHMHDR ((shm_core_hdr *)d->my_shm) +/* +Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling) +we end up with this silly thing +*/ bool Process::Private::waitWhile (CORE_COMMAND state) { uint32_t cnt = 0; struct shmid_ds descriptor; while (SHMCMD == state) { - if(cnt == 10000) + if(cnt == 10000)// check if the other process is still there { shmctl(my_shmid, IPC_STAT, &descriptor); @@ -98,7 +104,10 @@ bool Process::Private::waitWhile (CORE_COMMAND state) cnt = 0; } } - SCHED_YIELD + if(useYield) + { + SCHED_YIELD + } cnt++; } if(SHMCMD == CORE_SV_ERROR) @@ -136,6 +145,31 @@ bool Process::Private::DF_GetPID(pid_t & ret) return true; } +uint32_t OS_getAffinity() +{ + cpu_set_t mask; + sched_getaffinity(0,sizeof(cpu_set_t),&mask); + // FIXME: truncation + uint32_t affinity = *(uint32_t *) &mask; + return affinity; +} + +void Process::Private::DF_SyncAffinity( void ) +{ + SHMHDR->value = OS_getAffinity(); + gcc_barrier + SHMCMD = CORE_SYNC_YIELD; + gcc_barrier + if(!waitWhile(CORE_SYNC_YIELD)) + return; + gcc_barrier + SHMCMD = CORE_SUSPENDED; + useYield = SHMHDR->value; + #ifdef DEBUG + if(useYield) cerr << "Using Yield!" << endl; + #endif +} + Process::Process(vector & known_versions) : d(new Private()) { @@ -204,6 +238,7 @@ Process::Process(vector & known_versions) // try to identify the DF version d->validate(target_name, d->my_pid, known_versions); + d->DF_SyncAffinity(); d->my_window = new DFWindow(this); } gcc_barrier diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index fe23cb9bf..abf06fdb2 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -23,6 +23,7 @@ distribution. */ #include "DFCommonInternal.h" #include "../shmserver/shms.h" +#include "../shmserver/shms-core.h" using namespace DFHack; // a full memory barrier! better be safe than sorry. @@ -38,6 +39,7 @@ class Process::Private attached = false; suspended = false; identified = false; + useYield = 0; DFSVMutex = 0; DFCLMutex = 0; }; @@ -52,13 +54,22 @@ class Process::Private bool attached; bool suspended; bool identified; + bool useYield; bool waitWhile (CORE_COMMAND state); bool isValidSV(); bool DF_TestBridgeVersion(bool & ret); bool DF_GetPID(uint32_t & ret); + void DF_SyncAffinity(void); }; +// some helpful macros to keep the code bloat in check +#define SHMCMD ((shm_cmd *)my_shm)->pingpong +#define D_SHMCMD ((shm_cmd *)d->my_shm)->pingpong + +#define SHMHDR ((shm_core_hdr *)my_shm) +#define D_SHMHDR ((shm_core_hdr *)d->my_shm) + // is the other side still there? bool Process::Private::isValidSV() { @@ -90,14 +101,17 @@ bool Process::Private::isValidSV() bool Process::Private::waitWhile (CORE_COMMAND state) { uint32_t cnt = 0; - SCHED_YIELD // yield the CPU, valid only on single-core CPUs while (((shm_cmd *)my_shm)->pingpong == state) { + // yield the CPU, only on single-core CPUs + if(useYield) + { + SCHED_YIELD + } if(cnt == 10000) { if(!isValidSV())// DF not there anymore? { - full_barrier ((shm_cmd *)my_shm)->pingpong = CORE_RUNNING; attached = suspended = false; ReleaseMutex(DFCLMutex); @@ -115,7 +129,6 @@ bool Process::Private::waitWhile (CORE_COMMAND state) ((shm_cmd *)my_shm)->pingpong = CORE_RUNNING; attached = suspended = false; cerr << "shm server error!" << endl; - assert (false); return false; } return true; @@ -145,6 +158,34 @@ bool Process::Private::DF_GetPID(uint32_t & ret) return true; } +void Process::Private::DF_SyncAffinity(void) +{ + +} + +uint32_t OS_getAffinity() +{ + HANDLE hProcess = GetCurrentProcess(); + DWORD dwProcessAffinityMask, dwSystemAffinityMask; + GetProcessAffinityMask( hProcess, &dwProcessAffinityMask, &dwSystemAffinityMask ); + return dwProcessAffinityMask; +} + +void Process::Private::DF_SyncAffinity( void ) +{ + SHMHDR->value = OS_getAffinity(); + full_barrier + SHMCMD = CORE_SYNC_YIELD; + full_barrier + if(!waitWhile(CORE_SYNC_YIELD)) + return; + full_barrier + SHMCMD = CORE_SUSPENDED; + useYield = SHMHDR->value; + if(useYield) cerr << "Using Yield!" << endl; +} + + Process::Process(vector & known_versions) : d(new Private()) { @@ -255,12 +296,13 @@ Process::Process(vector & known_versions) if(d->identified) { d->my_window = new DFWindow(this); + d->DF_SyncAffinity(); } else { ((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING; UnmapViewOfFile(d->my_shm); - d->my_shm = 0; + d->my_shm = 0; ReleaseMutex(d->DFCLMutex); CloseHandle(d->DFSVMutex); d->DFSVMutex = 0; diff --git a/shmserver/shms-core.cpp b/shmserver/shms-core.cpp index 308a9e0db..3a20a2439 100644 --- a/shmserver/shms-core.cpp +++ b/shmserver/shms-core.cpp @@ -33,50 +33,7 @@ distribution. #include #include #include "shms.h" - -enum DFPP_CmdType -{ - CANCELLATION, // we should jump out of the Act() - CLIENT_WAIT, // we are waiting for the client - FUNCTION, // we call a function as a result of the command -}; - -struct DFPP_command -{ - DFPP_CmdType type:32; // force the enum to 32 bits for compatibility reasons - std::string name; - void (*_function)(void); -}; - -struct DFPP_module -{ - inline void push_command(DFPP_CmdType type, const char * name, void (*_function)(void)) - { - DFPP_command cmd; - cmd.type = type; - cmd.name = name; - cmd._function = _function; - commands.push_back(cmd); - } - inline void set_command(unsigned int index, DFPP_CmdType type, const char * name, void (*_function)(void)) - { - DFPP_command cmd; - cmd.type = type; - cmd.name = name; - cmd._function = _function; - commands[index] = cmd; - } - inline void reserve (unsigned int numcommands) - { - commands.clear(); - DFPP_command cmd = {CANCELLATION,"",0}; - commands.resize(numcommands,cmd); - } - std::string name; - uint32_t version; // version - std::vector commands; - void * modulestate; -}; +#include "shms-core.h" std::vector module_registry; @@ -84,78 +41,59 @@ std::vector module_registry; extern int errorstate; extern char *shm; extern int shmid; +bool useYield = 0; -#define SHMHDR ((shm_header *)shm) +#define SHMHDR ((shm_core_hdr *)shm) #define SHMCMD ((shm_cmd *)shm)->pingpong void GetCoreVersion (void) { SHMHDR->value = module_registry[0].version; - full_barrier - SHMCMD = CORE_RET_VERSION; } void GetPID (void) { SHMHDR->value = OS_getPID(); - full_barrier - SHMCMD = CORE_RET_PID; } void ReadRaw (void) { memcpy(shm + SHM_HEADER, (void *) SHMHDR->address,SHMHDR->length); - full_barrier - SHMCMD = CORE_RET_DATA; } void ReadDWord (void) { SHMHDR->value = *((uint32_t*) SHMHDR->address); - full_barrier - SHMCMD = CORE_RET_DWORD; } void ReadWord (void) { SHMHDR->value = *((uint16_t*) SHMHDR->address); - full_barrier - SHMCMD = CORE_RET_WORD; } void ReadByte (void) { SHMHDR->value = *((uint8_t*) SHMHDR->address); - full_barrier - SHMCMD = CORE_RET_BYTE; } void WriteRaw (void) { memcpy((void *)SHMHDR->address, shm + SHM_HEADER,SHMHDR->length); - full_barrier - SHMCMD = CORE_SUSPENDED; } void WriteDWord (void) { (*(uint32_t*)SHMHDR->address) = SHMHDR->value; - full_barrier - SHMCMD = CORE_SUSPENDED; } void WriteWord (void) { (*(uint16_t*)SHMHDR->address) = SHMHDR->value; - full_barrier - SHMCMD = CORE_SUSPENDED; } void WriteByte (void) { (*(uint8_t*)SHMHDR->address) = SHMHDR->value; - full_barrier - SHMCMD = CORE_SUSPENDED; } void ReadSTLString (void) @@ -163,10 +101,8 @@ void ReadSTLString (void) std::string * myStringPtr = (std::string *) SHMHDR->address; unsigned int l = myStringPtr->length(); SHMHDR->value = l; - // there doesn't have to be a null terminator! + // FIXME: there doesn't have to be a null terminator! strncpy(shm+SHM_HEADER,myStringPtr->c_str(),l+1); - full_barrier - SHMCMD = CORE_RET_STRING; } void WriteSTLString (void) @@ -174,13 +110,31 @@ void WriteSTLString (void) std::string * myStringPtr = (std::string *) SHMHDR->address; // here we DO expect a 0 terminator myStringPtr->assign((const char *) (shm + SHM_HEADER)); - full_barrier - SHMCMD = CORE_SUSPENDED; } -void Suspend (void) +// MIT HAKMEM bitcount +int bitcount(uint32_t n) { - SHMCMD = CORE_SUSPENDED; + register uint32_t tmp; + + tmp = n - ((n >> 1) & 033333333333) - ((n >> 2) & 011111111111); + return ((tmp + (tmp >> 3)) & 030707070707) % 63; +} + +// get local and remote affinity, set up yield if required (single core available) +void SyncYield (void) +{ + uint32_t local = OS_getAffinity(); + uint32_t remote = SHMHDR->value; + uint32_t pool = local | remote; + if(bitcount(pool) == 1) + { + SHMHDR->value = useYield = 1; + } + else + { + SHMHDR->value = useYield = 0; + } } void InitCore(void) @@ -191,41 +145,42 @@ void InitCore(void) core.modulestate = 0; // this one is dumb and has no real state core.reserve(NUM_CORE_CMDS); - core.set_command(CORE_RUNNING, CANCELLATION, "Running", NULL); + core.set_command(CORE_RUNNING, CANCELLATION, "Running"); - core.set_command(CORE_GET_VERSION, FUNCTION,"Get core version",GetCoreVersion); - core.set_command(CORE_RET_VERSION, CLIENT_WAIT,"Core version return",0); + core.set_command(CORE_GET_VERSION, FUNCTION,"Get core version",GetCoreVersion, CORE_RET_VERSION); + core.set_command(CORE_RET_VERSION, CLIENT_WAIT,"Core version return"); - core.set_command(CORE_GET_PID, FUNCTION, "Get PID", GetPID); - core.set_command(CORE_RET_PID, CLIENT_WAIT, "PID return", 0); + core.set_command(CORE_GET_PID, FUNCTION, "Get PID", GetPID, CORE_RET_PID); + core.set_command(CORE_RET_PID, CLIENT_WAIT, "PID return"); - core.set_command(CORE_DFPP_READ, FUNCTION,"Raw read",ReadRaw); - core.set_command(CORE_RET_DATA, CLIENT_WAIT,"Raw read return",0); + core.set_command(CORE_DFPP_READ, FUNCTION,"Raw read",ReadRaw, CORE_RET_DATA); + core.set_command(CORE_RET_DATA, CLIENT_WAIT,"Raw read return"); - core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord); - core.set_command(CORE_RET_DWORD, CLIENT_WAIT,"Read DWORD return",0); + core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord, CORE_RET_DWORD); + core.set_command(CORE_RET_DWORD, CLIENT_WAIT,"Read DWORD return"); - core.set_command(CORE_READ_WORD, FUNCTION,"Read WORD",ReadWord); - core.set_command(CORE_RET_WORD, CLIENT_WAIT,"Read WORD return",0); + core.set_command(CORE_READ_WORD, FUNCTION,"Read WORD",ReadWord, CORE_RET_WORD); + core.set_command(CORE_RET_WORD, CLIENT_WAIT,"Read WORD return"); - core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte); - core.set_command(CORE_RET_BYTE, CLIENT_WAIT,"Read BYTE return",0); + core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte, CORE_RET_BYTE); + core.set_command(CORE_RET_BYTE, CLIENT_WAIT,"Read BYTE return"); - core.set_command(CORE_SV_ERROR, CANCELLATION, "Server error", 0); - core.set_command(CORE_CL_ERROR, CANCELLATION, "Client error", 0); + core.set_command(CORE_SV_ERROR, CANCELLATION, "Server error"); + core.set_command(CORE_CL_ERROR, CANCELLATION, "Client error"); - core.set_command(CORE_WRITE, FUNCTION, "Raw write", WriteRaw); - core.set_command(CORE_WRITE_DWORD, FUNCTION, "Write DWORD", WriteDWord); - core.set_command(CORE_WRITE_WORD, FUNCTION, "Write WORD", WriteWord); - core.set_command(CORE_WRITE_BYTE, FUNCTION, "Write BYTE", WriteByte); + core.set_command(CORE_WRITE, FUNCTION, "Raw write", WriteRaw, CORE_SUSPENDED); + core.set_command(CORE_WRITE_DWORD, FUNCTION, "Write DWORD", WriteDWord, CORE_SUSPENDED); + core.set_command(CORE_WRITE_WORD, FUNCTION, "Write WORD", WriteWord, CORE_SUSPENDED); + core.set_command(CORE_WRITE_BYTE, FUNCTION, "Write BYTE", WriteByte, CORE_SUSPENDED); - core.set_command(CORE_SUSPEND, FUNCTION, "Suspend", Suspend); - core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended", 0); + core.set_command(CORE_SUSPEND, CLIENT_WAIT, "Suspend", 0 , CORE_SUSPENDED); + core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended"); - core.set_command(CORE_READ_STL_STRING, FUNCTION, "Read STL string", ReadSTLString); - core.set_command(CORE_READ_C_STRING, CLIENT_WAIT, "RESERVED", 0); - core.set_command(CORE_RET_STRING, CLIENT_WAIT, "Return string", 0); - core.set_command(CORE_WRITE_STL_STRING, FUNCTION, "Write STL string", WriteSTLString); + core.set_command(CORE_READ_STL_STRING, FUNCTION, "Read STL string", ReadSTLString, CORE_RET_STRING); + core.set_command(CORE_READ_C_STRING, CLIENT_WAIT, "RESERVED"); + core.set_command(CORE_RET_STRING, CLIENT_WAIT, "Return string"); + core.set_command(CORE_WRITE_STL_STRING, FUNCTION, "Write STL string", WriteSTLString, CORE_SUSPENDED); + core.set_command(CORE_SYNC_YIELD, FUNCTION, "Synchronize affinity/yield", SyncYield, CORE_SYNC_YIELD_RET); module_registry.push_back(core); } @@ -233,6 +188,7 @@ void InitModules (void) { // create the core module InitCore(); + // TODO: dynamic module init } void SHM_Act (void) @@ -252,7 +208,7 @@ void SHM_Act (void) } else { - full_barrier + // full_barrier SHMCMD = CORE_RUNNING; fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n"); } @@ -264,9 +220,16 @@ void SHM_Act (void) { cmd._function(); } + if(cmd.nextState != -1) + { + SHMCMD = cmd.nextState; + } if(cmd.type != CANCELLATION) { - SCHED_YIELD + if(useYield) + { + SCHED_YIELD + } numwaits ++; // watchdog timeout goto check_again; } diff --git a/shmserver/shms-linux.cpp b/shmserver/shms-linux.cpp index 59b2ea120..9fa02595d 100644 --- a/shmserver/shms-linux.cpp +++ b/shmserver/shms-linux.cpp @@ -37,11 +37,8 @@ distribution. #include #include #include "shms.h" -#include -#include -#include -#include -#include +#include "shms-core.h" +#include #define DFhackCExport extern "C" __attribute__ ((visibility("default"))) @@ -69,6 +66,15 @@ uint32_t OS_getPID() return getpid(); } +uint32_t OS_getAffinity() +{ + cpu_set_t mask; + sched_getaffinity(0,sizeof(cpu_set_t),&mask); + // FIXME: truncation + uint32_t affinity = *(uint32_t *) &mask; + return affinity; +} + void SHM_Init ( void ) { // check that we do this only once per process diff --git a/shmserver/shms.h b/shmserver/shms.h index f80a6a6c1..5eb0db961 100644 --- a/shmserver/shms.h +++ b/shmserver/shms.h @@ -1,7 +1,6 @@ #ifndef DFCONNECT_H #define DFCONNECT_H -#define CORE_VERSION 3 #define SHM_KEY 123466 #define SHM_HEADER 1024 // 1kB reserved for a header #define SHM_BODY 1024*1024 // 1MB reserved for bulk data transfer @@ -12,16 +11,14 @@ #ifdef LINUX_BUILD // a full memory barrier! better be safe than sorry. #define full_barrier asm volatile("" ::: "memory"); __sync_synchronize(); - #define SCHED_YIELD sched_yield(); // slow but allows the SHM to work on single-core - // #define SCHED_YIELD usleep(0); // extremely slow - // #define SCHED_YIELD // works only on multi-core + #define SCHED_YIELD sched_yield(); // a requirement for single-core #else // we need windows.h for Sleep() #define _WIN32_WINNT 0x0501 // needed for INPUT struct #define WINVER 0x0501 // OpenThread(), PSAPI, Toolhelp32 #define WIN32_LEAN_AND_MEAN #include - #define SCHED_YIELD Sleep(0); // slow on single-core, but avoids infinite lockup + #define SCHED_YIELD Sleep(0); // avoids infinite lockup on single core // FIXME: detect MSVC here and use the right barrier magic #ifdef __MINGW32__ #define full_barrier asm volatile("" ::: "memory"); @@ -32,66 +29,40 @@ #endif #endif -enum DF_SHM_ERRORSTATE +enum DFPP_CmdType { - SHM_OK, // all OK - SHM_CANT_GET_SHM, // getting the SHM ID failed for some reason - SHM_CANT_ATTACH, // we can't attach the shm for some reason - SHM_SECOND_DF // we are a second DF process, can't use SHM at all + CANCELLATION, // we should jump out of the Act() + CLIENT_WAIT, // we are waiting for the client + FUNCTION, // we call a function as a result of the command }; -enum CORE_COMMAND +struct DFPP_command { - CORE_RUNNING = 0, // no command, normal server execution - - CORE_GET_VERSION, // protocol version query - CORE_RET_VERSION, // return the protocol version - - CORE_GET_PID, // query for the process ID - CORE_RET_PID, // return process ID - - // version 1 stuff below - CORE_DFPP_READ, // cl -> sv, read some data - CORE_RET_DATA, // sv -> cl, returned data - - CORE_READ_DWORD, // cl -> sv, read a dword - CORE_RET_DWORD, // sv -> cl, returned dword - - CORE_READ_WORD, // cl -> sv, read a word - CORE_RET_WORD, // sv -> cl, returned word - - CORE_READ_BYTE, // cl -> sv, read a byte - CORE_RET_BYTE, // sv -> cl, returned byte - - CORE_SV_ERROR, // there was a server error - CORE_CL_ERROR, // there was a client error - - CORE_WRITE,// client writes to server - CORE_WRITE_DWORD,// client writes a DWORD to server - CORE_WRITE_WORD,// client writes a WORD to server - CORE_WRITE_BYTE,// client writes a BYTE to server - - CORE_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait) - CORE_SUSPENDED, // response to WAIT, server is stalled in busy wait - - // all strings capped at 1MB - CORE_READ_STL_STRING,// client requests contents of STL string at address - CORE_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated) - CORE_RET_STRING, // sv -> cl length + string contents - CORE_WRITE_STL_STRING,// client wants to set STL string at address to something - - // compare affinity and determine if using yield is required - CORE_SYNC_YIELD,// cl sends affinity to sv, sv sets yield - CORE_SYNC_YIELD_RET,// sv returns yield bool - - NUM_CORE_CMDS + void (*_function)(void); + DFPP_CmdType type:32; // force the enum to 32 bits for compatibility reasons + std::string name; + uint32_t nextState; }; - -enum DF_ERROR +struct DFPP_module { - DFEE_INVALID_COMMAND, - DFEE_BUFFER_OVERFLOW + inline void set_command(const unsigned int index, const DFPP_CmdType type, const char * name, void (*_function)(void) = 0,uint32_t nextState = -1) + { + commands[index].type = type; + commands[index].name = name; + commands[index]._function = _function; + commands[index].nextState = nextState; + } + inline void reserve (unsigned int numcommands) + { + commands.clear(); + DFPP_command cmd = {0,CANCELLATION,"",0}; + commands.resize(numcommands,cmd); + } + std::string name; + uint32_t version; // version + std::vector commands; + void * modulestate; }; typedef union @@ -108,17 +79,10 @@ typedef union } } shm_cmd; -typedef struct -{ - shm_cmd cmd; - uint32_t address; - uint32_t value; - uint32_t length; -} shm_header; - void SHM_Act (void); void InitModules (void); bool isValidSHM(); uint32_t OS_getPID(); +uint32_t OS_getAffinity(); // limited to 32 processors. Silly, eh? #endif From d06fd70789809235519f72ec6613586f68830239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 4 Mar 2010 18:35:26 +0100 Subject: [PATCH 04/16] Missing file + some new --- shmserver/mod-maps.cpp | 114 +++++++++++++++++++++++++++++++++++++++++ shmserver/mod-maps.h | 99 +++++++++++++++++++++++++++++++++++ shmserver/shms-core.h | 96 ++++++++++++++++++++++++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 shmserver/mod-maps.cpp create mode 100644 shmserver/mod-maps.h create mode 100644 shmserver/shms-core.h diff --git a/shmserver/mod-maps.cpp b/shmserver/mod-maps.cpp new file mode 100644 index 000000000..a6cfc0fe1 --- /dev/null +++ b/shmserver/mod-maps.cpp @@ -0,0 +1,114 @@ +#include +#include +#include + +#include "shms.h" +#include "shms-core.h" +#include "mod-maps.h" +#include +using namespace DFHack; +using namespace DFHack::Maps; + +#include +#include +#include + +extern char *shm; + +//TODO: circular buffer streaming primitives required +//TODO: commands can fail without the proper offsets. Hot to handle that? + +#define SHMHDR ((shm_maps_hdr *)shm) +#define SHMCMD ((shm_cmd *)shm)->pingpong +#define SHMDATA ((char *)(shm + SHM_HEADER)) + +void NullCommand (void* data) +{ +}; + +void InitOffsets (void* data) +{ + maps_modulestate * state = (maps_modulestate *) data; + memcpy((void *) &(state->offsets), SHMDATA, sizeof(maps_offsets)); + ((maps_modulestate *) data)->inited = true; +} + +void GetMapSize (void *data) +{ + maps_modulestate * state = (maps_modulestate *) data; + if(state->inited) + { + SHMHDR->x = *((uint32_t *)state->offsets.x_count_offset); + SHMHDR->y = *((uint32_t *)state->offsets.y_count_offset); + SHMHDR->z = *((uint32_t *)state->offsets.z_count_offset); + SHMHDR->error = false; + } + else + { + SHMHDR->error = true; + } +} + +struct mblock +{ + uint32_t * ptr_to_dirty; +}; + +#define SHMBLOCK ((mapblock40d *)(shm + SHM_HEADER)) + +void ReadBlockByCoords (void * data) +{ + maps_modulestate * state = (maps_modulestate *) data; + maps_offsets & offsets = state->offsets; + /* map_offset is a pointer to + a pointer to + an X block of pointers to + an Y blocks of pointers to + a Z blocks of pointers to + map blocks + only Z blocks can have NULL pointers? TODO: verify + */ + mblock * *** mapArray = *(mblock * ****)offsets.map_offset; + mblock * block = mapArray[SHMHDR->x][SHMHDR->y][SHMHDR->z]; + fprintf(stderr, "Readblock: %d %d %d 0x%x\n", SHMHDR->x,SHMHDR->y,SHMHDR->z, block); + if(block) + { + memcpy(&(SHMBLOCK->tiletypes), block + offsets.tile_type_offset, sizeof(SHMBLOCK->tiletypes)); + memcpy(&(SHMBLOCK->designaton), block + offsets.designation_offset, sizeof(SHMBLOCK->designaton)); + memcpy(&(SHMBLOCK->occupancy), block + offsets.occupancy_offset, sizeof(SHMBLOCK->occupancy)); + memcpy(&(SHMBLOCK->biome_indices), block + offsets.biome_stuffs, sizeof(SHMBLOCK->biome_indices)); + SHMBLOCK->dirty_dword = *block->ptr_to_dirty; + SHMHDR->error = false; + } + else + { + SHMHDR->error = true; + } +} + +DFPP_module InitMaps(void) +{ + DFPP_module maps; + maps.name = "Maps"; + maps.version = MAPS_VERSION; + // freed by the core + maps.modulestate = malloc(sizeof(maps_modulestate)); // we store a flag + memset(maps.modulestate,0,sizeof(maps_modulestate)); + + maps.reserve(NUM_MAPS_CMDS); + + // client sends a maps_offsets struct -> inited = true; + maps.set_command(MAP_INIT, FUNCTION, "Supply the module with offsets",InitOffsets,CORE_SUSPENDED); + maps.set_command(MAP_GET_SIZE, FUNCTION, "Get map size in 16x16x1 tile blocks", GetMapSize, CORE_SUSPENDED); + maps.set_command(MAP_READ_BLOCK_BY_COORDS, FUNCTION, "Read the whole block with specified coords", ReadBlockByCoords, CORE_SUSPENDED); + + // will it fit into 1MB? We shouldn't assume this is the case + maps.set_command(MAP_READ_BLOCKTREE, FUNCTION,"Get the tree of block pointers as a single structure", NullCommand, CORE_SUSPENDED); + + + + // really doesn't fit into 1MB, there should be a streaming variant to better utilize context switches + maps.set_command(MAP_READ_BLOCKS_3D, FUNCTION, "Read a range of blocks between two sets of coords", NullCommand, CORE_SUSPENDED); + + return maps; +} \ No newline at end of file diff --git a/shmserver/mod-maps.h b/shmserver/mod-maps.h new file mode 100644 index 000000000..34e6889a1 --- /dev/null +++ b/shmserver/mod-maps.h @@ -0,0 +1,99 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix) + +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 MOD_MAPS_H +#define MOD_MAPS_H + +// increment on every change +#include + +namespace DFHack +{ + namespace Maps + { + +#define MAPS_VERSION 1 +typedef struct +{ + uint32_t map_offset;// = d->offset_descriptor->getAddress ("map_data"); + uint32_t x_count_offset;// = d->offset_descriptor->getAddress ("x_count"); + uint32_t y_count_offset;// = d->offset_descriptor->getAddress ("y_count"); + uint32_t z_count_offset;// = d->offset_descriptor->getAddress ("z_count"); + uint32_t tile_type_offset;// = d->offset_descriptor->getOffset ("type"); + uint32_t designation_offset;// = d->offset_descriptor->getOffset ("designation"); + uint32_t occupancy_offset;// = d->offset_descriptor->getOffset ("occupancy"); + uint32_t biome_stuffs;// = d->offset_descriptor->getOffset ("biome_stuffs"); + uint32_t veinvector;// = d->offset_descriptor->getOffset ("v_vein"); + uint32_t vein_mineral_vptr; + uint32_t vein_ice_vptr; + /* + GEOLOGY + uint32_t region_x_offset;// = minfo->getAddress ("region_x"); + uint32_t region_y_offset;// = minfo->getAddress ("region_y"); + uint32_t region_z_offset;// = minfo->getAddress ("region_z"); + uint32_t world_offset;// = minfo->getAddress ("world"); + uint32_t world_regions_offset;// = minfo->getOffset ("w_regions_arr"); + uint32_t region_size;// = minfo->getHexValue ("region_size"); + uint32_t region_geo_index_offset;// = minfo->getOffset ("region_geo_index_off"); + uint32_t world_geoblocks_offset;// = minfo->getOffset ("w_geoblocks"); + uint32_t world_size_x;// = minfo->getOffset ("world_size_x"); + uint32_t world_size_y;// = minfo->getOffset ("world_size_y"); + uint32_t geolayer_geoblock_offset;// = minfo->getOffset ("geolayer_geoblock_offset"); + */ +} maps_offsets; + +typedef struct +{ + bool inited; + maps_offsets offsets; +} maps_modulestate; + +typedef struct +{ + shm_cmd cmd; + uint32_t x; + uint32_t y; + uint32_t z; + uint32_t x2; + uint32_t y2; + uint32_t z2; + uint32_t address; + uint32_t error; +} shm_maps_hdr; + +enum MAPS_COMMAND +{ + MAP_INIT = 0, // initialization + MAP_PROBE, // check if the map is still there + MAP_GET_SIZE, // get the map size in 16x16x1 blocks + MAP_READ_BLOCKTREE, // read the structure of pointers to blocks + MAP_READ_BLOCK_BY_COORDS, // read block by cords + MAP_READ_BLOCKS_3D, // read blocks between two coords (volumetric) + MAP_READ_ALL_BLOCKS, // read the entire map + NUM_MAPS_CMDS, +}; + } +} + +#endif \ No newline at end of file diff --git a/shmserver/shms-core.h b/shmserver/shms-core.h new file mode 100644 index 000000000..be407691c --- /dev/null +++ b/shmserver/shms-core.h @@ -0,0 +1,96 @@ +/* +www.sourceforge.net/projects/dfhack +Copyright (c) 2009 Petr Mrázek (peterix) + +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 SHMS_CORE_H +#define SHMS_CORE_H + +// increment on every core change +#define CORE_VERSION 6 + +typedef struct +{ + shm_cmd cmd; + uint32_t address; + uint32_t value; + uint32_t length; + uint32_t error; +} shm_core_hdr; + +typedef struct +{ + uint32_t version; + char name[256]; +} modulelookup; + +enum CORE_COMMAND +{ + CORE_RUNNING = 0, // no command, normal server execution + + CORE_GET_VERSION, // protocol version query + CORE_RET_VERSION, // return the protocol version + + CORE_GET_PID, // query for the process ID + CORE_RET_PID, // return process ID + + // version 1 stuff below + CORE_DFPP_READ, // cl -> sv, read some data + CORE_RET_DATA, // sv -> cl, returned data + + CORE_READ_DWORD, // cl -> sv, read a dword + CORE_RET_DWORD, // sv -> cl, returned dword + + CORE_READ_WORD, // cl -> sv, read a word + CORE_RET_WORD, // sv -> cl, returned word + + CORE_READ_BYTE, // cl -> sv, read a byte + CORE_RET_BYTE, // sv -> cl, returned byte + + CORE_SV_ERROR, // there was a server error + CORE_CL_ERROR, // there was a client error + + CORE_WRITE,// client writes to server + CORE_WRITE_DWORD,// client writes a DWORD to server + CORE_WRITE_WORD,// client writes a WORD to server + CORE_WRITE_BYTE,// client writes a BYTE to server + + CORE_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait) + CORE_SUSPENDED, // response to WAIT, server is stalled in busy wait + + // all strings capped at 1MB + CORE_READ_STL_STRING,// client requests contents of STL string at address + CORE_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated) + CORE_RET_STRING, // sv -> cl length + string contents + CORE_WRITE_STL_STRING,// client wants to set STL string at address to something + + // compare affinity and determine if using yield is required + CORE_SYNC_YIELD,// cl sends affinity to sv, sv sets yield + CORE_SYNC_YIELD_RET,// sv returns yield bool + + // get index of a loaded module by name and version + CORE_ACQUIRE_MODULE, + // returning module index + CORE_RET_MODULE, + NUM_CORE_CMDS +}; +#endif \ No newline at end of file From 088028cc5f0ce7ee27b4fad1b41065261259b7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 4 Mar 2010 18:46:37 +0100 Subject: [PATCH 05/16] Small change --- shmserver/mod-maps.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shmserver/mod-maps.cpp b/shmserver/mod-maps.cpp index a6cfc0fe1..54700101a 100644 --- a/shmserver/mod-maps.cpp +++ b/shmserver/mod-maps.cpp @@ -11,7 +11,6 @@ using namespace DFHack::Maps; #include #include -#include extern char *shm; @@ -38,9 +37,9 @@ void GetMapSize (void *data) maps_modulestate * state = (maps_modulestate *) data; if(state->inited) { - SHMHDR->x = *((uint32_t *)state->offsets.x_count_offset); - SHMHDR->y = *((uint32_t *)state->offsets.y_count_offset); - SHMHDR->z = *((uint32_t *)state->offsets.z_count_offset); + SHMHDR->x = *(uint32_t *) (state->offsets.x_count_offset); + SHMHDR->y = *(uint32_t *) (state->offsets.y_count_offset); + SHMHDR->z = *(uint32_t *) (state->offsets.z_count_offset); SHMHDR->error = false; } else @@ -86,7 +85,7 @@ void ReadBlockByCoords (void * data) } } -DFPP_module InitMaps(void) +DFPP_module InitMaps(std::vector * module_registry) { DFPP_module maps; maps.name = "Maps"; @@ -110,5 +109,5 @@ DFPP_module InitMaps(void) // really doesn't fit into 1MB, there should be a streaming variant to better utilize context switches maps.set_command(MAP_READ_BLOCKS_3D, FUNCTION, "Read a range of blocks between two sets of coords", NullCommand, CORE_SUSPENDED); - return maps; + module_registry->push_back(maps); } \ No newline at end of file From c86464502cd0ceb44b9a8b0364b8b97abe4bf7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 5 Mar 2010 00:05:01 +0100 Subject: [PATCH 06/16] SHM rework, stage 2 --- examples/expbench.cpp | 10 +- examples/veinlook.cpp | 26 ++-- library/DFHackAPI.cpp | 88 +++++++++++- library/DFHackAPI.h | 2 + library/DFProcess-linux-SHM.cpp | 102 +++++++++++--- library/DFProcess-windows-SHM.cpp | 161 ++++++++++++---------- library/DFProcess.h | 6 + library/DFTypes.h | 9 ++ shmserver/CMakeLists.txt | 5 +- shmserver/{shms-core.cpp => mod-core.cpp} | 85 +++++++++--- shmserver/{shms-core.h => mod-core.h} | 0 shmserver/mod-maps.cpp | 12 +- shmserver/shms-linux.cpp | 3 +- shmserver/shms-windows.cpp | 13 ++ shmserver/shms.h | 20 ++- 15 files changed, 396 insertions(+), 146 deletions(-) rename shmserver/{shms-core.cpp => mod-core.cpp} (76%) rename shmserver/{shms-core.h => mod-core.h} (100%) diff --git a/examples/expbench.cpp b/examples/expbench.cpp index c2b7621d9..272e46021 100644 --- a/examples/expbench.cpp +++ b/examples/expbench.cpp @@ -47,9 +47,7 @@ int main (int numargs, char** args) uint32_t x_max,y_max,z_max; uint32_t num_blocks = 0; uint64_t bytes_read = 0; - uint16_t tiletypes[16][16]; - DFHack::t_designation designations[16][16]; - DFHack::t_occupancy occupancies[16][16]; + DFHack::mapblock40d Block; DFHack::API DF("Memory.xml"); if(!DF.Attach()) @@ -76,11 +74,9 @@ int main (int numargs, char** args) { if(DF.isValidBlock(x,y,z)) { - DF.ReadTileTypes(x,y,z, (uint16_t *) tiletypes); - DF.ReadDesignations(x,y,z, (uint32_t *) designations); - DF.ReadOccupancy(x,y,z, (uint32_t *) occupancies); + DF.ReadBlock40d(x, y, z, &Block); num_blocks ++; - bytes_read += sizeof(tiletypes) + sizeof(designations) + sizeof(occupancies); + bytes_read += sizeof(DFHack::mapblock40d); } } } diff --git a/examples/veinlook.cpp b/examples/veinlook.cpp index e26aa2950..5d1e7bbda 100644 --- a/examples/veinlook.cpp +++ b/examples/veinlook.cpp @@ -144,8 +144,6 @@ void clrscr() GRASS2, GRASS_DEAD, GRASS_DRY, -#include -#include DRIFTWOOD, HFS, MAGMA, @@ -272,9 +270,12 @@ main(int argc, char *argv[]) int x_max,y_max,z_max; uint32_t x_max_a,y_max_a,z_max_a; + /* uint16_t tiletypes[16][16]; DFHack::t_designation designations[16][16]; uint8_t regionoffsets[16]; + */ + mapblock40d Block; map materials; materials.clear(); vector stonetypes; @@ -300,7 +301,6 @@ main(int argc, char *argv[]) error = "Can't find a map to look at."; pDF = 0; finish(0); -#include } DF.getSize(x_max_a,y_max_a,z_max_a); @@ -401,30 +401,34 @@ main(int argc, char *argv[]) if(DF.isValidBlock(cursorX+i,cursorY+j,cursorZ)) { // read data + DF.ReadBlock40d(cursorX+i,cursorY+j,cursorZ, &Block); + /* DF.ReadTileTypes(cursorX+i,cursorY+j,cursorZ, (uint16_t *) tiletypes); DF.ReadDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) designations); + */ for(int x = 0; x < 16; x++) { for(int y = 0; y < 16; y++) { if(dig) { - if(tileTypeTable[tiletypes[x][y]].c == WALL && tileTypeTable[tiletypes[x][y]].m == VEIN - || tileTypeTable[tiletypes[x][y]].c == TREE_OK || tileTypeTable[tiletypes[x][y]].c == TREE_DEAD) + TileClass tc = tileTypeTable[Block.tiletypes[x][y]].c; + TileMaterial tm = tileTypeTable[Block.tiletypes[x][y]].m; + if( tc == WALL && tm == VEIN || tc == TREE_OK || tc == TREE_DEAD) { - designations[x][y].bits.dig = designation_default; + Block.designaton[x][y].bits.dig = designation_default; } } int color = COLOR_BLACK; - color = pickColor(tiletypes[x][y]); - if(designations[x][y].bits.hidden) + color = pickColor(Block.tiletypes[x][y]); + if(Block.designaton[x][y].bits.hidden) { - puttile(x+(i+1)*16,y+(j+1)*16,tiletypes[x][y], color); + puttile(x+(i+1)*16,y+(j+1)*16,Block.tiletypes[x][y], color); } else { attron(A_STANDOUT); - puttile(x+(i+1)*16,y+(j+1)*16,tiletypes[x][y], color); + puttile(x+(i+1)*16,y+(j+1)*16,Block.tiletypes[x][y], color); attroff(A_STANDOUT); } } @@ -439,7 +443,7 @@ main(int argc, char *argv[]) filenum++; } if(dig) - DF.WriteDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) designations); + DF.WriteDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) Block.designaton); DF.ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit); if(digbit) { diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index 9c732fe26..0dc311609 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -23,6 +23,9 @@ distribution. */ #include "DFCommonInternal.h" +#include "../shmserver/shms.h" +#include "../shmserver/mod-core.h" +#include "../shmserver/mod-maps.h" using namespace DFHack; /* @@ -106,6 +109,7 @@ public: ProcessEnumerator* pm; Process* p; + char * shm_start; memory_info* offset_descriptor; vector v_geology[eBiomeCount]; string xml; @@ -121,6 +125,8 @@ public: bool hotkeyInited; bool settlementsInited; bool nameTablesInited; + + uint32_t maps_module; uint32_t tree_offset; DfVector *p_cre; @@ -149,6 +155,8 @@ API::API (const string path_to_xml) d->notesInited = false; d->hotkeyInited = false; d->pm = NULL; + d->shm_start = 0; + d->maps_module = 0; } API::~API() @@ -156,6 +164,11 @@ API::~API() delete d; } +#define SHMCMD ((shm_cmd *)d->shm_start)->pingpong +#define SHMHDR ((shm_core_hdr *)d->shm_start) +#define SHMMAPSHDR ((Maps::shm_maps_hdr *)d->shm_start) +#define SHMDATA(type) ((type *)(d->shm_start + SHM_HEADER)) + /*-----------------------------------* * Init the mapblock pointer array * *-----------------------------------*/ @@ -181,19 +194,43 @@ bool API::InitMap() d->offset_descriptor->resolveClassnameToVPtr("block_square_event_frozen_liquid", d->vein_ice_vptr); d->vein_mineral_vptr = 0; d->offset_descriptor->resolveClassnameToVPtr("block_square_event_mineral",d->vein_mineral_vptr); - + + /* + * --> SHM initialization (if possible) <-- + */ + g_pProcess->getModuleIndex("Maps",1,d->maps_module); + + if(d->maps_module) + { + // supply the module with offsets so it can work with them + Maps::maps_offsets *off = SHMDATA(Maps::maps_offsets); + off->biome_stuffs = d->biome_stuffs; + off->designation_offset = d->designation_offset; + off->map_offset = map_offset; + off->occupancy_offset = d->occupancy_offset; + off->tile_type_offset = d->tile_type_offset; + off->vein_ice_vptr = d->vein_ice_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_< + off->vein_mineral_vptr = d->vein_mineral_vptr; // FIXME: not necessarily true, the shm server side needs a class lookup >_< + off->veinvector = d->veinvector; + off->x_count_offset = x_count_offset; + off->y_count_offset = y_count_offset; + off->z_count_offset = z_count_offset; + full_barrier + const uint32_t cmd = Maps::MAP_INIT + d->maps_module << 16; + SHMCMD = cmd; + g_pProcess->waitWhile(cmd); + //cerr << "Map acceleration enabled!" << endl; + } + // get the map pointer uint32_t x_array_loc = g_pProcess->readDWord (map_offset); - //FIXME: very inadequate if (!x_array_loc) { throw Error::NoMapLoaded(); - // bad stuffz happend - //return false; } - uint32_t mx, my, mz; - + // get the size + uint32_t mx, my, mz; mx = d->x_block_count = g_pProcess->readDWord (x_count_offset); my = d->y_block_count = g_pProcess->readDWord (y_count_offset); mz = d->z_block_count = g_pProcess->readDWord (z_count_offset); @@ -253,6 +290,41 @@ uint32_t API::getBlockPtr (uint32_t x, uint32_t y, uint32_t z) return d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; } +bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) +{ + if(d->shm_start && d->maps_module) // ACCELERATE! + { + SHMMAPSHDR->x = x; + SHMMAPSHDR->y = y; + SHMMAPSHDR->z = z; + const uint32_t cmd = Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16); + full_barrier + SHMCMD = cmd; + if(!g_pProcess->waitWhile(cmd)) + { + return false; + } + memcpy(buffer,SHMDATA(mapblock40d),sizeof(mapblock40d)); + return true; + } + else // plain old block read + { + uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; + if (addr) + { + g_pProcess->read (addr + d->tile_type_offset, sizeof (buffer->tiletypes), (uint8_t *) buffer->tiletypes); + g_pProcess->read (addr + d->occupancy_offset, sizeof (buffer->occupancy), (uint8_t *) buffer->occupancy); + g_pProcess->read (addr + d->designation_offset, sizeof (buffer->designaton), (uint8_t *) buffer->designaton); + g_pProcess->read (addr + d->biome_stuffs, sizeof (buffer->biome_indices), (uint8_t *) buffer->biome_indices); + uint32_t addr_of_struct = g_pProcess->readDWord(addr); + buffer->dirty_dword = g_pProcess->readDWord(addr_of_struct); + return true; + } + return false; + } +} + + // 256 * sizeof(uint16_t) bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer) { @@ -713,7 +785,7 @@ bool API::ReadGeology (vector < vector >& assign) } assign.clear(); assign.reserve (eBiomeCount); - // TODO: clean this up +// // TODO: clean this up for (int i = 0; i < eBiomeCount;i++) { assign.push_back (d->v_geology[i]); @@ -1341,6 +1413,7 @@ bool API::Attach() //cerr << "couldn't attach to process" << endl; //return false; // couldn't attach to process, no go } + d->shm_start = d->p->getSHMStart(); d->offset_descriptor = d->p->getDescriptor(); // process is attached, everything went just fine... hopefully return true; @@ -1359,6 +1432,7 @@ bool API::Detach() } d->pm = NULL; d->p = NULL; + d->shm_start = 0; d->offset_descriptor = NULL; return true; } diff --git a/library/DFHackAPI.h b/library/DFHackAPI.h index 77d75f9da..cc140807f 100644 --- a/library/DFHackAPI.h +++ b/library/DFHackAPI.h @@ -135,6 +135,8 @@ namespace DFHack */ uint32_t getBlockPtr (uint32_t blockx, uint32_t blocky, uint32_t blockz); + bool ReadBlock40d(uint32_t blockx, uint32_t blocky, uint32_t blockz, mapblock40d * buffer); + bool ReadTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t) bool WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, uint16_t *buffer); // 256 * sizeof(uint16_t) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 15c6a0c9e..84772de5d 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -28,7 +28,7 @@ distribution. #include #include #include "../shmserver/shms.h" -#include "../shmserver/shms-core.h" +#include "../shmserver/mod-core.h" #include #include #include @@ -59,6 +59,7 @@ class Process::Private pid_t my_pid; char *my_shm; int my_shmid; + Process* q; bool attached; bool suspended; @@ -66,10 +67,10 @@ class Process::Private bool useYield; bool validate(char* exe_file, uint32_t pid, std::vector< memory_info* >& known_versions); - bool waitWhile (CORE_COMMAND state); bool DF_TestBridgeVersion(bool & ret); bool DF_GetPID(pid_t & ret); void DF_SyncAffinity(void); + bool waitWhile (uint32_t state); }; // some helpful macros to keep the code bloat in check @@ -83,7 +84,7 @@ class Process::Private Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling) we end up with this silly thing */ -bool Process::Private::waitWhile (CORE_COMMAND state) +bool Process::Private::waitWhile (uint32_t state) { uint32_t cnt = 0; struct shmid_ds descriptor; @@ -121,6 +122,48 @@ bool Process::Private::waitWhile (CORE_COMMAND state) return true; } +/* +Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling) +we end up with this silly thing +*/ +bool Process::waitWhile (uint32_t state) +{ + uint32_t cnt = 0; + struct shmid_ds descriptor; + while (D_SHMCMD == state) + { + if(cnt == 10000)// check if the other process is still there + { + + shmctl(d->my_shmid, IPC_STAT, &descriptor); + if(descriptor.shm_nattch == 1)// DF crashed? + { + D_SHMCMD = CORE_RUNNING; + d->attached = d->suspended = false; + return false; + } + else + { + cnt = 0; + } + } + if(d->useYield) + { + SCHED_YIELD + } + cnt++; + } + if(D_SHMCMD == CORE_SV_ERROR) + { + D_SHMCMD = CORE_RUNNING; + d->attached = d->suspended = false; + cerr << "shm server error!" << endl; + assert (false); + return false; + } + return true; +} + bool Process::Private::DF_TestBridgeVersion(bool & ret) { SHMCMD = CORE_GET_VERSION; @@ -363,7 +406,7 @@ bool Process::suspend() return true; } D_SHMCMD = CORE_SUSPEND; - if(!d->waitWhile(CORE_SUSPEND)) + if(!waitWhile(CORE_SUSPEND)) { return false; } @@ -472,7 +515,7 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) D_SHMHDR->length = size; gcc_barrier D_SHMCMD = CORE_DFPP_READ; - d->waitWhile(CORE_DFPP_READ); + waitWhile(CORE_DFPP_READ); memcpy (target_buffer, d->my_shm + SHM_HEADER,size); } // a big read, we pull data over the shm in iterations @@ -487,7 +530,7 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) D_SHMHDR->length = to_read; gcc_barrier D_SHMCMD = CORE_DFPP_READ; - d->waitWhile(CORE_DFPP_READ); + waitWhile(CORE_DFPP_READ); memcpy (target_buffer, d->my_shm + SHM_HEADER,size); // decrease size by bytes read size -= to_read; @@ -505,7 +548,7 @@ uint8_t Process::readByte (const uint32_t offset) D_SHMHDR->address = offset; gcc_barrier D_SHMCMD = CORE_READ_BYTE; - d->waitWhile(CORE_READ_BYTE); + waitWhile(CORE_READ_BYTE); return D_SHMHDR->value; } @@ -514,7 +557,7 @@ void Process::readByte (const uint32_t offset, uint8_t &val ) D_SHMHDR->address = offset; gcc_barrier D_SHMCMD = CORE_READ_BYTE; - d->waitWhile(CORE_READ_BYTE); + waitWhile(CORE_READ_BYTE); val = D_SHMHDR->value; } @@ -523,7 +566,7 @@ uint16_t Process::readWord (const uint32_t offset) D_SHMHDR->address = offset; gcc_barrier D_SHMCMD = CORE_READ_WORD; - d->waitWhile(CORE_READ_WORD); + waitWhile(CORE_READ_WORD); return D_SHMHDR->value; } @@ -532,7 +575,7 @@ void Process::readWord (const uint32_t offset, uint16_t &val) D_SHMHDR->address = offset; gcc_barrier D_SHMCMD = CORE_READ_WORD; - d->waitWhile(CORE_READ_WORD); + waitWhile(CORE_READ_WORD); val = D_SHMHDR->value; } @@ -541,7 +584,7 @@ uint32_t Process::readDWord (const uint32_t offset) D_SHMHDR->address = offset; gcc_barrier D_SHMCMD = CORE_READ_DWORD; - d->waitWhile(CORE_READ_DWORD); + waitWhile(CORE_READ_DWORD); return D_SHMHDR->value; } void Process::readDWord (const uint32_t offset, uint32_t &val) @@ -549,7 +592,7 @@ void Process::readDWord (const uint32_t offset, uint32_t &val) D_SHMHDR->address = offset; gcc_barrier D_SHMCMD = CORE_READ_DWORD; - d->waitWhile(CORE_READ_DWORD); + waitWhile(CORE_READ_DWORD); val = D_SHMHDR->value; } @@ -563,7 +606,7 @@ void Process::writeDWord (uint32_t offset, uint32_t data) D_SHMHDR->value = data; gcc_barrier D_SHMCMD = CORE_WRITE_DWORD; - d->waitWhile(CORE_WRITE_DWORD); + waitWhile(CORE_WRITE_DWORD); } // using these is expensive. @@ -573,7 +616,7 @@ void Process::writeWord (uint32_t offset, uint16_t data) D_SHMHDR->value = data; gcc_barrier D_SHMCMD = CORE_WRITE_WORD; - d->waitWhile(CORE_WRITE_WORD); + waitWhile(CORE_WRITE_WORD); } void Process::writeByte (uint32_t offset, uint8_t data) @@ -582,7 +625,7 @@ void Process::writeByte (uint32_t offset, uint8_t data) D_SHMHDR->value = data; gcc_barrier D_SHMCMD = CORE_WRITE_BYTE; - d->waitWhile(CORE_WRITE_BYTE); + waitWhile(CORE_WRITE_BYTE); } void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) @@ -595,7 +638,7 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer memcpy(d->my_shm+SHM_HEADER,source_buffer, size); gcc_barrier D_SHMCMD = CORE_WRITE; - d->waitWhile(CORE_WRITE); + waitWhile(CORE_WRITE); } // a big write, we push this over the shm in iterations else @@ -610,7 +653,7 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write); gcc_barrier D_SHMCMD = CORE_WRITE; - d->waitWhile(CORE_WRITE); + waitWhile(CORE_WRITE); // decrease size by bytes written size -= to_write; // move the cursors @@ -661,7 +704,7 @@ const std::string Process::readSTLString(uint32_t offset) D_SHMHDR->address = offset; full_barrier D_SHMCMD = CORE_READ_STL_STRING; - d->waitWhile(CORE_READ_STL_STRING); + waitWhile(CORE_READ_STL_STRING); //int length = ((shm_retval *)d->my_shm)->value; return(string( (char *)d->my_shm+SHM_HEADER)); } @@ -671,7 +714,7 @@ size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacit D_SHMHDR->address = offset; full_barrier D_SHMCMD = CORE_READ_STL_STRING; - d->waitWhile(CORE_READ_STL_STRING); + waitWhile(CORE_READ_STL_STRING); size_t length = D_SHMHDR->value; size_t fit = min(bufcapacity - 1, length); strncpy(buffer,(char *)d->my_shm+SHM_HEADER,fit); @@ -685,7 +728,7 @@ void Process::writeSTLString(const uint32_t address, const std::string writeStri strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator full_barrier D_SHMCMD = CORE_WRITE_STL_STRING; - d->waitWhile(CORE_WRITE_STL_STRING); + waitWhile(CORE_WRITE_STL_STRING); } string Process::readClassName (uint32_t vptr) @@ -696,4 +739,23 @@ string Process::readClassName (uint32_t vptr) size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers size_t end = raw.length(); return raw.substr(start,end-start - 2); // trim the 'st' from the end +} + +// get module index by name and version. bool 1 = error +bool Process::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) +{ + modulelookup * payload = (modulelookup *) (d->my_shm + SHM_HEADER); + payload->version = version; + strcpy(payload->name,name); + full_barrier + D_SHMCMD = CORE_ACQUIRE_MODULE; + waitWhile(CORE_ACQUIRE_MODULE); + if(D_SHMHDR->error) return false; + OUTPUT = D_SHMHDR->value; + return true; +} + +char * Process::getSHMStart (void) +{ + return d->my_shm; } \ No newline at end of file diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index abf06fdb2..62c2cc50d 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -23,7 +23,7 @@ distribution. */ #include "DFCommonInternal.h" #include "../shmserver/shms.h" -#include "../shmserver/shms-core.h" +#include "../shmserver/mod-core.h" using namespace DFHack; // a full memory barrier! better be safe than sorry. @@ -56,7 +56,7 @@ class Process::Private bool identified; bool useYield; - bool waitWhile (CORE_COMMAND state); + bool waitWhile (uint32_t state); bool isValidSV(); bool DF_TestBridgeVersion(bool & ret); bool DF_GetPID(uint32_t & ret); @@ -98,10 +98,15 @@ bool Process::Private::isValidSV() } } -bool Process::Private::waitWhile (CORE_COMMAND state) +bool Process::waitWhile (uint32_t state) +{ + return d->waitWhile(state); +} + +bool Process::Private::waitWhile (uint32_t state) { uint32_t cnt = 0; - while (((shm_cmd *)my_shm)->pingpong == state) + while (SHMCMD == state) { // yield the CPU, only on single-core CPUs if(useYield) @@ -112,7 +117,7 @@ bool Process::Private::waitWhile (CORE_COMMAND state) { if(!isValidSV())// DF not there anymore? { - ((shm_cmd *)my_shm)->pingpong = CORE_RUNNING; + SHMCMD = CORE_RUNNING; attached = suspended = false; ReleaseMutex(DFCLMutex); return false; @@ -124,9 +129,9 @@ bool Process::Private::waitWhile (CORE_COMMAND state) } cnt++; } - if(((shm_cmd *)my_shm)->pingpong == CORE_SV_ERROR) + if(SHMCMD == CORE_SV_ERROR) { - ((shm_cmd *)my_shm)->pingpong = CORE_RUNNING; + SHMCMD = CORE_RUNNING; attached = suspended = false; cerr << "shm server error!" << endl; return false; @@ -136,33 +141,28 @@ bool Process::Private::waitWhile (CORE_COMMAND state) bool Process::Private::DF_TestBridgeVersion(bool & ret) { - ((shm_cmd *)my_shm)->pingpong = CORE_GET_VERSION; + SHMCMD = CORE_GET_VERSION; full_barrier if(!waitWhile(CORE_GET_VERSION)) return false; full_barrier - ((shm_cmd *)my_shm)->pingpong = CORE_SUSPENDED; - ret =( ((shm_val *)my_shm)->value == CORE_VERSION ); + SHMCMD = CORE_SUSPENDED; + ret =( SHMHDR->value == CORE_VERSION ); return true; } bool Process::Private::DF_GetPID(uint32_t & ret) { - ((shm_cmd *)my_shm)->pingpong = CORE_GET_PID; + SHMCMD = CORE_GET_PID; full_barrier if(!waitWhile(CORE_GET_PID)) return false; full_barrier - ((shm_cmd *)my_shm)->pingpong = CORE_SUSPENDED; - ret = ((shm_val *)my_shm)->value; + SHMCMD = CORE_SUSPENDED; + ret = SHMHDR->value; return true; } -void Process::Private::DF_SyncAffinity(void) -{ - -} - uint32_t OS_getAffinity() { HANDLE hProcess = GetCurrentProcess(); @@ -223,7 +223,7 @@ Process::Process(vector & known_versions) if(!bridgeOK) { fprintf(stderr,"SHM bridge version mismatch\n"); - ((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING; + D_SHMCMD = CORE_RUNNING; UnmapViewOfFile(d->my_shm); ReleaseMutex(d->DFCLMutex); CloseHandle(d->DFSVMutex); @@ -300,7 +300,7 @@ Process::Process(vector & known_versions) } else { - ((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING; + D_SHMCMD = CORE_RUNNING; UnmapViewOfFile(d->my_shm); d->my_shm = 0; ReleaseMutex(d->DFCLMutex); @@ -417,7 +417,7 @@ bool Process::suspend() cerr << "couldn't suspend, already suspended" << endl; return true; } - ((shm_cmd *)d->my_shm)->pingpong = CORE_SUSPEND; + D_SHMCMD = CORE_SUSPEND; if(!d->waitWhile(CORE_SUSPEND)) { cerr << "couldn't suspend, DF not responding to commands" << endl; @@ -437,14 +437,14 @@ bool Process::asyncSuspend() { return true; } - if(((shm_cmd *)d->my_shm)->pingpong == CORE_SUSPENDED) + if(D_SHMCMD == CORE_SUSPENDED) { d->suspended = true; return true; } else { - ((shm_cmd *)d->my_shm)->pingpong = CORE_SUSPEND; + D_SHMCMD = CORE_SUSPEND; return false; } } @@ -466,7 +466,7 @@ bool Process::resume() cerr << "couldn't resume because of not being suspended" << endl; return true; } - ((shm_cmd *)d->my_shm)->pingpong = CORE_RUNNING; + D_SHMCMD = CORE_RUNNING; d->suspended = false; return true; } @@ -541,10 +541,10 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) // normal read under 1MB if(size <= SHM_BODY) { - ((shm_addrlen *)d->my_shm)->address = src_address; - ((shm_addrlen *)d->my_shm)->length = size; + D_SHMHDR->address = src_address; + D_SHMHDR->length = size; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_DFPP_READ; + D_SHMCMD = CORE_DFPP_READ; d->waitWhile(CORE_DFPP_READ); memcpy (target_buffer, d->my_shm + SHM_HEADER,size); } @@ -556,10 +556,10 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) while (size) { // read to_read bytes from src_cursor - ((shm_addrlen *)d->my_shm)->address = src_address; - ((shm_addrlen *)d->my_shm)->length = to_read; + D_SHMHDR->address = src_address; + D_SHMHDR->length = to_read; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_DFPP_READ; + D_SHMCMD = CORE_DFPP_READ; d->waitWhile(CORE_DFPP_READ); memcpy (target_buffer, d->my_shm + SHM_HEADER,size); // decrease size by bytes read @@ -575,55 +575,55 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) uint8_t Process::readByte (const uint32_t offset) { - ((shm_addr *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_BYTE; + D_SHMCMD = CORE_READ_BYTE; d->waitWhile(CORE_READ_BYTE); - return ((shm_val *)d->my_shm)->value; + return D_SHMHDR->value; } void Process::readByte (const uint32_t offset, uint8_t &val ) { - ((shm_addr *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_BYTE; + D_SHMCMD = CORE_READ_BYTE; d->waitWhile(CORE_READ_BYTE); - val = ((shm_val *)d->my_shm)->value; + val = D_SHMHDR->value; } uint16_t Process::readWord (const uint32_t offset) { - ((shm_addr *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_WORD; + D_SHMCMD = CORE_READ_WORD; d->waitWhile(CORE_READ_WORD); - return ((shm_val *)d->my_shm)->value; + return D_SHMHDR->value; } void Process::readWord (const uint32_t offset, uint16_t &val) { - ((shm_addr *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_WORD; + D_SHMCMD = CORE_READ_WORD; d->waitWhile(CORE_READ_WORD); - val = ((shm_val *)d->my_shm)->value; + val = D_SHMHDR->value; } uint32_t Process::readDWord (const uint32_t offset) { - ((shm_addr *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_DWORD; + D_SHMCMD = CORE_READ_DWORD; d->waitWhile(CORE_READ_DWORD); - return ((shm_val *)d->my_shm)->value; + return D_SHMHDR->value; } void Process::readDWord (const uint32_t offset, uint32_t &val) { - ((shm_addr *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_DWORD; + D_SHMCMD = CORE_READ_DWORD; d->waitWhile(CORE_READ_DWORD); - val = ((shm_val *)d->my_shm)->value; + val = D_SHMHDR->value; } /* @@ -632,29 +632,29 @@ void Process::readDWord (const uint32_t offset, uint32_t &val) void Process::writeDWord (uint32_t offset, uint32_t data) { - ((shm_addrval *)d->my_shm)->address = offset; - ((shm_addrval *)d->my_shm)->value = data; + D_SHMHDR->address = offset; + D_SHMHDR->value = data; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_DWORD; + D_SHMCMD = CORE_WRITE_DWORD; d->waitWhile(CORE_WRITE_DWORD); } // using these is expensive. void Process::writeWord (uint32_t offset, uint16_t data) { - ((shm_addrval *)d->my_shm)->address = offset; - ((shm_addrval *)d->my_shm)->value = data; + D_SHMHDR->address = offset; + D_SHMHDR->value = data; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_WORD; + D_SHMCMD = CORE_WRITE_WORD; d->waitWhile(CORE_WRITE_WORD); } void Process::writeByte (uint32_t offset, uint8_t data) { - ((shm_addrval *)d->my_shm)->address = offset; - ((shm_addrval *)d->my_shm)->value = data; + D_SHMHDR->address = offset; + D_SHMHDR->value = data; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_BYTE; + D_SHMCMD = CORE_WRITE_BYTE; d->waitWhile(CORE_WRITE_BYTE); } @@ -663,11 +663,11 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer // normal write under 1MB if(size <= SHM_BODY) { - ((shm_addrlen *)d->my_shm)->address = dst_address; - ((shm_addrlen *)d->my_shm)->length = size; + D_SHMHDR->address = dst_address; + D_SHMHDR->length = size; memcpy(d->my_shm+SHM_HEADER,source_buffer, size); full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE; + D_SHMCMD = CORE_WRITE; d->waitWhile(CORE_WRITE); } // a big write, we push this over the shm in iterations @@ -678,11 +678,11 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer while (size) { // write to_write bytes to dst_cursor - ((shm_addrlen *)d->my_shm)->address = dst_address; - ((shm_addrlen *)d->my_shm)->length = to_write; + D_SHMHDR->address = dst_address; + D_SHMHDR->length = to_write; memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write); full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE; + D_SHMCMD = CORE_WRITE; d->waitWhile(CORE_WRITE); // decrease size by bytes written size -= to_write; @@ -734,11 +734,11 @@ DfVector Process::readVector (uint32_t offset, uint32_t item_size) const std::string Process::readSTLString(uint32_t offset) { //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 - ((shm_addr *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_STL_STRING; + D_SHMCMD = CORE_READ_STL_STRING; d->waitWhile(CORE_READ_STL_STRING); - int length = ((shm_val *)d->my_shm)->value; + int length = D_SHMHDR->value; // char temp_c[256]; // strncpy(temp_c, d->my_shm+SHM_HEADER,length+1); // length + 1 for the null terminator return(string(d->my_shm+SHM_HEADER)); @@ -747,11 +747,11 @@ const std::string Process::readSTLString(uint32_t offset) size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 - ((shm_addr *)d->my_shm)->address = offset; + D_SHMHDR->address = offset; full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_READ_STL_STRING; + D_SHMCMD = CORE_READ_STL_STRING; d->waitWhile(CORE_READ_STL_STRING); - size_t length = ((shm_val *)d->my_shm)->value; + size_t length = D_SHMHDR->value; size_t real = min(length, bufcapacity - 1); strncpy(buffer, d->my_shm+SHM_HEADER,real); // length + 1 for the null terminator buffer[real] = 0; @@ -760,10 +760,10 @@ size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacit void Process::writeSTLString(const uint32_t address, const std::string writeString) { - ((shm_addr *)d->my_shm)->address = address/*-4*/; + D_SHMHDR->address = address/*-4*/; strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator full_barrier - ((shm_cmd *)d->my_shm)->pingpong = CORE_WRITE_STL_STRING; + D_SHMCMD = CORE_WRITE_STL_STRING; d->waitWhile(CORE_WRITE_STL_STRING); } @@ -774,4 +774,23 @@ string Process::readClassName (uint32_t vptr) string raw = readCString(typeinfo + 0xC); // skips the .?AV raw.resize(raw.length() - 4);// trim st@@ from end return raw; +} + +// get module index by name and version. bool 1 = error +bool Process::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) +{ + modulelookup * payload = (modulelookup *) (d->my_shm + SHM_HEADER); + payload->version = version; + strcpy(payload->name,name); + full_barrier + D_SHMCMD = CORE_ACQUIRE_MODULE; + d->waitWhile(CORE_ACQUIRE_MODULE); + if(D_SHMHDR->error) return false; + OUTPUT = D_SHMHDR->value; + return true; +} + +char * Process::getSHMStart (void) +{ + return d->my_shm; } \ No newline at end of file diff --git a/library/DFProcess.h b/library/DFProcess.h index 28525daec..8ad71e04e 100644 --- a/library/DFProcess.h +++ b/library/DFProcess.h @@ -121,6 +121,12 @@ namespace DFHack DFWindow * getWindow(); // get the DF Process ID int getPID(); + // get module index by name and version. bool 1 = error + bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT); + // get the SHM start if available + char * getSHMStart (void); + // wait for a SHM state. returns 0 without the SHM + bool waitWhile (uint32_t state); }; } #endif diff --git a/library/DFTypes.h b/library/DFTypes.h index 9959526d5..db47c23fc 100644 --- a/library/DFTypes.h +++ b/library/DFTypes.h @@ -764,6 +764,15 @@ union t_occupancy naked_occupancy_grouped unibits; }; +typedef struct +{ + int16_t tiletypes [16][16]; + DFHack::t_designation designaton [16][16]; + DFHack::t_occupancy occupancy [16][16]; + uint8_t biome_indices [7]; + uint32_t dirty_dword; // bit 1 set means that the block is to be included in job checks +} mapblock40d; + struct t_viewscreen { int32_t type; diff --git a/shmserver/CMakeLists.txt b/shmserver/CMakeLists.txt index 108b30e8c..75c007678 100644 --- a/shmserver/CMakeLists.txt +++ b/shmserver/CMakeLists.txt @@ -2,10 +2,13 @@ SET(PROJECT_HDRS shms.h +mod-core.h +mod-maps.h ) SET(PROJECT_SRCS -shms-core.cpp +mod-core.cpp +mod-maps.cpp ) SET(PROJECT_HDRS_LINUX diff --git a/shmserver/shms-core.cpp b/shmserver/mod-core.cpp similarity index 76% rename from shmserver/shms-core.cpp rename to shmserver/mod-core.cpp index 3a20a2439..093aefec5 100644 --- a/shmserver/shms-core.cpp +++ b/shmserver/mod-core.cpp @@ -32,8 +32,12 @@ distribution. #include #include #include + +#define SHM_INTERNAL // for things only visible to the SHM + #include "shms.h" -#include "shms-core.h" +#include "mod-core.h" +#include "mod-maps.h" std::vector module_registry; @@ -46,57 +50,57 @@ bool useYield = 0; #define SHMHDR ((shm_core_hdr *)shm) #define SHMCMD ((shm_cmd *)shm)->pingpong -void GetCoreVersion (void) +void GetCoreVersion (void * data) { SHMHDR->value = module_registry[0].version; } -void GetPID (void) +void GetPID (void * data) { SHMHDR->value = OS_getPID(); } -void ReadRaw (void) +void ReadRaw (void * data) { memcpy(shm + SHM_HEADER, (void *) SHMHDR->address,SHMHDR->length); } -void ReadDWord (void) +void ReadDWord (void * data) { SHMHDR->value = *((uint32_t*) SHMHDR->address); } -void ReadWord (void) +void ReadWord (void * data) { SHMHDR->value = *((uint16_t*) SHMHDR->address); } -void ReadByte (void) +void ReadByte (void * data) { SHMHDR->value = *((uint8_t*) SHMHDR->address); } -void WriteRaw (void) +void WriteRaw (void * data) { memcpy((void *)SHMHDR->address, shm + SHM_HEADER,SHMHDR->length); } -void WriteDWord (void) +void WriteDWord (void * data) { (*(uint32_t*)SHMHDR->address) = SHMHDR->value; } -void WriteWord (void) +void WriteWord (void * data) { (*(uint16_t*)SHMHDR->address) = SHMHDR->value; } -void WriteByte (void) +void WriteByte (void * data) { (*(uint8_t*)SHMHDR->address) = SHMHDR->value; } -void ReadSTLString (void) +void ReadSTLString (void * data) { std::string * myStringPtr = (std::string *) SHMHDR->address; unsigned int l = myStringPtr->length(); @@ -105,7 +109,7 @@ void ReadSTLString (void) strncpy(shm+SHM_HEADER,myStringPtr->c_str(),l+1); } -void WriteSTLString (void) +void WriteSTLString (void * data) { std::string * myStringPtr = (std::string *) SHMHDR->address; // here we DO expect a 0 terminator @@ -122,7 +126,7 @@ int bitcount(uint32_t n) } // get local and remote affinity, set up yield if required (single core available) -void SyncYield (void) +void SyncYield (void * data) { uint32_t local = OS_getAffinity(); uint32_t remote = SHMHDR->value; @@ -137,7 +141,33 @@ void SyncYield (void) } } -void InitCore(void) +void FindModule (void * data) +{ + bool found = false; + modulelookup * payload = (modulelookup *) (shm + SHM_HEADER); + std::string test = payload->name; + uint32_t version = payload->version; + for(unsigned int i = 0; i < module_registry.size();i++) + { + if(module_registry[i].name == test && module_registry[i].version == version) + { + // gotcha + SHMHDR->value = i; + found = true; + break; + } + } + if(found) + { + SHMHDR->error = false; + } + else + { + SHMHDR->error = true; + } +} + +DFPP_module InitCore(void) { DFPP_module core; core.name = "Core"; @@ -181,16 +211,31 @@ void InitCore(void) core.set_command(CORE_RET_STRING, CLIENT_WAIT, "Return string"); core.set_command(CORE_WRITE_STL_STRING, FUNCTION, "Write STL string", WriteSTLString, CORE_SUSPENDED); core.set_command(CORE_SYNC_YIELD, FUNCTION, "Synchronize affinity/yield", SyncYield, CORE_SYNC_YIELD_RET); - module_registry.push_back(core); + core.set_command(CORE_SYNC_YIELD_RET, CLIENT_WAIT, "Synchronize affinity/yield return"); + + core.set_command(CORE_ACQUIRE_MODULE, FUNCTION, "Module lookup", FindModule, CORE_RET_MODULE); + core.set_command(CORE_RET_MODULE, CLIENT_WAIT, "Return module index or error"); + return core; } void InitModules (void) { // create the core module - InitCore(); + module_registry.push_back(InitCore()); + module_registry.push_back(InitMaps()); // TODO: dynamic module init } +void KillModules (void) +{ + for(unsigned int i = 0; i < module_registry.size();i++) + { + if(module_registry[i].modulestate) + free(module_registry[i].modulestate); + } + module_registry.clear(); +} + void SHM_Act (void) { if(errorstate) @@ -215,10 +260,12 @@ void SHM_Act (void) } DFPP_module & mod = module_registry[((shm_cmd *)shm)->parts.module]; DFPP_command & cmd = mod.commands[((shm_cmd *)shm)->parts.command]; - //fprintf(stderr, "Client invoked %s\n", cmd.name.c_str() ); + //fprintf(stderr, "Client invoked %d:%d = ",((shm_cmd *)shm)->parts.module,((shm_cmd *)shm)->parts.command); + //fprintf(stderr, "%s\n",cmd.name.c_str()); + if(cmd._function) { - cmd._function(); + cmd._function(mod.modulestate); } if(cmd.nextState != -1) { diff --git a/shmserver/shms-core.h b/shmserver/mod-core.h similarity index 100% rename from shmserver/shms-core.h rename to shmserver/mod-core.h diff --git a/shmserver/mod-maps.cpp b/shmserver/mod-maps.cpp index 54700101a..a67d040db 100644 --- a/shmserver/mod-maps.cpp +++ b/shmserver/mod-maps.cpp @@ -3,7 +3,7 @@ #include #include "shms.h" -#include "shms-core.h" +#include "mod-core.h" #include "mod-maps.h" #include using namespace DFHack; @@ -69,7 +69,7 @@ void ReadBlockByCoords (void * data) */ mblock * *** mapArray = *(mblock * ****)offsets.map_offset; mblock * block = mapArray[SHMHDR->x][SHMHDR->y][SHMHDR->z]; - fprintf(stderr, "Readblock: %d %d %d 0x%x\n", SHMHDR->x,SHMHDR->y,SHMHDR->z, block); + //fprintf(stderr, "Readblock: %d %d %d 0x%x\n", SHMHDR->x,SHMHDR->y,SHMHDR->z, block); if(block) { memcpy(&(SHMBLOCK->tiletypes), block + offsets.tile_type_offset, sizeof(SHMBLOCK->tiletypes)); @@ -85,7 +85,7 @@ void ReadBlockByCoords (void * data) } } -DFPP_module InitMaps(std::vector * module_registry) +DFPP_module InitMaps( void ) { DFPP_module maps; maps.name = "Maps"; @@ -103,11 +103,9 @@ DFPP_module InitMaps(std::vector * module_registry) // will it fit into 1MB? We shouldn't assume this is the case maps.set_command(MAP_READ_BLOCKTREE, FUNCTION,"Get the tree of block pointers as a single structure", NullCommand, CORE_SUSPENDED); - - - + // really doesn't fit into 1MB, there should be a streaming variant to better utilize context switches maps.set_command(MAP_READ_BLOCKS_3D, FUNCTION, "Read a range of blocks between two sets of coords", NullCommand, CORE_SUSPENDED); - module_registry->push_back(maps); + return maps; } \ No newline at end of file diff --git a/shmserver/shms-linux.cpp b/shmserver/shms-linux.cpp index 9fa02595d..63812b673 100644 --- a/shmserver/shms-linux.cpp +++ b/shmserver/shms-linux.cpp @@ -37,7 +37,7 @@ distribution. #include #include #include "shms.h" -#include "shms-core.h" +#include "mod-core.h" #include #define DFhackCExport extern "C" __attribute__ ((visibility("default"))) @@ -125,6 +125,7 @@ void SHM_Destroy ( void ) { if(inited && !errorstate) { + KillModules(); shmid_ds descriptor; shmctl(shmid, IPC_STAT, &descriptor); shmdt(shm); diff --git a/shmserver/shms-windows.cpp b/shmserver/shms-windows.cpp index 19c22548b..25b90b4ab 100644 --- a/shmserver/shms-windows.cpp +++ b/shmserver/shms-windows.cpp @@ -37,6 +37,7 @@ distribution. #include #include #include "shms.h" +#include "mod-core.h" #include int errorstate = 0; char *shm = 0; @@ -150,6 +151,7 @@ void SHM_Destroy ( void ) { if(errorstate) return; + KillModules(); ReleaseMutex(DFSVMutex); CloseHandle(DFSVMutex); CloseHandle(DFCLMutex); @@ -160,6 +162,17 @@ uint32_t OS_getPID() return GetCurrentProcessId(); } +// TODO: move to some utils file +uint32_t OS_getAffinity() +{ + HANDLE hProcess = GetCurrentProcess(); + DWORD dwProcessAffinityMask, dwSystemAffinityMask; + GetProcessAffinityMask( hProcess, &dwProcessAffinityMask, &dwSystemAffinityMask ); + return dwProcessAffinityMask; +} + + + // is the other side still there? bool isValidSHM() { diff --git a/shmserver/shms.h b/shmserver/shms.h index 5eb0db961..174614c8e 100644 --- a/shmserver/shms.h +++ b/shmserver/shms.h @@ -38,7 +38,7 @@ enum DFPP_CmdType struct DFPP_command { - void (*_function)(void); + void (*_function)(void *); DFPP_CmdType type:32; // force the enum to 32 bits for compatibility reasons std::string name; uint32_t nextState; @@ -46,7 +46,21 @@ struct DFPP_command struct DFPP_module { - inline void set_command(const unsigned int index, const DFPP_CmdType type, const char * name, void (*_function)(void) = 0,uint32_t nextState = -1) + DFPP_module() + { + name = "Uninitialized module"; + version = 0; + modulestate = 0; + } + // ALERT: the structures share state + DFPP_module(const DFPP_module & orig) + { + commands = orig.commands; + name = orig.name; + modulestate = orig.modulestate; + version = orig.version; + } + inline void set_command(const unsigned int index, const DFPP_CmdType type, const char * name, void (*_function)(void *) = 0,uint32_t nextState = -1) { commands[index].type = type; commands[index].name = name; @@ -81,8 +95,10 @@ typedef union void SHM_Act (void); void InitModules (void); +void KillModules (void); bool isValidSHM(); uint32_t OS_getPID(); +DFPP_module InitMaps(void); uint32_t OS_getAffinity(); // limited to 32 processors. Silly, eh? #endif From 8e8d320a0bb2dfb0a8f8c586ced6ccd7d31e560f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 5 Mar 2010 01:26:39 +0100 Subject: [PATCH 07/16] Don't build SHM on 64bit, makes no sense Added origin to mapblock40d --- examples/veinlook.cpp | 4 +++- library/DFHackAPI.cpp | 1 + library/DFTypes.h | 4 +++- shmserver/CMakeLists.txt | 25 +++++++++++++------------ shmserver/mod-maps.cpp | 2 ++ 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/examples/veinlook.cpp b/examples/veinlook.cpp index 5d1e7bbda..91a21f566 100644 --- a/examples/veinlook.cpp +++ b/examples/veinlook.cpp @@ -337,6 +337,7 @@ main(int argc, char *argv[]) int filenum = 0; bool dirtybit = false; uint32_t blockaddr = 0; + uint32_t blockaddr2 = 0; // walk the map! for (;;) { @@ -437,6 +438,7 @@ main(int argc, char *argv[]) if(i == 0 && j == 0) { blockaddr = DF.getBlockPtr(cursorX+i,cursorY+j,cursorZ); + blockaddr2 = Block.origin; if(dump) { hexdump(DF,blockaddr,0x1E00/*0x1DB8*/,filenum); @@ -516,7 +518,7 @@ main(int argc, char *argv[]) } } gotoxy (0,52); - cprintf("block address 0x%x",blockaddr); + cprintf("block address 0x%x 0x%x",blockaddr, blockaddr2); gotoxy (0,53); cprintf("dirty bit: %d",dirtybit); gotoxy (0,54); diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index 0dc311609..88cde1396 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -316,6 +316,7 @@ bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) g_pProcess->read (addr + d->occupancy_offset, sizeof (buffer->occupancy), (uint8_t *) buffer->occupancy); g_pProcess->read (addr + d->designation_offset, sizeof (buffer->designaton), (uint8_t *) buffer->designaton); g_pProcess->read (addr + d->biome_stuffs, sizeof (buffer->biome_indices), (uint8_t *) buffer->biome_indices); + buffer->origin = addr; uint32_t addr_of_struct = g_pProcess->readDWord(addr); buffer->dirty_dword = g_pProcess->readDWord(addr_of_struct); return true; diff --git a/library/DFTypes.h b/library/DFTypes.h index db47c23fc..6b9e467a5 100644 --- a/library/DFTypes.h +++ b/library/DFTypes.h @@ -769,7 +769,9 @@ typedef struct int16_t tiletypes [16][16]; DFHack::t_designation designaton [16][16]; DFHack::t_occupancy occupancy [16][16]; - uint8_t biome_indices [7]; + // really a '7', but I use 8 to make it neater :) + uint8_t biome_indices [8]; + uint32_t origin; // the address where it came from uint32_t dirty_dword; // bit 1 set means that the block is to be included in job checks } mapblock40d; diff --git a/shmserver/CMakeLists.txt b/shmserver/CMakeLists.txt index 75c007678..cc4b8cc57 100644 --- a/shmserver/CMakeLists.txt +++ b/shmserver/CMakeLists.txt @@ -38,15 +38,16 @@ SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE ) LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS}) -IF(UNIX) - add_definitions(-DLINUX_BUILD) - SET(PROJECT_LIBS rt) - SET(CMAKE_CXX_FLAGS "-fvisibility=hidden") - ADD_LIBRARY(dfconnect SHARED ${PROJECT_SRCS}) - TARGET_LINK_LIBRARIES(dfconnect ${PROJECT_LIBS}) -ELSE(UNIX) - # SET(PROJECT_LIBS psapi) - ADD_LIBRARY(SDL SHARED ${PROJECT_SRCS}) - TARGET_LINK_LIBRARIES(SDL ${PROJECT_LIBS}) -ENDIF(UNIX) - +IF(CMAKE_SIZEOF_VOID_P EQUAL 4) + IF(UNIX) + add_definitions(-DLINUX_BUILD) + SET(PROJECT_LIBS rt) + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden") + ADD_LIBRARY(dfconnect SHARED ${PROJECT_SRCS}) + TARGET_LINK_LIBRARIES(dfconnect ${PROJECT_LIBS}) + ELSE(UNIX) + # SET(PROJECT_LIBS psapi) + ADD_LIBRARY(SDL SHARED ${PROJECT_SRCS}) + TARGET_LINK_LIBRARIES(SDL ${PROJECT_LIBS}) + ENDIF(UNIX) +ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 4) diff --git a/shmserver/mod-maps.cpp b/shmserver/mod-maps.cpp index a67d040db..a34f01975 100644 --- a/shmserver/mod-maps.cpp +++ b/shmserver/mod-maps.cpp @@ -77,6 +77,8 @@ void ReadBlockByCoords (void * data) memcpy(&(SHMBLOCK->occupancy), block + offsets.occupancy_offset, sizeof(SHMBLOCK->occupancy)); memcpy(&(SHMBLOCK->biome_indices), block + offsets.biome_stuffs, sizeof(SHMBLOCK->biome_indices)); SHMBLOCK->dirty_dword = *block->ptr_to_dirty; + + SHMBLOCK->origin = reinterpret_cast(block); SHMHDR->error = false; } else From 73f95e4a6d38b71de6889cd3c285b1cdd1a1a6d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 5 Mar 2010 01:57:51 +0100 Subject: [PATCH 08/16] Fix the mapblock reading - C++ was being 'helpful' again --- examples/veinlook.cpp | 5 ++++- shmserver/mod-maps.cpp | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/veinlook.cpp b/examples/veinlook.cpp index 91a21f566..30c9bf212 100644 --- a/examples/veinlook.cpp +++ b/examples/veinlook.cpp @@ -407,6 +407,7 @@ main(int argc, char *argv[]) DF.ReadTileTypes(cursorX+i,cursorY+j,cursorZ, (uint16_t *) tiletypes); DF.ReadDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) designations); */ + for(int x = 0; x < 16; x++) { for(int y = 0; y < 16; y++) @@ -441,9 +442,10 @@ main(int argc, char *argv[]) blockaddr2 = Block.origin; if(dump) { - hexdump(DF,blockaddr,0x1E00/*0x1DB8*/,filenum); + hexdump(DF,blockaddr,0x1E00,filenum); filenum++; } + if(dig) DF.WriteDesignations(cursorX+i,cursorY+j,cursorZ, (uint32_t *) Block.designaton); DF.ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit); @@ -455,6 +457,7 @@ main(int argc, char *argv[]) veinVector.clear(); IceVeinVector.clear(); DF.ReadVeins(cursorX+i,cursorY+j,cursorZ,veinVector,IceVeinVector); + } } } diff --git a/shmserver/mod-maps.cpp b/shmserver/mod-maps.cpp index a34f01975..1ab220c58 100644 --- a/shmserver/mod-maps.cpp +++ b/shmserver/mod-maps.cpp @@ -69,16 +69,22 @@ void ReadBlockByCoords (void * data) */ mblock * *** mapArray = *(mblock * ****)offsets.map_offset; mblock * block = mapArray[SHMHDR->x][SHMHDR->y][SHMHDR->z]; - //fprintf(stderr, "Readblock: %d %d %d 0x%x\n", SHMHDR->x,SHMHDR->y,SHMHDR->z, block); + /* + fprintf(stderr, "map_offset: 0x%x\n", offsets.map_offset); + fprintf(stderr, "x_array: 0x%x\n", mapArray); + fprintf(stderr, "y_array: 0x%x\n", mapArray[SHMHDR->x]); + fprintf(stderr, "z_array: 0x%x\n", mapArray[SHMHDR->x][SHMHDR->y]); + fprintf(stderr, "Readblock: %d %d %d 0x%x\n", SHMHDR->x,SHMHDR->y,SHMHDR->z, block); + */ if(block) { - memcpy(&(SHMBLOCK->tiletypes), block + offsets.tile_type_offset, sizeof(SHMBLOCK->tiletypes)); - memcpy(&(SHMBLOCK->designaton), block + offsets.designation_offset, sizeof(SHMBLOCK->designaton)); - memcpy(&(SHMBLOCK->occupancy), block + offsets.occupancy_offset, sizeof(SHMBLOCK->occupancy)); - memcpy(&(SHMBLOCK->biome_indices), block + offsets.biome_stuffs, sizeof(SHMBLOCK->biome_indices)); + memcpy(&(SHMBLOCK->tiletypes), ((char *) block) + offsets.tile_type_offset, sizeof(SHMBLOCK->tiletypes)); + memcpy(&(SHMBLOCK->designaton), ((char *) block) + offsets.designation_offset, sizeof(SHMBLOCK->designaton)); + memcpy(&(SHMBLOCK->occupancy), ((char *) block) + offsets.occupancy_offset, sizeof(SHMBLOCK->occupancy)); + memcpy(&(SHMBLOCK->biome_indices), ((char *) block) + offsets.biome_stuffs, sizeof(SHMBLOCK->biome_indices)); SHMBLOCK->dirty_dword = *block->ptr_to_dirty; - SHMBLOCK->origin = reinterpret_cast(block); + SHMBLOCK->origin = (uint32_t)block; SHMHDR->error = false; } else From 9aedc561865fc545eecc12793b7baa6c7857ae71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 5 Mar 2010 02:45:53 +0100 Subject: [PATCH 09/16] A waitWhile method copy turned into wrapper --- library/DFProcess-linux-SHM.cpp | 35 +-------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 84772de5d..0ac7954b1 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -128,40 +128,7 @@ we end up with this silly thing */ bool Process::waitWhile (uint32_t state) { - uint32_t cnt = 0; - struct shmid_ds descriptor; - while (D_SHMCMD == state) - { - if(cnt == 10000)// check if the other process is still there - { - - shmctl(d->my_shmid, IPC_STAT, &descriptor); - if(descriptor.shm_nattch == 1)// DF crashed? - { - D_SHMCMD = CORE_RUNNING; - d->attached = d->suspended = false; - return false; - } - else - { - cnt = 0; - } - } - if(d->useYield) - { - SCHED_YIELD - } - cnt++; - } - if(D_SHMCMD == CORE_SV_ERROR) - { - D_SHMCMD = CORE_RUNNING; - d->attached = d->suspended = false; - cerr << "shm server error!" << endl; - assert (false); - return false; - } - return true; + return d->waitWhile(state); } bool Process::Private::DF_TestBridgeVersion(bool & ret) From 958ca0e3842d053ef8322206f135bf101d0461dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 5 Mar 2010 16:06:02 +0100 Subject: [PATCH 10/16] Some map module bits --- library/DFHackAPI.cpp | 2 +- shmserver/mod-maps.cpp | 38 ++++++++++++++++++++------------------ shmserver/mod-maps.h | 5 ++++- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index 88cde1396..8ad8f1e48 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -198,7 +198,7 @@ bool API::InitMap() /* * --> SHM initialization (if possible) <-- */ - g_pProcess->getModuleIndex("Maps",1,d->maps_module); + g_pProcess->getModuleIndex("Maps",2,d->maps_module); if(d->maps_module) { diff --git a/shmserver/mod-maps.cpp b/shmserver/mod-maps.cpp index 1ab220c58..54fe1cb57 100644 --- a/shmserver/mod-maps.cpp +++ b/shmserver/mod-maps.cpp @@ -55,27 +55,11 @@ struct mblock #define SHMBLOCK ((mapblock40d *)(shm + SHM_HEADER)) -void ReadBlockByCoords (void * data) +inline void ReadBlockByAddress (void * data) { maps_modulestate * state = (maps_modulestate *) data; maps_offsets & offsets = state->offsets; - /* map_offset is a pointer to - a pointer to - an X block of pointers to - an Y blocks of pointers to - a Z blocks of pointers to - map blocks - only Z blocks can have NULL pointers? TODO: verify - */ - mblock * *** mapArray = *(mblock * ****)offsets.map_offset; - mblock * block = mapArray[SHMHDR->x][SHMHDR->y][SHMHDR->z]; - /* - fprintf(stderr, "map_offset: 0x%x\n", offsets.map_offset); - fprintf(stderr, "x_array: 0x%x\n", mapArray); - fprintf(stderr, "y_array: 0x%x\n", mapArray[SHMHDR->x]); - fprintf(stderr, "z_array: 0x%x\n", mapArray[SHMHDR->x][SHMHDR->y]); - fprintf(stderr, "Readblock: %d %d %d 0x%x\n", SHMHDR->x,SHMHDR->y,SHMHDR->z, block); - */ + mblock * block = (mblock *) SHMHDR->address; if(block) { memcpy(&(SHMBLOCK->tiletypes), ((char *) block) + offsets.tile_type_offset, sizeof(SHMBLOCK->tiletypes)); @@ -93,6 +77,23 @@ void ReadBlockByCoords (void * data) } } +void ReadBlockByCoords (void * data) +{ + maps_modulestate * state = (maps_modulestate *) data; + maps_offsets & offsets = state->offsets; + /* map_offset is a pointer to + a pointer to + an X block of pointers to + an Y blocks of pointers to + a Z blocks of pointers to + map blocks + only Z blocks can have NULL pointers? TODO: verify + */ + mblock * *** mapArray = *(mblock * ****)offsets.map_offset; + SHMHDR->address = (uint32_t) mapArray[SHMHDR->x][SHMHDR->y][SHMHDR->z]; + ReadBlockByAddress(data); // I wonder... will this inline properly? +} + DFPP_module InitMaps( void ) { DFPP_module maps; @@ -108,6 +109,7 @@ DFPP_module InitMaps( void ) maps.set_command(MAP_INIT, FUNCTION, "Supply the module with offsets",InitOffsets,CORE_SUSPENDED); maps.set_command(MAP_GET_SIZE, FUNCTION, "Get map size in 16x16x1 tile blocks", GetMapSize, CORE_SUSPENDED); maps.set_command(MAP_READ_BLOCK_BY_COORDS, FUNCTION, "Read the whole block with specified coords", ReadBlockByCoords, CORE_SUSPENDED); + maps.set_command(MAP_READ_BLOCK_BY_ADDRESS, FUNCTION, "Read the whole block from an address", ReadBlockByAddress, CORE_SUSPENDED); // will it fit into 1MB? We shouldn't assume this is the case maps.set_command(MAP_READ_BLOCKTREE, FUNCTION,"Get the tree of block pointers as a single structure", NullCommand, CORE_SUSPENDED); diff --git a/shmserver/mod-maps.h b/shmserver/mod-maps.h index 34e6889a1..5ff5f0f2e 100644 --- a/shmserver/mod-maps.h +++ b/shmserver/mod-maps.h @@ -33,7 +33,7 @@ namespace DFHack namespace Maps { -#define MAPS_VERSION 1 +#define MAPS_VERSION 2 typedef struct { uint32_t map_offset;// = d->offset_descriptor->getAddress ("map_data"); @@ -89,8 +89,11 @@ enum MAPS_COMMAND MAP_GET_SIZE, // get the map size in 16x16x1 blocks MAP_READ_BLOCKTREE, // read the structure of pointers to blocks MAP_READ_BLOCK_BY_COORDS, // read block by cords + MAP_READ_BLOCK_BY_ADDRESS, // read block by address + MAP_WRITE_BLOCK, MAP_READ_BLOCKS_3D, // read blocks between two coords (volumetric) MAP_READ_ALL_BLOCKS, // read the entire map + MAP_REVEAL, // reveal the whole map NUM_MAPS_CMDS, }; } From 90baaad19bc33c07418497e5bcc4748fa4c9463f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 8 Mar 2010 01:54:46 +0100 Subject: [PATCH 11/16] Allow recognizing multiple DF SHM processes by the client --- library/DFProcess-linux-SHM.cpp | 4 ++-- library/DFProcess.h | 2 +- library/DFProcessEnumerator-linux.cpp | 10 ++++++---- shmserver/shms-linux.cpp | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 0ac7954b1..fb7226d16 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -180,7 +180,7 @@ void Process::Private::DF_SyncAffinity( void ) #endif } -Process::Process(vector & known_versions) +Process::Process(uint32_t PID, vector< memory_info* >& known_versions) : d(new Private()) { char exe_link_name [256]; @@ -232,7 +232,7 @@ Process::Process(vector & known_versions) /* * get the PID from DF */ - if(d->DF_GetPID(d->my_pid)) + if(d->DF_GetPID(d->my_pid) && d->my_pid == PID) { // find its binary sprintf(exe_link_name,"/proc/%d/exe", d->my_pid); diff --git a/library/DFProcess.h b/library/DFProcess.h index 8ad71e04e..91d1d773e 100644 --- a/library/DFProcess.h +++ b/library/DFProcess.h @@ -66,7 +66,7 @@ namespace DFHack Private *d; public: // this is the single most important destructor ever. ~px - Process(vector & known_versions); + Process(uint32_t PID ,vector & known_versions); ~Process(); // Set up stuff so we can read memory diff --git a/library/DFProcessEnumerator-linux.cpp b/library/DFProcessEnumerator-linux.cpp index 783bff27c..b67e83b3a 100644 --- a/library/DFProcessEnumerator-linux.cpp +++ b/library/DFProcessEnumerator-linux.cpp @@ -46,7 +46,7 @@ bool ProcessEnumerator::findProcessess() { DIR *dir_p; struct dirent *dir_entry_p; - + /* Process *p = 0; p = new Process(d->meminfo->meminfo); if(p->isIdentified()) @@ -58,7 +58,7 @@ bool ProcessEnumerator::findProcessess() delete p; p = 0; } - /* + */ // Open /proc/ directory dir_p = opendir("/proc/"); // Reading /proc/ entries @@ -69,7 +69,7 @@ bool ProcessEnumerator::findProcessess() { continue; } - Process *p2 = new NormalProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo); + Process *p2 = new Process(atoi(dir_entry_p->d_name),d->meminfo->meminfo); if(p2->isIdentified()) { d->processes.push_back(p2); @@ -79,6 +79,7 @@ bool ProcessEnumerator::findProcessess() { delete p2; } + /* Process *p3 = new WineProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo); if(p3->isIdentified()) { @@ -89,9 +90,10 @@ bool ProcessEnumerator::findProcessess() { delete p3; } + */ } closedir(dir_p); - */ + // return value depends on if we found some DF processes if(d->processes.size()) { diff --git a/shmserver/shms-linux.cpp b/shmserver/shms-linux.cpp index 63812b673..79e185203 100644 --- a/shmserver/shms-linux.cpp +++ b/shmserver/shms-linux.cpp @@ -85,8 +85,8 @@ void SHM_Init ( void ) } inited = true; - // name for the segment - key_t key = 123466; + // name for the segment, an accident waiting to happen + key_t key = SHM_KEY + OS_getPID(); // find previous segment, check if it's used by some processes. // if it isn't, kill it with fire From 36a6f1f0a4f86f61604b9270ccd24e1dc62c9654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 8 Mar 2010 05:15:11 +0100 Subject: [PATCH 12/16] mod-core rework squashed some init commands together fixed a problem with non-atomic shm command reading on the DF side that caused segfaults --- library/DFHackAPI.cpp | 3 +- library/DFProcess-linux-SHM.cpp | 123 +++++++------ library/DFProcess-windows-SHM.cpp | 220 +++++++++++------------- library/DFProcessEnumerator-windows.cpp | 41 ++--- shmserver/mod-core.cpp | 121 ++++++------- shmserver/mod-core.h | 62 +++---- 6 files changed, 272 insertions(+), 298 deletions(-) diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index 8ad8f1e48..24da74d1c 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -297,9 +297,10 @@ bool API::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) SHMMAPSHDR->x = x; SHMMAPSHDR->y = y; SHMMAPSHDR->z = z; - const uint32_t cmd = Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16); + volatile uint32_t cmd = Maps::MAP_READ_BLOCK_BY_COORDS + (d->maps_module << 16); full_barrier SHMCMD = cmd; + full_barrier if(!g_pProcess->waitWhile(cmd)) { return false; diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index fb7226d16..766e1e3f9 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -67,9 +67,8 @@ class Process::Private bool useYield; bool validate(char* exe_file, uint32_t pid, std::vector< memory_info* >& known_versions); - bool DF_TestBridgeVersion(bool & ret); - bool DF_GetPID(pid_t & ret); - void DF_SyncAffinity(void); + + bool Aux_Core_Attach(bool & versionOK, pid_t & PID); bool waitWhile (uint32_t state); }; @@ -80,6 +79,9 @@ class Process::Private #define SHMHDR ((shm_core_hdr *)my_shm) #define D_SHMHDR ((shm_core_hdr *)d->my_shm) +#define SHMDATA(type) ((type *)(my_shm + SHM_HEADER)) +#define D_SHMDATA(type) ((type *)(d->my_shm + SHM_HEADER)) + /* Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling) we end up with this silly thing @@ -111,7 +113,7 @@ bool Process::Private::waitWhile (uint32_t state) } cnt++; } - if(SHMCMD == CORE_SV_ERROR) + if(SHMCMD == CORE_ERROR) { SHMCMD = CORE_RUNNING; attached = suspended = false; @@ -131,53 +133,31 @@ bool Process::waitWhile (uint32_t state) return d->waitWhile(state); } -bool Process::Private::DF_TestBridgeVersion(bool & ret) -{ - SHMCMD = CORE_GET_VERSION; - gcc_barrier - if(!waitWhile(CORE_GET_VERSION)) - return false; - gcc_barrier - SHMCMD = CORE_SUSPENDED; - ret =( SHMHDR->value == CORE_VERSION ); - return true; -} - -bool Process::Private::DF_GetPID(pid_t & ret) -{ - SHMCMD = CORE_GET_PID; - gcc_barrier - if(!waitWhile(CORE_GET_PID)) - return false; - gcc_barrier - SHMCMD = CORE_SUSPENDED; - ret = SHMHDR->value; - return true; -} - uint32_t OS_getAffinity() { cpu_set_t mask; sched_getaffinity(0,sizeof(cpu_set_t),&mask); // FIXME: truncation - uint32_t affinity = *(uint32_t *) &mask; - return affinity; + uint32_t affinity = *(uint32_t *) &mask; + return affinity; } -void Process::Private::DF_SyncAffinity( void ) + +bool Process::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID) { - SHMHDR->value = OS_getAffinity(); + SHMDATA(coreattach)->cl_affinity = OS_getAffinity(); gcc_barrier - SHMCMD = CORE_SYNC_YIELD; - gcc_barrier - if(!waitWhile(CORE_SYNC_YIELD)) - return; + SHMCMD = CORE_ATTACH; + if(!waitWhile(CORE_ATTACH)) + return false; gcc_barrier - SHMCMD = CORE_SUSPENDED; - useYield = SHMHDR->value; + versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION ); + PID = SHMDATA(coreattach)->sv_PID; + useYield = SHMDATA(coreattach)->sv_useYield; #ifdef DEBUG - if(useYield) cerr << "Using Yield!" << endl; + if(useYield) cerr << "Using Yield!" << endl; #endif + return true; } Process::Process(uint32_t PID, vector< memory_info* >& known_versions) @@ -190,7 +170,7 @@ Process::Process(uint32_t PID, vector< memory_info* >& known_versions) /* * Locate the segment. */ - if ((d->my_shmid = shmget(SHM_KEY, SHM_SIZE, 0666)) < 0) + if ((d->my_shmid = shmget(SHM_KEY + PID, SHM_SIZE, 0666)) < 0) { return; } @@ -216,41 +196,40 @@ Process::Process(uint32_t PID, vector< memory_info* >& known_versions) } /* - * Test bridge version, will also detect when we connect to something that doesn't respond + * Test bridge version, get PID, sync Yield */ bool bridgeOK; - if(!d->DF_TestBridgeVersion(bridgeOK)) + if(!d->Aux_Core_Attach(bridgeOK,d->my_pid)) { fprintf(stderr,"DF terminated during reading\n"); + shmdt(d->my_shm); return; } if(!bridgeOK) { fprintf(stderr,"SHM bridge version mismatch\n"); + shmdt(d->my_shm); return; } - /* - * get the PID from DF - */ - if(d->DF_GetPID(d->my_pid) && d->my_pid == PID) + + // find the binary + sprintf(exe_link_name,"/proc/%d/exe", d->my_pid); + target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); + if (target_result == -1) { - // find its binary - sprintf(exe_link_name,"/proc/%d/exe", d->my_pid); - target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); - if (target_result == -1) - { - perror("readlink"); - return; - } - // make sure we have a null terminated string... - // see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html - target_name[target_result] = 0; - - // try to identify the DF version - d->validate(target_name, d->my_pid, known_versions); - d->DF_SyncAffinity(); - d->my_window = new DFWindow(this); + perror("readlink"); + shmdt(d->my_shm); + return; } + + // make sure we have a null terminated string... + // see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html + target_name[target_result] = 0; + + // try to identify the DF version + d->validate(target_name, d->my_pid, known_versions); + d->my_window = new DFWindow(this); + gcc_barrier // at this point, DF is stopped and waiting for commands. make it run again D_SHMCMD = CORE_RUNNING; @@ -708,16 +687,30 @@ string Process::readClassName (uint32_t vptr) return raw.substr(start,end-start - 2); // trim the 'st' from the end } +// FIXME: having this around could lead to bad things in the hands of unsuspecting fools +// *!!DON'T BE AN UNSUSPECTING FOOL!!* +// the whole SHM thing works only because copying DWORDS is an atomic operation on i386 and x86_64 archs // get module index by name and version. bool 1 = error bool Process::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { modulelookup * payload = (modulelookup *) (d->my_shm + SHM_HEADER); payload->version = version; - strcpy(payload->name,name); + + strncpy(payload->name,name,255); + payload->name[255] = 0; + full_barrier + D_SHMCMD = CORE_ACQUIRE_MODULE; - waitWhile(CORE_ACQUIRE_MODULE); - if(D_SHMHDR->error) return false; + if(!waitWhile(CORE_ACQUIRE_MODULE)) + { + return false; // FIXME: throw a fatal exception instead + } + if(D_SHMHDR->error) + { + return false; + } + //fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value); OUTPUT = D_SHMHDR->value; return true; } diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 62c2cc50d..1fcd34fb0 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -58,9 +58,7 @@ class Process::Private bool waitWhile (uint32_t state); bool isValidSV(); - bool DF_TestBridgeVersion(bool & ret); - bool DF_GetPID(uint32_t & ret); - void DF_SyncAffinity(void); + bool Aux_Core_Attach(bool & versionOK, uint32_t & PID); }; // some helpful macros to keep the code bloat in check @@ -70,6 +68,9 @@ class Process::Private #define SHMHDR ((shm_core_hdr *)my_shm) #define D_SHMHDR ((shm_core_hdr *)d->my_shm) +#define SHMDATA(type) ((type *)(my_shm + SHM_HEADER)) +#define D_SHMDATA(type) ((type *)(d->my_shm + SHM_HEADER)) + // is the other side still there? bool Process::Private::isValidSV() { @@ -129,7 +130,7 @@ bool Process::Private::waitWhile (uint32_t state) } cnt++; } - if(SHMCMD == CORE_SV_ERROR) + if(SHMCMD == CORE_ERROR) { SHMCMD = CORE_RUNNING; attached = suspended = false; @@ -139,30 +140,6 @@ bool Process::Private::waitWhile (uint32_t state) return true; } -bool Process::Private::DF_TestBridgeVersion(bool & ret) -{ - SHMCMD = CORE_GET_VERSION; - full_barrier - if(!waitWhile(CORE_GET_VERSION)) - return false; - full_barrier - SHMCMD = CORE_SUSPENDED; - ret =( SHMHDR->value == CORE_VERSION ); - return true; -} - -bool Process::Private::DF_GetPID(uint32_t & ret) -{ - SHMCMD = CORE_GET_PID; - full_barrier - if(!waitWhile(CORE_GET_PID)) - return false; - full_barrier - SHMCMD = CORE_SUSPENDED; - ret = SHMHDR->value; - return true; -} - uint32_t OS_getAffinity() { HANDLE hProcess = GetCurrentProcess(); @@ -171,22 +148,24 @@ uint32_t OS_getAffinity() return dwProcessAffinityMask; } -void Process::Private::DF_SyncAffinity( void ) +bool Process::Private::Aux_Core_Attach(bool & versionOK, uint32_t & PID) { - SHMHDR->value = OS_getAffinity(); - full_barrier - SHMCMD = CORE_SYNC_YIELD; + SHMDATA(coreattach)->cl_affinity = OS_getAffinity(); full_barrier - if(!waitWhile(CORE_SYNC_YIELD)) - return; + SHMCMD = CORE_ATTACH; + if(!waitWhile(CORE_ATTACH)) + return false; full_barrier - SHMCMD = CORE_SUSPENDED; - useYield = SHMHDR->value; - if(useYield) cerr << "Using Yield!" << endl; + versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION ); + PID = SHMDATA(coreattach)->sv_PID; + useYield = SHMDATA(coreattach)->sv_useYield; + #ifdef DEBUG + if(useYield) cerr << "Using Yield!" << endl; + #endif + return true; } - -Process::Process(vector & known_versions) +Process::Process(uint32_t PID, vector & known_versions) : d(new Private()) { // get server and client mutex @@ -200,29 +179,28 @@ Process::Process(vector & known_versions) { return; } + + // attach the SHM if(!attach()) { return; } - // All seems to be OK so far. Attached and connected to something that looks like DF - - // Test bridge version, will also detect when we connect to something that doesn't respond + // Test bridge version, get PID, sync Yield bool bridgeOK; - if(!d->DF_TestBridgeVersion(bridgeOK)) + bool error = 0; + if(!d->Aux_Core_Attach(bridgeOK,d->my_pid)) { fprintf(stderr,"DF terminated during reading\n"); - UnmapViewOfFile(d->my_shm); - ReleaseMutex(d->DFCLMutex); - CloseHandle(d->DFSVMutex); - d->DFSVMutex = 0; - CloseHandle(d->DFCLMutex); - d->DFCLMutex = 0; - return; + error = 1; } - if(!bridgeOK) + else if(!bridgeOK) { fprintf(stderr,"SHM bridge version mismatch\n"); + error = 1; + } + if(error) + { D_SHMCMD = CORE_RUNNING; UnmapViewOfFile(d->my_shm); ReleaseMutex(d->DFCLMutex); @@ -232,84 +210,78 @@ Process::Process(vector & known_versions) d->DFCLMutex = 0; return; } - /* - * get the PID from DF - */ - if(d->DF_GetPID(d->my_pid)) - { - // try to identify the DF version - do // glorified goto - { - IMAGE_NT_HEADERS32 pe_header; - IMAGE_SECTION_HEADER sections[16]; - HMODULE hmod = NULL; - DWORD junk; - HANDLE hProcess; - bool found = false; - d->identified = false; - // open process, we only need the process open - hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid ); - if (NULL == hProcess) - break; - - // try getting the first module of the process - if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) - { - CloseHandle(hProcess); - cout << "EnumProcessModules fail'd" << endl; - break; - } - // got base ;) - uint32_t base = (uint32_t)hmod; - - // read from this process - uint32_t pe_offset = readDWord(base+0x3C); - read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); - read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)§ions ); - - // iterate over the list of memory locations - vector::iterator it; - for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) - { - uint32_t pe_timestamp; - try - { - pe_timestamp = (*it)->getHexValue("pe_timestamp"); - } - catch(Error::MissingMemoryDefinition& e) - { - continue; - } - if (pe_timestamp == pe_header.FileHeader.TimeDateStamp) - { - memory_info *m = new memory_info(**it); - m->RebaseAll(base); - d->my_descriptor = m; - d->identified = true; - cerr << "identified " << m->getVersion() << endl; - break; - } - } - CloseHandle(hProcess); - } while (0); // glorified goto end + + // try to identify the DF version + do // glorified goto + { + IMAGE_NT_HEADERS32 pe_header; + IMAGE_SECTION_HEADER sections[16]; + HMODULE hmod = NULL; + DWORD junk; + HANDLE hProcess; + bool found = false; + d->identified = false; + // open process, we only need the process open + hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->my_pid ); + if (NULL == hProcess) + break; - if(d->identified) + // try getting the first module of the process + if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) { - d->my_window = new DFWindow(this); - d->DF_SyncAffinity(); + CloseHandle(hProcess); + cout << "EnumProcessModules fail'd" << endl; + break; } - else + // got base ;) + uint32_t base = (uint32_t)hmod; + + // read from this process + uint32_t pe_offset = readDWord(base+0x3C); + read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); + read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)§ions ); + + // iterate over the list of memory locations + vector::iterator it; + for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) { - D_SHMCMD = CORE_RUNNING; - UnmapViewOfFile(d->my_shm); - d->my_shm = 0; - ReleaseMutex(d->DFCLMutex); - CloseHandle(d->DFSVMutex); - d->DFSVMutex = 0; - CloseHandle(d->DFCLMutex); - d->DFCLMutex = 0; - return; + uint32_t pe_timestamp; + try + { + pe_timestamp = (*it)->getHexValue("pe_timestamp"); + } + catch(Error::MissingMemoryDefinition& e) + { + continue; + } + if (pe_timestamp == pe_header.FileHeader.TimeDateStamp) + { + memory_info *m = new memory_info(**it); + m->RebaseAll(base); + d->my_descriptor = m; + d->identified = true; + cerr << "identified " << m->getVersion() << endl; + break; + } } + CloseHandle(hProcess); + } while (0); // glorified goto end + + if(d->identified) + { + d->my_window = new DFWindow(this); + } + else + { + D_SHMCMD = CORE_RUNNING; + UnmapViewOfFile(d->my_shm); + d->my_shm = 0; + ReleaseMutex(d->DFCLMutex); + CloseHandle(d->DFSVMutex); + d->DFSVMutex = 0; + CloseHandle(d->DFCLMutex); + d->DFCLMutex = 0; + return; } full_barrier // at this point, DF is attached and suspended, make it run diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp index f263e6380..1c906cb9d 100644 --- a/library/DFProcessEnumerator-windows.cpp +++ b/library/DFProcessEnumerator-windows.cpp @@ -41,12 +41,23 @@ bool ProcessEnumerator::findProcessess() { // Get the list of process identifiers. DWORD ProcArray[2048], memoryNeeded, numProccesses; + //EnableDebugPriv(); + if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) ) { - Process * p = new Process(d->meminfo->meminfo); + cout << "EnumProcesses fail'd" << endl; + 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); - return true; } else { @@ -55,30 +66,20 @@ bool ProcessEnumerator::findProcessess() } } /* - EnableDebugPriv(); - if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) ) { - cout << "EnumProcesses fail'd" << endl; - 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 *q = new NormalProcess(ProcArray[i],d->meminfo->meminfo); - if(q->isIdentified()) + Process * p = new Process(d->meminfo->meminfo); + if(p->isIdentified()) { - d->processes.push_back(q); + d->processes.push_back(p); + return true; } else { - delete q; - q = 0; + delete p; + p = 0; } - }*/ + } + */ if(d->processes.size()) return true; return false; diff --git a/shmserver/mod-core.cpp b/shmserver/mod-core.cpp index 093aefec5..5131303d1 100644 --- a/shmserver/mod-core.cpp +++ b/shmserver/mod-core.cpp @@ -49,16 +49,7 @@ bool useYield = 0; #define SHMHDR ((shm_core_hdr *)shm) #define SHMCMD ((shm_cmd *)shm)->pingpong - -void GetCoreVersion (void * data) -{ - SHMHDR->value = module_registry[0].version; -} - -void GetPID (void * data) -{ - SHMHDR->value = OS_getPID(); -} +#define SHMDATA(type) ((type *)(shm + SHM_HEADER)) void ReadRaw (void * data) { @@ -126,19 +117,17 @@ int bitcount(uint32_t n) } // get local and remote affinity, set up yield if required (single core available) -void SyncYield (void * data) +void CoreAttach (void * data) { + // sync affinity uint32_t local = OS_getAffinity(); - uint32_t remote = SHMHDR->value; + uint32_t remote = SHMDATA(coreattach)->cl_affinity; uint32_t pool = local | remote; - if(bitcount(pool) == 1) - { - SHMHDR->value = useYield = 1; - } - else - { - SHMHDR->value = useYield = 0; - } + SHMDATA(coreattach)->sv_useYield = useYield = (bitcount(pool) == 1); + // return our PID + SHMDATA(coreattach)->sv_PID = OS_getPID(); + // return core version + SHMDATA(coreattach)->sv_version = module_registry[0].version; } void FindModule (void * data) @@ -157,14 +146,33 @@ void FindModule (void * data) break; } } - if(found) - { - SHMHDR->error = false; - } - else + SHMHDR->error = !found; +} + +void FindCommand (void * data) +{ + bool found = false; + commandlookup * payload = SHMDATA(commandlookup); + std::string modname = payload->module; + std::string cmdname = payload->name; + uint32_t version = payload->version; + for(unsigned int i = 0; i < module_registry.size();i++) { - SHMHDR->error = true; + if(module_registry[i].name == modname && module_registry[i].version == version) + { + for(unsigned int j = 0 ; j < module_registry[i].commands.size();j++) + { + if(module_registry[i].commands[j].name == cmdname) + { + // gotcha + SHMHDR->value = j + (i << 16); + SHMHDR->error = false; + return; + } + } + } } + SHMHDR->error = true; } DFPP_module InitCore(void) @@ -176,45 +184,29 @@ DFPP_module InitCore(void) core.reserve(NUM_CORE_CMDS); core.set_command(CORE_RUNNING, CANCELLATION, "Running"); + core.set_command(CORE_SUSPEND, CLIENT_WAIT, "Suspend", 0 , CORE_SUSPENDED); + core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended"); - core.set_command(CORE_GET_VERSION, FUNCTION,"Get core version",GetCoreVersion, CORE_RET_VERSION); - core.set_command(CORE_RET_VERSION, CLIENT_WAIT,"Core version return"); - - core.set_command(CORE_GET_PID, FUNCTION, "Get PID", GetPID, CORE_RET_PID); - core.set_command(CORE_RET_PID, CLIENT_WAIT, "PID return"); - - core.set_command(CORE_DFPP_READ, FUNCTION,"Raw read",ReadRaw, CORE_RET_DATA); - core.set_command(CORE_RET_DATA, CLIENT_WAIT,"Raw read return"); - - core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord, CORE_RET_DWORD); - core.set_command(CORE_RET_DWORD, CLIENT_WAIT,"Read DWORD return"); - - core.set_command(CORE_READ_WORD, FUNCTION,"Read WORD",ReadWord, CORE_RET_WORD); - core.set_command(CORE_RET_WORD, CLIENT_WAIT,"Read WORD return"); + core.set_command(CORE_ATTACH, FUNCTION,"Core attach",CoreAttach, CORE_SUSPENDED); - core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte, CORE_RET_BYTE); - core.set_command(CORE_RET_BYTE, CLIENT_WAIT,"Read BYTE return"); + core.set_command(CORE_DFPP_READ, FUNCTION,"Raw read",ReadRaw, CORE_SUSPENDED); + core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord, CORE_SUSPENDED); + core.set_command(CORE_READ_WORD, FUNCTION,"Read WORD",ReadWord, CORE_SUSPENDED); + core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte, CORE_SUSPENDED); - core.set_command(CORE_SV_ERROR, CANCELLATION, "Server error"); - core.set_command(CORE_CL_ERROR, CANCELLATION, "Client error"); + core.set_command(CORE_ERROR, CANCELLATION, "Error"); core.set_command(CORE_WRITE, FUNCTION, "Raw write", WriteRaw, CORE_SUSPENDED); core.set_command(CORE_WRITE_DWORD, FUNCTION, "Write DWORD", WriteDWord, CORE_SUSPENDED); core.set_command(CORE_WRITE_WORD, FUNCTION, "Write WORD", WriteWord, CORE_SUSPENDED); core.set_command(CORE_WRITE_BYTE, FUNCTION, "Write BYTE", WriteByte, CORE_SUSPENDED); - core.set_command(CORE_SUSPEND, CLIENT_WAIT, "Suspend", 0 , CORE_SUSPENDED); - core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended"); - - core.set_command(CORE_READ_STL_STRING, FUNCTION, "Read STL string", ReadSTLString, CORE_RET_STRING); + core.set_command(CORE_READ_STL_STRING, FUNCTION, "Read STL string", ReadSTLString, CORE_SUSPENDED); core.set_command(CORE_READ_C_STRING, CLIENT_WAIT, "RESERVED"); - core.set_command(CORE_RET_STRING, CLIENT_WAIT, "Return string"); core.set_command(CORE_WRITE_STL_STRING, FUNCTION, "Write STL string", WriteSTLString, CORE_SUSPENDED); - core.set_command(CORE_SYNC_YIELD, FUNCTION, "Synchronize affinity/yield", SyncYield, CORE_SYNC_YIELD_RET); - core.set_command(CORE_SYNC_YIELD_RET, CLIENT_WAIT, "Synchronize affinity/yield return"); - core.set_command(CORE_ACQUIRE_MODULE, FUNCTION, "Module lookup", FindModule, CORE_RET_MODULE); - core.set_command(CORE_RET_MODULE, CLIENT_WAIT, "Return module index or error"); + core.set_command(CORE_ACQUIRE_MODULE, FUNCTION, "Module lookup", FindModule, CORE_SUSPENDED); + core.set_command(CORE_ACQUIRE_COMMAND, FUNCTION, "Command lookup", FindCommand, CORE_SUSPENDED); return core; } @@ -253,24 +245,37 @@ void SHM_Act (void) } else { - // full_barrier + full_barrier SHMCMD = CORE_RUNNING; fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n"); } } - DFPP_module & mod = module_registry[((shm_cmd *)shm)->parts.module]; - DFPP_command & cmd = mod.commands[((shm_cmd *)shm)->parts.command]; - //fprintf(stderr, "Client invoked %d:%d = ",((shm_cmd *)shm)->parts.module,((shm_cmd *)shm)->parts.command); - //fprintf(stderr, "%s\n",cmd.name.c_str()); + // this is very important! copying two words separately from the command variable leads to inconsistency. + // Always copy the thing in one go. + // Also, this whole SHM thing probably only works on intel processors + + volatile shm_cmd atomic = SHMHDR->cmd; + full_barrier + DFPP_module & mod = module_registry[atomic.parts.module]; + DFPP_command & cmd = mod.commands[atomic.parts.command]; + full_barrier + /* + fprintf(stderr, "Called %x\0", cmd._function); + fprintf(stderr, "Client invoked %d:%d = ",atomic.parts.module,atomic.parts.command); + fprintf(stderr, "%s\n",cmd.name.c_str()); + */ + full_barrier if(cmd._function) { cmd._function(mod.modulestate); } + full_barrier if(cmd.nextState != -1) { SHMCMD = cmd.nextState; } + full_barrier if(cmd.type != CANCELLATION) { if(useYield) diff --git a/shmserver/mod-core.h b/shmserver/mod-core.h index be407691c..955c7deda 100644 --- a/shmserver/mod-core.h +++ b/shmserver/mod-core.h @@ -43,54 +43,56 @@ typedef struct char name[256]; } modulelookup; +typedef struct +{ + uint32_t version; + char module[256]; + char name[256]; +} commandlookup; + +typedef struct +{ + uint32_t sv_version; // output + uint32_t cl_affinity; // input + uint32_t sv_PID; // output + uint32_t sv_useYield; // output +} coreattach; + enum CORE_COMMAND { + // suspend / resume CORE_RUNNING = 0, // no command, normal server execution + CORE_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait) + CORE_SUSPENDED, // response to WAIT, server is stalled in busy wait - CORE_GET_VERSION, // protocol version query - CORE_RET_VERSION, // return the protocol version - - CORE_GET_PID, // query for the process ID - CORE_RET_PID, // return process ID + // aux + CORE_ATTACH, // compare affinity, get core version and process ID - // version 1 stuff below + // reads CORE_DFPP_READ, // cl -> sv, read some data - CORE_RET_DATA, // sv -> cl, returned data - CORE_READ_DWORD, // cl -> sv, read a dword - CORE_RET_DWORD, // sv -> cl, returned dword - CORE_READ_WORD, // cl -> sv, read a word - CORE_RET_WORD, // sv -> cl, returned word - CORE_READ_BYTE, // cl -> sv, read a byte - CORE_RET_BYTE, // sv -> cl, returned byte - - CORE_SV_ERROR, // there was a server error - CORE_CL_ERROR, // there was a client error - + + // writes CORE_WRITE,// client writes to server CORE_WRITE_DWORD,// client writes a DWORD to server CORE_WRITE_WORD,// client writes a WORD to server CORE_WRITE_BYTE,// client writes a BYTE to server + + // error state + CORE_ERROR, // there was a server error - CORE_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait) - CORE_SUSPENDED, // response to WAIT, server is stalled in busy wait - - // all strings capped at 1MB + // string functions CORE_READ_STL_STRING,// client requests contents of STL string at address CORE_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated) - CORE_RET_STRING, // sv -> cl length + string contents CORE_WRITE_STL_STRING,// client wants to set STL string at address to something - // compare affinity and determine if using yield is required - CORE_SYNC_YIELD,// cl sends affinity to sv, sv sets yield - CORE_SYNC_YIELD_RET,// sv returns yield bool - - // get index of a loaded module by name and version - CORE_ACQUIRE_MODULE, - // returning module index - CORE_RET_MODULE, + // extension module enumeration + CORE_ACQUIRE_MODULE, // get index of a loaded module by name and version + CORE_ACQUIRE_COMMAND, // get module::command callsign by module name, command name and module version + + // total commands NUM_CORE_CMDS }; #endif \ No newline at end of file From 9d7574dafe2da7b93131996a667c583243f9e7c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 9 Mar 2010 03:30:22 +0100 Subject: [PATCH 13/16] DF disappeared exception --- library/DFError.h | 11 +++++++++++ library/DFProcess-linux-SHM.cpp | 10 ++++++++-- library/DFProcess-windows-SHM.cpp | 3 ++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/library/DFError.h b/library/DFError.h index 3e905b491..a3a0a036c 100644 --- a/library/DFError.h +++ b/library/DFError.h @@ -208,6 +208,17 @@ namespace DFHack return s.str().c_str(); } }; + + class DFHACK_EXPORT SHMServerDisappeared : public std::exception + { + public: + SHMServerDisappeared(){} + virtual ~SHMServerDisappeared() throw(){}; + virtual const char* what() const throw() + { + return "The server process has disappeared"; + } + }; } } diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 766e1e3f9..581635e5e 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -96,10 +96,16 @@ bool Process::Private::waitWhile (uint32_t state) { shmctl(my_shmid, IPC_STAT, &descriptor); - if(descriptor.shm_nattch == 1)// DF crashed? + if(descriptor.shm_nattch == 1)// DF crashed or exited - no way to tell? { - SHMCMD = CORE_RUNNING; + //detach the shared memory + shmdt(my_shm); attached = suspended = false; + + // we aren't the current process anymore + g_pProcess = NULL; + + throw Error::SHMServerDisappeared(); return false; } else diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 1fcd34fb0..a8ccdf431 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -118,9 +118,10 @@ bool Process::Private::waitWhile (uint32_t state) { if(!isValidSV())// DF not there anymore? { - SHMCMD = CORE_RUNNING; attached = suspended = false; ReleaseMutex(DFCLMutex); + UnmapViewOfFile(my_shm); + throw Error::SHMServerDisappeared(); return false; } else From 3e581908c1cec1ca1b7084f110a81a16a5a5d9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 9 Mar 2010 13:41:55 +0100 Subject: [PATCH 14/16] Each DF process on windows now has unique mutex and shm names. --- library/DFProcess-windows-SHM.cpp | 15 ++++++++++++--- shmserver/mod-core.cpp | 13 ++++++++----- shmserver/mod-core.h | 24 ++++++++++-------------- shmserver/shms-windows.cpp | 19 +++++++++++++------ 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index a8ccdf431..59fe25bd1 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -169,17 +169,23 @@ bool Process::Private::Aux_Core_Attach(bool & versionOK, uint32_t & PID) Process::Process(uint32_t PID, vector & known_versions) : d(new Private()) { + char svmutexname [256]; + sprintf(svmutexname,"DFSVMutex-%d",PID); + char clmutexname [256]; + sprintf(clmutexname,"DFCLMutex-%d",PID); + // get server and client mutex - d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex"); + d->DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname); if(d->DFSVMutex == 0) { return; } - d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex"); + d->DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname); if(d->DFCLMutex == 0) { return; } + d->my_pid = PID; // attach the SHM if(!attach()) @@ -469,8 +475,11 @@ bool Process::attach() return false; // we couldn't lock it } + char shmname [256]; + sprintf(shmname,"DFShm-%d",d->my_pid); + // now try getting and attaching the shared memory - HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,"DFShm"); + HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,shmname); if(!shmHandle) { ReleaseMutex(d->DFCLMutex); diff --git a/shmserver/mod-core.cpp b/shmserver/mod-core.cpp index 5131303d1..cd3137d62 100644 --- a/shmserver/mod-core.cpp +++ b/shmserver/mod-core.cpp @@ -183,30 +183,33 @@ DFPP_module InitCore(void) core.modulestate = 0; // this one is dumb and has no real state core.reserve(NUM_CORE_CMDS); + // basic states core.set_command(CORE_RUNNING, CANCELLATION, "Running"); core.set_command(CORE_SUSPEND, CLIENT_WAIT, "Suspend", 0 , CORE_SUSPENDED); core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended"); + core.set_command(CORE_ERROR, CANCELLATION, "Error"); + // utility commands core.set_command(CORE_ATTACH, FUNCTION,"Core attach",CoreAttach, CORE_SUSPENDED); + core.set_command(CORE_ACQUIRE_MODULE, FUNCTION, "Module lookup", FindModule, CORE_SUSPENDED); + core.set_command(CORE_ACQUIRE_COMMAND, FUNCTION, "Command lookup", FindCommand, CORE_SUSPENDED); + // raw reads core.set_command(CORE_DFPP_READ, FUNCTION,"Raw read",ReadRaw, CORE_SUSPENDED); core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord, CORE_SUSPENDED); core.set_command(CORE_READ_WORD, FUNCTION,"Read WORD",ReadWord, CORE_SUSPENDED); core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte, CORE_SUSPENDED); - core.set_command(CORE_ERROR, CANCELLATION, "Error"); - + // raw writes core.set_command(CORE_WRITE, FUNCTION, "Raw write", WriteRaw, CORE_SUSPENDED); core.set_command(CORE_WRITE_DWORD, FUNCTION, "Write DWORD", WriteDWord, CORE_SUSPENDED); core.set_command(CORE_WRITE_WORD, FUNCTION, "Write WORD", WriteWord, CORE_SUSPENDED); core.set_command(CORE_WRITE_BYTE, FUNCTION, "Write BYTE", WriteByte, CORE_SUSPENDED); + // stl string commands core.set_command(CORE_READ_STL_STRING, FUNCTION, "Read STL string", ReadSTLString, CORE_SUSPENDED); core.set_command(CORE_READ_C_STRING, CLIENT_WAIT, "RESERVED"); core.set_command(CORE_WRITE_STL_STRING, FUNCTION, "Write STL string", WriteSTLString, CORE_SUSPENDED); - - core.set_command(CORE_ACQUIRE_MODULE, FUNCTION, "Module lookup", FindModule, CORE_SUSPENDED); - core.set_command(CORE_ACQUIRE_COMMAND, FUNCTION, "Command lookup", FindCommand, CORE_SUSPENDED); return core; } diff --git a/shmserver/mod-core.h b/shmserver/mod-core.h index 955c7deda..37717cb6f 100644 --- a/shmserver/mod-core.h +++ b/shmserver/mod-core.h @@ -26,7 +26,7 @@ distribution. #define SHMS_CORE_H // increment on every core change -#define CORE_VERSION 6 +#define CORE_VERSION 7 typedef struct { @@ -60,37 +60,33 @@ typedef struct enum CORE_COMMAND { - // suspend / resume + // basic states CORE_RUNNING = 0, // no command, normal server execution CORE_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait) CORE_SUSPENDED, // response to WAIT, server is stalled in busy wait - - // aux + CORE_ERROR, // there was a server error + + // utility commands CORE_ATTACH, // compare affinity, get core version and process ID - - // reads + CORE_ACQUIRE_MODULE, // get index of a loaded module by name and version + CORE_ACQUIRE_COMMAND, // get module::command callsign by module name, command name and module version + + // raw reads CORE_DFPP_READ, // cl -> sv, read some data CORE_READ_DWORD, // cl -> sv, read a dword CORE_READ_WORD, // cl -> sv, read a word CORE_READ_BYTE, // cl -> sv, read a byte - // writes + // raw writes CORE_WRITE,// client writes to server CORE_WRITE_DWORD,// client writes a DWORD to server CORE_WRITE_WORD,// client writes a WORD to server CORE_WRITE_BYTE,// client writes a BYTE to server - // error state - CORE_ERROR, // there was a server error - // string functions CORE_READ_STL_STRING,// client requests contents of STL string at address CORE_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated) CORE_WRITE_STL_STRING,// client wants to set STL string at address to something - - // extension module enumeration - CORE_ACQUIRE_MODULE, // get index of a loaded module by name and version - CORE_ACQUIRE_COMMAND, // get module::command callsign by module name, command name and module version // total commands NUM_CORE_CMDS diff --git a/shmserver/shms-windows.cpp b/shmserver/shms-windows.cpp index 25b90b4ab..9581ad68f 100644 --- a/shmserver/shms-windows.cpp +++ b/shmserver/shms-windows.cpp @@ -38,7 +38,7 @@ distribution. #include #include "shms.h" #include "mod-core.h" -#include +#include int errorstate = 0; char *shm = 0; int shmid = 0; @@ -56,21 +56,28 @@ void SHM_Init ( void ) } inited = true; + char svmutexname [256]; + sprintf(svmutexname,"DFSVMutex-%d",OS_getPID()); + char clmutexname [256]; + sprintf(clmutexname,"DFCLMutex-%d",OS_getPID()); + char shmname [256]; + sprintf(shmname,"DFShm-%d",OS_getPID()); + // create or open mutexes - DFSVMutex = CreateMutex( 0, 1, "DFSVMutex"); + DFSVMutex = CreateMutex( 0, 1, svmutexname); if(DFSVMutex == 0) { - DFSVMutex = OpenMutex(SYNCHRONIZE,false, "DFSVMutex"); + DFSVMutex = OpenMutex(SYNCHRONIZE,false, svmutexname); if(DFSVMutex == 0) { errorstate = 1; return; } } - DFCLMutex = CreateMutex( 0, 0, "DFCLMutex"); + DFCLMutex = CreateMutex( 0, 0, clmutexname); if(DFCLMutex == 0) { - DFCLMutex = OpenMutex(SYNCHRONIZE,false, "DFCLMutex"); + DFCLMutex = OpenMutex(SYNCHRONIZE,false, clmutexname); if(DFCLMutex == 0) { CloseHandle(DFSVMutex); @@ -110,7 +117,7 @@ void SHM_Init ( void ) } // create virtual memory mapping - shmHandle = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,SHM_SIZE,"DFShm"); + shmHandle = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,SHM_SIZE,shmname); // if can't create or already exists -> nothing happens if(GetLastError() == ERROR_ALREADY_EXISTS) { From f0087926c51552a9d95a5ade5a4a75063259ee47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 9 Mar 2010 15:15:15 +0100 Subject: [PATCH 15/16] Revert "Nuked many Process classes. Only SHM remains. We'll see how it goes :)" This reverts commit b3424418e6a046e0da8f3e6f7bfe9d4d6dd77602. Conflicts: library/DFProcess-linux-SHM.cpp library/DFProcess-windows-SHM.cpp library/DFProcess.h library/DFProcessEnumerator-linux.cpp library/DFProcessEnumerator-windows.cpp Minor manual changes were required. --- library/CMakeLists.txt | 6 +- library/DFProcess-linux-SHM.cpp | 80 ++-- library/DFProcess-linux-wine.cpp | 595 ++++++++++++++++++++++++ library/DFProcess-linux.cpp | 546 ++++++++++++++++++++++ library/DFProcess-windows-SHM.cpp | 82 ++-- library/DFProcess-windows.cpp | 482 +++++++++++++++++++ library/DFProcess.h | 209 ++++++++- library/DFProcessEnumerator-linux.cpp | 29 +- library/DFProcessEnumerator-windows.cpp | 38 +- 9 files changed, 1941 insertions(+), 126 deletions(-) create mode 100644 library/DFProcess-linux-wine.cpp create mode 100644 library/DFProcess-linux.cpp create mode 100644 library/DFProcess-windows.cpp diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 9df32d6d6..321ef5b3b 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -47,15 +47,15 @@ stdint_win.h ) SET(PROJECT_SRCS_LINUX -#DFProcess-linux.cpp +DFProcess-linux.cpp DFProcess-linux-SHM.cpp -#DFProcess-linux-wine.cpp +DFProcess-linux-wine.cpp DFWindow-linux.cpp DFProcessEnumerator-linux.cpp ) SET(PROJECT_SRCS_WINDOWS -#DFProcess-windows.cpp +DFProcess-windows.cpp DFProcess-windows-SHM.cpp DFWindow-windows.cpp DFProcessEnumerator-windows.cpp diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index 581635e5e..1ae294355 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -38,7 +38,7 @@ using namespace DFHack; // a full memory barrier! better be safe than sorry. #define gcc_barrier asm volatile("" ::: "memory"); __sync_synchronize(); -class Process::Private +class SHMProcess::Private { public: Private() @@ -86,7 +86,7 @@ class Process::Private Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling) we end up with this silly thing */ -bool Process::Private::waitWhile (uint32_t state) +bool SHMProcess::Private::waitWhile (uint32_t state) { uint32_t cnt = 0; struct shmid_ds descriptor; @@ -134,7 +134,7 @@ bool Process::Private::waitWhile (uint32_t state) Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us enough control over scheduling) we end up with this silly thing */ -bool Process::waitWhile (uint32_t state) +bool SHMProcess::waitWhile (uint32_t state) { return d->waitWhile(state); } @@ -149,7 +149,7 @@ uint32_t OS_getAffinity() } -bool Process::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID) +bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID) { SHMDATA(coreattach)->cl_affinity = OS_getAffinity(); gcc_barrier @@ -166,7 +166,7 @@ bool Process::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID) return true; } -Process::Process(uint32_t PID, vector< memory_info* >& known_versions) +SHMProcess::SHMProcess(uint32_t PID, vector< memory_info* >& known_versions) : d(new Private()) { char exe_link_name [256]; @@ -242,21 +242,21 @@ Process::Process(uint32_t PID, vector< memory_info* >& known_versions) shmdt(d->my_shm); // detach so we don't attach twice when attach() is called } -bool Process::isSuspended() +bool SHMProcess::isSuspended() { return d->suspended; } -bool Process::isAttached() +bool SHMProcess::isAttached() { return d->attached; } -bool Process::isIdentified() +bool SHMProcess::isIdentified() { return d->identified; } -bool Process::Private::validate(char * exe_file, uint32_t pid, vector & known_versions) +bool SHMProcess::Private::validate(char * exe_file, uint32_t pid, vector & known_versions) { md5wrapper md5; // get hash of the running DF process @@ -285,7 +285,7 @@ bool Process::Private::validate(char * exe_file, uint32_t pid, vector attached) { @@ -299,29 +299,29 @@ Process::~Process() delete d; } -memory_info * Process::getDescriptor() +memory_info * SHMProcess::getDescriptor() { return d->my_descriptor; } -DFWindow * Process::getWindow() +DFWindow * SHMProcess::getWindow() { return d->my_window; } -int Process::getPID() +int SHMProcess::getPID() { return d->my_pid; } //FIXME: implement -bool Process::getThreadIDs(vector & threads ) +bool SHMProcess::getThreadIDs(vector & threads ) { return false; } //FIXME: cross-reference with ELF segment entries? -void Process::getMemRanges( vector & ranges ) +void SHMProcess::getMemRanges( vector & ranges ) { char buffer[1024]; char permissions[5]; // r/-, w/-, x/-, p/s, 0 @@ -347,7 +347,7 @@ void Process::getMemRanges( vector & ranges ) } } -bool Process::suspend() +bool SHMProcess::suspend() { if(!d->attached) { @@ -366,7 +366,7 @@ bool Process::suspend() return true; } -bool Process::asyncSuspend() +bool SHMProcess::asyncSuspend() { if(!d->attached) { @@ -388,12 +388,12 @@ bool Process::asyncSuspend() } } -bool Process::forceresume() +bool SHMProcess::forceresume() { return resume(); } -bool Process::resume() +bool SHMProcess::resume() { if(!d->attached) return false; @@ -405,7 +405,7 @@ bool Process::resume() } -bool Process::attach() +bool SHMProcess::attach() { int status; if(g_pProcess != 0) @@ -434,7 +434,7 @@ bool Process::attach() return false; } -bool Process::detach() +bool SHMProcess::detach() { if(!d->attached) { @@ -458,7 +458,7 @@ bool Process::detach() return false; } -void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) +void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) { // normal read under 1MB if(size <= SHM_BODY) @@ -495,7 +495,7 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) } } -uint8_t Process::readByte (const uint32_t offset) +uint8_t SHMProcess::readByte (const uint32_t offset) { D_SHMHDR->address = offset; gcc_barrier @@ -504,7 +504,7 @@ uint8_t Process::readByte (const uint32_t offset) return D_SHMHDR->value; } -void Process::readByte (const uint32_t offset, uint8_t &val ) +void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) { D_SHMHDR->address = offset; gcc_barrier @@ -513,7 +513,7 @@ void Process::readByte (const uint32_t offset, uint8_t &val ) val = D_SHMHDR->value; } -uint16_t Process::readWord (const uint32_t offset) +uint16_t SHMProcess::readWord (const uint32_t offset) { D_SHMHDR->address = offset; gcc_barrier @@ -522,7 +522,7 @@ uint16_t Process::readWord (const uint32_t offset) return D_SHMHDR->value; } -void Process::readWord (const uint32_t offset, uint16_t &val) +void SHMProcess::readWord (const uint32_t offset, uint16_t &val) { D_SHMHDR->address = offset; gcc_barrier @@ -531,7 +531,7 @@ void Process::readWord (const uint32_t offset, uint16_t &val) val = D_SHMHDR->value; } -uint32_t Process::readDWord (const uint32_t offset) +uint32_t SHMProcess::readDWord (const uint32_t offset) { D_SHMHDR->address = offset; gcc_barrier @@ -539,7 +539,7 @@ uint32_t Process::readDWord (const uint32_t offset) waitWhile(CORE_READ_DWORD); return D_SHMHDR->value; } -void Process::readDWord (const uint32_t offset, uint32_t &val) +void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) { D_SHMHDR->address = offset; gcc_barrier @@ -552,7 +552,7 @@ void Process::readDWord (const uint32_t offset, uint32_t &val) * WRITING */ -void Process::writeDWord (uint32_t offset, uint32_t data) +void SHMProcess::writeDWord (uint32_t offset, uint32_t data) { D_SHMHDR->address = offset; D_SHMHDR->value = data; @@ -562,7 +562,7 @@ void Process::writeDWord (uint32_t offset, uint32_t data) } // using these is expensive. -void Process::writeWord (uint32_t offset, uint16_t data) +void SHMProcess::writeWord (uint32_t offset, uint16_t data) { D_SHMHDR->address = offset; D_SHMHDR->value = data; @@ -571,7 +571,7 @@ void Process::writeWord (uint32_t offset, uint16_t data) waitWhile(CORE_WRITE_WORD); } -void Process::writeByte (uint32_t offset, uint8_t data) +void SHMProcess::writeByte (uint32_t offset, uint8_t data) { D_SHMHDR->address = offset; D_SHMHDR->value = data; @@ -580,7 +580,7 @@ void Process::writeByte (uint32_t offset, uint8_t data) waitWhile(CORE_WRITE_BYTE); } -void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) +void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) { // normal write under 1MB if(size <= SHM_BODY) @@ -618,7 +618,7 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer } // FIXME: butt-fugly -const std::string Process::readCString (uint32_t offset) +const std::string SHMProcess::readCString (uint32_t offset) { std::string temp; char temp_c[256]; @@ -635,7 +635,7 @@ const std::string Process::readCString (uint32_t offset) return temp; } -DfVector Process::readVector (uint32_t offset, uint32_t item_size) +DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size) { /* GNU libstdc++ vector is three pointers long @@ -651,7 +651,7 @@ DfVector Process::readVector (uint32_t offset, uint32_t item_size) return DfVector(start,size,item_size); } -const std::string Process::readSTLString(uint32_t offset) +const std::string SHMProcess::readSTLString(uint32_t offset) { D_SHMHDR->address = offset; full_barrier @@ -661,7 +661,7 @@ const std::string Process::readSTLString(uint32_t offset) return(string( (char *)d->my_shm+SHM_HEADER)); } -size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) +size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { D_SHMHDR->address = offset; full_barrier @@ -674,7 +674,7 @@ size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacit return fit; } -void Process::writeSTLString(const uint32_t address, const std::string writeString) +void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) { D_SHMHDR->address = address; strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator @@ -683,7 +683,7 @@ void Process::writeSTLString(const uint32_t address, const std::string writeStri waitWhile(CORE_WRITE_STL_STRING); } -string Process::readClassName (uint32_t vptr) +string SHMProcess::readClassName (uint32_t vptr) { int typeinfo = readDWord(vptr - 0x4); int typestring = readDWord(typeinfo + 0x4); @@ -697,7 +697,7 @@ string Process::readClassName (uint32_t vptr) // *!!DON'T BE AN UNSUSPECTING FOOL!!* // the whole SHM thing works only because copying DWORDS is an atomic operation on i386 and x86_64 archs // get module index by name and version. bool 1 = error -bool Process::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) +bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { modulelookup * payload = (modulelookup *) (d->my_shm + SHM_HEADER); payload->version = version; @@ -721,7 +721,7 @@ bool Process::getModuleIndex (const char * name, const uint32_t version, uint32_ return true; } -char * Process::getSHMStart (void) +char * SHMProcess::getSHMStart (void) { return d->my_shm; } \ No newline at end of file diff --git a/library/DFProcess-linux-wine.cpp b/library/DFProcess-linux-wine.cpp new file mode 100644 index 000000000..880a9a06a --- /dev/null +++ b/library/DFProcess-linux-wine.cpp @@ -0,0 +1,595 @@ +/* +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" +#include +#include +#include +using namespace DFHack; + +class WineProcess::Private +{ + public: + Private() + { + my_descriptor = NULL; + my_handle = NULL; + my_window = NULL; + my_pid = 0; + attached = false; + suspended = false; + memFileHandle = 0; + }; + ~Private(){}; + DFWindow* my_window; + memory_info * my_descriptor; + ProcessHandle my_handle; + uint32_t my_pid; + string memFile; + int memFileHandle; + bool attached; + bool suspended; + bool identified; + bool validate(char * exe_file, uint32_t pid, char * mem_file, vector & known_versions); +}; + +WineProcess::WineProcess(uint32_t pid, vector & known_versions) +: d(new Private()) +{ + char dir_name [256]; + char exe_link_name [256]; + char mem_name [256]; + char cwd_name [256]; + char cmdline_name [256]; + char target_name[1024]; + int target_result; + + d->identified = false; + + sprintf(dir_name,"/proc/%d/", pid); + sprintf(exe_link_name,"/proc/%d/exe", pid); + sprintf(mem_name,"/proc/%d/mem", pid); + sprintf(cwd_name,"/proc/%d/cwd", pid); + sprintf(cmdline_name,"/proc/%d/cmdline", pid); + + // resolve /proc/PID/exe link + target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); + if (target_result == -1) + { + return; + } + // make sure we have a null terminated string... + target_name[target_result] = 0; + + // FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline + // is this windows version of Df running in wine? + if(strstr(target_name, "wine-preloader")!= NULL) + { + // get working directory + target_result = readlink(cwd_name, target_name, sizeof(target_name)-1); + target_name[target_result] = 0; + + // got path to executable, do the same for its name + ifstream ifs ( cmdline_name , ifstream::in ); + string cmdline; + getline(ifs,cmdline); + if (cmdline.find("dwarfort-w.exe") != string::npos || cmdline.find("dwarfort.exe") != string::npos || cmdline.find("Dwarf Fortress.exe") != string::npos) + { + char exe_link[1024]; + // put executable name and path together + sprintf(exe_link,"%s/%s",target_name,cmdline.c_str()); + + // create wine process, add it to the vector + d->identified = d->validate(exe_link,pid,mem_name,known_versions); + d->my_window = new DFWindow(this); + return; + } + } +} + +bool WineProcess::isSuspended() +{ + return d->suspended; +} +bool WineProcess::isAttached() +{ + return d->attached; +} + +bool WineProcess::isIdentified() +{ + return d->identified; +} + +bool WineProcess::Private::validate(char* exe_file, uint32_t pid, char* mem_file, std::vector< memory_info* >& known_versions) +{ + md5wrapper md5; + // get hash of the running DF process + string hash = md5.getHashFromFile(exe_file); + vector::iterator it; + + // iterate over the list of memory locations + for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) + { + string thishash; + try + { + thishash = (*it)->getString("md5"); + } + catch (Error::MissingMemoryDefinition& e) + { + continue; + } + // are the md5 hashes the same? + if(memory_info::OS_WINDOWS == (*it)->getOS() && hash == thishash) + { + memory_info * m = *it; + my_descriptor = m; + my_handle = my_pid = pid; + // tell WineProcess about the /proc/PID/mem file + memFile = mem_file; + identified = true; + return true; + } + } + return false; +} + +WineProcess::~WineProcess() +{ + if(d->attached) + { + detach(); + } + if(d->my_window) + delete d->my_window; + delete d; +} + +memory_info * WineProcess::getDescriptor() +{ + return d->my_descriptor; +} + +DFWindow * WineProcess::getWindow() +{ + return d->my_window; +} + +int WineProcess::getPID() +{ + return d->my_pid; +} + +//FIXME: implement +bool WineProcess::getThreadIDs(vector & threads ) +{ + return false; +} + +//FIXME: cross-reference with ELF segment entries? +void WineProcess::getMemRanges( vector & ranges ) +{ + char buffer[1024]; + char permissions[5]; // r/-, w/-, x/-, p/s, 0 + + sprintf(buffer, "/proc/%lu/maps", d->my_pid); + FILE *mapFile = ::fopen(buffer, "r"); + uint64_t offset, device1, device2, node; + + while (fgets(buffer, 1024, mapFile)) + { + t_memrange temp; + temp.name[0] = 0; + sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s", + &temp.start, + &temp.end, + (char*)&permissions, + &offset, &device1, &device2, &node, + (char*)&temp.name); + temp.read = permissions[0] == 'r'; + temp.write = permissions[1] == 'w'; + temp.execute = permissions[2] == 'x'; + ranges.push_back(temp); + } +} + +bool WineProcess::asyncSuspend() +{ + return suspend(); +} + +bool WineProcess::suspend() +{ + int status; + if(!d->attached) + return false; + if(d->suspended) + return true; + if (kill(d->my_handle, SIGSTOP) == -1) + { + // no, we got an error + perror("kill SIGSTOP error"); + return false; + } + while(true) + { + // we wait on the pid + pid_t w = waitpid(d->my_handle, &status, 0); + if (w == -1) + { + // child died + perror("DF exited during suspend call"); + return false; + } + // stopped -> let's continue + if (WIFSTOPPED(status)) + { + break; + } + } + d->suspended = true; + return true; +} + +bool WineProcess::forceresume() +{ + return resume(); +} + +bool WineProcess::resume() +{ + if(!d->attached) + return false; + if(!d->suspended) + return true; + if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1) + { + // no, we got an error + perror("ptrace resume error"); + return false; + } + d->suspended = false; + return true; +} + + +bool WineProcess::attach() +{ + int status; + if(g_pProcess != NULL) + { + return false; + } + // can we attach? + if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1) + { + // no, we got an error + perror("ptrace attach error"); + cerr << "attach failed on pid " << d->my_handle << endl; + return false; + } + while(true) + { + // we wait on the pid + pid_t w = waitpid(d->my_handle, &status, 0); + if (w == -1) + { + // child died + perror("wait inside attach()"); + return false; + } + // stopped -> let's continue + if (WIFSTOPPED(status)) + { + break; + } + } + d->suspended = true; + + int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); + if(proc_pid_mem == -1) + { + ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); + cerr << d->memFile << endl; + cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl; + perror("open(memFile.c_str(),O_RDONLY)"); + return false; + } + else + { + d->attached = true; + g_pProcess = this; + + d->memFileHandle = proc_pid_mem; + return true; // we are attached + } +} + +bool WineProcess::detach() +{ + if(!d->attached) return false; + if(!d->suspended) suspend(); + int result = 0; + // close /proc/PID/mem + result = close(d->memFileHandle); + if(result == -1) + { + cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl; + perror("mem file close"); + return false; + } + else + { + // detach + result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); + if(result == -1) + { + cerr << "couldn't detach from process pid" << d->my_handle << endl; + perror("ptrace detach"); + return false; + } + else + { + d->attached = false; + g_pProcess = NULL; + return true; + } + } +} + + +// danger: uses recursion! +void WineProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target) +{ + if(size == 0) return; + + ssize_t result; + result = pread(d->memFileHandle, target,size,offset); + if(result != size) + { + if(result == -1) + { + cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl; + cerr << "errno: " << errno << endl; + errno = 0; + } + else + { + read(offset + result, size - result, target + result); + } + } +} + +uint8_t WineProcess::readByte (const uint32_t offset) +{ + uint8_t val; + read(offset, 1, &val); + return val; +} + +void WineProcess::readByte (const uint32_t offset, uint8_t &val ) +{ + read(offset, 1, &val); +} + +uint16_t WineProcess::readWord (const uint32_t offset) +{ + uint16_t val; + read(offset, 2, (uint8_t *) &val); + return val; +} + +void WineProcess::readWord (const uint32_t offset, uint16_t &val) +{ + read(offset, 2, (uint8_t *) &val); +} + +uint32_t WineProcess::readDWord (const uint32_t offset) +{ + uint32_t val; + read(offset, 4, (uint8_t *) &val); + return val; +} +void WineProcess::readDWord (const uint32_t offset, uint32_t &val) +{ + read(offset, 4, (uint8_t *) &val); +} + +/* + * WRITING + */ + +void WineProcess::writeDWord (uint32_t offset, uint32_t data) +{ + ptrace(PTRACE_POKEDATA,d->my_handle, offset, data); +} + +// using these is expensive. +void WineProcess::writeWord (uint32_t offset, uint16_t data) +{ + uint32_t orig = readDWord(offset); + orig &= 0xFFFF0000; + orig |= data; + /* + orig |= 0x0000FFFF; + orig &= data; + */ + ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); +} + +void WineProcess::writeByte (uint32_t offset, uint8_t data) +{ + uint32_t orig = readDWord(offset); + orig &= 0xFFFFFF00; + orig |= data; + /* + orig |= 0x000000FF; + orig &= data; + */ + ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); +} + +// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS +void WineProcess::write (uint32_t offset, uint32_t size, uint8_t *source) +{ + uint32_t indexptr = 0; + while (size > 0) + { + // default: we push 4 bytes + if(size >= 4) + { + writeDWord(offset, *(uint32_t *) (source + indexptr)); + offset +=4; + indexptr +=4; + size -=4; + } + // last is either three or 2 bytes + else if(size >= 2) + { + writeWord(offset, *(uint16_t *) (source + indexptr)); + offset +=2; + indexptr +=2; + size -=2; + } + // finishing move + else if(size == 1) + { + writeByte(offset, *(uint8_t *) (source + indexptr)); + return; + } + } +} + +const std::string WineProcess::readCString (uint32_t offset) +{ + std::string temp; + char temp_c[256]; + int counter = 0; + char r; + do + { + r = readByte(offset+counter); + temp_c[counter] = r; + counter++; + } while (r && counter < 255); + temp_c[counter] = 0; + temp = temp_c; + return temp; +} + +DfVector WineProcess::readVector (uint32_t offset, uint32_t item_size) +{ + /* + MSVC++ vector is four pointers long + ptr allocator + ptr start + ptr end + ptr alloc_end + + we don't care about alloc_end because we don't try to add stuff + we also don't care about the allocator thing in front + */ + uint32_t start = g_pProcess->readDWord(offset+4); + uint32_t end = g_pProcess->readDWord(offset+8); + uint32_t size = (end - start) /4; + return DfVector(start,size,item_size); +} + +size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) +{ + /* + MSVC++ string + ptr allocator + union + { + char[16] start; + char * start_ptr + } + Uint32 length + Uint32 capacity + */ + uint32_t start_offset = offset + 4; + size_t length = g_pProcess->readDWord(offset + 20); + + size_t capacity = g_pProcess->readDWord(offset + 24); + size_t read_real = min(length, bufcapacity-1);// keep space for null termination + + // read data from inside the string structure + if(capacity < 16) + { + g_pProcess->read(start_offset, read_real , (uint8_t *)buffer); + } + else // read data from what the offset + 4 dword points to + { + start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset + g_pProcess->read(start_offset, read_real, (uint8_t *)buffer); + } + + buffer[read_real] = 0; + return read_real; +} + +const string WineProcess::readSTLString (uint32_t offset) +{ + /* + MSVC++ string + ptr allocator + union + { + char[16] start; + char * start_ptr + } + Uint32 length + Uint32 capacity + */ + uint32_t start_offset = offset + 4; + uint32_t length = g_pProcess->readDWord(offset + 20); + uint32_t capacity = g_pProcess->readDWord(offset + 24); + char * temp = new char[capacity+1]; + + // read data from inside the string structure + if(capacity < 16) + { + g_pProcess->read(start_offset, capacity, (uint8_t *)temp); + } + else // read data from what the offset + 4 dword points to + { + start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset + g_pProcess->read(start_offset, capacity, (uint8_t *)temp); + } + + temp[length] = 0; + string ret = temp; + delete temp; + return ret; +} + +string WineProcess::readClassName (uint32_t vptr) +{ + int rtti = readDWord(vptr - 0x4); + int typeinfo = readDWord(rtti + 0xC); + string raw = readCString(typeinfo + 0xC); // skips the .?AV + raw.resize(raw.length() - 4);// trim st@@ from end + return raw; +} \ No newline at end of file diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp new file mode 100644 index 000000000..3294cbaf2 --- /dev/null +++ b/library/DFProcess-linux.cpp @@ -0,0 +1,546 @@ +/* +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" +#include +#include +using namespace DFHack; + +class NormalProcess::Private +{ + public: + Private() + { + my_descriptor = NULL; + my_handle = NULL; + my_window = NULL; + my_pid = 0; + attached = false; + suspended = false; + memFileHandle = 0; + }; + ~Private(){}; + DFWindow* my_window; + memory_info * my_descriptor; + ProcessHandle my_handle; + uint32_t my_pid; + string memFile; + int memFileHandle; + bool attached; + bool suspended; + bool identified; + bool validate(char * exe_file, uint32_t pid, char * mem_file, vector & known_versions); +}; + +NormalProcess::NormalProcess(uint32_t pid, vector< memory_info* >& known_versions) +: d(new Private()) +{ + char dir_name [256]; + char exe_link_name [256]; + char mem_name [256]; + char cwd_name [256]; + char cmdline_name [256]; + char target_name[1024]; + int target_result; + + d->identified = false; + + sprintf(dir_name,"/proc/%d/", pid); + sprintf(exe_link_name,"/proc/%d/exe", pid); + sprintf(mem_name,"/proc/%d/mem", pid); + sprintf(cwd_name,"/proc/%d/cwd", pid); + sprintf(cmdline_name,"/proc/%d/cmdline", pid); + + // resolve /proc/PID/exe link + target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1); + if (target_result == -1) + { + return; + } + // make sure we have a null terminated string... + target_name[target_result] = 0; + + // is this the regular linux DF? + if (strstr(target_name, "dwarfort.exe") != NULL) + { + // create linux process, add it to the vector + d->identified = d->validate(target_name,pid,mem_name,known_versions ); + d->my_window = new DFWindow(this); + return; + } +} + +bool NormalProcess::isSuspended() +{ + return d->suspended; +} +bool NormalProcess::isAttached() +{ + return d->attached; +} + +bool NormalProcess::isIdentified() +{ + return d->identified; +} + +bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions) +{ + md5wrapper md5; + // get hash of the running DF process + string hash = md5.getHashFromFile(exe_file); + vector::iterator it; + + // iterate over the list of memory locations + for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) + { + try + { + if(hash == (*it)->getString("md5")) // are the md5 hashes the same? + { + memory_info * m = *it; + if (memory_info::OS_LINUX == m->getOS()) + { + my_descriptor = m; + my_handle = my_pid = pid; + } + else + { + // some error happened, continue with next process + continue; + } + // tell NormalProcess about the /proc/PID/mem file + this->memFile = memFile; + identified = true; + return true; + } + } + catch (Error::MissingMemoryDefinition&) + { + continue; + } + } + return false; +} + +NormalProcess::~NormalProcess() +{ + if(d->attached) + { + detach(); + } + // destroy data model. this is assigned by processmanager + if(d->my_window) + delete d->my_window; + delete d; +} + +memory_info * NormalProcess::getDescriptor() +{ + return d->my_descriptor; +} + +DFWindow * NormalProcess::getWindow() +{ + return d->my_window; +} + +int NormalProcess::getPID() +{ + return d->my_pid; +} + +//FIXME: implement +bool NormalProcess::getThreadIDs(vector & threads ) +{ + return false; +} + +//FIXME: cross-reference with ELF segment entries? +void NormalProcess::getMemRanges( vector & ranges ) +{ + char buffer[1024]; + char permissions[5]; // r/-, w/-, x/-, p/s, 0 + + sprintf(buffer, "/proc/%lu/maps", d->my_pid); + FILE *mapFile = ::fopen(buffer, "r"); + uint64_t offset, device1, device2, node; + + while (fgets(buffer, 1024, mapFile)) + { + t_memrange temp; + temp.name[0] = 0; + sscanf(buffer, "%llx-%llx %s %llx %2llu:%2llu %llu %s", + &temp.start, + &temp.end, + (char*)&permissions, + &offset, &device1, &device2, &node, + (char*)&temp.name); + temp.read = permissions[0] == 'r'; + temp.write = permissions[1] == 'w'; + temp.execute = permissions[2] == 'x'; + ranges.push_back(temp); + } +} + +bool NormalProcess::asyncSuspend() +{ + return suspend(); +} + +bool NormalProcess::suspend() +{ + int status; + if(!d->attached) + return false; + if(d->suspended) + return true; + if (kill(d->my_handle, SIGSTOP) == -1) + { + // no, we got an error + perror("kill SIGSTOP error"); + return false; + } + while(true) + { + // we wait on the pid + pid_t w = waitpid(d->my_handle, &status, 0); + if (w == -1) + { + // child died + perror("DF exited during suspend call"); + return false; + } + // stopped -> let's continue + if (WIFSTOPPED(status)) + { + break; + } + } + d->suspended = true; + return true; +} + +bool NormalProcess::forceresume() +{ + return resume(); +} + +bool NormalProcess::resume() +{ + if(!d->attached) + return false; + if(!d->suspended) + return true; + if (ptrace(PTRACE_CONT, d->my_handle, NULL, NULL) == -1) + { + // no, we got an error + perror("ptrace resume error"); + return false; + } + d->suspended = false; + return true; +} + + +bool NormalProcess::attach() +{ + int status; + if(g_pProcess != NULL) + { + return false; + } + // can we attach? + if (ptrace(PTRACE_ATTACH , d->my_handle, NULL, NULL) == -1) + { + // no, we got an error + perror("ptrace attach error"); + cerr << "attach failed on pid " << d->my_handle << endl; + return false; + } + while(true) + { + // we wait on the pid + pid_t w = waitpid(d->my_handle, &status, 0); + if (w == -1) + { + // child died + perror("wait inside attach()"); + return false; + } + // stopped -> let's continue + if (WIFSTOPPED(status)) + { + break; + } + } + d->suspended = true; + + int proc_pid_mem = open(d->memFile.c_str(),O_RDONLY); + if(proc_pid_mem == -1) + { + ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); + cerr << "couldn't open /proc/" << d->my_handle << "/mem" << endl; + perror("open(memFile.c_str(),O_RDONLY)"); + return false; + } + else + { + d->attached = true; + g_pProcess = this; + + d->memFileHandle = proc_pid_mem; + return true; // we are attached + } +} + +bool NormalProcess::detach() +{ + if(!d->attached) return false; + if(!d->suspended) suspend(); + int result = 0; + // close /proc/PID/mem + result = close(d->memFileHandle); + if(result == -1) + { + cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl; + perror("mem file close"); + return false; + } + else + { + // detach + result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); + if(result == -1) + { + cerr << "couldn't detach from process pid" << d->my_handle << endl; + perror("ptrace detach"); + return false; + } + else + { + d->attached = false; + g_pProcess = NULL; + return true; + } + } +} + + +// danger: uses recursion! +void NormalProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target) +{ + if(size == 0) return; + + ssize_t result; + result = pread(d->memFileHandle, target,size,offset); + if(result != size) + { + if(result == -1) + { + cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl; + cerr << "errno: " << errno << endl; + errno = 0; + } + else + { + read(offset + result, size - result, target + result); + } + } +} + +uint8_t NormalProcess::readByte (const uint32_t offset) +{ + uint8_t val; + read(offset, 1, &val); + return val; +} + +void NormalProcess::readByte (const uint32_t offset, uint8_t &val ) +{ + read(offset, 1, &val); +} + +uint16_t NormalProcess::readWord (const uint32_t offset) +{ + uint16_t val; + read(offset, 2, (uint8_t *) &val); + return val; +} + +void NormalProcess::readWord (const uint32_t offset, uint16_t &val) +{ + read(offset, 2, (uint8_t *) &val); +} + +uint32_t NormalProcess::readDWord (const uint32_t offset) +{ + uint32_t val; + read(offset, 4, (uint8_t *) &val); + return val; +} +void NormalProcess::readDWord (const uint32_t offset, uint32_t &val) +{ + read(offset, 4, (uint8_t *) &val); +} + +/* + * WRITING + */ + +void NormalProcess::writeDWord (uint32_t offset, uint32_t data) +{ + ptrace(PTRACE_POKEDATA,d->my_handle, offset, data); +} + +// using these is expensive. +void NormalProcess::writeWord (uint32_t offset, uint16_t data) +{ + uint32_t orig = readDWord(offset); + orig &= 0xFFFF0000; + orig |= data; + /* + orig |= 0x0000FFFF; + orig &= data; + */ + ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); +} + +void NormalProcess::writeByte (uint32_t offset, uint8_t data) +{ + uint32_t orig = readDWord(offset); + orig &= 0xFFFFFF00; + orig |= data; + /* + orig |= 0x000000FF; + orig &= data; + */ + ptrace(PTRACE_POKEDATA,d->my_handle, offset, orig); +} + +// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS +void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) +{ + uint32_t indexptr = 0; + while (size > 0) + { + // default: we push 4 bytes + if(size >= 4) + { + writeDWord(offset, *(uint32_t *) (source + indexptr)); + offset +=4; + indexptr +=4; + size -=4; + } + // last is either three or 2 bytes + else if(size >= 2) + { + writeWord(offset, *(uint16_t *) (source + indexptr)); + offset +=2; + indexptr +=2; + size -=2; + } + // finishing move + else if(size == 1) + { + writeByte(offset, *(uint8_t *) (source + indexptr)); + return; + } + } +} + +const std::string NormalProcess::readCString (uint32_t offset) +{ + std::string temp; + char temp_c[256]; + int counter = 0; + char r; + do + { + r = readByte(offset+counter); + temp_c[counter] = r; + counter++; + } while (r && counter < 255); + temp_c[counter] = 0; + temp = temp_c; + return temp; +} + +DfVector NormalProcess::readVector (uint32_t offset, uint32_t item_size) +{ + /* + GNU libstdc++ vector is three pointers long + ptr start + ptr end + ptr alloc_end + + we don't care about alloc_end because we don't try to add stuff + */ + uint32_t start = g_pProcess->readDWord(offset); + uint32_t end = g_pProcess->readDWord(offset+4); + uint32_t size = (end - start) /4; + return DfVector(start,size,item_size); +} + +struct _Rep_base +{ + uint32_t _M_length; + uint32_t _M_capacity; + uint32_t _M_refcount; +}; + +size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) +{ + _Rep_base header; + offset = g_pProcess->readDWord(offset); + g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header); + size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination + g_pProcess->read(offset,read_real,(uint8_t * )buffer); + buffer[read_real] = 0; + return read_real; +} + +const string NormalProcess::readSTLString (uint32_t offset) +{ + _Rep_base header; + + offset = g_pProcess->readDWord(offset); + g_pProcess->read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header); + + // FIXME: use char* everywhere, avoid string + char * temp = new char[header._M_length+1]; + g_pProcess->read(offset,header._M_length+1,(uint8_t * )temp); + string ret(temp); + delete temp; + return ret; +} + +string NormalProcess::readClassName (uint32_t vptr) +{ + int typeinfo = readDWord(vptr - 0x4); + int typestring = readDWord(typeinfo + 0x4); + string raw = readCString(typestring); + size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers + size_t end = raw.length(); + return raw.substr(start,end-start - 2); // trim the 'st' from the end +} \ No newline at end of file diff --git a/library/DFProcess-windows-SHM.cpp b/library/DFProcess-windows-SHM.cpp index 59fe25bd1..8886c0e7c 100644 --- a/library/DFProcess-windows-SHM.cpp +++ b/library/DFProcess-windows-SHM.cpp @@ -27,7 +27,7 @@ distribution. using namespace DFHack; // a full memory barrier! better be safe than sorry. -class Process::Private +class SHMProcess::Private { public: Private() @@ -72,7 +72,7 @@ class Process::Private #define D_SHMDATA(type) ((type *)(d->my_shm + SHM_HEADER)) // is the other side still there? -bool Process::Private::isValidSV() +bool SHMProcess::Private::isValidSV() { // try if CL mutex is free uint32_t result = WaitForSingleObject(DFSVMutex,0); @@ -99,12 +99,12 @@ bool Process::Private::isValidSV() } } -bool Process::waitWhile (uint32_t state) +bool SHMProcess::waitWhile (uint32_t state) { return d->waitWhile(state); } -bool Process::Private::waitWhile (uint32_t state) +bool SHMProcess::Private::waitWhile (uint32_t state) { uint32_t cnt = 0; while (SHMCMD == state) @@ -149,7 +149,7 @@ uint32_t OS_getAffinity() return dwProcessAffinityMask; } -bool Process::Private::Aux_Core_Attach(bool & versionOK, uint32_t & PID) +bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, uint32_t & PID) { SHMDATA(coreattach)->cl_affinity = OS_getAffinity(); full_barrier @@ -166,7 +166,7 @@ bool Process::Private::Aux_Core_Attach(bool & versionOK, uint32_t & PID) return true; } -Process::Process(uint32_t PID, vector & known_versions) +SHMProcess::SHMProcess(uint32_t PID, vector & known_versions) : d(new Private()) { char svmutexname [256]; @@ -237,7 +237,7 @@ Process::Process(uint32_t PID, vector & known_versions) if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) { CloseHandle(hProcess); - cout << "EnumProcessModules fail'd" << endl; + // cout << "EnumProcessModules fail'd" << endl; break; } // got base ;) @@ -295,21 +295,21 @@ Process::Process(uint32_t PID, vector & known_versions) detach(); } -bool Process::isSuspended() +bool SHMProcess::isSuspended() { return d->suspended; } -bool Process::isAttached() +bool SHMProcess::isAttached() { return d->attached; } -bool Process::isIdentified() +bool SHMProcess::isIdentified() { return d->identified; } -Process::~Process() +SHMProcess::~SHMProcess() { if(d->attached) { @@ -336,29 +336,29 @@ Process::~Process() delete d; } -memory_info * Process::getDescriptor() +memory_info * SHMProcess::getDescriptor() { return d->my_descriptor; } -DFWindow * Process::getWindow() +DFWindow * SHMProcess::getWindow() { return d->my_window; } -int Process::getPID() +int SHMProcess::getPID() { return d->my_pid; } //FIXME: implement -bool Process::getThreadIDs(vector & threads ) +bool SHMProcess::getThreadIDs(vector & threads ) { return false; } //FIXME: cross-reference with ELF segment entries? -void Process::getMemRanges( vector & ranges ) +void SHMProcess::getMemRanges( vector & ranges ) { char buffer[1024]; char permissions[5]; // r/-, w/-, x/-, p/s, 0 @@ -384,7 +384,7 @@ void Process::getMemRanges( vector & ranges ) } } -bool Process::suspend() +bool SHMProcess::suspend() { if(!d->attached) { @@ -406,7 +406,7 @@ bool Process::suspend() return true; } -bool Process::asyncSuspend() +bool SHMProcess::asyncSuspend() { if(!d->attached) { @@ -428,12 +428,12 @@ bool Process::asyncSuspend() } } -bool Process::forceresume() +bool SHMProcess::forceresume() { return resume(); } -bool Process::resume() +bool SHMProcess::resume() { if(!d->attached) { @@ -451,7 +451,7 @@ bool Process::resume() } -bool Process::attach() +bool SHMProcess::attach() { if(g_pProcess != 0) { @@ -502,7 +502,7 @@ bool Process::attach() return true; } -bool Process::detach() +bool SHMProcess::detach() { if(!d->attached) { @@ -518,7 +518,7 @@ bool Process::detach() return true; } -void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) +void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) { // normal read under 1MB if(size <= SHM_BODY) @@ -555,7 +555,7 @@ void Process::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) } } -uint8_t Process::readByte (const uint32_t offset) +uint8_t SHMProcess::readByte (const uint32_t offset) { D_SHMHDR->address = offset; full_barrier @@ -564,7 +564,7 @@ uint8_t Process::readByte (const uint32_t offset) return D_SHMHDR->value; } -void Process::readByte (const uint32_t offset, uint8_t &val ) +void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) { D_SHMHDR->address = offset; full_barrier @@ -573,7 +573,7 @@ void Process::readByte (const uint32_t offset, uint8_t &val ) val = D_SHMHDR->value; } -uint16_t Process::readWord (const uint32_t offset) +uint16_t SHMProcess::readWord (const uint32_t offset) { D_SHMHDR->address = offset; full_barrier @@ -582,7 +582,7 @@ uint16_t Process::readWord (const uint32_t offset) return D_SHMHDR->value; } -void Process::readWord (const uint32_t offset, uint16_t &val) +void SHMProcess::readWord (const uint32_t offset, uint16_t &val) { D_SHMHDR->address = offset; full_barrier @@ -591,7 +591,7 @@ void Process::readWord (const uint32_t offset, uint16_t &val) val = D_SHMHDR->value; } -uint32_t Process::readDWord (const uint32_t offset) +uint32_t SHMProcess::readDWord (const uint32_t offset) { D_SHMHDR->address = offset; full_barrier @@ -599,7 +599,7 @@ uint32_t Process::readDWord (const uint32_t offset) d->waitWhile(CORE_READ_DWORD); return D_SHMHDR->value; } -void Process::readDWord (const uint32_t offset, uint32_t &val) +void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) { D_SHMHDR->address = offset; full_barrier @@ -612,7 +612,7 @@ void Process::readDWord (const uint32_t offset, uint32_t &val) * WRITING */ -void Process::writeDWord (uint32_t offset, uint32_t data) +void SHMProcess::writeDWord (uint32_t offset, uint32_t data) { D_SHMHDR->address = offset; D_SHMHDR->value = data; @@ -622,7 +622,7 @@ void Process::writeDWord (uint32_t offset, uint32_t data) } // using these is expensive. -void Process::writeWord (uint32_t offset, uint16_t data) +void SHMProcess::writeWord (uint32_t offset, uint16_t data) { D_SHMHDR->address = offset; D_SHMHDR->value = data; @@ -631,7 +631,7 @@ void Process::writeWord (uint32_t offset, uint16_t data) d->waitWhile(CORE_WRITE_WORD); } -void Process::writeByte (uint32_t offset, uint8_t data) +void SHMProcess::writeByte (uint32_t offset, uint8_t data) { D_SHMHDR->address = offset; D_SHMHDR->value = data; @@ -640,7 +640,7 @@ void Process::writeByte (uint32_t offset, uint8_t data) d->waitWhile(CORE_WRITE_BYTE); } -void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) +void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) { // normal write under 1MB if(size <= SHM_BODY) @@ -678,7 +678,7 @@ void Process::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer } // FIXME: butt-fugly -const std::string Process::readCString (uint32_t offset) +const std::string SHMProcess::readCString (uint32_t offset) { std::string temp; char temp_c[256]; @@ -695,7 +695,7 @@ const std::string Process::readCString (uint32_t offset) return temp; } -DfVector Process::readVector (uint32_t offset, uint32_t item_size) +DfVector SHMProcess::readVector (uint32_t offset, uint32_t item_size) { /* MSVC++ vector is four pointers long @@ -713,7 +713,7 @@ DfVector Process::readVector (uint32_t offset, uint32_t item_size) return DfVector(start,size,item_size); } -const std::string Process::readSTLString(uint32_t offset) +const std::string SHMProcess::readSTLString(uint32_t offset) { //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 D_SHMHDR->address = offset; @@ -726,7 +726,7 @@ const std::string Process::readSTLString(uint32_t offset) return(string(d->my_shm+SHM_HEADER)); } -size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) +size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { //offset -= 4; //msvc std::string pointers are 8 bytes ahead of their data, not 4 D_SHMHDR->address = offset; @@ -740,7 +740,7 @@ size_t Process::readSTLString (uint32_t offset, char * buffer, size_t bufcapacit return real; } -void Process::writeSTLString(const uint32_t address, const std::string writeString) +void SHMProcess::writeSTLString(const uint32_t address, const std::string writeString) { D_SHMHDR->address = address/*-4*/; strncpy(d->my_shm+SHM_HEADER,writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator @@ -749,7 +749,7 @@ void Process::writeSTLString(const uint32_t address, const std::string writeStri d->waitWhile(CORE_WRITE_STL_STRING); } -string Process::readClassName (uint32_t vptr) +string SHMProcess::readClassName (uint32_t vptr) { int rtti = readDWord(vptr - 0x4); int typeinfo = readDWord(rtti + 0xC); @@ -759,7 +759,7 @@ string Process::readClassName (uint32_t vptr) } // get module index by name and version. bool 1 = error -bool Process::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) +bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { modulelookup * payload = (modulelookup *) (d->my_shm + SHM_HEADER); payload->version = version; @@ -772,7 +772,7 @@ bool Process::getModuleIndex (const char * name, const uint32_t version, uint32_ return true; } -char * Process::getSHMStart (void) +char * SHMProcess::getSHMStart (void) { return d->my_shm; } \ No newline at end of file diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp new file mode 100644 index 000000000..72ab8e06a --- /dev/null +++ b/library/DFProcess-windows.cpp @@ -0,0 +1,482 @@ +/* +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; + +class NormalProcess::Private +{ + public: + Private() + { + my_descriptor = NULL; + my_handle = NULL; + my_main_thread = NULL; + my_window = NULL; + my_pid = 0; + attached = false; + suspended = false; + }; + ~Private(){}; + memory_info * my_descriptor; + DFWindow * my_window; + ProcessHandle my_handle; + HANDLE my_main_thread; + uint32_t my_pid; + string memFile; + bool attached; + bool suspended; + bool identified; +}; + +NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) +: d(new Private()) +{ + HMODULE hmod = NULL; + DWORD junk; + HANDLE hProcess; + bool found = false; + + IMAGE_NT_HEADERS32 pe_header; + IMAGE_SECTION_HEADER sections[16]; + d->identified = false; + // open process + hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ); + if (NULL == hProcess) + return; + + // try getting the first module of the process + if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0) + { + CloseHandle(hProcess); + // cout << "EnumProcessModules fail'd" << endl; + return; //if enumprocessModules fails, give up + } + + // got base ;) + uint32_t base = (uint32_t)hmod; + + // temporarily assign this to allow some checks + d->my_handle = hProcess; + // read from this process + uint32_t pe_offset = readDWord(base+0x3C); + read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); + read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)§ions ); + d->my_handle = 0; + + // see if there's a version entry that matches this process + vector::iterator it; + for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) + { + // filter by OS + if(memory_info::OS_WINDOWS != (*it)->getOS()) + continue; + uint32_t pe_timestamp; + // filter by timestamp, skip entries without a timestamp + try + { + pe_timestamp = (*it)->getHexValue("pe_timestamp"); + } + catch(Error::MissingMemoryDefinition& e) + { + continue; + } + if (pe_timestamp != pe_header.FileHeader.TimeDateStamp) + continue; + + // all went well + { + printf("Match found! Using version %s.\n", (*it)->getVersion().c_str()); + d->identified = true; + // give the process a data model and memory layout fixed for the base of first module + memory_info *m = new memory_info(**it); + m->RebaseAll(base); + // keep track of created memory_info object so we can destroy it later + d->my_descriptor = m; + // process is responsible for destroying its data model + d->my_pid = pid; + d->my_handle = hProcess; + d->identified = true; + + // TODO: detect errors in thread enumeration + vector threads; + getThreadIDs( threads ); + d->my_main_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads[0]); + + found = true; + break; // break the iterator loop + } + } + // close handle of processes that aren't DF + if(!found) + { + CloseHandle(hProcess); + } + else + { + d->my_window = new DFWindow(this); + } +} +/* +*/ + +NormalProcess::~NormalProcess() +{ + if(d->attached) + { + detach(); + } + // destroy our rebased copy of the memory descriptor + delete d->my_descriptor; + if(d->my_handle != NULL) + { + CloseHandle(d->my_handle); + } + if(d->my_main_thread != NULL) + { + CloseHandle(d->my_main_thread); + } + if(d->my_window) + { + delete d->my_window; + } + delete d; +} + +memory_info * NormalProcess::getDescriptor() +{ + return d->my_descriptor; +} + +DFWindow * NormalProcess::getWindow() +{ + return d->my_window; +} + +int NormalProcess::getPID() +{ + return d->my_pid; +} + +bool NormalProcess::isSuspended() +{ + return d->suspended; +} +bool NormalProcess::isAttached() +{ + return d->attached; +} + +bool NormalProcess::isIdentified() +{ + return d->identified; +} + +bool NormalProcess::asyncSuspend() +{ + return suspend(); +} + +bool NormalProcess::suspend() +{ + if(!d->attached) + return false; + if(d->suspended) + { + return true; + } + SuspendThread(d->my_main_thread); + d->suspended = true; + return true; +} + +bool NormalProcess::forceresume() +{ + if(!d->attached) + return false; + while (ResumeThread(d->my_main_thread) > 1); + d->suspended = false; + return true; +} + + +bool NormalProcess::resume() +{ + if(!d->attached) + return false; + if(!d->suspended) + { + return true; + } + ResumeThread(d->my_main_thread); + d->suspended = false; + return true; +} + +bool NormalProcess::attach() +{ + if(g_pProcess != NULL) + { + return false; + } + d->attached = true; + g_pProcess = this; + suspend(); + + return true; +} + + +bool NormalProcess::detach() +{ + if(!d->attached) + { + return false; + } + resume(); + d->attached = false; + g_pProcess = NULL; + return true; +} + +bool NormalProcess::getThreadIDs(vector & threads ) +{ + HANDLE AllThreads = INVALID_HANDLE_VALUE; + THREADENTRY32 te32; + + AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); + if( AllThreads == INVALID_HANDLE_VALUE ) + { + return false; + } + te32.dwSize = sizeof(THREADENTRY32 ); + + if( !Thread32First( AllThreads, &te32 ) ) + { + CloseHandle( AllThreads ); + return false; + } + + do + { + if( te32.th32OwnerProcessID == d->my_pid ) + { + threads.push_back(te32.th32ThreadID); + } + } while( Thread32Next(AllThreads, &te32 ) ); + + CloseHandle( AllThreads ); + return true; +} + +//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries +void NormalProcess::getMemRanges( vector & ranges ) +{ + // code here is taken from hexsearch by Silas Dunmore. + // As this IMHO isn't a 'sunstantial portion' of anything, I'm not including the MIT license here + + // I'm faking this, because there's no way I'm using VirtualQuery + + t_memrange temp; + uint32_t base = d->my_descriptor->getBase(); + temp.start = base + 0x1000; // more fakery. + temp.end = base + readDWord(base+readDWord(base+0x3C)+0x50)-1; // yay for magic. + temp.read = 1; + temp.write = 1; + temp.execute = 0; // fake + strcpy(temp.name,"pants");// that's right. I'm calling it pants. Windows can go to HELL + ranges.push_back(temp); +} + +uint8_t NormalProcess::readByte (const uint32_t offset) +{ + uint8_t result; + ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL); + return result; +} + +void NormalProcess::readByte (const uint32_t offset,uint8_t &result) +{ + ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint8_t), NULL); +} + +uint16_t NormalProcess::readWord (const uint32_t offset) +{ + uint16_t result; + ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL); + return result; +} + +void NormalProcess::readWord (const uint32_t offset, uint16_t &result) +{ + ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint16_t), NULL); +} + +uint32_t NormalProcess::readDWord (const uint32_t offset) +{ + uint32_t result; + ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL); + return result; +} + +void NormalProcess::readDWord (const uint32_t offset, uint32_t &result) +{ + ReadProcessMemory(d->my_handle, (int*) offset, &result, sizeof(uint32_t), NULL); +} + +void NormalProcess::read (const uint32_t offset, uint32_t size, uint8_t *target) +{ + ReadProcessMemory(d->my_handle, (int*) offset, target, size, NULL); +} + +// WRITING +void NormalProcess::writeDWord (const uint32_t offset, uint32_t data) +{ + WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(uint32_t), NULL); +} + +// using these is expensive. +void NormalProcess::writeWord (uint32_t offset, uint16_t data) +{ + WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(uint16_t), NULL); +} + +void NormalProcess::writeByte (uint32_t offset, uint8_t data) +{ + WriteProcessMemory(d->my_handle, (int*) offset, &data, sizeof(uint8_t), NULL); +} + +void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) +{ + WriteProcessMemory(d->my_handle, (int*) offset, source, size, NULL); +} + + + +///FIXME: reduce use of temporary objects +const string NormalProcess::readCString (const uint32_t offset) +{ + string temp; + char temp_c[256]; + DWORD read; + ReadProcessMemory(d->my_handle, (int *) offset, temp_c, 255, &read); + temp_c[read+1] = 0; + temp = temp_c; + return temp; +} + +DfVector NormalProcess::readVector (uint32_t offset, uint32_t item_size) +{ + /* + MSVC++ vector is four pointers long + ptr allocator + ptr start + ptr end + ptr alloc_end + + we don't care about alloc_end because we don't try to add stuff + we also don't care about the allocator thing in front + */ + uint32_t start = g_pProcess->readDWord(offset+4); + uint32_t end = g_pProcess->readDWord(offset+8); + uint32_t size = (end - start) /4; + return DfVector(start,size,item_size); +} + +size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) +{ + /* + MSVC++ string + ptr allocator + union + { + char[16] start; + char * start_ptr +} +Uint32 length +Uint32 capacity +*/ + uint32_t start_offset = offset + 4; + size_t length = g_pProcess->readDWord(offset + 20); + + size_t capacity = g_pProcess->readDWord(offset + 24); + size_t read_real = min(length, bufcapacity-1);// keep space for null termination + + // read data from inside the string structure + if(capacity < 16) + { + g_pProcess->read(start_offset, read_real , (uint8_t *)buffer); + } + else // read data from what the offset + 4 dword points to + { + start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset + g_pProcess->read(start_offset, read_real, (uint8_t *)buffer); + } + + buffer[read_real] = 0; + return read_real; +} + +const string NormalProcess::readSTLString (uint32_t offset) +{ + /* + MSVC++ string + ptr allocator + union + { + char[16] start; + char * start_ptr + } + Uint32 length + Uint32 capacity + */ + uint32_t start_offset = offset + 4; + uint32_t length = g_pProcess->readDWord(offset + 20); + uint32_t capacity = g_pProcess->readDWord(offset + 24); + char * temp = new char[capacity+1]; + + // read data from inside the string structure + if(capacity < 16) + { + g_pProcess->read(start_offset, capacity, (uint8_t *)temp); + } + else // read data from what the offset + 4 dword points to + { + start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset + g_pProcess->read(start_offset, capacity, (uint8_t *)temp); + } + + temp[length] = 0; + string ret = temp; + delete temp; + return ret; +} + +string NormalProcess::readClassName (uint32_t vptr) +{ + int rtti = readDWord(vptr - 0x4); + int typeinfo = readDWord(rtti + 0xC); + string raw = readCString(typeinfo + 0xC); // skips the .?AV + raw.resize(raw.length() - 4);// trim st@@ from end + return raw; +} \ No newline at end of file diff --git a/library/DFProcess.h b/library/DFProcess.h index 91d1d773e..878e68d37 100644 --- a/library/DFProcess.h +++ b/library/DFProcess.h @@ -61,28 +61,147 @@ namespace DFHack class DFHACK_EXPORT Process { - private: - class Private; - Private *d; public: // this is the single most important destructor ever. ~px - Process(uint32_t PID ,vector & known_versions); - ~Process(); - - // Set up stuff so we can read memory - bool attach(); + virtual ~Process(){}; + // Set up stuff so we can read memory, suspends synchronously + virtual bool attach() = 0; // detach from DF, resume its execution if it's suspended - bool detach(); + virtual bool detach() = 0; // synchronous suspend // waits for DF to be actually suspended, // this might take a while depending on implementation - bool suspend(); + virtual bool suspend() = 0; // asynchronous suspend to use together with polling and timers - bool asyncSuspend(); + virtual bool asyncSuspend() = 0; // resume DF execution + virtual bool resume() = 0; + // force-resume DF execution + virtual bool forceresume() = 0; + + virtual uint32_t readDWord(const uint32_t address) = 0; + virtual void readDWord(const uint32_t address, uint32_t & value) = 0; + virtual uint16_t readWord(const uint32_t address) = 0; + virtual void readWord(const uint32_t address, uint16_t & value) = 0; + virtual uint8_t readByte(const uint32_t address) = 0; + virtual void readByte(const uint32_t address, uint8_t & value) = 0; + virtual void read( uint32_t address, uint32_t length, uint8_t* buffer) = 0; + + virtual void writeDWord(const uint32_t address, const uint32_t value) = 0; + virtual void writeWord(const uint32_t address, const uint16_t value) = 0; + virtual void writeByte(const uint32_t address, const uint8_t value) = 0; + virtual void write(uint32_t address, uint32_t length, uint8_t* buffer) = 0; + + // read a string + virtual const string readSTLString (uint32_t offset) = 0; + virtual size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) = 0; + virtual void writeSTLString(const uint32_t address, const std::string writeString) = 0; + // read a vector from memory + virtual DfVector readVector (uint32_t offset, uint32_t item_size) = 0; + // get class name of an object with rtti/type info + virtual string readClassName(uint32_t vptr) = 0; + + virtual const std::string readCString (uint32_t offset) = 0; + + virtual bool isSuspended() = 0; + virtual bool isAttached() = 0; + virtual bool isIdentified() = 0; + + // find the thread IDs of the process + virtual bool getThreadIDs(vector & threads ) = 0; + // get virtual memory ranges of the process (what is mapped where) + virtual void getMemRanges( vector & ranges ) = 0; + + // get the flattened Memory.xml entry of this process + virtual memory_info *getDescriptor() = 0; + // get the DF's window (first that can be found ~_~) + virtual DFWindow * getWindow() = 0; + // get the DF Process ID + virtual int getPID() = 0; + // get module index by name and version. bool 1 = error + virtual bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) = 0; + // get the SHM start if available + virtual char * getSHMStart (void) = 0; + // wait for a SHM state. returns 0 without the SHM + virtual bool waitWhile (uint32_t state) = 0; + }; + + class DFHACK_EXPORT NormalProcess : virtual public Process + { + friend class ProcessEnumerator; + class Private; + private: + Private * const d; + + public: + NormalProcess(uint32_t pid, vector & known_versions); + ~NormalProcess(); + bool attach(); + bool detach(); + + bool suspend(); + bool asyncSuspend(); + bool resume(); + bool forceresume(); + + uint32_t readDWord(const uint32_t address); + void readDWord(const uint32_t address, uint32_t & value); + uint16_t readWord(const uint32_t address); + void readWord(const uint32_t address, uint16_t & value); + uint8_t readByte(const uint32_t address); + void readByte(const uint32_t address, uint8_t & value); + void read( uint32_t address, uint32_t length, uint8_t* buffer); + + void writeDWord(const uint32_t address, const uint32_t value); + void writeWord(const uint32_t address, const uint16_t value); + void writeByte(const uint32_t address, const uint8_t value); + void write(uint32_t address, uint32_t length, uint8_t* buffer); + + const string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // read a vector from memory + DfVector readVector (uint32_t offset, uint32_t item_size); + // get class name of an object with rtti/type info + string readClassName(uint32_t vptr); + + const std::string readCString (uint32_t offset); + + bool isSuspended(); + bool isAttached(); + bool isIdentified(); + + bool getThreadIDs(vector & threads ); + void getMemRanges( vector & ranges ); + memory_info *getDescriptor(); + DFWindow * getWindow(); + int getPID(); + // get module index by name and version. bool 1 = error + bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {return false;}; + // get the SHM start if available + char * getSHMStart (void){return 0;}; + // wait for a SHM state. returns 0 without the SHM + bool waitWhile (uint32_t state){return false;}; + }; + + class DFHACK_EXPORT SHMProcess : virtual public Process + { + friend class ProcessEnumerator; + class Private; + private: + Private * const d; + + public: + SHMProcess(uint32_t PID, vector & known_versions); + ~SHMProcess(); + // Set up stuff so we can read memory + bool attach(); + bool detach(); + + bool suspend(); + bool asyncSuspend(); bool resume(); - // force-resume DF execution - maybe nonsense in this branch? :P bool forceresume(); uint32_t readDWord(const uint32_t address); @@ -105,21 +224,17 @@ namespace DFHack DfVector readVector (uint32_t offset, uint32_t item_size); // get class name of an object with rtti/type info string readClassName(uint32_t vptr); + const std::string readCString (uint32_t offset); bool isSuspended(); bool isAttached(); bool isIdentified(); - // find the thread IDs of the process bool getThreadIDs(vector & threads ); - // get virtual memory ranges of the process (what is mapped where) void getMemRanges( vector & ranges ); - // get the flattened Memory.xml entry of this process memory_info *getDescriptor(); - // get the DF's window (first that can be found ~_~) DFWindow * getWindow(); - // get the DF Process ID int getPID(); // get module index by name and version. bool 1 = error bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT); @@ -128,5 +243,65 @@ namespace DFHack // wait for a SHM state. returns 0 without the SHM bool waitWhile (uint32_t state); }; + +#ifdef LINUX_BUILD + class DFHACK_EXPORT WineProcess : virtual public Process + { + friend class ProcessEnumerator; + class Private; + private: + Private * const d; + + public: + WineProcess(uint32_t pid, vector & known_versions); + ~WineProcess(); + bool attach(); + bool detach(); + + bool suspend(); + bool asyncSuspend(); + bool resume(); + bool forceresume(); + + uint32_t readDWord(const uint32_t address); + void readDWord(const uint32_t address, uint32_t & value); + uint16_t readWord(const uint32_t address); + void readWord(const uint32_t address, uint16_t & value); + uint8_t readByte(const uint32_t address); + void readByte(const uint32_t address, uint8_t & value); + void read( uint32_t address, uint32_t length, uint8_t* buffer); + + void writeDWord(const uint32_t address, const uint32_t value); + void writeWord(const uint32_t address, const uint16_t value); + void writeByte(const uint32_t address, const uint8_t value); + void write(uint32_t address, uint32_t length, uint8_t* buffer); + + const string readSTLString (uint32_t offset); + size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity); + void writeSTLString(const uint32_t address, const std::string writeString){}; + // read a vector from memory + DfVector readVector (uint32_t offset, uint32_t item_size); + // get class name of an object with rtti/type info + string readClassName(uint32_t vptr); + + const std::string readCString (uint32_t offset); + + bool isSuspended(); + bool isAttached(); + bool isIdentified(); + + bool getThreadIDs(vector & threads ); + void getMemRanges( vector & ranges ); + memory_info *getDescriptor(); + DFWindow * getWindow(); + int getPID(); + // get module index by name and version. bool 1 = error + bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) {return false;}; + // get the SHM start if available + char * getSHMStart (void){return 0;}; + // wait for a SHM state. returns 0 without the SHM + bool waitWhile (uint32_t state){return false;}; + }; +#endif } #endif diff --git a/library/DFProcessEnumerator-linux.cpp b/library/DFProcessEnumerator-linux.cpp index b67e83b3a..c4eddd127 100644 --- a/library/DFProcessEnumerator-linux.cpp +++ b/library/DFProcessEnumerator-linux.cpp @@ -46,19 +46,6 @@ bool ProcessEnumerator::findProcessess() { DIR *dir_p; struct dirent *dir_entry_p; - /* - Process *p = 0; - p = new Process(d->meminfo->meminfo); - if(p->isIdentified()) - { - d->processes.push_back(p); - } - else - { - delete p; - p = 0; - } - */ // Open /proc/ directory dir_p = opendir("/proc/"); // Reading /proc/ entries @@ -69,7 +56,17 @@ bool ProcessEnumerator::findProcessess() { continue; } - Process *p2 = new Process(atoi(dir_entry_p->d_name),d->meminfo->meminfo); + Process *p1 = new SHMProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo); + if(p1->isIdentified()) + { + d->processes.push_back(p1); + continue; + } + else + { + delete p1; + } + Process *p2 = new NormalProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo); if(p2->isIdentified()) { d->processes.push_back(p2); @@ -79,7 +76,6 @@ bool ProcessEnumerator::findProcessess() { delete p2; } - /* Process *p3 = new WineProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo); if(p3->isIdentified()) { @@ -90,10 +86,9 @@ bool ProcessEnumerator::findProcessess() { delete p3; } - */ + } closedir(dir_p); - // return value depends on if we found some DF processes if(d->processes.size()) { diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp index 1c906cb9d..a922b5b9a 100644 --- a/library/DFProcessEnumerator-windows.cpp +++ b/library/DFProcessEnumerator-windows.cpp @@ -36,6 +36,32 @@ class DFHack::ProcessEnumerator::Private 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() { @@ -50,11 +76,12 @@ bool ProcessEnumerator::findProcessess() // Calculate how many process identifiers were returned. numProccesses = memoryNeeded / sizeof(DWORD); - + EnableDebugPriv(); + // iterate through processes for ( int i = 0; i < (int)numProccesses; i++ ) { - Process *p = new Process(ProcArray[i],d->meminfo->meminfo); + Process *p = new SHMProcess(ProcArray[i],d->meminfo->meminfo); if(p->isIdentified()) { d->processes.push_back(p); @@ -64,14 +91,10 @@ bool ProcessEnumerator::findProcessess() delete p; p = 0; } - } - /* - { - Process * p = new Process(d->meminfo->meminfo); + p = new NormalProcess(ProcArray[i],d->meminfo->meminfo); if(p->isIdentified()) { d->processes.push_back(p); - return true; } else { @@ -79,7 +102,6 @@ bool ProcessEnumerator::findProcessess() p = 0; } } - */ if(d->processes.size()) return true; return false; From 7207996940baa956e8d8ba92a30d052e1b8ef7f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 9 Mar 2010 15:21:53 +0100 Subject: [PATCH 16/16] Prevent windows process enumerator from listing the same process twice --- library/DFProcessEnumerator-windows.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp index a922b5b9a..7e3c095e8 100644 --- a/library/DFProcessEnumerator-windows.cpp +++ b/library/DFProcessEnumerator-windows.cpp @@ -85,6 +85,7 @@ bool ProcessEnumerator::findProcessess() if(p->isIdentified()) { d->processes.push_back(p); + continue; } else { @@ -95,6 +96,7 @@ bool ProcessEnumerator::findProcessess() if(p->isIdentified()) { d->processes.push_back(p); + continue; } else {