diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index eae353c1b..b07636897 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -1115,6 +1115,11 @@ bool API::Suspend() { return d->p->suspend(); } +bool API::AsyncSuspend() +{ + return d->p->asyncSuspend(); +} + bool API::Resume() { return d->p->resume(); diff --git a/library/DFHackAPI.h b/library/DFHackAPI.h index be9b6b638..8a6f13518 100644 --- a/library/DFHackAPI.h +++ b/library/DFHackAPI.h @@ -57,6 +57,8 @@ namespace DFHack // stop DF from executing bool Suspend(); + // stop DF from executing, asynchronous, use with polling + bool AsyncSuspend(); // resume DF bool Resume(); /** diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp index cd0bf75cc..48e8816e3 100644 --- a/library/DFProcess-linux-SHM.cpp +++ b/library/DFProcess-linux-SHM.cpp @@ -236,7 +236,6 @@ SHMProcess::SHMProcess(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; - fprintf(stderr,"detach: %d",shmdt(d->my_shm)); } bool SHMProcess::isSuspended() @@ -355,7 +354,6 @@ void SHMProcess::getMemRanges( vector & ranges ) bool SHMProcess::suspend() { - int status; if(!d->attached) { return false; @@ -373,6 +371,28 @@ bool SHMProcess::suspend() return true; } +bool SHMProcess::asyncSuspend() +{ + if(!d->attached) + { + return false; + } + if(d->suspended) + { + return true; + } + if(((shm_cmd *)d->my_shm)->pingpong == DFPP_SUSPENDED) + { + d->suspended = true; + return true; + } + else + { + ((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; + return false; + } +} + bool SHMProcess::forceresume() { return resume(); @@ -442,17 +462,41 @@ bool SHMProcess::detach() return false; } - -// FIXME: use recursion -void SHMProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target) +void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer) { - assert (size < (SHM_SIZE - sizeof(shm_read))); - ((shm_read *)d->my_shm)->address = offset; - ((shm_read *)d->my_shm)->length = size; - gcc_barrier - ((shm_read *)d->my_shm)->pingpong = DFPP_READ; - d->waitWhile(DFPP_READ); - memcpy (target, d->my_shm + SHM_HEADER,size); + // normal read under 1MB + if(size <= SHM_BODY) + { + ((shm_read *)d->my_shm)->address = src_address; + ((shm_read *)d->my_shm)->length = size; + gcc_barrier + ((shm_read *)d->my_shm)->pingpong = DFPP_READ; + d->waitWhile(DFPP_READ); + memcpy (target_buffer, d->my_shm + SHM_HEADER,size); + } + // a big read, we pull data over the shm in iterations + else + { + // first read equals the size of the SHM window + uint32_t to_read = SHM_BODY; + 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; + gcc_barrier + ((shm_read *)d->my_shm)->pingpong = DFPP_READ; + d->waitWhile(DFPP_READ); + memcpy (target_buffer, d->my_shm + SHM_HEADER,size); + // decrease size by bytes read + size -= to_read; + // move the cursors + src_address += to_read; + target_buffer += to_read; + // check how much to write in the next iteration + to_read = min(size, (uint32_t) SHM_BODY); + } + } } uint8_t SHMProcess::readByte (const uint32_t offset) @@ -540,14 +584,41 @@ void SHMProcess::writeByte (uint32_t offset, uint8_t data) d->waitWhile(DFPP_WRITE_BYTE); } -void SHMProcess::write (uint32_t offset, uint32_t size, const uint8_t *source) +void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer) { - ((shm_write *)d->my_shm)->address = offset; - ((shm_write *)d->my_shm)->length = size; - memcpy(d->my_shm+SHM_HEADER,source, size); - gcc_barrier - ((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; - d->waitWhile(DFPP_WRITE); + // normal write under 1MB + if(size <= SHM_BODY) + { + ((shm_write *)d->my_shm)->address = dst_address; + ((shm_write *)d->my_shm)->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); + } + // a big write, we push this over the shm in iterations + else + { + // first write equals the size of the SHM window + uint32_t to_write = SHM_BODY; + 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; + memcpy(d->my_shm+SHM_HEADER,source_buffer, to_write); + gcc_barrier + ((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; + d->waitWhile(DFPP_WRITE); + // decrease size by bytes written + size -= to_write; + // move the cursors + source_buffer += to_write; + dst_address += to_write; + // check how much to write in the next iteration + to_write = min(size, (uint32_t) SHM_BODY); + } + } } // FIXME: butt-fugly diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 4a846cc83..31d4c72de 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -239,6 +239,11 @@ void NormalProcess::getMemRanges( vector & ranges ) } } +bool NormalProcess::asyncSuspend() +{ + return suspend(); +} + bool NormalProcess::suspend() { int status; @@ -470,7 +475,7 @@ void NormalProcess::writeByte (uint32_t offset, uint8_t data) } // blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS -void NormalProcess::write (uint32_t offset, uint32_t size, const uint8_t *source) +void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) { uint32_t indexptr = 0; while (size > 0) diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index f61d8065f..4a230b765 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -196,6 +196,11 @@ bool NormalProcess::isIdentified() return d->identified; } +bool NormalProcess::asyncSuspend() +{ + return suspend(); +} + bool NormalProcess::suspend() { if(!d->attached) @@ -365,7 +370,7 @@ 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, const uint8_t *source) +void NormalProcess::write (uint32_t offset, uint32_t size, uint8_t *source) { WriteProcessMemory(d->my_handle, (int*) offset, source, size, NULL); } diff --git a/library/DFProcess.h b/library/DFProcess.h index 7ce68850b..d6302100f 100644 --- a/library/DFProcess.h +++ b/library/DFProcess.h @@ -61,11 +61,20 @@ namespace DFHack class DFHACK_EXPORT Process { public: + // 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; @@ -74,12 +83,12 @@ namespace DFHack 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( const uint32_t address, const uint32_t length, uint8_t* buffer) = 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(const uint32_t address,const uint32_t length, const uint8_t* buffer) = 0; + virtual void write(uint32_t address, uint32_t length, uint8_t* buffer) = 0; virtual const std::string readCString (uint32_t offset) = 0; @@ -87,12 +96,18 @@ namespace DFHack 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 DataModel for reading stl containers (depends on the version of stl DF was compiled with) virtual DataModel *getDataModel() = 0; + // get the DF's window (first that can be found ~_~) virtual DFWindow * getWindow() = 0; + // get the DF Process ID virtual int getPID() = 0; }; @@ -105,11 +120,11 @@ namespace DFHack NormalProcess(uint32_t pid, vector & known_versions); ~NormalProcess(); public: - // Set up stuff so we can read memory bool attach(); bool detach(); bool suspend(); + bool asyncSuspend(); bool resume(); bool forceresume(); @@ -119,12 +134,12 @@ namespace DFHack 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( const uint32_t address, const uint32_t length, uint8_t* buffer); + 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(const uint32_t address,const uint32_t length, const uint8_t* buffer); + void write(uint32_t address, uint32_t length, uint8_t* buffer); const std::string readCString (uint32_t offset); @@ -154,6 +169,7 @@ namespace DFHack bool detach(); bool suspend(); + bool asyncSuspend(); bool resume(); bool forceresume(); @@ -163,12 +179,12 @@ namespace DFHack 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( const uint32_t address, const uint32_t length, uint8_t* buffer); + 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(const uint32_t address,const uint32_t length, const uint8_t* buffer); + void write(uint32_t address, uint32_t length, uint8_t* buffer); const std::string readCString (uint32_t offset); diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp index 50532e42b..808add445 100644 --- a/library/DFProcessEnumerator-windows.cpp +++ b/library/DFProcessEnumerator-windows.cpp @@ -115,7 +115,7 @@ ProcessEnumerator::ProcessEnumerator( string path_to_xml ) d->meminfo = new MemInfoManager(path_to_xml); } -ProcessEnumerator::purge() +void ProcessEnumerator::purge() { for(uint32_t i = 0;i < d->processes.size();i++) { diff --git a/tools/suspendtest.cpp b/tools/suspendtest.cpp index 92a95a85c..ea786e173 100644 --- a/tools/suspendtest.cpp +++ b/tools/suspendtest.cpp @@ -31,13 +31,13 @@ int main (void) cout << "Suspended, DF should be suspended now" << endl; getline(cin, blah); - DF.Resume(); - cout << "Resumed, testing ForceResume. Suspend using SysInternals Process Explorer" << endl; - getline(cin, blah); + DF.Resume(); + cout << "Resumed, testing ForceResume. Suspend using SysInternals Process Explorer" << endl; + getline(cin, blah); - DF.ForceResume(); - cout << "ForceResumed. DF should be running." << endl; - getline(cin, blah); + DF.ForceResume(); + cout << "ForceResumed. DF should be running." << endl; + getline(cin, blah); if(!DF.Detach()) { @@ -48,4 +48,4 @@ int main (void) getline(cin, blah); return 0; -} \ No newline at end of file +}