diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 7b01f22fd..f6eb29e12 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -4,7 +4,6 @@ SET(PROJECT_HDRS DFCommonInternal.h DFDataModel.h DFHackAPI.h -DFMemAccess.h DFMemInfo.h DFMemInfoManager.h DFProcessEnumerator.h @@ -12,6 +11,7 @@ DFProcess.h DFTileTypes.h DFTypes.h DFVector.h +DFWindow.h integers.h md5/md5.h @@ -19,6 +19,8 @@ md5/md5wrapper.h tinyxml/tinystr.h tinyxml/tinyxml.h + +shmserver/dfconnect.h ) SET(PROJECT_SRCS @@ -36,23 +38,22 @@ tinyxml/tinyxmlparser.cpp ) SET(PROJECT_HDRS_LINUX -MemAccess-linux.h ) SET(PROJECT_HDRS_WINDOWS -MemAccess-windows.h stdint_win.h ) SET(PROJECT_SRCS_LINUX DFProcess-linux.cpp -DFKeys-linux.cpp +DFProcess-linux-SHM.cpp +DFWindow-linux.cpp DFProcessEnumerator-linux.cpp ) SET(PROJECT_SRCS_WINDOWS DFProcess-windows.cpp -DFKeys-windows.cpp +DFWindow-windows.cpp DFProcessEnumerator-windows.cpp ) @@ -84,7 +85,7 @@ IF(UNIX) find_library(X11_LIBRARY X11) SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -pedantic") - SET(PROJECT_LIBS ${X11_LIBRARY}) + SET(PROJECT_LIBS ${X11_LIBRARY} rt) ELSE(UNIX) SET(PROJECT_LIBS psapi) ENDIF(UNIX) diff --git a/library/DFCommonInternal.h b/library/DFCommonInternal.h index d21bfd660..9fd0dd0c0 100644 --- a/library/DFCommonInternal.h +++ b/library/DFCommonInternal.h @@ -86,8 +86,6 @@ namespace DFHack * Currently attached process and its handle */ extern Process * g_pProcess; ///< current process. non-NULL when picked - extern ProcessHandle g_ProcessHandle; ///< cache of handle to current process. used for speed reasons - extern int g_ProcessMemFile; ///< opened /proc/PID/mem, valid when attached } #ifndef BUILD_DFHACK_LIB # define BUILD_DFHACK_LIB @@ -96,9 +94,9 @@ namespace DFHack #include "DFTypes.h" #include "DFDataModel.h" #include "DFProcess.h" +#include "DFWindow.h" #include "DFProcessEnumerator.h" #include "DFMemInfoManager.h" -#include "DFMemAccess.h" #include "DFVector.h" #include "DFMemInfo.h" #include diff --git a/library/DFDataModel.cpp b/library/DFDataModel.cpp index 4be7c50e0..1e48a0bf5 100644 --- a/library/DFDataModel.cpp +++ b/library/DFDataModel.cpp @@ -37,8 +37,8 @@ DfVector DMWindows40d::readVector (uint32_t offset, uint32_t item_size) 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 = MreadDWord(offset+4); - uint32_t end = MreadDWord(offset+8); + 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); } @@ -58,20 +58,20 @@ Uint32 length Uint32 capacity */ uint32_t start_offset = offset + 4; - size_t length = MreadDWord(offset + 20); + size_t length = g_pProcess->readDWord(offset + 20); - size_t capacity = MreadDWord(offset + 24); + 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) { - Mread(start_offset, read_real , (uint8_t *)buffer); + g_pProcess->read(start_offset, read_real , (uint8_t *)buffer); } else // read data from what the offset + 4 dword points to { - start_offset = MreadDWord(start_offset);// dereference the start offset - Mread(start_offset, read_real, (uint8_t *)buffer); + 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; @@ -92,19 +92,19 @@ const string DMWindows40d::readSTLString (uint32_t offset) Uint32 capacity */ uint32_t start_offset = offset + 4; - uint32_t length = MreadDWord(offset + 20); - uint32_t capacity = MreadDWord(offset + 24); + 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) { - Mread(start_offset, capacity, (uint8_t *)temp); + g_pProcess->read(start_offset, capacity, (uint8_t *)temp); } else // read data from what the offset + 4 dword points to { - start_offset = MreadDWord(start_offset);// dereference the start offset - Mread(start_offset, capacity, (uint8_t *)temp); + start_offset = g_pProcess->readDWord(start_offset);// dereference the start offset + g_pProcess->read(start_offset, capacity, (uint8_t *)temp); } temp[length] = 0; @@ -124,8 +124,8 @@ DfVector DMLinux40d::readVector (uint32_t offset, uint32_t item_size) we don't care about alloc_end because we don't try to add stuff */ - uint32_t start = MreadDWord(offset); - uint32_t end = MreadDWord(offset+4); + 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); } @@ -140,10 +140,10 @@ struct _Rep_base size_t DMLinux40d::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity) { _Rep_base header; - offset = MreadDWord(offset); - Mread(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&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 - Mread(offset,read_real,(uint8_t * )buffer); + g_pProcess->read(offset,read_real,(uint8_t * )buffer); buffer[read_real] = 0; return read_real; } @@ -152,12 +152,12 @@ const string DMLinux40d::readSTLString (uint32_t offset) { _Rep_base header; - offset = MreadDWord(offset); - Mread(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&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]; - Mread(offset,header._M_length+1,(uint8_t * )temp); + g_pProcess->read(offset,header._M_length+1,(uint8_t * )temp); string ret(temp); delete temp; return ret; diff --git a/library/DFHackAPI.cpp b/library/DFHackAPI.cpp index bd2675d03..264cf1a25 100644 --- a/library/DFHackAPI.cpp +++ b/library/DFHackAPI.cpp @@ -105,21 +105,7 @@ public: DfVector *p_cons; DfVector *p_bld; DfVector *p_veg; - -// DfVector *p_trans; -// DfVector *p_generic; -// DfVector *p_dwarf_names; - DfVector *p_itm; - /* - string getLastNameByAddress(const uint32_t &address, bool use_generic=false); - string getSquadNameByAddress(const uint32_t &address, bool use_generic=false); - string getProfessionByAddress(const uint32_t &address); - string getCurrentJobByAddress(const uint32_t &address); - void getSkillsByAddress(const uint32_t &address, vector &); - void getTraitsByAddress(const uint32_t &address, vector &); - void getLaborsByAddress(const uint32_t &address, vector &); - */ }; API::API (const string path_to_xml) @@ -163,7 +149,7 @@ bool API::InitMap() d->veinsize = d->offset_descriptor->getHexValue ("v_vein_size"); // get the map pointer - uint32_t x_array_loc = MreadDWord (map_offset); + uint32_t x_array_loc = g_pProcess->readDWord (map_offset); //FIXME: very inadequate if (!x_array_loc) { @@ -173,9 +159,9 @@ bool API::InitMap() uint32_t mx, my, mz; // get the size - mx = d->x_block_count = MreadDWord (x_count_offset); - my = d->y_block_count = MreadDWord (y_count_offset); - mz = d->z_block_count = MreadDWord (z_count_offset); + 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); // test for wrong map dimensions if (mx == 0 || mx > 48 || my == 0 || my > 48 || mz == 0) @@ -189,14 +175,14 @@ bool API::InitMap() uint32_t *temp_y = new uint32_t[my]; uint32_t *temp_z = new uint32_t[mz]; - Mread (x_array_loc, mx * sizeof (uint32_t), (uint8_t *) temp_x); + g_pProcess->read (x_array_loc, mx * sizeof (uint32_t), (uint8_t *) temp_x); for (uint32_t x = 0; x < mx; x++) { - Mread (temp_x[x], my * sizeof (uint32_t), (uint8_t *) temp_y); + g_pProcess->read (temp_x[x], my * sizeof (uint32_t), (uint8_t *) temp_y); // y -> map column for (uint32_t y = 0; y < my; y++) { - Mread (temp_y[y], + g_pProcess->read (temp_y[y], mz * sizeof (uint32_t), (uint8_t *) (d->block + x*my*mz + y*mz)); } @@ -229,7 +215,7 @@ bool API::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer) uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - Mread (addr + d->tile_type_offset, 256 * sizeof (uint16_t), (uint8_t *) buffer); + g_pProcess->read (addr + d->tile_type_offset, 256 * sizeof (uint16_t), (uint8_t *) buffer); return true; } return false; @@ -242,7 +228,7 @@ bool API::ReadDesignations (uint32_t x, uint32_t y, uint32_t z, uint32_t *buffer uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - Mread (addr + d->designation_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); + g_pProcess->read (addr + d->designation_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); return true; } return false; @@ -255,7 +241,7 @@ bool API::ReadOccupancy (uint32_t x, uint32_t y, uint32_t z, uint32_t *buffer) uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - Mread (addr + d->occupancy_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); + g_pProcess->read (addr + d->occupancy_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); return true; } return false; @@ -268,7 +254,7 @@ bool API::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, uint16_t *buffer) uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - Mwrite (addr + d->tile_type_offset, 256 * sizeof (uint16_t), (uint8_t *) buffer); + g_pProcess->write (addr + d->tile_type_offset, 256 * sizeof (uint16_t), (uint8_t *) buffer); return true; } return false; @@ -297,7 +283,7 @@ bool API::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, uint32_t *buffe uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - Mwrite (addr + d->designation_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); + g_pProcess->write (addr + d->designation_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); return true; } return false; @@ -309,7 +295,7 @@ bool API::WriteOccupancy (uint32_t x, uint32_t y, uint32_t z, uint32_t *buffer) uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - Mwrite (addr + d->occupancy_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); + g_pProcess->write (addr + d->occupancy_offset, 256 * sizeof (uint32_t), (uint8_t *) buffer); return true; } return false; @@ -323,7 +309,7 @@ bool API::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, uint8_t *buffer uint32_t addr = d->block[x*d->y_block_count*d->z_block_count + y*d->z_block_count + z]; if (addr) { - Mread (addr + d->biome_stuffs, 16 * sizeof (uint8_t), buffer); + g_pProcess->read (addr + d->biome_stuffs, 16 * sizeof (uint8_t), buffer); return true; } return false; @@ -352,7 +338,7 @@ bool API::ReadVeins (uint32_t x, uint32_t y, uint32_t z, vector & veins // read the vein pointer from the vector uint32_t temp = * (uint32_t *) p_veins[i]; // read the vein data (dereference pointer) - Mread (temp, d->veinsize, (uint8_t *) &v); + g_pProcess->read (temp, d->veinsize, (uint8_t *) &v); // store it in the vector veins.push_back (v); } @@ -417,9 +403,9 @@ bool API::ReadStoneMatgloss (vector & stones) t_matgloss mat; //fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address d->dm->readSTLString (temp, mat.id, 128); - mat.fore = (uint8_t) MreadWord (temp + matgloss_colors); - mat.back = (uint8_t) MreadWord (temp + matgloss_colors + 2); - mat.bright = (uint8_t) MreadWord (temp + matgloss_colors + 4); + mat.fore = (uint8_t) g_pProcess->readWord (temp + matgloss_colors); + mat.back = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 2); + mat.bright = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 4); stones.push_back (mat); } return true; @@ -444,9 +430,9 @@ bool API::ReadMetalMatgloss (vector & metals) t_matgloss mat; //fill_char_buf(mat.id, d->dm->readSTLString(temp)); // reads a C string given an address d->dm->readSTLString (temp, mat.id, 128); - mat.fore = (uint8_t) MreadWord (temp + matgloss_colors); - mat.back = (uint8_t) MreadWord (temp + matgloss_colors + 2); - mat.bright = (uint8_t) MreadWord (temp + matgloss_colors + 4); + mat.fore = (uint8_t) g_pProcess->readWord (temp + matgloss_colors); + mat.back = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 2); + mat.bright = (uint8_t) g_pProcess->readWord (temp + matgloss_colors + 4); metals.push_back (mat); } return true; @@ -539,16 +525,16 @@ bool API::ReadGeology (vector < vector >& assign) } // read position of the region inside DF world - MreadDWord (region_x_offset, regionX); - MreadDWord (region_y_offset, regionY); - MreadDWord (region_z_offset, regionZ); + g_pProcess->readDWord (region_x_offset, regionX); + g_pProcess->readDWord (region_y_offset, regionY); + g_pProcess->readDWord (region_z_offset, regionZ); // get world size - MreadWord (world_offset + world_size_x, worldSizeX); - MreadWord (world_offset + world_size_y, worldSizeY); + g_pProcess->readWord (world_offset + world_size_x, worldSizeX); + g_pProcess->readWord (world_offset + world_size_y, worldSizeY); // get pointer to first part of 2d array of regions - uint32_t regions = MreadDWord (world_offset + world_regions_offset); + uint32_t regions = g_pProcess->readDWord (world_offset + world_regions_offset); // read the geoblock vector DfVector geoblocks = d->dm->readVector (world_offset + world_geoblocks_offset, 4); @@ -566,11 +552,11 @@ bool API::ReadGeology (vector < vector >& assign) // get pointer to column of regions uint32_t geoX; - MreadDWord (regions + bioRX*4, geoX); + g_pProcess->readDWord (regions + bioRX*4, geoX); // get index into geoblock vector uint16_t geoindex; - MreadWord (geoX + bioRY*region_size + region_geo_index_offset, geoindex); + g_pProcess->readWord (geoX + bioRY*region_size + region_geo_index_offset, geoindex); // get the geoblock from the geoblock vector using the geoindex // read the matgloss pointer from the vector into temp @@ -588,7 +574,7 @@ bool API::ReadGeology (vector < vector >& assign) // read pointer to a layer uint32_t geol_offset = * (uint32_t *) geolayers[j]; // read word at pointer + 2, store in our geology vectors - d->v_geology[i].push_back (MreadWord (geol_offset + 2)); + d->v_geology[i].push_back (g_pProcess->readWord (geol_offset + 2)); } } assign.clear(); @@ -626,7 +612,7 @@ bool API::ReadBuilding (const int32_t &index, t_building & building) //d->p_bld->read(index,(uint8_t *)&temp); //read building from memory - Mread (temp, sizeof (t_building_df40d), (uint8_t *) &bld_40d); + g_pProcess->read (temp, sizeof (t_building_df40d), (uint8_t *) &bld_40d); // transform int32_t type = -1; @@ -675,7 +661,7 @@ bool API::ReadConstruction (const int32_t &index, t_construction & construction) uint32_t temp = * (uint32_t *) d->p_cons->at (index); //read construction from memory - Mread (temp, sizeof (t_construction_df40d), (uint8_t *) &c_40d); + g_pProcess->read (temp, sizeof (t_construction_df40d), (uint8_t *) &c_40d); // transform construction.x = c_40d.x; @@ -713,7 +699,7 @@ bool API::ReadVegetation (const int32_t &index, t_tree_desc & shrubbery) // read pointer from vector at position uint32_t temp = * (uint32_t *) d->p_veg->at (index); //read construction from memory - Mread (temp + d->tree_offset, sizeof (t_tree_desc), (uint8_t *) &shrubbery); + g_pProcess->read (temp + d->tree_offset, sizeof (t_tree_desc), (uint8_t *) &shrubbery); // FIXME: this is completely wrong. type isn't just tree/shrub but also different kinds of trees. stuff that grows around ponds has its own type ID if (shrubbery.material.type == 3) shrubbery.material.type = 2; return true; @@ -795,194 +781,6 @@ uint32_t API::InitReadCreatures() return false; } } -/* -//This code was mostly adapted fromh dwarftherapist by chmod -string API::Private::getLastNameByAddress(const uint32_t &address, bool use_generic) -{ - string out; - uint32_t wordIndex; - for (int i = 0; i<7;i++) - { - MreadDWord(address+i*4, wordIndex); - if(wordIndex == 0xFFFFFFFF) - { - break; - } - if(use_generic) - { - uint32_t genericPtr; - p_generic->read(wordIndex,(uint8_t *)&genericPtr); - out.append(dm->readSTLString(genericPtr)); - } - else - { - uint32_t transPtr; - p_dwarf_names->read(wordIndex,(uint8_t *)&transPtr); - out.append(dm->readSTLString(transPtr)); - } - } - return out; -} - -string API::Private::getSquadNameByAddress(const uint32_t &address, bool use_generic) -{ - string out; - uint32_t wordIndex; - for (int i = 0; i<6;i++) - { - MreadDWord(address+i*4, wordIndex); - if(wordIndex == 0xFFFFFFFF) - { - continue; - } - if(wordIndex == 0) - { - break; - } - if(use_generic) - { - uint32_t genericPtr; - p_generic->read(wordIndex,(uint8_t *)&genericPtr); - out.append(dm->readSTLString(genericPtr)); - } - else - { - if(i == 4) // There will be a space in game if there is a name in the last - { - out.append(" "); - } - uint32_t transPtr; - p_dwarf_names->read(wordIndex,(uint8_t *)&transPtr); - out.append(dm->readSTLString(transPtr)); - } - } - return out; -} - -string API::Private::getProfessionByAddress(const uint32_t &address) -{ - string profession; - uint8_t profId = MreadByte(address); - profession = offset_descriptor->getProfession(profId); - return profession; -} - -string API::Private::getCurrentJobByAddress(const uint32_t &address) -{ - string job; - uint32_t jobIdAddr = MreadDWord(address); - if(jobIdAddr != 0) - { - uint8_t jobId = MreadByte(jobIdAddr+creature_current_job_id_offset); - job = offset_descriptor->getJob(jobId); - } - else - { - job ="No Job"; - } - return job; -} - -string API::getLastName(const uint32_t &index, bool use_generic=false) -{ - assert(d->creaturesInited); - uint32_t temp; - // read pointer from vector at position - d->p_cre->read(index,(uint8_t *)&temp); - return(d->getLastNameByAddress(temp+d->creature_last_name_offset,use_generic)); -} -string API::getSquadName(const uint32_t &index, bool use_generic=false) -{ - assert(d->creaturesInited); - uint32_t temp; - // read pointer from vector at position - d->p_cre->read(index,(uint8_t *)&temp); - return(d->getSquadNameByAddress(temp+d->creature_squad_name_offset,use_generic)); -} -string API::getProfession(const uint32_t &index) -{ - assert(d->creaturesInited); - uint32_t temp; - // read pointer from vector at position - d->p_cre->read(index,(uint8_t *)&temp); - return(d->getProfessionByAddress(temp+d->creature_profession_offset)); -} -string API::getCurrentJob(const uint32_t &index) -{ - assert(d->creaturesInited); - uint32_t temp; - // read pointer from vector at position - d->p_cre->read(index,(uint8_t *)&temp); - return(d->getCurrentJobByAddress(temp+d->creature_current_job_offset)); -} -vector API::getSkills(const uint32_t &index) -{ - assert(d->creaturesInited); - uint32_t temp; - // read pointer from vector at position - d->p_cre->read(index,(uint8_t *)&temp); - vector tempSkillVec; - d->getSkillsByAddress(temp+d->creature_last_name_offset,tempSkillVec); - return(tempSkillVec); -} - -vector API::getTraits(const uint32_t &index) -{ - assert(d->creaturesInited); - uint32_t temp; - // read pointer from vector at position - d->p_cre->read(index,(uint8_t *)&temp); - vector tempTraitVec; - d->getTraitsByAddress(temp+d->creature_traits_offset,tempTraitVec); - return(tempTraitVec); -} - -void API::Private::getSkillsByAddress(const uint32_t &address, vector & skills) -{ - DfVector* skillVector = new DfVector(dm->readVector(address,4)); - for(uint32_t i = 0; igetSize();i++) - { - uint32_t temp; - skillVector->read(i, (uint8_t *) &temp); - t_skill tempSkill; - tempSkill.id= MreadByte(temp); - tempSkill.name = offset_descriptor->getSkill(tempSkill.id); - tempSkill.experience = MreadWord(temp+8); - tempSkill.rating = MreadByte(temp+4); -// add up all the experience per level -// for (int j = 0; j < tempSkill.rating; ++j) -// { -// tempSkill.experience += 500 + (j * 100); -// } -// - skills.push_back(tempSkill); - } -} - -void API::Private::getTraitsByAddress(const uint32_t &address, vector & traits) -{ - for(int i = 0; i < 30; i++) - { - t_trait tempTrait; - tempTrait.value =MreadWord(address+i*2); - tempTrait.displayTxt = offset_descriptor->getTrait(i,tempTrait.value); - tempTrait.name = offset_descriptor->getTraitName(i); - traits.push_back(tempTrait); - } -} - -void API::Private::getLaborsByAddress(const uint32_t &address, vector & labors) -{ - uint8_t laborArray[102] = {0}; - Mread(address, 102, laborArray); - for(int i = 0;i<102; i++) - { - t_labor tempLabor; - tempLabor.name = offset_descriptor->getLabor(i); - tempLabor.value = laborArray[i]; - labors.push_back(tempLabor); - } -}*/ // returns index of creature actually read or -1 if no creature can be found int32_t API::ReadCreatureInBox (int32_t index, t_creature & furball, @@ -996,7 +794,7 @@ int32_t API::ReadCreatureInBox (int32_t index, t_creature & furball, { // read pointer from vector at position uint32_t temp = * (uint32_t *) d->p_cre->at (index); - Mread (temp + d->creature_pos_offset, 3 * sizeof (uint16_t), (uint8_t *) &coords); + g_pProcess->read (temp + d->creature_pos_offset, 3 * sizeof (uint16_t), (uint8_t *) &coords); if (coords[0] >= x1 && coords[0] < x2) { if (coords[1] >= y1 && coords[1] < y2) @@ -1020,10 +818,10 @@ bool API::ReadCreature (const int32_t &index, t_creature & furball) uint32_t temp = * (uint32_t *) d->p_cre->at (index); furball.origin = temp; //read creature from memory - Mread (temp + d->creature_pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (furball.x)); // xyz really - MreadDWord (temp + d->creature_type_offset, furball.type); - MreadDWord (temp + d->creature_flags1_offset, furball.flags1.whole); - MreadDWord (temp + d->creature_flags2_offset, furball.flags2.whole); + g_pProcess->read (temp + d->creature_pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (furball.x)); // xyz really + g_pProcess->readDWord (temp + d->creature_type_offset, furball.type); + g_pProcess->readDWord (temp + d->creature_flags1_offset, furball.flags1.whole); + g_pProcess->readDWord (temp + d->creature_flags2_offset, furball.flags2.whole); // normal names d->dm->readSTLString (temp + d->creature_first_name_offset, furball.first_name, 128); d->dm->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128); @@ -1031,15 +829,15 @@ bool API::ReadCreature (const int32_t &index, t_creature & furball) d->dm->readSTLString (temp + d->creature_nick_name_offset, furball.nick_name, 128); fill_char_buf (furball.custom_profession, d->dm->readSTLString (temp + d->creature_custom_profession_offset)); // crazy composited names - Mread (temp + d->creature_last_name_offset, sizeof (t_lastname), (uint8_t *) &furball.last_name); - Mread (temp + d->creature_squad_name_offset, sizeof (t_squadname), (uint8_t *) &furball.squad_name); + g_pProcess->read (temp + d->creature_last_name_offset, sizeof (t_lastname), (uint8_t *) &furball.last_name); + g_pProcess->read (temp + d->creature_squad_name_offset, sizeof (t_squadname), (uint8_t *) &furball.squad_name); // labors - Mread (temp + d->creature_labors_offset, NUM_CREATURE_LABORS, furball.labors); + g_pProcess->read (temp + d->creature_labors_offset, NUM_CREATURE_LABORS, furball.labors); // traits - Mread (temp + d->creature_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS, (uint8_t *) &furball.traits); + g_pProcess->read (temp + d->creature_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS, (uint8_t *) &furball.traits); // learned skills DfVector skills (d->dm->readVector (temp + d->creature_skills_offset, 4)); furball.numSkills = skills.getSize(); @@ -1048,32 +846,31 @@ bool API::ReadCreature (const int32_t &index, t_creature & furball) uint32_t temp2 = * (uint32_t *) skills[i]; //skills.read(i, (uint8_t *) &temp2); // a byte: this gives us 256 skills maximum. - furball.skills[i].id = MreadByte (temp2); - furball.skills[i].rating = MreadByte (temp2 + 4); - furball.skills[i].experience = MreadWord (temp2 + 8); + furball.skills[i].id = g_pProcess->readByte (temp2); + furball.skills[i].rating = g_pProcess->readByte (temp2 + 4); + furball.skills[i].experience = g_pProcess->readWord (temp2 + 8); } // profession - furball.profession = MreadByte (temp + d->creature_profession_offset); + furball.profession = g_pProcess->readByte (temp + d->creature_profession_offset); // current job HACK: the job object isn't cleanly represented here - uint32_t jobIdAddr = MreadDWord (temp + d->creature_current_job_offset); + uint32_t jobIdAddr = g_pProcess->readDWord (temp + d->creature_current_job_offset); furball.current_job.active = jobIdAddr; if (jobIdAddr) { - furball.current_job.jobId = MreadByte (jobIdAddr + d->creature_current_job_id_offset); + furball.current_job.jobId = g_pProcess->readByte (jobIdAddr + d->creature_current_job_id_offset); } - MreadDWord (temp + d->creature_happiness_offset, furball.happiness); - MreadDWord (temp + d->creature_id_offset, furball.id); - MreadDWord (temp + d->creature_agility_offset, furball.agility); - MreadDWord (temp + d->creature_strength_offset, furball.strength); - MreadDWord (temp + d->creature_toughness_offset, furball.toughness); - MreadDWord (temp + d->creature_money_offset, furball.money); - furball.squad_leader_id = (int32_t) MreadDWord (temp + d->creature_squad_leader_id_offset); - MreadByte (temp + d->creature_sex_offset, furball.sex); + g_pProcess->readDWord (temp + d->creature_happiness_offset, furball.happiness); + g_pProcess->readDWord (temp + d->creature_id_offset, furball.id); + g_pProcess->readDWord (temp + d->creature_agility_offset, furball.agility); + g_pProcess->readDWord (temp + d->creature_strength_offset, furball.strength); + g_pProcess->readDWord (temp + d->creature_toughness_offset, furball.toughness); + g_pProcess->readDWord (temp + d->creature_money_offset, furball.money); + furball.squad_leader_id = (int32_t) g_pProcess->readDWord (temp + d->creature_squad_leader_id_offset); + g_pProcess->readByte (temp + d->creature_sex_offset, furball.sex); return true; } -//FIXME: this just isn't enough void API::InitReadNameTables (map< string, vector > & nameTable) { int genericAddress = d->offset_descriptor->getAddress ("language_vector"); @@ -1176,11 +973,13 @@ bool API::Attach() // find a process (ProcessManager can find multiple when used properly) if (!d->pm->findProcessess()) { + cerr << "couldn't find a suitable process" << endl; return false; } d->p = (*d->pm) [0]; if (!d->p->attach()) { + cerr << "couldn't attach to process" << endl; return false; // couldn't attach to process, no go } d->offset_descriptor = d->p->getDescriptor(); @@ -1231,12 +1030,12 @@ bool API::isSuspended() void API::ReadRaw (const uint32_t &offset, const uint32_t &size, uint8_t *target) { - Mread (offset, size, target); + g_pProcess->read (offset, size, target); } void API::WriteRaw (const uint32_t &offset, const uint32_t &size, uint8_t *source) { - Mwrite (offset, size, source); + g_pProcess->write (offset, size, source); } bool API::InitViewAndCursor() @@ -1278,18 +1077,18 @@ bool API::InitViewSize() bool API::getViewCoords (int32_t &x, int32_t &y, int32_t &z) { assert (d->cursorWindowInited); - MreadDWord (d->window_x_offset, (uint32_t &) x); - MreadDWord (d->window_y_offset, (uint32_t &) y); - MreadDWord (d->window_z_offset, (uint32_t &) z); + g_pProcess->readDWord (d->window_x_offset, (uint32_t &) x); + g_pProcess->readDWord (d->window_y_offset, (uint32_t &) y); + g_pProcess->readDWord (d->window_z_offset, (uint32_t &) z); return true; } //FIXME: confine writing of coords to map bounds? bool API::setViewCoords (const int32_t &x, const int32_t &y, const int32_t &z) { assert (d->cursorWindowInited); - MwriteDWord (d->window_x_offset, (uint32_t &) x); - MwriteDWord (d->window_y_offset, (uint32_t &) y); - MwriteDWord (d->window_z_offset, (uint32_t &) z); + g_pProcess->writeDWord (d->window_x_offset, (uint32_t &) x); + g_pProcess->writeDWord (d->window_y_offset, (uint32_t &) y); + g_pProcess->writeDWord (d->window_z_offset, (uint32_t &) z); return true; } @@ -1297,7 +1096,7 @@ bool API::getCursorCoords (int32_t &x, int32_t &y, int32_t &z) { assert (d->cursorWindowInited); int32_t coords[3]; - Mread (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); + g_pProcess->read (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); x = coords[0]; y = coords[1]; z = coords[2]; @@ -1309,26 +1108,18 @@ bool API::setCursorCoords (const int32_t &x, const int32_t &y, const int32_t &z) { assert (d->cursorWindowInited); int32_t coords[3] = {x, y, z}; - Mwrite (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); + g_pProcess->write (d->cursor_xyz_offset, 3*sizeof (int32_t), (uint8_t *) coords); return true; } bool API::getWindowSize (int32_t &width, int32_t &height) { assert (d->viewSizeInited); int32_t coords[2]; - Mread (d->window_dims_offset, 2*sizeof (int32_t), (uint8_t *) coords); + g_pProcess->read (d->window_dims_offset, 2*sizeof (int32_t), (uint8_t *) coords); width = coords[0]; height = coords[1]; return true; } -////FIXME: I don't know what is going to happen if you try to set these to bad values, probably bad things... -//bool API::setWindowSize(const int32_t &width, const int32_t &height) -//{ -// assert(d->viewSizeInited); -// int32_t coords[2] = {width,height}; -// Mwrite(d->window_dims_offset,2*sizeof(int32_t),(uint8_t *)coords); -// return true; -//} memory_info API::getMemoryInfo() { @@ -1339,6 +1130,11 @@ Process * API::getProcess() return d->p; } +DFWindow * API::getWindow() +{ + return d->p->getWindow(); +} + uint32_t API::InitReadItems() { int items = d->offset_descriptor->getAddress ("items"); @@ -1362,7 +1158,7 @@ bool API::ReadItem (const uint32_t &index, t_item & item) uint32_t temp = * (uint32_t *) d->p_itm->at (index); //read building from memory - Mread (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d); + g_pProcess->read (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d); // transform int32_t type = -1; @@ -1377,7 +1173,7 @@ bool API::ReadItem (const uint32_t &index, t_item & item) item.flags = item_40d.flags; //TODO certain item types (creature based, threads, seeds, bags do not have the first matType byte, instead they have the material index only located at 0x68 - Mread (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material); + g_pProcess->read (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material); //for(int i = 0; i < 0xCC; i++){ // used for item research // uint8_t byte = MreadByte(temp+i); // item.bytes.push_back(byte); @@ -1395,21 +1191,21 @@ bool API::ReadPauseState() { assert (d->cursorWindowInited); - uint32_t pauseState = MreadDWord (d->pause_state_offset); + uint32_t pauseState = g_pProcess->readDWord (d->pause_state_offset); return (pauseState); } bool API::ReadViewScreen (t_viewscreen &screen) { assert (d->cursorWindowInited); - uint32_t last = MreadDWord (d->view_screen_offset); - uint32_t screenAddr = MreadDWord (last); - uint32_t nextScreenPtr = MreadDWord (last + 4); + uint32_t last = g_pProcess->readDWord (d->view_screen_offset); + uint32_t screenAddr = g_pProcess->readDWord (last); + uint32_t nextScreenPtr = g_pProcess->readDWord (last + 4); while (nextScreenPtr != 0) { last = nextScreenPtr; - screenAddr = MreadDWord (nextScreenPtr); - nextScreenPtr = MreadDWord (nextScreenPtr + 4); + screenAddr = g_pProcess->readDWord (nextScreenPtr); + nextScreenPtr = g_pProcess->readDWord (nextScreenPtr + 4); } return d->offset_descriptor->resolveClassId (last, screen.type); } diff --git a/library/DFHackAPI.h b/library/DFHackAPI.h index 32e2a0b57..b52a78f6f 100644 --- a/library/DFHackAPI.h +++ b/library/DFHackAPI.h @@ -31,7 +31,7 @@ distribution. #include #include "integers.h" #include "DFTileTypes.h" -#include "DFKeys.h" +#include "DFWindow.h" namespace DFHack { @@ -48,13 +48,6 @@ namespace DFHack bool Detach(); bool isAttached(); - // type a string into the DF window - //Capitals are shifted automatically, other keys !@# ect need to have useShift set for them - void TypeStr(const char *lpszString,int delay = 0,bool useShift = false); - - // type a special key into DF window $count times - void TypeSpecial(t_special command,int count=1,int delay = 0); - //true if paused, false if not bool ReadPauseState(); @@ -209,6 +202,7 @@ namespace DFHack memory_info getMemoryInfo(); Process * getProcess(); + DFWindow * getWindow(); }; } // namespace DFHack #endif // SIMPLEAPI_H_INCLUDED diff --git a/library/DFMemAccess.h b/library/DFMemAccess.h deleted file mode 100644 index 181025c1f..000000000 --- a/library/DFMemAccess.h +++ /dev/null @@ -1,34 +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. -*/ - -#ifndef PROCESSUTIL_H_INCLUDED -#define PROCESSUTIL_H_INCLUDED - -#ifdef LINUX_BUILD - #include "MemAccess-linux.h" -#else - #include "MemAccess-windows.h" -#endif - -#endif // PROCESSUTIL_H_INCLUDED diff --git a/library/DFMemInfo.cpp b/library/DFMemInfo.cpp index 27629a812..64dcf8ba5 100644 --- a/library/DFMemInfo.cpp +++ b/library/DFMemInfo.cpp @@ -296,7 +296,7 @@ void memory_info::setMultiClassChild (uint32_t multi_index, const char * name, c bool memory_info::resolveClassId(uint32_t address, int32_t & classid) { - uint32_t vtable = MreadDWord(address); + uint32_t vtable = g_pProcess->readDWord(address); // FIXME: stupid search. we need a better container for(uint32_t i = 0;i< classes.size();i++) { @@ -306,7 +306,7 @@ bool memory_info::resolveClassId(uint32_t address, int32_t & classid) if(classes[i].is_multiclass) { vector & vec = classsubtypes[classes[i].multi_index]; - uint32_t type = MreadWord(address + classes[i].type_offset); + uint32_t type = g_pProcess->readWord(address + classes[i].type_offset); //printf ("class %d:%s offset 0x%x\n", i , classes[i].classname.c_str(), classes[i].type_offset); // return typed building if successful for (uint32_t k = 0; k < vec.size();k++) diff --git a/library/DFProcess-linux-SHM.cpp b/library/DFProcess-linux-SHM.cpp new file mode 100644 index 000000000..3d6d4203f --- /dev/null +++ b/library/DFProcess-linux-SHM.cpp @@ -0,0 +1,402 @@ +/* +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 +#include +#include +#include "shmserver/dfconnect.h" +using namespace DFHack; + +class SHMProcess::Private +{ + public: + Private() + { + my_datamodel = NULL; + my_descriptor = NULL; + my_pid = 0; + my_window = NULL; + attached = false; + suspended = false; + identified = false; + }; + ~Private(){}; + DataModel* my_datamodel; + memory_info * my_descriptor; + DFWindow * my_window; + uint32_t my_pid; + char *my_shm; + int my_shmid; + + bool attached; + bool suspended; + bool identified; + bool validate(char * exe_file, uint32_t pid, vector & known_versions); + bool waitWhile (DF_PINGPONG state); +}; + +bool SHMProcess::Private::waitWhile (DF_PINGPONG state) +{ + uint32_t cnt = 0; + struct shmid_ds descriptor; + while (((shm_cmd *)my_shm)->pingpong == state) + { + if(cnt == 10000) + { + shmctl(my_shmid, IPC_STAT, &descriptor); + if(descriptor.shm_nattch == 1)// DF crashed? + { + ((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; + attached = suspended = false; + return false; + } + else + { + cnt = 0; + } + } + cnt++; + } + if(((shm_cmd *)my_shm)->pingpong == DFPP_SV_ERROR) + { + ((shm_cmd *)my_shm)->pingpong = DFPP_RUNNING; + attached = suspended = false; + cerr << "shm server error!" << endl; + assert (false); + return false; + } + return true; +} + +SHMProcess::SHMProcess(uint32_t pid, int shmid, char * shm, vector & known_versions) +: d(new Private()) +{ + char exe_link_name [256]; + char target_name[1024]; + int target_result; + + sprintf(exe_link_name,"/proc/%d/exe", pid); + + // resolve /proc/PID/exe link + 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... + target_name[target_result] = 0; + + // is this the regular linux DF? + // create linux process, add it to the vector + d->validate(target_name,pid,known_versions ); + d->my_shmid = shmid; + d->my_shm = shm; + d->my_window = new DFWindow(this); + // make sure we restart the process + ((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; +} + +bool SHMProcess::isSuspended() +{ + return d->suspended; +} +bool SHMProcess::isAttached() +{ + return d->attached; +} + +bool SHMProcess::isIdentified() +{ + return d->identified; +} + +bool SHMProcess::Private::validate(char * exe_file,uint32_t pid, vector & known_versions) +{ + md5wrapper md5; + // get hash of the running DF process + string hash = md5.getHashFromFile(exe_file); + vector::iterator it; + cerr << exe_file << " " << hash << endl; + // iterate over the list of memory locations + for ( it=known_versions.begin() ; it < known_versions.end(); it++ ) + { + if(hash == (*it).getString("md5")) // are the md5 hashes the same? + { + memory_info * m = &*it; + my_datamodel =new DMLinux40d(); + my_descriptor = m; + my_pid = pid; + identified = true; + cerr << "identified " << m->getVersion() << endl; + return true; + } + } + return false; +} + +SHMProcess::~SHMProcess() +{ + if(d->attached) + { + detach(); + } + // destroy data model. this is assigned by processmanager + if(d->my_datamodel) + delete d->my_datamodel; + if(d->my_window) + delete d->my_window; + delete d; +} + + +DataModel *SHMProcess::getDataModel() +{ + return d->my_datamodel; +} + +memory_info * SHMProcess::getDescriptor() +{ + return d->my_descriptor; +} + +DFWindow * SHMProcess::getWindow() +{ + return d->my_window; +} + +int SHMProcess::getPID() +{ + return d->my_pid; +} + +//FIXME: implement +bool SHMProcess::getThreadIDs(vector & threads ) +{ + return false; +} + +//FIXME: cross-reference with ELF segment entries? +void SHMProcess::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 SHMProcess::suspend() +{ + int status; + if(!d->attached) + return false; + if(d->suspended) + return true; + ((shm_cmd *)d->my_shm)->pingpong = DFPP_SUSPEND; + if(!d->waitWhile(DFPP_SUSPEND)) + return false; + d->suspended = true; + return true; +} + +bool SHMProcess::forceresume() +{ + return resume(); +} + +bool SHMProcess::resume() +{ + if(!d->attached) + return false; + if(!d->suspended) + return true; + ((shm_cmd *)d->my_shm)->pingpong = DFPP_RUNNING; + d->suspended = false; + return true; +} + + +bool SHMProcess::attach() +{ + int status; + if(g_pProcess != NULL) + { + cerr << "there's already a different process attached" << endl; + return false; + } + d->attached = true; + if(suspend()) + { + d->suspended = true; + g_pProcess = this; + return true; + } + d->attached = false; + cerr << "unable to suspend" << endl; + return false; +} + +bool SHMProcess::detach() +{ + if(!d->attached) return false; + if(d->suspended) resume(); + d->attached = false; + d->suspended = false; +} + + +// FIXME: use recursion +void SHMProcess::read (const uint32_t offset, const uint32_t size, uint8_t *target) +{ + assert (size < (SHM_SIZE - sizeof(shm_read))); + ((shm_read *)d->my_shm)->address = offset; + ((shm_read *)d->my_shm)->length = size; + ((shm_read *)d->my_shm)->pingpong = DFPP_READ; + d->waitWhile(DFPP_READ); + memcpy (target, d->my_shm + sizeof(shm_ret_data),size); +} + +uint8_t SHMProcess::readByte (const uint32_t offset) +{ + ((shm_read_small *)d->my_shm)->address = offset; + ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; + d->waitWhile(DFPP_READ_BYTE); + return ((shm_retval *)d->my_shm)->value; +} + +void SHMProcess::readByte (const uint32_t offset, uint8_t &val ) +{ + ((shm_read_small *)d->my_shm)->address = offset; + ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_BYTE; + d->waitWhile(DFPP_READ_BYTE); + val = ((shm_retval *)d->my_shm)->value; +} + +uint16_t SHMProcess::readWord (const uint32_t offset) +{ + ((shm_read_small *)d->my_shm)->address = offset; + ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; + d->waitWhile(DFPP_READ_WORD); + return ((shm_retval *)d->my_shm)->value; +} + +void SHMProcess::readWord (const uint32_t offset, uint16_t &val) +{ + ((shm_read_small *)d->my_shm)->address = offset; + ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_WORD; + d->waitWhile(DFPP_READ_WORD); + val = ((shm_retval *)d->my_shm)->value; +} + +uint32_t SHMProcess::readDWord (const uint32_t offset) +{ + ((shm_read_small *)d->my_shm)->address = offset; + ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; + d->waitWhile(DFPP_READ_DWORD); + return ((shm_retval *)d->my_shm)->value; +} +void SHMProcess::readDWord (const uint32_t offset, uint32_t &val) +{ + ((shm_read_small *)d->my_shm)->address = offset; + ((shm_read_small *)d->my_shm)->pingpong = DFPP_READ_DWORD; + d->waitWhile(DFPP_READ_DWORD); + val = ((shm_retval *)d->my_shm)->value; +} + +/* + * WRITING + */ + +void SHMProcess::writeDWord (uint32_t offset, uint32_t data) +{ + ((shm_write_small *)d->my_shm)->address = offset; + ((shm_write_small *)d->my_shm)->value = data; + ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_DWORD; + d->waitWhile(DFPP_WRITE_DWORD); +} + +// using these is expensive. +void SHMProcess::writeWord (uint32_t offset, uint16_t data) +{ + ((shm_write_small *)d->my_shm)->address = offset; + ((shm_write_small *)d->my_shm)->value = data; + ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_WORD; + d->waitWhile(DFPP_WRITE_WORD); +} + +void SHMProcess::writeByte (uint32_t offset, uint8_t data) +{ + ((shm_write_small *)d->my_shm)->address = offset; + ((shm_write_small *)d->my_shm)->value = data; + ((shm_write_small *)d->my_shm)->pingpong = DFPP_WRITE_BYTE; + d->waitWhile(DFPP_WRITE_BYTE); +} + +void SHMProcess::write (uint32_t offset, uint32_t size, const uint8_t *source) +{ + ((shm_write *)d->my_shm)->address = offset; + ((shm_write *)d->my_shm)->length = size; + memcpy(d->my_shm+sizeof(shm_write),source, size); + ((shm_write *)d->my_shm)->pingpong = DFPP_WRITE; + d->waitWhile(DFPP_WRITE); +} + +// FIXME: butt-fugly +const std::string SHMProcess::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; +} + diff --git a/library/DFProcess-linux.cpp b/library/DFProcess-linux.cpp index 615010298..47747c395 100644 --- a/library/DFProcess-linux.cpp +++ b/library/DFProcess-linux.cpp @@ -22,9 +22,10 @@ must not be misrepresented as being the original software. distribution. */ #include "DFCommonInternal.h" +#include using namespace DFHack; -class Process::Private +class NormalProcess::Private { public: Private() @@ -32,23 +33,27 @@ class Process::Private my_datamodel = NULL; my_descriptor = NULL; my_handle = NULL; + my_window = NULL; my_pid = 0; attached = false; suspended = false; + memFileHandle = 0; }; ~Private(){}; DataModel* my_datamodel; + 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); }; -Process::Process(uint32_t pid, vector & known_versions) +NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) : d(new Private()) { char dir_name [256]; @@ -81,6 +86,7 @@ Process::Process(uint32_t pid, vector & known_versions) { // 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; } @@ -104,25 +110,27 @@ Process::Process(uint32_t pid, vector & known_versions) // 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 Process::isSuspended() +bool NormalProcess::isSuspended() { return d->suspended; } -bool Process::isAttached() +bool NormalProcess::isAttached() { return d->attached; } -bool Process::isIdentified() +bool NormalProcess::isIdentified() { return d->identified; } -bool Process::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions) +bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector & known_versions) { md5wrapper md5; // get hash of the running DF process @@ -153,7 +161,7 @@ bool Process::Private::validate(char * exe_file,uint32_t pid, char * memFile, ve // some error happened, continue with next process continue; } - // tell Process about the /proc/PID/mem file + // tell NormalProcess about the /proc/PID/mem file this->memFile = memFile; identified = true; return true; @@ -162,36 +170,49 @@ bool Process::Private::validate(char * exe_file,uint32_t pid, char * memFile, ve return false; } -Process::~Process() +NormalProcess::~NormalProcess() { if(d->attached) { detach(); } // destroy data model. this is assigned by processmanager - delete d->my_datamodel; + if(d->my_datamodel) + delete d->my_datamodel; + if(d->my_window) + delete d->my_window; delete d; } -DataModel *Process::getDataModel() +DataModel *NormalProcess::getDataModel() { return d->my_datamodel; } -memory_info * Process::getDescriptor() +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 Process::getThreadIDs(vector & threads ) +bool NormalProcess::getThreadIDs(vector & threads ) { return false; } //FIXME: cross-reference with ELF segment entries? -void Process::getMemRanges( vector & ranges ) +void NormalProcess::getMemRanges( vector & ranges ) { char buffer[1024]; char permissions[5]; // r/-, w/-, x/-, p/s, 0 @@ -217,7 +238,7 @@ void Process::getMemRanges( vector & ranges ) } } -bool Process::suspend() +bool NormalProcess::suspend() { int status; if(!d->attached) @@ -250,12 +271,12 @@ bool Process::suspend() return true; } -bool Process::forceresume() +bool NormalProcess::forceresume() { return resume(); } -bool Process::resume() +bool NormalProcess::resume() { if(!d->attached) return false; @@ -272,7 +293,7 @@ bool Process::resume() } -bool Process::attach() +bool NormalProcess::attach() { int status; if(g_pProcess != NULL) @@ -317,20 +338,19 @@ bool Process::attach() { d->attached = true; g_pProcess = this; - g_ProcessHandle = d->my_handle; - g_ProcessMemFile = proc_pid_mem; + d->memFileHandle = proc_pid_mem; return true; // we are attached } } -bool Process::detach() +bool NormalProcess::detach() { if(!d->attached) return false; if(!d->suspended) suspend(); int result = 0; // close /proc/PID/mem - result = close(g_ProcessMemFile); + result = close(d->memFileHandle); if(result == -1) { cerr << "couldn't close /proc/"<< d->my_handle <<"/mem" << endl; @@ -340,7 +360,6 @@ bool Process::detach() else { // detach - g_ProcessMemFile = -1; result = ptrace(PTRACE_DETACH, d->my_handle, NULL, NULL); if(result == -1) { @@ -352,8 +371,148 @@ bool Process::detach() { d->attached = false; g_pProcess = NULL; - g_ProcessHandle = 0; 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, const 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; +} + diff --git a/library/DFProcess-windows.cpp b/library/DFProcess-windows.cpp index bab4c7de1..f61d8065f 100644 --- a/library/DFProcess-windows.cpp +++ b/library/DFProcess-windows.cpp @@ -24,7 +24,7 @@ distribution. #include "DFCommonInternal.h" using namespace DFHack; -class Process::Private +class NormalProcess::Private { public: Private() @@ -33,6 +33,7 @@ class Process::Private my_descriptor = NULL; my_handle = NULL; my_main_thread = NULL; + my_window = NULL; my_pid = 0; attached = false; suspended = false; @@ -40,6 +41,7 @@ class Process::Private ~Private(){}; DataModel* my_datamodel; memory_info * my_descriptor; + DFWindow * my_window; ProcessHandle my_handle; HANDLE my_main_thread; uint32_t my_pid; @@ -49,7 +51,7 @@ class Process::Private bool identified; }; -Process::Process(uint32_t pid, vector & known_versions) +NormalProcess::NormalProcess(uint32_t pid, vector & known_versions) : d(new Private()) { HMODULE hmod = NULL; @@ -69,17 +71,20 @@ Process::Process(uint32_t pid, vector & known_versions) 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 - g_ProcessHandle = hProcess; - uint32_t pe_offset = MreadDWord(base+0x3C); - Mread(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header); - Mread(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)§ions ); + 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; @@ -123,11 +128,15 @@ Process::Process(uint32_t pid, vector & known_versions) { CloseHandle(hProcess); } + else + { + d->my_window = new DFWindow(this); + } } /* */ -Process::~Process() +NormalProcess::~NormalProcess() { if(d->attached) { @@ -144,36 +153,50 @@ Process::~Process() { CloseHandle(d->my_main_thread); } + if(d->my_window) + { + delete d->my_window; + } delete d; } -DataModel *Process::getDataModel() +DataModel *NormalProcess::getDataModel() { return d->my_datamodel; } -memory_info * Process::getDescriptor() +memory_info * NormalProcess::getDescriptor() { return d->my_descriptor; } -bool Process::isSuspended() +DFWindow * NormalProcess::getWindow() +{ + return d->my_window; +} + +int NormalProcess::getPID() +{ + return d->my_pid; +} + +bool NormalProcess::isSuspended() { return d->suspended; } -bool Process::isAttached() +bool NormalProcess::isAttached() { return d->attached; } -bool Process::isIdentified() +bool NormalProcess::isIdentified() { return d->identified; } -bool Process::suspend() +bool NormalProcess::suspend() { if(!d->attached) return false; @@ -186,7 +209,7 @@ bool Process::suspend() return true; } -bool Process::forceresume() +bool NormalProcess::forceresume() { if(!d->attached) return false; @@ -196,7 +219,7 @@ bool Process::forceresume() } -bool Process::resume() +bool NormalProcess::resume() { if(!d->attached) return false; @@ -209,7 +232,7 @@ bool Process::resume() return true; } -bool Process::attach() +bool NormalProcess::attach() { if(g_pProcess != NULL) { @@ -217,14 +240,13 @@ bool Process::attach() } d->attached = true; g_pProcess = this; - g_ProcessHandle = d->my_handle; suspend(); return true; } -bool Process::detach() +bool NormalProcess::detach() { if(!d->attached) { @@ -233,11 +255,10 @@ bool Process::detach() resume(); d->attached = false; g_pProcess = NULL; - g_ProcessHandle = 0; return true; } -bool Process::getThreadIDs(vector & threads ) +bool NormalProcess::getThreadIDs(vector & threads ) { HANDLE AllThreads = INVALID_HANDLE_VALUE; THREADENTRY32 te32; @@ -268,7 +289,7 @@ bool Process::getThreadIDs(vector & threads ) } //FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries -void Process::getMemRanges( vector & ranges ) +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 @@ -278,10 +299,88 @@ void Process::getMemRanges( vector & ranges ) t_memrange temp; uint32_t base = d->my_descriptor->getBase(); temp.start = base + 0x1000; // more fakery. - temp.end = base + MreadDWord(base+MreadDWord(base+0x3C)+0x50)-1; // yay for magic. + 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, const 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; +} + diff --git a/library/DFProcess.h b/library/DFProcess.h index 6be9d48ff..548399af0 100644 --- a/library/DFProcess.h +++ b/library/DFProcess.h @@ -32,6 +32,7 @@ namespace DFHack class memory_info; class DataModel; class Process; + class DFWindow; // structure describing a memory range struct DFHACK_EXPORT t_memrange @@ -58,13 +59,51 @@ namespace DFHack }; class DFHACK_EXPORT Process + { + public: + virtual bool attach() = 0; + virtual bool detach() = 0; + + virtual bool suspend() = 0; + virtual bool resume() = 0; + 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( const uint32_t address, const 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 const std::string readCString (uint32_t offset) = 0; + + virtual bool isSuspended() = 0; + virtual bool isAttached() = 0; + virtual bool isIdentified() = 0; + + virtual bool getThreadIDs(vector & threads ) = 0; + virtual void getMemRanges( vector & ranges ) = 0; + + virtual memory_info *getDescriptor() = 0; + virtual DataModel *getDataModel() = 0; + virtual DFWindow * getWindow() = 0; + virtual int getPID() = 0; + }; + + class DFHACK_EXPORT NormalProcess : virtual public Process { friend class ProcessEnumerator; class Private; private: Private * const d; - Process(uint32_t pid, vector & known_versions); - ~Process(); + NormalProcess(uint32_t pid, vector & known_versions); + ~NormalProcess(); public: // Set up stuff so we can read memory bool attach(); @@ -74,15 +113,75 @@ namespace DFHack 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( const uint32_t address, const 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); + + const std::string readCString (uint32_t offset); + + bool isSuspended(); + bool isAttached(); + bool isIdentified(); + + bool getThreadIDs(vector & threads ); + void getMemRanges( vector & ranges ); + memory_info *getDescriptor(); + DataModel *getDataModel(); + DFWindow * getWindow(); + int getPID(); + }; + + class DFHACK_EXPORT SHMProcess : virtual public Process + { + friend class ProcessEnumerator; + class Private; + private: + Private * const d; + SHMProcess(uint32_t pid, int shmid, char * shm, vector & known_versions); + ~SHMProcess(); + public: + // Set up stuff so we can read memory + bool attach(); + bool detach(); + + bool suspend(); + 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( const uint32_t address, const 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); + + const std::string readCString (uint32_t offset); + bool isSuspended(); bool isAttached(); bool isIdentified(); bool getThreadIDs(vector & threads ); void getMemRanges( vector & ranges ); - // is the process still there? memory_info *getDescriptor(); DataModel *getDataModel(); + DFWindow * getWindow(); + int getPID(); }; } #endif diff --git a/library/DFProcessEnumerator-linux.cpp b/library/DFProcessEnumerator-linux.cpp index 145c88ac7..921383e98 100644 --- a/library/DFProcessEnumerator-linux.cpp +++ b/library/DFProcessEnumerator-linux.cpp @@ -23,12 +23,62 @@ distribution. */ #include "DFCommonInternal.h" +#include +#include +#include +#include +#include "shmserver/dfconnect.h" + using namespace DFHack; /// HACK: global variables (only one process can be attached at the same time.) Process * DFHack::g_pProcess; ///< current process. non-NULL when picked -ProcessHandle DFHack::g_ProcessHandle; ///< cache of handle to current process. used for speed reasons -int DFHack::g_ProcessMemFile; ///< opened /proc/PID/mem, valid when attached + +bool waitWhile (char *shm, int shmid, uint32_t state) +{ + uint32_t cnt = 0; + struct shmid_ds descriptor; + while (((shm_cmd *)shm)->pingpong == state) + { + if(cnt == 10000) + { + shmctl(shmid, IPC_STAT, &descriptor); + if(descriptor.shm_nattch == 1)// DF crashed? + { + ((shm_cmd *)shm)->pingpong = DFPP_RUNNING; + fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n"); + return false; + } + else + { + cnt = 0; + } + } + cnt++; + } + if(((shm_cmd *)shm)->pingpong == DFPP_SV_ERROR) return false; + return true; +} + +bool DF_TestBridgeVersion(char *shm, int shmid, bool & ret) +{ + ((shm_cmd *)shm)->pingpong = DFPP_VERSION; + if(!waitWhile(shm, shmid, DFPP_VERSION)) + return false; + ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; + ret =( ((shm_retval *)shm)->value == PINGPONG_VERSION ); + return true; +} + +bool DF_GetPID(char *shm, int shmid, pid_t & ret) +{ + ((shm_cmd *)shm)->pingpong = DFPP_PID; + if(!waitWhile(shm, shmid, DFPP_PID)) + return false; + ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; + ret = ((shm_retval *)shm)->value; + return true; +} class DFHack::ProcessEnumerator::Private { @@ -42,19 +92,76 @@ bool ProcessEnumerator::findProcessess() { DIR *dir_p; struct dirent *dir_entry_p; - string dir_name; - string exe_link; - string cwd_link; - string cmdline_path; - string cmdline; - - // ALERT: buffer overrun potential int errorcount; int result; - - errorcount=0; - result=0; + + char *shm = 0; + int shmid; + Process *p = 0; + /* + * Locate the segment. + */ + if ((shmid = shmget(SHM_KEY, SHM_SIZE, 0666)) < 0) + { + perror("shmget"); + } + else + { + if ((shm = (char *) shmat(shmid, NULL, 0)) == (char *) -1) + { + perror("shmat"); + } + else + { + struct shmid_ds descriptor; + shmctl(shmid, IPC_STAT, &descriptor); + /* + * Now we attach the segment to our data space. + */ + + if(descriptor.shm_nattch != 2)// badness + { + fprintf(stderr,"dfhack: WTF\n"); + } + else + { + bool bridgeOK; + if(!DF_TestBridgeVersion(shm, shmid, bridgeOK)) + { + fprintf(stderr,"DF terminated during reading\n"); + } + else + { + if(!bridgeOK) + { + fprintf(stderr,"SHM bridge version mismatch\n"); + } + else + { + pid_t DFPID; + if(DF_GetPID(shm, shmid, DFPID)) + { + printf("shm: DF PID: %d\n",DFPID); + p = new SHMProcess(DFPID,shmid,shm,d->meminfo->meminfo); + } + } + } + } + if(p && p->isIdentified()) + { + cerr << "added process to vector" << endl; + d->processes.push_back(p); + } + else + { + // couldn't use the hooked process, make sure it's running fine + ((shm_cmd *)shm)->pingpong = DFPP_RUNNING; + delete p; + } + } + } + // Open /proc/ directory dir_p = opendir("/proc/"); // Reading /proc/ entries @@ -65,14 +172,14 @@ bool ProcessEnumerator::findProcessess() { continue; } - Process *p = new Process(atoi(dir_entry_p->d_name),d->meminfo->meminfo); - if(p->isIdentified()) + Process *p2 = new NormalProcess(atoi(dir_entry_p->d_name),d->meminfo->meminfo); + if(p2->isIdentified()) { - d->processes.push_back(p); + d->processes.push_back(p2); } else { - delete p; + delete p2; } } closedir(dir_p); diff --git a/library/DFProcessEnumerator-windows.cpp b/library/DFProcessEnumerator-windows.cpp index ace2cfada..d6156f196 100644 --- a/library/DFProcessEnumerator-windows.cpp +++ b/library/DFProcessEnumerator-windows.cpp @@ -27,8 +27,6 @@ using namespace DFHack; /// HACK: global variables (only one process can be attached at the same time.) Process * DFHack::g_pProcess; ///< current process. non-NULL when picked -ProcessHandle DFHack::g_ProcessHandle; ///< cache of handle to current process. used for speed reasons -int DFHack::g_ProcessMemFile; ///< opened /proc/PID/mem, valid when attached class DFHack::ProcessEnumerator::Private { @@ -73,6 +71,7 @@ bool ProcessEnumerator::findProcessess() EnableDebugPriv(); if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) ) { + cout << "EnumProcesses fail'd" << endl; return false; } @@ -82,7 +81,7 @@ bool ProcessEnumerator::findProcessess() // iterate through processes for ( int i = 0; i < (int)numProccesses; i++ ) { - Process *p = new Process(ProcArray[i],d->meminfo->meminfo); + Process *p = new NormalProcess(ProcArray[i],d->meminfo->meminfo); if(p->isIdentified()) { d->processes.push_back(p); diff --git a/library/DFTypes.h b/library/DFTypes.h index fd5ea064e..9fb8ef2ca 100644 --- a/library/DFTypes.h +++ b/library/DFTypes.h @@ -609,10 +609,7 @@ union t_occupancy // splatter. everyone loves splatter. unsigned int mud : 1; unsigned int vomit :1; - unsigned int debris1 :1; - unsigned int debris2 :1; - unsigned int debris3 :1; - unsigned int debris4 :1; + unsigned int broken_arrows_color :4; unsigned int blood_g : 1; unsigned int blood_g2 : 1; unsigned int blood_b : 1; @@ -631,7 +628,7 @@ union t_occupancy unsigned int slime2 : 1; unsigned int blood : 1; unsigned int blood2 : 1; - unsigned int debris5 : 1; + unsigned int broken_arrows_variant : 1; unsigned int snow : 1; } bits; struct { diff --git a/library/DFVector.h b/library/DFVector.h index 784801bfa..d706e6681 100644 --- a/library/DFVector.h +++ b/library/DFVector.h @@ -45,8 +45,9 @@ namespace DFHack start(_start),size(_size),item_size(_item_size) { data = (uint8_t *) new char[size * item_size]; - Mread(start,size*item_size, (uint8_t *)data); + g_pProcess->read(start,size*item_size, (uint8_t *)data); }; + /* DfVector(const DfVector & vec) { start = vec.start; @@ -54,7 +55,7 @@ namespace DFHack item_size = vec.item_size; data = (uint8_t *) new char[size * item_size]; memcpy(data,vec.data,item_size * size); - }; + };*/ ~DfVector() { if(data) diff --git a/library/DFKeys-linux.cpp b/library/DFWindow-linux.cpp similarity index 67% rename from library/DFKeys-linux.cpp rename to library/DFWindow-linux.cpp index f4932b485..cf066e9ca 100644 --- a/library/DFKeys-linux.cpp +++ b/library/DFWindow-linux.cpp @@ -26,8 +26,6 @@ distribution. #include //need for X11 functions #include -//FIXME: - using namespace DFHack; // should always reflect the enum in DFkeys.h @@ -85,9 +83,43 @@ const static KeySym ksTable[NUM_SPECIALS]= XK_KP_Decimal }; -// Source: http://www.experts-exchange.com/OS/Unix/X_Windows/Q_21341279.html -// find named window recursively -Window EnumerateWindows (Display *display, Window rootWindow, const char *searchString) +class DFWindow::Private +{ + public: + Private(Process * _p) + { + p=_p; + }; + ~Private(){}; + + // Source: http://www.experts-exchange.com/OS/Unix/X_Windows/Q_21341279.html + // find named window recursively + Window EnumerateWindows (Display *display, Window rootWindow, const char *searchString); + + // iterate through X screens, find the window + // FIXME: use _NET_WM_PID primarily and this current stuff only as a fallback + // see http://www.mail-archive.com/devel@xfree86.org/msg05818.html + bool getDFWindow (Display *dpy, Window& dfWindow, Window & rootWindow); + + // send synthetic key events to a window + // Source: http://homepage3.nifty.com/tsato/xvkbd/events.html + void send_xkeyevent(Display *display, Window dfW,Window rootW, int keycode, int modstate, int is_press, useconds_t delay); + + // our parent process + Process * p; +}; + +// ctor +DFWindow::DFWindow (Process * p) +{ + d = new Private(p); +} + +// dtor +DFWindow::~DFWindow () +{} + +Window DFWindow::Private::EnumerateWindows (Display *display, Window rootWindow, const char *searchString) { Window parent; Window *children; @@ -126,7 +158,7 @@ Window EnumerateWindows (Display *display, Window rootWindow, const char *search return retWindow; } -bool getDFWindow (Display *dpy, Window& dfWindow, Window & rootWindow) +bool DFWindow::Private::getDFWindow (Display *dpy, Window& dfWindow, Window & rootWindow) { // int numScreeens = ScreenCount(dpy); for (int i = 0;i < ScreenCount (dpy);i++) @@ -138,15 +170,11 @@ bool getDFWindow (Display *dpy, Window& dfWindow, Window & rootWindow) dfWindow = retWindow; return true; } - //I would ideally like to find the dfwindow using the PID, but X11 Windows only know their processes pid if the _NET_WM_PID attribute is set, which it is not for SDL 1.2. Supposedly SDL 1.3 will set this, but who knows when that will occur. } return false; } -// let's hope it works -// Source: http://homepage3.nifty.com/tsato/xvkbd/events.html -// TODO: is permission from original author needed here? -void send_xkeyevent(Display *display, Window dfW,Window rootW, int keycode, int modstate, int is_press, useconds_t delay) +void DFWindow::Private::send_xkeyevent(Display *display, Window dfW,Window rootW, int keycode, int modstate, int is_press, useconds_t delay) { XKeyEvent event; @@ -168,32 +196,31 @@ void send_xkeyevent(Display *display, Window dfW,Window rootW, int keycode, int usleep(delay); } -void API::TypeStr (const char *lpszString, int delay, bool useShift) +void DFWindow::TypeStr (const char *input, int delay, bool useShift) { - ForceResume(); Display *dpy = XOpenDisplay (NULL); // null opens the display in $DISPLAY Window dfWin; Window rootWin; - if (getDFWindow (dpy, dfWin, rootWin)) + if (d->getDFWindow (dpy, dfWin, rootWin)) { char cChar; int realDelay = delay * 1000; KeyCode xkeycode; - while ( (cChar = *lpszString++)) // loops through chars + while ( (cChar = *input++)) // loops through chars { // HACK: the timing here is a strange beast xkeycode = XKeysymToKeycode (dpy, cChar); - send_xkeyevent(dpy,dfWin,rootWin,XKeysymToKeycode(dpy, ksTable[DFHack::LEFT_SHIFT]),0,false, realDelay); + d->send_xkeyevent(dpy,dfWin,rootWin,XKeysymToKeycode(dpy, ksTable[DFHack::LEFT_SHIFT]),0,false, realDelay); if (useShift || (cChar >= 'A' && cChar <= 'Z')) { - send_xkeyevent(dpy,dfWin,rootWin,xkeycode,ShiftMask,true, realDelay); - send_xkeyevent(dpy,dfWin,rootWin,xkeycode,ShiftMask,false, realDelay); + d->send_xkeyevent(dpy,dfWin,rootWin,xkeycode,ShiftMask,true, realDelay); + d->send_xkeyevent(dpy,dfWin,rootWin,xkeycode,ShiftMask,false, realDelay); XSync (dpy, false); } else { - send_xkeyevent(dpy,dfWin,rootWin,xkeycode,0,true, realDelay); - send_xkeyevent(dpy,dfWin,rootWin,xkeycode,0,false, realDelay); + d->send_xkeyevent(dpy,dfWin,rootWin,xkeycode,0,true, realDelay); + d->send_xkeyevent(dpy,dfWin,rootWin,xkeycode,0,false, realDelay); XSync (dpy, false); } } @@ -204,9 +231,8 @@ void API::TypeStr (const char *lpszString, int delay, bool useShift) } } -void API::TypeSpecial (t_special command, int count, int delay) +void DFWindow::TypeSpecial (t_special command, int count, int delay) { - ForceResume(); if (command != WAIT) { KeySym mykeysym; @@ -215,16 +241,16 @@ void API::TypeSpecial (t_special command, int count, int delay) int realDelay = delay * 1000; Window dfWin; Window rootWin; - if (getDFWindow (dpy, dfWin, rootWin)) + if (d->getDFWindow (dpy, dfWin, rootWin)) { for (int i = 0;i < count; i++) { // HACK: the timing here is a strange beast mykeysym = ksTable[command]; xkeycode = XKeysymToKeycode (dpy, mykeysym); - send_xkeyevent(dpy,dfWin,rootWin,XKeysymToKeycode(dpy, ksTable[DFHack::LEFT_SHIFT]),0,false, realDelay); - send_xkeyevent(dpy,dfWin,rootWin,xkeycode,0,true, realDelay); - send_xkeyevent(dpy,dfWin,rootWin,xkeycode,0,false, realDelay); + d->send_xkeyevent(dpy,dfWin,rootWin,XKeysymToKeycode(dpy, ksTable[DFHack::LEFT_SHIFT]),0,false, realDelay); + d->send_xkeyevent(dpy,dfWin,rootWin,xkeycode,0,true, realDelay); + d->send_xkeyevent(dpy,dfWin,rootWin,xkeycode,0,false, realDelay); XSync (dpy, false); } } diff --git a/library/DFKeys-windows.cpp b/library/DFWindow-windows.cpp similarity index 88% rename from library/DFKeys-windows.cpp rename to library/DFWindow-windows.cpp index 2415c4813..95d09fa09 100644 --- a/library/DFKeys-windows.cpp +++ b/library/DFWindow-windows.cpp @@ -79,47 +79,62 @@ const static int ksTable[NUM_SPECIALS]= VK_NUMPAD9, VK_SEPARATOR }; - - - //Windows key handlers struct window { HWND windowHandle; uint32_t pid; }; + BOOL CALLBACK EnumWindowsProc (HWND hwnd, LPARAM lParam) { uint32_t pid; - + GetWindowThreadProcessId (hwnd, (LPDWORD) &pid); if (pid == ( (window *) lParam)->pid) { ( (window *) lParam)->windowHandle = hwnd; return FALSE; } - return TRUE; + return TRUE; } -// TODO: investigate use of PostMessage() for input sending to background windows -// TODO: also investigate possible problems with UIPI on Vista and 7 +class DFWindow::Private +{ + public: + Private(Process * _p) + { + p=_p; + }; + ~Private(){}; + // our parent process + Process * p; +}; -void API::TypeStr (const char *lpszString, int delay, bool useShift) +// ctor +DFWindow::DFWindow (Process * p) { - //Resume(); - ForceResume(); + d = new Private(p); +} + +// dtor +DFWindow::~DFWindow () +{} +// TODO: also investigate possible problems with UIPI on Vista and 7 +void DFWindow::TypeStr (const char *input, int delay, bool useShift) +{ //sendmessage needs a window handle HWND, so have to get that from the process HANDLE HWND currentWindow = GetForegroundWindow(); window myWindow; - myWindow.pid = GetProcessId (DFHack::g_ProcessHandle); + myWindow.pid = d->p->getPID(); EnumWindows (EnumWindowsProc, (LPARAM) &myWindow); char cChar; DWORD dfProccess = GetWindowThreadProcessId(myWindow.windowHandle,NULL); DWORD currentProccess = GetWindowThreadProcessId(currentWindow,NULL); AttachThreadInput(currentProccess,dfProccess,TRUE); //The two threads have to have attached input in order to change the keyboard state, which is needed to set the shift state - while ( (cChar = *lpszString++)) // loops through chars + while ( (cChar = *input++)) // loops through chars { short vk = VkKeyScan (cChar); // keycode of char if (useShift || (vk >> 8) &1) // char is capital, so need to hold down shift @@ -143,14 +158,14 @@ void API::TypeStr (const char *lpszString, int delay, bool useShift) AttachThreadInput(currentProccess,dfProccess,FALSE); //detach the threads Sleep (delay); } -void API::TypeSpecial (t_special command, int count, int delay) + +void DFWindow::TypeSpecial (t_special command, int count, int delay) { - ForceResume(); if (command != WAIT) { HWND currentWindow = GetForegroundWindow(); window myWindow; - myWindow.pid = GetProcessId (DFHack::g_ProcessHandle); + myWindow.pid = d->p->getPID(); EnumWindows (EnumWindowsProc, (LPARAM) &myWindow); for (int i = 0; i < count;i++) diff --git a/library/DFKeys.h b/library/DFWindow.h similarity index 83% rename from library/DFKeys.h rename to library/DFWindow.h index 05527a92a..1e0664b09 100644 --- a/library/DFKeys.h +++ b/library/DFWindow.h @@ -25,9 +25,13 @@ distribution. #ifndef KEYS_H_INCLUDED #define KEYS_H_INCLUDED +#include "Export.h" + namespace DFHack { +class Process; + enum t_special { ENTER, @@ -82,5 +86,18 @@ enum t_special KEYPAD_DECIMAL_POINT, NUM_SPECIALS }; + +class DFHACK_EXPORT DFWindow +{ + class Private; + private: + Private * d; + public: + DFWindow(Process * p); + ~DFWindow(); + void TypeStr (const char *input, int delay = 0, bool useShift = false); + void TypeSpecial (t_special command, int count = 1, int delay = 0); +}; + } #endif // KEYS_H_INCLUDED diff --git a/library/MemAccess-linux.h b/library/MemAccess-linux.h deleted file mode 100644 index 128bb1356..000000000 --- a/library/MemAccess-linux.h +++ /dev/null @@ -1,184 +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. -*/ - -/** - * DO NOT USE THIS FILE DIRECTLY! USE MemAccess.h INSTEAD! - */ -#include "integers.h" -#include -#include -#include -using namespace std; - -// danger: uses recursion! -inline -void Mread (const uint32_t &offset, const uint32_t &size, uint8_t *target) -{ - if(size == 0) return; - - ssize_t result; - result = pread(DFHack::g_ProcessMemFile, 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 - { - Mread(offset + result, size - result, target + result); - } - } -} - -inline -uint8_t MreadByte (const uint32_t &offset) -{ - uint8_t val; - Mread(offset, 1, &val); - return val; -} - -inline -void MreadByte (const uint32_t &offset, uint8_t &val ) -{ - Mread(offset, 1, &val); -} - -inline -uint16_t MreadWord (const uint32_t &offset) -{ - uint16_t val; - Mread(offset, 2, (uint8_t *) &val); - return val; -} - -inline -void MreadWord (const uint32_t &offset, uint16_t &val) -{ - Mread(offset, 2, (uint8_t *) &val); -} - -inline -uint32_t MreadDWord (const uint32_t &offset) -{ - uint32_t val; - Mread(offset, 4, (uint8_t *) &val); - return val; -} -inline -void MreadDWord (const uint32_t &offset, uint32_t &val) -{ - Mread(offset, 4, (uint8_t *) &val); -} - -/* - * WRITING - */ - -inline -void MwriteDWord (uint32_t offset, uint32_t data) -{ - ptrace(PTRACE_POKEDATA,DFHack::g_ProcessHandle, offset, data); -} - -// using these is expensive. -inline -void MwriteWord (uint32_t offset, uint16_t data) -{ - uint32_t orig = MreadDWord(offset); - orig &= 0xFFFF0000; - orig |= data; - /* - orig |= 0x0000FFFF; - orig &= data; - */ - ptrace(PTRACE_POKEDATA,DFHack::g_ProcessHandle, offset, orig); -} - -inline -void MwriteByte (uint32_t offset, uint8_t data) -{ - uint32_t orig = MreadDWord(offset); - orig &= 0xFFFFFF00; - orig |= data; - /* - orig |= 0x000000FF; - orig &= data; - */ - ptrace(PTRACE_POKEDATA,DFHack::g_ProcessHandle, offset, orig); -} - -// blah. I hate the kernel devs for crippling /proc/PID/mem. THIS IS RIDICULOUS -inline -bool Mwrite (uint32_t offset, uint32_t size, uint8_t *source) -{ - uint32_t indexptr = 0; - while (size > 0) - { - // default: we push 4 bytes - if(size >= 4) - { - MwriteDWord(offset, *(uint32_t *) (source + indexptr)); - offset +=4; - indexptr +=4; - size -=4; - } - // last is either three or 2 bytes - else if(size >= 2) - { - MwriteWord(offset, *(uint16_t *) (source + indexptr)); - offset +=2; - indexptr +=2; - size -=2; - } - // finishing move - else if(size == 1) - { - MwriteByte(offset, *(uint8_t *) (source + indexptr)); - return true; - } - } - return false; // dead code -} - -inline -const std::string MreadCString (uint32_t offset) -{ - std::string temp; - char temp_c[256]; - int counter = 0; - char r; - do - { - r = MreadByte(offset+counter); - temp_c[counter] = r; - counter++; - } while (r && counter < 255); - temp_c[counter] = 0; - temp = temp_c; - return temp; -} diff --git a/library/MemAccess-windows.h b/library/MemAccess-windows.h deleted file mode 100644 index 77b01d28b..000000000 --- a/library/MemAccess-windows.h +++ /dev/null @@ -1,150 +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. -*/ - -/** - * DO NOT USE THIS FILE DIRECTLY! USE MemAccess.h INSTEAD! - */ - -// let's hope this commented crap is never needed - /* - char buffer[256]; - DWORD oldProtect = 0; - DWORD numRead = 0; - VirtualProtectEx( hProc, (LPVOID)0x77810F34, 256, PAGE_EXECUTE_READWRITE, &oldProtect ); - ReadProcessMemory( hProc, (LPVOID)0x77810F34, buffer, 256, &numRead ); - VirtualProtectEx( hProc, (LPVOID)0x77810F34, 256, oldProtect, NULL ); //restore the original protection when you're done - */ - -// it would be possible to replace all this by macros - -inline -uint8_t MreadByte (const uint32_t &offset) -{ - uint8_t result; - ReadProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &result, sizeof(uint8_t), NULL); - return result; -} - - -inline -void MreadByte (const uint32_t &offset,uint8_t &result) -{ - ReadProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &result, sizeof(uint8_t), NULL); -} - - -inline -uint16_t MreadWord (const uint32_t &offset) -{ - uint16_t result; - ReadProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &result, sizeof(uint16_t), NULL); - return result; -} - - -inline -void MreadWord (const uint32_t &offset, uint16_t &result) -{ - ReadProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &result, sizeof(uint16_t), NULL); -} - - -inline -uint32_t MreadDWord (const uint32_t &offset) -{ - uint32_t result; - ReadProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &result, sizeof(uint32_t), NULL); - return result; -} - - -inline -void MreadDWord (const uint32_t &offset, uint32_t &result) -{ - ReadProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &result, sizeof(uint32_t), NULL); -} - - -inline -uint64_t MreadQuad (const uint32_t &offset) -{ - uint64_t result; - ReadProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &result, sizeof(uint64_t), NULL); - return result; -} - - -inline -void MreadQuad (const uint32_t &offset, uint64_t &result) -{ - ReadProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &result, sizeof(uint64_t), NULL); -} - - -inline -void Mread (const uint32_t &offset, uint32_t size, uint8_t *target) -{ - ReadProcessMemory(DFHack::g_ProcessHandle, (int*) offset, target, size, NULL); -} - -// WRITING -inline -void MwriteDWord (const uint32_t offset, uint32_t data) -{ - WriteProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &data, sizeof(uint32_t), NULL); -} - -// using these is expensive. -inline -void MwriteWord (uint32_t offset, uint16_t data) -{ - WriteProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &data, sizeof(uint16_t), NULL); -} - -inline -void MwriteByte (uint32_t offset, uint8_t data) -{ - WriteProcessMemory(DFHack::g_ProcessHandle, (int*) offset, &data, sizeof(uint8_t), NULL); -} - -inline -void Mwrite (uint32_t offset, uint32_t size, uint8_t *source) -{ - WriteProcessMemory(DFHack::g_ProcessHandle, (int*) offset, source, size, NULL); -} - - - -///FIXME: reduce use of temporary objects -inline -const string MreadCString (const uint32_t &offset) -{ - string temp; - char temp_c[256]; - DWORD read; - ReadProcessMemory(DFHack::g_ProcessHandle, (int *) offset, temp_c, 255, &read); - temp_c[read+1] = 0; - temp = temp_c; - return temp; -} diff --git a/library/shmserver/dfconnect.c b/library/shmserver/dfconnect.c new file mode 100644 index 000000000..cfb93e0c7 --- /dev/null +++ b/library/shmserver/dfconnect.c @@ -0,0 +1,246 @@ +/* +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 + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dfconnect.h" + +// ptr to the real functions +static void (*_SDL_GL_SwapBuffers)(void) = 0; +static void (*_SDL_Quit)(void) = 0; +static int (*_SDL_Init)(uint32_t flags) = 0; +// various crud +int counter = 0; +int errorstate = 0; +char *shm; +int shmid; + +static unsigned char * BigFat; + +void SHM_Init ( void ) +{ + // name for the segment + key_t key = 123466; + BigFat = (unsigned char *) malloc(SHM_SIZE); + + // create the segment + if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0600)) < 0) + { + perror("shmget"); + errorstate = 1; + return; + } + + // attach the segment + if ((shm = (char *) shmat(shmid, 0, 0)) == (char *) -1) + { + perror("shmat"); + errorstate = 1; + return; + } + ((shm_cmd *)shm)->pingpong = DFPP_RUNNING; // make sure we don't stall or do crazy stuff +} + +void SHM_Destroy ( void ) +{ + // blah, I don't care +} + +void SHM_Act (void) +{ + struct shmid_ds descriptor; + uint32_t numwaits = 0; + if(errorstate) + { + return; + } + uint32_t length; + uint32_t address; + check_again: // goto target!!! + if(numwaits == 10000) + { + shmctl(shmid, IPC_STAT, &descriptor); + if(descriptor.shm_nattch == 1)// other guy crashed + { + ((shm_cmd *)shm)->pingpong = DFPP_RUNNING; + fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n"); + return; + } + else + { + numwaits = 0; + } + } + 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_SUSPENDED: + case DFPP_RET_PID: + case DFPP_SV_ERROR: + numwaits++; + goto check_again; + case DFPP_SUSPEND: + ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; + goto check_again; + + case DFPP_BOUNCE: + length = ((shm_bounce *)shm)->length; + memcpy(BigFat,shm + sizeof(shm_bounce),length); + memcpy(shm + sizeof(shm_ret_data),BigFat,length); + ((shm_cmd *)shm)->pingpong = DFPP_RET_DATA; + goto check_again; + + case DFPP_PID: + ((shm_retval *)shm)->value = getpid(); + ((shm_retval *)shm)->pingpong = DFPP_RET_PID; + goto check_again; + + case DFPP_VERSION: + ((shm_retval *)shm)->value = PINGPONG_VERSION; + ((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 + sizeof(shm_ret_data), (void *) address,length); + ((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); + ((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); + ((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); + ((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 + sizeof(shm_write),length); + ((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; + ((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; + ((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; + ((shm_cmd *)shm)->pingpong = DFPP_SUSPENDED; + goto check_again; + + case DFPP_CL_ERROR: + case DFPP_RUNNING: + fprintf(stderr, "no. of waits: %d\n", numwaits); + break; + + default: + ((shm_retval *)shm)->value = DFEE_INVALID_COMMAND; + ((shm_retval *)shm)->pingpong = DFPP_SV_ERROR; + break; + } +} + +// hook - called every tick +extern "C" void SDL_GL_SwapBuffers(void) +{ + if(_SDL_GL_SwapBuffers) + { + if(((shm_cmd *)shm)->pingpong != DFPP_RUNNING) + { + SHM_Act(); + } + counter ++; + _SDL_GL_SwapBuffers(); + } +} + +// hook - called at program exit +extern "C" void SDL_Quit(void) +{ + if(_SDL_Quit) + { + _SDL_Quit(); + } + fprintf(stderr,"dfhack: DF called SwapBuffers %d times, lol\n", counter); +} + +// hook - called at program start, initialize some stuffs we'll use later +extern "C" int SDL_Init(uint32_t flags) +{ + // find real functions + _SDL_GL_SwapBuffers = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_GL_SwapBuffers"); + _SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init"); + _SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit"); + + // check if we got them + if(_SDL_GL_SwapBuffers && _SDL_Init && _SDL_Quit) + { + fprintf(stderr,"dfhack: hooking successful\n"); + } + else + { + // bail, this would be a disaster otherwise + fprintf(stderr,"dfhack: something went horribly wrong\n"); + exit(1); + } + SHM_Init(); + + return _SDL_Init(flags); +} + diff --git a/library/shmserver/dfconnect.h b/library/shmserver/dfconnect.h new file mode 100644 index 000000000..a75b3ea09 --- /dev/null +++ b/library/shmserver/dfconnect.h @@ -0,0 +1,102 @@ +#ifndef DFCONNECT_H +#define DFCONNECT_H + +#define PINGPONG_VERSION 1 +#define SHM_KEY 123466 +#define SHM_SIZE 1024*1024 + +/* + * 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_PINGPONG +{ + DFPP_RUNNING = 0, // no command, normal server execution + + DFPP_VERSION, // protocol version query + DFPP_RET_VERSION, // return the protocol version + + DFPP_PID, // query for the process ID + DFPP_RET_PID, // return process ID + + // version 1 stuff below + DFPP_READ, // cl -> sv, read some data + DFPP_RET_DATA, // sv -> cl, returned data + + DFPP_READ_DWORD, // cl -> sv, read a dword + DFPP_RET_DWORD, // sv -> cl, returned dword + + DFPP_READ_WORD, // cl -> sv, read a word + DFPP_RET_WORD, // sv -> cl, returned word + + DFPP_READ_BYTE, // cl -> sv, read a byte + DFPP_RET_BYTE, // sv -> cl, returned byte + + DFPP_SV_ERROR, // there was a server error + DFPP_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 + + 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 + + // similar to DFPP_WRITE, writes to a local buffer, writes the same back to shm, sends DFPP_RET_DATA + // used for benchmarking + DFPP_BOUNCE, + + NUM_DFPP +}; + + +enum DF_ERROR +{ + DFEE_INVALID_COMMAND, + DFEE_BUFFER_OVERFLOW +}; + +typedef struct +{ + uint32_t pingpong; // = 0 +} shm_cmd; + +typedef struct +{ + uint32_t pingpong; + uint32_t address; + uint32_t length; +} shm_read; + +typedef shm_read shm_write; +typedef shm_read shm_bounce; + +typedef struct +{ + uint32_t pingpong; +} shm_ret_data; + +typedef struct +{ + uint32_t pingpong; + uint32_t address; +} shm_read_small; + +typedef struct +{ + uint32_t pingpong; + uint32_t address; + uint32_t value; +} shm_write_small; + +typedef struct +{ + uint32_t pingpong; + uint32_t value; +} shm_retval; + +#endif \ No newline at end of file diff --git a/library/shmserver/readme.txt b/library/shmserver/readme.txt new file mode 100644 index 000000000..16a1c6c7d --- /dev/null +++ b/library/shmserver/readme.txt @@ -0,0 +1,11 @@ +Using the shm server: +copy files to DF/libs folder +g++ -fPIC -c dfconnect.c -o dfconnect.o +g++ -shared -o dfconnect.so dfconnect.o -ldl + +edit DF/df script and add this line just before DF is called: +export LD_PRELOAD="./libs/dfconnect.so" # Hack DF! + +save and run the script! + +Has to be compiled for 32bit arch, otherwise the library isn't recognised. Client can be any arch. diff --git a/tools/customCreatureNameProf.cpp b/tools/customCreatureNameProf.cpp index 6062d3d9e..e774ed9b7 100644 --- a/tools/customCreatureNameProf.cpp +++ b/tools/customCreatureNameProf.cpp @@ -137,6 +137,7 @@ bool getDwarfSelection(DFHack::API & DF, DFHack::t_creature & toChange,string & } bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, bool isName) { + DFHack::DFWindow * w = DF.getWindow(); DF.Suspend(); DFHack::t_creature testCre; DF.ReadCreature(creatureToCheck,testCre); @@ -145,7 +146,8 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b { while(testCre.nick_name != changeValue && tryCount <50) { - DF.TypeSpecial(DFHack::WAIT,1,100); + DF.Resume(); + w->TypeSpecial(DFHack::WAIT,1,100); DF.Suspend(); DF.ReadCreature(creatureToCheck,testCre); tryCount++; @@ -155,7 +157,8 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b { while(testCre.custom_profession != changeValue && tryCount < 50) { - DF.TypeSpecial(DFHack::WAIT,1,100); + DF.Resume(); + w->TypeSpecial(DFHack::WAIT,1,100); DF.Suspend(); DF.ReadCreature(creatureToCheck,testCre); tryCount++; @@ -169,12 +172,15 @@ bool waitTillChanged(DFHack::API &DF, int creatureToCheck, string changeValue, b } bool waitTillScreenState(DFHack::API &DF, string screenState) { + DFHack::DFWindow * w = DF.getWindow(); DFHack::t_viewscreen current; DF.Suspend(); DF.ReadViewScreen(current); int tryCount = 0; - while(buildingtypes[current.type] != screenState && tryCount < 50){ - DF.TypeSpecial(DFHack::WAIT,1,100); + while(buildingtypes[current.type] != screenState && tryCount < 50) + { + DF.Resume(); + w->TypeSpecial(DFHack::WAIT,1,100); DF.Suspend(); DF.ReadViewScreen(current); tryCount++; @@ -188,13 +194,15 @@ bool waitTillScreenState(DFHack::API &DF, string screenState) bool waitTillCursorState(DFHack::API &DF, bool On) { + DFHack::DFWindow * w = DF.getWindow(); int32_t x,y,z; int tryCount = 0; DF.Suspend(); bool cursorResult = DF.getCursorCoords(x,y,z); while(tryCount < 50 && On && !cursorResult || !On && cursorResult) { - DF.TypeSpecial(DFHack::WAIT,1,100); + DF.Resume(); + w->TypeSpecial(DFHack::WAIT,1,100); tryCount++; DF.Suspend(); cursorResult = DF.getCursorCoords(x,y,z); @@ -235,6 +243,7 @@ int main (void) int eraseAmount; int toChangeNum; bool isName; + DFHack::DFWindow * w = DF.getWindow(); while(getDwarfSelection(DF,toChange,changeString,commandString,eraseAmount,toChangeNum,isName)) { bool completed = false; @@ -243,7 +252,8 @@ int main (void) DF.getCursorCoords(x,y,z); if(x == -30000)// cursor not displayed { - DF.TypeStr("v"); + DF.Resume(); + w->TypeStr("v"); } if(waitTillCursorState(DF,true)) { @@ -252,7 +262,8 @@ int main (void) vector underCursor; while(!DF.getCurrentCursorCreatures(underCursor)) { - DF.TypeSpecial(DFHack::WAIT,1,100); + DF.Resume(); + w->TypeSpecial(DFHack::WAIT,1,100); DF.Suspend(); DF.setCursorCoords(toChange.x, toChange.y,toChange.z); } @@ -264,7 +275,8 @@ int main (void) { for(int i = 0;iTypeStr("v",100); if(underCursor[i] == toChange.origin) { break; @@ -272,23 +284,28 @@ int main (void) } } DF.Resume(); - DF.TypeStr(commandString.c_str()); + w->TypeStr(commandString.c_str()); if(waitTillScreenState(DF,"viewscreen_customize_unit")) { - DF.TypeSpecial(DFHack::BACK_SPACE,eraseAmount); + DF.Resume(); + w->TypeSpecial(DFHack::BACK_SPACE,eraseAmount); if(waitTillChanged(DF,toChangeNum,"",isName)) { - DF.TypeStr(changeString.c_str()); + DF.Resume(); + w->TypeStr(changeString.c_str()); if(waitTillChanged(DF,toChangeNum,changeString,isName)) { - DF.TypeSpecial(DFHack::ENTER); - DF.TypeSpecial(DFHack::SPACE); // should take you to unit screen if everything worked + DF.Resume(); + w->TypeSpecial(DFHack::ENTER); + w->TypeSpecial(DFHack::SPACE); // should take you to unit screen if everything worked if(waitTillScreenState(DF,"viewscreen_unit")) { - DF.TypeSpecial(DFHack::SPACE); + DF.Resume(); + w->TypeSpecial(DFHack::SPACE); if(waitTillScreenState(DF,"viewscreen_dwarfmode")) { - DF.TypeSpecial(DFHack::SPACE); + DF.Resume(); + w->TypeSpecial(DFHack::SPACE); if(waitTillCursorState(DF,false)) { completed = true;