Merge branch 'dfapi' of github.com:peterix/dfhack into dfapi

develop
Petr Mrázek 2011-07-18 16:28:06 +02:00
commit 00cf7bc39e
6 changed files with 291 additions and 5 deletions

@ -1028,6 +1028,7 @@
<Address name="current_weather" description="5x5 array of bytes for surrounding biomes. For each: 0=clear, 1=raining, 2=snowing." />
<Address name="game_mode" description="Current game mode" />
<Address name="control_mode" description="Current control mode" />
<Address name="save_folder" descript="Name of save folder of current game"/>
<!--<Address name="control_mode_copy" description="Copy of the control mode in DF memory" />-->
</Group>
<Group name="Legends">
@ -3058,6 +3059,7 @@
<Address name="control_mode" value="0x8c3de90" />
<Address name="game_mode" value="0x8c3deA0" />
<Address name="current_weather" value="0x93F05E4" />
<Address name="save_folder" value="0x958a378" />
</Group>
<Group name="Items">
<Address name="items_vector" value="0x940b1fc" />

@ -107,6 +107,7 @@ namespace DFHack
void SetCurrentWeather(uint8_t weather);
bool ReadGameMode(t_gamemodes& rd);
bool WriteGameMode(const t_gamemodes & wr); // this is very dangerous
std::string ReadWorldFolder();
private:
struct Private;
Private *d;

@ -67,6 +67,10 @@ struct World::Private
uint32_t gamemode_offset;
uint32_t controlmode_offset;
uint32_t controlmodecopy_offset;
bool StartedFolder;
uint32_t folder_name_offset;
Process * owner;
};
@ -106,6 +110,14 @@ World::World()
d->StartedMode = true;
}
catch(Error::All &){};
try
{
d->folder_name_offset = OG_World->getAddress( "save_folder" );
d->StartedFolder = true;
}
catch(Error::All &){};
d->Inited = true;
}
@ -220,3 +232,12 @@ void World::SetCurrentWeather(uint8_t weather)
d->owner->write(d->weather_offset,sizeof(buf),buf);
}
}
string World::ReadWorldFolder()
{
if (d->Inited && d->StartedFolder)
{
return string( * ( (string*) d->folder_name_offset ) );
}
return string("");
}

@ -4,28 +4,53 @@
# changed to properly set LD_PRELOAD so as to run DFHACK.
#
# You can run DF under gdb by passing -g or --gdb as the first argument.
#
# If the file ".dfhackrc" exists in the DF directory or your home directory
# it will be sourced by this script, to let you set environmental variables.
# If it exists in both places it will first source the one in your home
# directory, then the on in the game directory.
#
# Shell variables .dfhackrc can set to affect this script:
# DF_GDB_OPTS: Options to pass to gdb, if it's being run
# DF_VALGRIND_OPTS: Options to pass to valgrind, if it's being run
# DF_HELGRIND_OPTS: Options to pass to helgrind, if it's being run
# DF_RESET_OPTS: Options to pass the reset command at the end of
# this script
# DF_POST_CMD: Shell command to be run at very end of script
DF_DIR=$(dirname "$0")
cd "${DF_DIR}"
export SDL_DISABLE_LOCK_KEYS=1 # Work around for bug in Debian/Ubuntu SDL patch.
#export SDL_VIDEO_CENTERED=1 # Centre the screen. Messes up resizing.
# User config files
RC=".dfhackrc"
if [ -r "$HOME/$RC" ]; then
. $HOME/$RC
fi
if [ -r "./$RC" ]; then
. "./$RC"
fi
# Now run
case "$1" in
-g | --gdb)
shift
echo "set environment LD_PRELOAD=./libdfhack.so" > gdbcmd.tmp
gdb -x gdbcmd.tmp ./libs/Dwarf_Fortress $*
gdb $DF_GDB_OPTS -x gdbcmd.tmp ./libs/Dwarf_Fortress $*
rm gdbcmd.tmp
ret=$?
;;
-h | --helgrind)
shift
LD_PRELOAD=./libdfhack.so valgrind --tool=helgrind --log-file=helgrind.log ./libs/Dwarf_Fortress $*
LD_PRELOAD=./libdfhack.so valgrind $DF_HELGRIND_OPTS --tool=helgrind --log-file=helgrind.log ./libs/Dwarf_Fortress $*
ret=$?
;;
-v | --valgrind)
shift
LD_PRELOAD=./libdfhack.so valgrind --log-file=valgrind.log ./libs/Dwarf_Fortress $*
LD_PRELOAD=./libdfhack.so valgrind $DF_VALGRIND_OPTS --log-file=valgrind.log ./libs/Dwarf_Fortress $*
ret=$?
;;
*)
@ -35,6 +60,10 @@ case "$1" in
esac
# Reset terminal to sane state in case of a crash
reset
reset $DF_RESET_OPTS
if [ -n "$DF_POST_CMD" ]; then
eval $DF_POST_CMD
fi
exit $ret

@ -108,10 +108,15 @@ if(BUILD_KITTENS)
endif()
IF(UNIX)
OPTION(BUILD_KILL_GAME "Build the kill gmae plugin." OFF)
OPTION(BUILD_KILL_GAME "Build the kill game plugin." OFF)
if(BUILD_KILL_GAME)
DFHACK_PLUGIN(die die.cpp)
endif()
OPTION(BUILD_VECTORS "Build the vectors search plugin." OFF)
if(BUILD_VECTORS)
DFHACK_PLUGIN(vectors vectors.cpp)
endif()
endif()
DFHACK_PLUGIN(reveal reveal.cpp)

@ -0,0 +1,228 @@
// Lists embeded STL vectors and pointers to STL vectors found in the given
// memory range.
//
// Linux only, enabled with BUILD_VECTORS cmake option.
#include <dfhack/Core.h>
#include <dfhack/Console.h>
#include <dfhack/Export.h>
#include <dfhack/PluginManager.h>
#include <dfhack/Process.h>
#include <vector>
#include <string>
#include <stdio.h>
using std::vector;
using std::string;
using namespace DFHack;
struct t_vecTriplet
{
uint32_t start;
uint32_t end;
uint32_t alloc_end;
};
DFhackCExport command_result df_vectors (Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void )
{
return "vectors";
}
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("vectors",
"Scan memory for vectors.\
\n 1st param: start of scan\
\n 2nd param: number of bytes to scan",
df_vectors));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}
static bool hexOrDec(string &str, uint32_t &value)
{
if (str.find("0x") == 0 && sscanf(str.c_str(), "%x", &value) == 1)
return true;
else if (sscanf(str.c_str(), "%u", &value) == 1)
return true;
return false;
}
static void usage(Console &con)
{
con << "Usage: vectors <start of scan address> <# bytes to scan>"
<< std::endl;
}
static bool mightBeVec(vector<t_memrange> &heap_ranges,
t_vecTriplet *vec)
{
if ((vec->start > vec->end) || (vec->end > vec->alloc_end))
return false;
if ((vec->end - vec->start) % 4 != 0)
return false;
for (size_t i = 0; i < heap_ranges.size(); i++)
{
t_memrange &range = heap_ranges[i];
if (range.isInRange(vec->start) && range.isInRange(vec->alloc_end))
return true;
}
return false;
}
static bool inAnyRange(vector<t_memrange> &ranges, uint32_t ptr)
{
for (size_t i = 0; i < ranges.size(); i++)
{
if (ranges[i].isInRange(ptr))
return true;
}
return false;
}
static void printVec(Console &con, const char* msg, t_vecTriplet *vec,
uint32_t start, uint32_t pos)
{
uint32_t length = vec->end - vec->start;
uint32_t offset = pos - start;
con.print("%8s offset %06p, addr %010p, start %010p, length %u\n",
msg, offset, pos, vec->start, length);
}
DFhackCExport command_result df_vectors (Core * c, vector <string> & parameters)
{
Console & con = c->con;
if (parameters.size() != 2)
{
usage(con);
return CR_FAILURE;
}
uint32_t start = 0, bytes = 0;
if (!hexOrDec(parameters[0], start))
{
usage(con);
return CR_FAILURE;
}
if (!hexOrDec(parameters[1], bytes))
{
usage(con);
return CR_FAILURE;
}
uint32_t end = start + bytes;
// 4 byte alignment.
while (start % 4 != 0)
start++;
c->Suspend();
std::vector<t_memrange> ranges;
std::vector<t_memrange> heap_ranges;
c->p->getMemRanges(ranges);
bool startInRange = false;
for (size_t i = 0; i < ranges.size(); i++)
{
t_memrange &range = ranges[i];
// Some kernels don't report [heap], and the heap can consist of
// more segments than just the one labeled with [heap], so include
// all segments which *might* be part of the heap.
if (range.read && range.write && !range.shared)
{
if (strlen(range.name) == 0 || strcmp(range.name, "[heap]") == 0)
heap_ranges.push_back(range);
}
if (!range.isInRange(start))
continue;
// Found the range containing the start
if (!range.isInRange(end))
{
con.print("Scanning %u bytes would read past end of memory "
"range.\n", bytes);
uint32_t diff = end - range.end;
con.print("Cutting bytes down by %u.\n", diff);
end = (uint32_t) range.end;
}
startInRange = true;
} // for (size_t i = 0; i < ranges.size(); i++)
if (!startInRange)
{
con << "Address not in any memory range." << std::endl;
c->Resume();
return CR_FAILURE;
}
if (heap_ranges.empty())
{
con << "No possible heap segments." << std::endl;
c->Resume();
return CR_FAILURE;
}
uint32_t pos = start;
const uint32_t ptr_size = sizeof(void*);
for (uint32_t pos = start; pos < end; pos += ptr_size)
{
// Is it an embeded vector?
if (pos <= ( end - sizeof(t_vecTriplet) ))
{
t_vecTriplet* vec = (t_vecTriplet*) pos;
if (mightBeVec(heap_ranges, vec))
{
printVec(con, "VEC:", vec, start, pos);
// Skip over rest of vector.
pos += sizeof(t_vecTriplet) - ptr_size;
continue;
}
}
// Is it a vector pointer?
if (pos <= (end - ptr_size))
{
uint32_t ptr = * ( (uint32_t*) pos);
if (inAnyRange(heap_ranges, ptr))
{
t_vecTriplet* vec = (t_vecTriplet*) ptr;
if (mightBeVec(heap_ranges, vec))
{
printVec(con, "VEC PTR:", vec, start, pos);
continue;
}
}
}
} // for (uint32_t pos = start; pos < end; pos += ptr_size)
c->Resume();
return CR_OK;
}