Petr Mrázek 2011-07-31 23:29:34 +02:00
commit a36d8b0619
16 changed files with 709 additions and 26 deletions

@ -25,6 +25,7 @@ distribution.
#include "Internal.h"
#include <dirent.h>
#include <errno.h>
#include <sys/mman.h>
#include <string>
#include <vector>
@ -176,4 +177,16 @@ string Process::getPath()
int Process::getPID()
{
return getpid();
}
bool Process::setPermisions(const t_memrange & range,const t_memrange &trgrange)
{
int result;
int protect=0;
if(trgrange.read)protect|=PROT_READ;
if(trgrange.write)protect|=PROT_WRITE;
if(trgrange.execute)protect|=PROT_EXECUTE;
result=mprotect((void *)range.start, range.end-range.start,protect);
return result==0;
}

@ -356,3 +356,18 @@ string Process::getPath()
string out(String);
return(out.substr(0,out.find_last_of("\\")));
}
bool Process::setPermisions(const t_memrange & range,const t_memrange &trgrange)
{
DWORD newprotect=0;
if(trgrange.read && !trgrange.write && !trgrange.execute)newprotect=PAGE_READONLY;
if(trgrange.read && trgrange.write && !trgrange.execute)newprotect=PAGE_READWRITE;
if(!trgrange.read && !trgrange.write && trgrange.execute)newprotect=PAGE_EXECUTE;
if(trgrange.read && !trgrange.write && trgrange.execute)newprotect=PAGE_EXECUTE_READ;
if(trgrange.read && trgrange.write && trgrange.execute)newprotect=PAGE_EXECUTE_READWRITE;
DWORD oldprotect=0;
bool result;
result=VirtualProtect((LPVOID)range.start,range.end-range.start,newprotect,&oldprotect);
return result;
}

@ -269,6 +269,9 @@ namespace DFHack
int getPID();
/// get the DF Process FilePath
std::string getPath();
/// modify permisions of memory range
bool setPermisions(const t_memrange & range,const t_memrange &trgrange);
private:
VersionInfo * my_descriptor;
PlatformSpecific *d;

@ -2,6 +2,7 @@ find_package(Lua51 QUIET)
if(LUA51_FOUND)
include_directories(${LUA_INCLUDE_DIR} include)
include_directories("${dfhack_SOURCE_DIR}/library/depends/tthread")
FILE(GLOB DFUSION_CPPS src/*.c*)
set(
DFUSION_CPPS_ALL
@ -10,6 +11,7 @@ if(LUA51_FOUND)
)
DFHACK_PLUGIN(dfusion ${DFUSION_CPPS_ALL})
target_link_libraries(dfusion ${LUA_LIBRARIES})
install(DIRECTORY luafiles/ DESTINATION ${DFHACK_DATA_DESTINATION}/dfusion)
else(LUA51_FOUND)
MESSAGE(STATUS "Required libraries (lua51) not found - dfusion plugin can't be built.")
endif(LUA51_FOUND)

@ -3,25 +3,29 @@
#include <dfhack/Export.h>
#include <dfhack/PluginManager.h>
#include <dfhack/Process.h>
#include "dfhack/extra/stopwatch.h"
#include <vector>
#include <string>
#include "tinythread.h"
#include "luamain.h"
#include "lua_Console.h"
#include "lua_Process.h"
#include "functioncall.h"
using std::vector;
using std::string;
using namespace DFHack;
static SDL::Mutex* mymutex=0;
static tthread::mutex* mymutex=0;
uint64_t timeLast=0;
DFhackCExport command_result dfusion (Core * c, vector <string> & parameters);
DFhackCExport command_result lua_run (Core * c, vector <string> & parameters);
typedef
int (__thiscall *dfprint)(const char*, char, char,void *) ;
DFhackCExport const char * plugin_name ( void )
{
return "dfusion";
@ -32,12 +36,12 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
commands.clear();
//maybe remake it to run automaticaly
lua::RegisterConsole(lua::glua::Get(),&c->con);
lua::RegisterProcess(lua::glua::Get(),c->p);
commands.push_back(PluginCommand("dfusion","Init dfusion system.",dfusion));
commands.push_back(PluginCommand("lua", "Run interactive interpreter.\
\n Options: <filename> = run <filename> instead",lua_run));
mymutex=SDL_CreateMutex();
mymutex=new tthread::mutex;
return CR_OK;
}
@ -45,20 +49,18 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
{
// shutdown stuff
delete mymutex;
return CR_OK;
}
DFhackCExport command_result plugin_onupdate ( Core * c )
{
/*if(timering == true) //TODO maybe reuse this to make it run less often.
{
uint64_t time2 = GetTimeMs64();
uint64_t delta = time2-timeLast;
timeLast = time2;
c->con.print("Time delta = %d ms\n", delta);
}
return CR_OK;*/
SDL_mutexP(mymutex);
{
uint64_t time2 = GetTimeMs64();
uint64_t delta = time2-timeLast;
if(delta<100)
return CR_OK;
timeLast = time2;
mymutex->lock();
lua::state s=lua::glua::Get();
s.getglobal("OnTick");
if(s.is<lua::function>())
@ -73,15 +75,38 @@ DFhackCExport command_result plugin_onupdate ( Core * c )
}
}
s.settop(0);
SDL_mutexV(mymutex);
mymutex->unlock();
return CR_OK;
}
void InterpreterLoop(Core* c)
{
Console &con=c->con;
lua::state s=lua::glua::Get();
string curline;
con.print("Type quit to exit interactive mode\n");
con.lineedit(">>",curline);
while (curline!="quit") {
con.history_add(curline);
try
{
s.loadstring(curline);
s.pcall();
}
catch(lua::exception &e)
{
con.printerr("Error:%s\n",e.what());
s.settop(0);
}
con.lineedit(">>",curline);
}
s.settop(0);
}
DFhackCExport command_result lua_run (Core * c, vector <string> & parameters)
{
Console &con=c->con;
SDL_mutexP(mymutex);
mymutex->lock();
lua::state s=lua::glua::Get();
if(parameters.size()>0)
{
@ -96,18 +121,17 @@ DFhackCExport command_result lua_run (Core * c, vector <string> & parameters)
}
else
{
//TODO interpreter...
InterpreterLoop(c);
}
s.settop(0);// clean up
SDL_mutexV(mymutex);
mymutex->unlock();
return CR_OK;
}
DFhackCExport command_result dfusion (Core * c, vector <string> & parameters)
{
Console &con=c->con;
con.print("%x\n",c->p->getBase());
SDL_mutexP(mymutex);
mymutex->lock();
lua::state s=lua::glua::Get();
try{
@ -119,6 +143,6 @@ DFhackCExport command_result dfusion (Core * c, vector <string> & parameters)
con.printerr("Error:%s\n",e.what());
}
s.settop(0);// clean up
SDL_mutexV(mymutex);
mymutex->unlock();
return CR_OK;
}

@ -0,0 +1,13 @@
#ifndef LUA_OFFSETS_H
#define LUA_OFFSETS_H
#include "luamain.h"
namespace lua
{
void RegisterEngine(lua::state &st);
}
#endif

@ -0,0 +1,13 @@
#ifndef LUA_PROCESS_H
#define LUA_PROCESS_H
#include <dfhack/Core.h>
#include <dfhack/Process.h>
#include "luamain.h"
namespace lua
{
void RegisterProcess(lua::state &st,DFHack::Process *p);
}
#endif

@ -0,0 +1,61 @@
offsets=offsets or {}
offsets._toff={}
offsets.get = function (name)
return offsets._toff[name]
end
offsets.getEx = function (name)
return offsets._toff[name]+Process.getBase()
end
offsets.load = function ()
local f=io.open("dfusion/offsets.txt")
local line=f:read()
while line~=nil do
--print(line)
local sppliter=string.find(line,":")
offsets._toff[string.sub(line,1,sppliter-2)]=tonumber(string.sub(line,sppliter+2))
line=f:read()
end
end
offsets.load()
function unlockDF()
local ranges=Process.getMemRanges()
for k,v in pairs(ranges) do
--for k2,v2 in pairs(v) do
-- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2)))
--end
--local num
--num=0
--if(v["read"])then num=num+1 end
--if(v["write"])then num=num+10 end
--if(v["execute"]) then num=num+100 end
--print(string.format("%d %x->%x %s %d",k,v["start"],v["end"],v.name,num))
local pos=string.find(v.name,".text")
if pos~=nil then
v["write"]=true
Process.setPermisions(v,v)
end
end
end
function lockDF()
local ranges=Process.getMemRanges()
for k,v in pairs(ranges) do
--for k2,v2 in pairs(v) do
-- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2)))
--end
--local num
--num=0
--if(v["read"])then num=num+1 end
--if(v["write"])then num=num+10 end
--if(v["execute"]) then num=num+100 end
--print(string.format("%d %x->%x %s %d",k,v["start"],v["end"],v.name,num))
local pos=string.find(v.name,".text")
if pos~=nil then
v["write"]=false
Process.setPermisions(v,v)
end
end
end
-- engine bindings
engine=engine or {}
engine.peekd=Process.readDWord
engine.poked=Process.writeDWord

@ -0,0 +1,33 @@
function err(msg) --make local maybe...
print(msg)
print(debug.traceback())
end
function dofile(filename) --safer dofile, with traceback (very usefull)
f,perr=loadfile(filename)
if f~=nil then
return xpcall(f,err)
else
print(perr)
end
end
dofile("dfusion/common.lua")
print("Unlocking Df .text section...")
unlockDF()
print("Done unlock")
lockDF()
dofile("dfusion/simple_embark/plugin.lua")
print("hello world")
Console.print("Hello world in console!\n")
--name=Console.lineedit("Enter name:")
--Console.print("Your name is:"..name)
function OnTick() -- floods the console
r=Console.get_rows()
c=Console.get_columns()
Console.clear()
Console.gotoxy(math.random(1,r),math.random(1,2))
Console.color(math.random(0,15))
Console.print("*")
end
OnTick=nil

@ -0,0 +1,15 @@
AdvCreatureVec : 0x12c44ac
CreatureGloss : 0x1308040
CreaturePtr : 0xaf2430
CreatureVec : 0x12c44ac
CurrentRace : 0x10f0c28
Items : 0x12c4550
Legends : 0x12c451c
Materials : 0x1307f50
PlayerLegend : 0x145bfec
SiteData : 0x1307778
StartDwarfs : 0x518332
WordVec : 0x1308254
WorldData : 0x1306148
Xpointer : 0x7347f0
vtableLegends : 0x6e7594

@ -0,0 +1,15 @@
function simple_embark(num)
stoff=offsets.getEx('StartDwarfs')
print("Starting dwarves found:"..engine.peekd(stoff))
engine.poked(stoff,num)
end
if not(FILE) then
print("Type in new ammount:")
repeat
ans=tonumber(io.read())
if ans==nil or not(ans<=15000 and ans>0) then
print("incorrect choice")
end
until ans~=nil and (ans<=15000 and ans>0)
simple_embark(ans)
end

@ -0,0 +1,19 @@
Dfusion command runs file <df dir>\dfusion\init.lua
Other than std lua commands supported:
* Console.
print(string)
printerr(string)
clear()
gotoxy(x,y)
color(int) //TODO add id's, use numbers upto 16 for now
reset_color()
cursor(true/false)
msleep(int)
get_columns()
get_rows()
lineedit(string) //text input through console
history_add(string) // adds string to console history
Functions searched:
OnTick()
If defined is called each DFHack tick.

@ -73,7 +73,10 @@ int FunctionCaller::CallF(size_t count,callconv conv,void* f,const vector<int> &
int FunctionCaller::CallFunction(size_t func_ptr,callconv conv,const vector<int> &arguments)
{
//nasty nasty code...
#ifdef LINUX_BUILD //quick fix
if(conv==THIS_CALL)
conv=STD_CALL
#endif
void* f= reinterpret_cast<void*>(func_ptr+base_);
size_t count=arguments.size();
if(count==0)

@ -126,7 +126,12 @@ const luaL_Reg lua_console_func[]=
};
void lua::RegisterConsole(lua::state &st, DFHack::Console *c)
{
st.newtable();
st.getglobal("Console");
if(st.is<lua::nil>())
{
st.pop();
st.newtable();
}
st.pushlightuserdata(c);
st.setfield("__pointer");

@ -0,0 +1,156 @@
#include "lua_Offsets.h"
//TODO make a seperate module with peeks/pokes and page permisions (linux/windows spec)
unsigned char peekb(size_t offset)
{
return *((unsigned char*)(offset));
}
unsigned short peekw(size_t offset)
{
return *((unsigned short*)(offset));
}
unsigned peekd(size_t offset)
{
return *((unsigned*)(offset));
}
void peekarb(size_t offset, void *mem,size_t size)
{
memcpy(mem,(void*)offset,size);
}
void peekstr(size_t offset, char* buf, size_t maxsize)
{
strcpy_s(buf,maxsize,(char*)offset);
}
void pokeb(size_t offset,unsigned char val)
{
*((unsigned char*)(offset))=val;
}
void pokew(size_t offset,unsigned short val)
{
*((unsigned short*)(offset))=val;
}
void poked(size_t offset,unsigned val)
{
*((unsigned*)(offset))=val;
}
void pokearb(size_t offset, void *mem,size_t size)
{
memcpy((void*)offset,mem,size);
}
void pokestr(size_t offset, char* buf, size_t maxsize)
{
strcpy_s((char*)offset,maxsize,buf);
}
template <typename T>
T peek(size_t offset) //prob lower performance
{
T tmp;
peekarb(offset,&tmp,sizeof(T));
return tmp;
}
//// lua stuff here
static int lua_peekb(lua_State *L)
{
lua::state st(L);
st.push(peekb(st.as<size_t>(1)));
return 1;
}
static int lua_peekd(lua_State *L)
{
lua::state st(L);
st.push(peekd(st.as<size_t>(1)));
return 1;
}
static int lua_peekw(lua_State *L)
{
lua::state st(L);
st.push(peekw(st.as<size_t>(1)));
return 1;
}
static int lua_peekarb(lua_State *L)
{
lua::state st(L);
size_t size=st.as<size_t>(2);
void *p=st.newuserdata(size);
peekarb(st.as<size_t>(1),p,size);
return 1;
}
static int lua_peekstr(lua_State *L)
{
lua::state st(L);
char *buf;
buf=new char[256];
peekstr(st.as<size_t>(1),buf,256);
std::string tstr(buf);
st.push(tstr);
delete [] buf;
return 1;
}
/*static int lua_peekarb(lua_State *L)
{
lua::state st(L);
st.push(peekarb(st.as<DWORD>(1)));
return 1;
}*/
static int lua_pokeb(lua_State *L)
{
lua::state st(L);
pokeb(st.as<size_t>(1),st.as<size_t>(2));
return 0;
}
static int lua_poked(lua_State *L)
{
lua::state st(L);
poked(st.as<size_t>(1),st.as<size_t>(2));
return 0;
}
static int lua_pokew(lua_State *L)
{
lua::state st(L);
pokew(st.as<size_t>(1),st.as<size_t>(2));
return 0;
}
static int lua_pokearb(lua_State *L)
{
lua::state st(L);
void *p=(void *)lua_touserdata(L, 2);//st.as<lua::userdata>(2);
size_t size=st.as<size_t>(3);
pokearb(st.as<size_t>(1),p,size);
return 0;
}
static int lua_pokestr(lua_State *L)
{
lua::state st(L);
std::string trg=st.as<std::string>(2);
pokestr(st.as<size_t>(1),(char*)trg.c_str(),trg.size());
return 0;
}
const luaL_Reg lua_engine_func[]=
{
{"peekb",lua_peekb},
{"peekw",lua_peekw},
{"peekd",lua_peekd},
{"peekarb",lua_peekarb},
{"peekstr",lua_peekstr},
{"pokeb",lua_pokeb},
{"pokew",lua_pokew},
{"poked",lua_poked},
{"pokearb",lua_pokearb},
{"pokestr",lua_pokestr},
{NULL,NULL}
};
void lua::RegisterEngine(lua::state &st)
{
st.getglobal("engine");
if(st.is<lua::nil>())
{
st.pop();
st.newtable();
}
lua::RegFunctionsLocal(st,lua_engine_func);
st.setglobal("engine");
}

@ -0,0 +1,293 @@
#include "lua_Process.h"
static DFHack::Process* GetProcessPtr(lua::state &st)
{
int t=st.gettop();
st.getglobal("Process");
st.getfield("__pointer");
DFHack::Process* c=static_cast<DFHack::Process*>(lua_touserdata(st,-1));
st.settop(t);
return c;
}
static int lua_Process_readDWord(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
uint32_t ret=c->readDWord(st.as<uint32_t>(1));
st.push(ret);
return 1;
}
static int lua_Process_writeDWord(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->writeDWord(st.as<uint32_t>(1),st.as<uint32_t>(2));
return 0;
}
static int lua_Process_readFloat(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
float ret=c->readFloat(st.as<uint32_t>(1));
st.push(ret);
return 1;
}
static int lua_Process_readWord(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
uint16_t ret=c->readWord(st.as<uint32_t>(1));
st.push(ret);
return 1;
}
static int lua_Process_writeWord(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->writeWord(st.as<uint32_t>(1),st.as<uint16_t>(2));
return 0;
}
static int lua_Process_readByte(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
uint8_t ret=c->readByte(st.as<uint32_t>(1));
st.push(ret);
return 1;
}
static int lua_Process_writeByte(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->writeByte(st.as<uint32_t>(1),st.as<uint8_t>(2));
return 0;
}
static int lua_Process_read(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
size_t len=st.as<uint32_t>(2);
uint8_t* buf;
if(!st.is<lua::nil>(3))
buf=(uint8_t*)lua_touserdata(st,3);
else
buf=new uint8_t[len];
c->read(st.as<uint32_t>(1),len,buf);
st.pushlightuserdata(buf);
return 1;
}
static int lua_Process_write(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c-> write(st.as<uint32_t>(1),st.as<uint32_t>(2),static_cast<uint8_t*>(lua_touserdata(st,3)));
return 0;
}
static int lua_Process_readSTLString (lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
std::string r=c->readSTLString(st.as<uint32_t>(1));
st.push(r);
return 1;
}
static int lua_Process_writeSTLString(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->writeSTLString(st.as<uint32_t>(1),st.as<std::string>(2));
return 0;
}
static int lua_Process_copySTLString(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->copySTLString(st.as<uint32_t>(1),st.as<uint32_t>(2));
return 0;
}
static int lua_Process_doReadClassName(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
std::string r=c->doReadClassName((void*)st.as<size_t>(1));
st.push(r);
return 1;
}
static int lua_Process_readClassName(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
std::string r=c->readClassName((void*)st.as<size_t>(1));
st.push(r);
return 1;
}
static int lua_Process_readCString (lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
std::string r=c->readCString(st.as<uint32_t>(1));
st.push(r);
return 1;
}
static int lua_Process_isSuspended(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
st.push(c->isSuspended());
return 1;
}
static int lua_Process_isIdentified(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
st.push(c->isIdentified());
return 1;
}
static int lua_Process_getThreadIDs(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
std::vector<uint32_t> threads;
c->getThreadIDs(threads);
st.newtable();
for(size_t i=0;i<threads.size();i++)
{
st.push(i);
st.push(threads[i]);
st.settable();
}
return 1;
}
static int lua_Process_getMemRanges(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
std::vector<DFHack::t_memrange> ranges;
c->getMemRanges(ranges);
st.newtable();
for(size_t i=0;i<ranges.size();i++)
{
st.push(i);
st.newtable();
st.push(ranges[i].start); // WARNING!! lua has only 32bit numbers, possible loss of data!!
st.setfield("start");
st.push(ranges[i].end);
st.setfield("end");
st.push(std::string(ranges[i].name));
st.setfield("name");
st.push(ranges[i].read);
st.setfield("read");
st.push(ranges[i].write);
st.setfield("write");
st.push(ranges[i].execute);
st.setfield("execute");
st.push(ranges[i].shared);
st.setfield("shared");
st.push(ranges[i].valid);
st.setfield("valid");
st.settable();
}
return 1;
}
static int lua_Process_getBase(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
uint32_t base=c->getBase();
st.push(base);
return 1;
}
/*static int lua_Process_getPID(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
int ret=c->getPID();
st.push(ret);
return 1;
}*/
static int lua_Process_getPath(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
std::string ret=c->getPath();
st.push(ret);
return 1;
}
static int lua_Process_setPermisions(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
DFHack::t_memrange range,trange;
st.getfield("start",1);
range.start=st.as<uint64_t>();
st.pop();
st.getfield("end",1);
range.end=st.as<uint64_t>();
st.pop();
st.getfield("read",2);
trange.read=st.as<bool>();
st.pop();
st.getfield("write",2);
trange.write=st.as<bool>();
st.pop();
st.getfield("execute",2);
trange.execute=st.as<bool>();
st.pop();
c->setPermisions(range,trange);
return 0;
}
#define PROC_FUNC(name) {#name,lua_Process_ ## name}
const luaL_Reg lua_process_func[]=
{
PROC_FUNC(readDWord),
PROC_FUNC(writeDWord),
PROC_FUNC(readFloat),
PROC_FUNC(readWord),
PROC_FUNC(writeWord),
PROC_FUNC(readByte),
PROC_FUNC(writeByte),
PROC_FUNC(read),
PROC_FUNC(write),
PROC_FUNC(readSTLString),
PROC_FUNC(writeSTLString),
PROC_FUNC(copySTLString),
PROC_FUNC(doReadClassName),
PROC_FUNC(readClassName),
PROC_FUNC(readCString ),
PROC_FUNC(isSuspended),
PROC_FUNC(isIdentified),
PROC_FUNC(getThreadIDs),
PROC_FUNC(getMemRanges),
PROC_FUNC(getBase),
//PROC_FUNC(getPID), //not implemented
PROC_FUNC(getPath),
PROC_FUNC(setPermisions),
{NULL,NULL}
};
#undef PROC_FUNC
void lua::RegisterProcess(lua::state &st,DFHack::Process *p)
{
st.getglobal("Process");
if(st.is<lua::nil>())
{
st.pop();
st.newtable();
}
st.pushlightuserdata(p);
st.setfield("__pointer");
lua::RegFunctionsLocal(st, lua_process_func);
st.setglobal("Process");
}