merge in shm branch

develop
Petr Mrázek 2009-12-22 21:19:39 +00:00
parent 4582e0548b
commit efce0ab21b
24 changed files with 1541 additions and 823 deletions

@ -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)

@ -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 <stdlib.h>

@ -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;

@ -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<t_skill> &);
void getTraitsByAddress(const uint32_t &address, vector<t_trait> &);
void getLaborsByAddress(const uint32_t &address, vector<t_labor> &);
*/
};
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 <t_vein> & 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<t_matgloss> & 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<t_matgloss> & 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 <uint16_t> >& 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 <uint16_t> >& 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 <uint16_t> >& 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<t_skill> 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<t_skill> tempSkillVec;
d->getSkillsByAddress(temp+d->creature_last_name_offset,tempSkillVec);
return(tempSkillVec);
}
vector<t_trait> 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<t_trait> tempTraitVec;
d->getTraitsByAddress(temp+d->creature_traits_offset,tempTraitVec);
return(tempTraitVec);
}
void API::Private::getSkillsByAddress(const uint32_t &address, vector<t_skill> & skills)
{
DfVector* skillVector = new DfVector(dm->readVector(address,4));
for(uint32_t i = 0; i<skillVector->getSize();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<t_trait> & 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<t_labor> & 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<string> > & 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);
}

@ -31,7 +31,7 @@ distribution.
#include <map>
#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

@ -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

@ -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 <t_type>& 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++)

@ -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 <errno.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <time.h>
#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 <memory_info> & 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 <memory_info> & 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 <memory_info> & known_versions)
{
md5wrapper md5;
// get hash of the running DF process
string hash = md5.getHashFromFile(exe_file);
vector<memory_info>::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<uint32_t> & threads )
{
return false;
}
//FIXME: cross-reference with ELF segment entries?
void SHMProcess::getMemRanges( vector<t_memrange> & 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;
}

@ -22,9 +22,10 @@ must not be misrepresented as being the original software.
distribution.
*/
#include "DFCommonInternal.h"
#include <errno.h>
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 <memory_info> & known_versions);
};
Process::Process(uint32_t pid, vector <memory_info> & known_versions)
NormalProcess::NormalProcess(uint32_t pid, vector <memory_info> & known_versions)
: d(new Private())
{
char dir_name [256];
@ -81,6 +86,7 @@ Process::Process(uint32_t pid, vector <memory_info> & 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 <memory_info> & 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 <memory_info> & known_versions)
bool NormalProcess::Private::validate(char * exe_file,uint32_t pid, char * memFile, vector <memory_info> & 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<uint32_t> & threads )
bool NormalProcess::getThreadIDs(vector<uint32_t> & threads )
{
return false;
}
//FIXME: cross-reference with ELF segment entries?
void Process::getMemRanges( vector<t_memrange> & ranges )
void NormalProcess::getMemRanges( vector<t_memrange> & ranges )
{
char buffer[1024];
char permissions[5]; // r/-, w/-, x/-, p/s, 0
@ -217,7 +238,7 @@ void Process::getMemRanges( vector<t_memrange> & 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;
}

@ -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 <memory_info> & known_versions)
NormalProcess::NormalProcess(uint32_t pid, vector <memory_info> & known_versions)
: d(new Private())
{
HMODULE hmod = NULL;
@ -69,17 +71,20 @@ Process::Process(uint32_t pid, vector <memory_info> & 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 *)&sections );
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 *)&sections );
d->my_handle = 0;
// see if there's a version entry that matches this process
vector<memory_info>::iterator it;
@ -123,11 +128,15 @@ Process::Process(uint32_t pid, vector <memory_info> & 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<uint32_t> & threads )
bool NormalProcess::getThreadIDs(vector<uint32_t> & threads )
{
HANDLE AllThreads = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
@ -268,7 +289,7 @@ bool Process::getThreadIDs(vector<uint32_t> & threads )
}
//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries
void Process::getMemRanges( vector<t_memrange> & ranges )
void NormalProcess::getMemRanges( vector<t_memrange> & 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<t_memrange> & 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;
}

@ -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<uint32_t> & threads ) = 0;
virtual void getMemRanges( vector<t_memrange> & 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 <memory_info> & known_versions);
~Process();
NormalProcess(uint32_t pid, vector <memory_info> & 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<uint32_t> & threads );
void getMemRanges( vector<t_memrange> & 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 <memory_info> & 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<uint32_t> & threads );
void getMemRanges( vector<t_memrange> & ranges );
// is the process still there?
memory_info *getDescriptor();
DataModel *getDataModel();
DFWindow * getWindow();
int getPID();
};
}
#endif

@ -23,12 +23,62 @@ distribution.
*/
#include "DFCommonInternal.h"
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <time.h>
#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);

@ -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);

@ -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 {

@ -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)

@ -26,8 +26,6 @@ distribution.
#include <X11/Xlib.h> //need for X11 functions
#include <X11/keysym.h>
//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);
}
}

@ -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++)

@ -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

@ -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 <iostream>
#include <string>
#include <errno.h>
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;
}

@ -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;
}

@ -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 <stdio.h>
#include <dlfcn.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
#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);
}

@ -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

@ -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.

@ -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<uint32_t> 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;i<underCursor.size()-1;i++)
{
DF.TypeStr("v",100);
DF.Resume();
w->TypeStr("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;