develop
Quietust 2014-02-27 15:49:18 -06:00
commit dd268d43d9
9 changed files with 50 additions and 235 deletions

@ -9,6 +9,7 @@ DFHack future
Misc improvements:
- digfort: improved csv parsing, add start() comment handling
- exterminate: allow specifying a caste (exterminate gob:male)
DFHack v0.34.11-r4

@ -2125,6 +2125,9 @@ With the special argument ``him``, targets only the selected creature.
With the special argument ``undead``, targets all undeads on the map,
regardless of their race.
When specifying a race, a caste can be specified to further restrict the
targeting. To do that, append and colon and the caste name after the race.
Any non-dead non-caged unit of the specified race gets its ``blood_count``
set to 0, which means immediate death at the next game tick. For creatures
such as vampires, it also sets animal.vanish_countdown to 2.
@ -2140,6 +2143,7 @@ but ignore caged/chained creatures.
Ex::
exterminate gob
exterminate gob:male
To kill a single creature, select the unit with the 'v' cursor and::

@ -246,28 +246,6 @@ static int getdir (string dir, vector<string> &files)
return 0;
}
bool Process::getThreadIDs(vector<uint32_t> & threads )
{
stringstream ss;
vector<string> subdirs;
if(getdir("/proc/self/task/",subdirs) != 0)
{
//FIXME: needs exceptions. this is a fatal error
cerr << "unable to enumerate threads. This is BAD!" << endl;
return false;
}
threads.clear();
for(size_t i = 0; i < subdirs.size();i++)
{
uint32_t tid;
if(sscanf(subdirs[i].c_str(),"%d", &tid))
{
threads.push_back(tid);
}
}
return true;
}
uint32_t Process::getTickCount()
{
struct timeval tp;

@ -181,28 +181,6 @@ static int getdir (string dir, vector<string> &files)
return 0;
}
bool Process::getThreadIDs(vector<uint32_t> & threads )
{
stringstream ss;
vector<string> subdirs;
if(getdir("/proc/self/task/",subdirs) != 0)
{
//FIXME: needs exceptions. this is a fatal error
cerr << "unable to enumerate threads. This is BAD!" << endl;
return false;
}
threads.clear();
for(size_t i = 0; i < subdirs.size();i++)
{
uint32_t tid;
if(sscanf(subdirs[i].c_str(),"%d", &tid))
{
threads.push_back(tid);
}
}
return true;
}
uint32_t Process::getTickCount()
{
struct timeval tp;

@ -24,63 +24,8 @@ distribution.
#include "Internal.h"
#define _WIN32_WINNT 0x0501 // needed for INPUT struct
#define WINVER 0x0501 // OpenThread(), PSAPI, Toolhelp32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <psapi.h>
#include <tlhelp32.h>
typedef LONG NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
// FIXME: it is uncertain how these map to 64bit
typedef struct _DEBUG_BUFFER
{
HANDLE SectionHandle;
PVOID SectionBase;
PVOID RemoteSectionBase;
ULONG SectionBaseDelta;
HANDLE EventPairHandle;
ULONG Unknown[2];
HANDLE RemoteThreadHandle;
ULONG InfoClassMask;
ULONG SizeOfInfo;
ULONG AllocatedSize;
ULONG SectionSize;
PVOID ModuleInformation;
PVOID BackTraceInformation;
PVOID HeapInformation;
PVOID LockInformation;
PVOID Reserved[8];
} DEBUG_BUFFER, *PDEBUG_BUFFER;
typedef struct _DEBUG_HEAP_INFORMATION
{
ULONG Base; // 0×00
ULONG Flags; // 0×04
USHORT Granularity; // 0×08
USHORT Unknown; // 0x0A
ULONG Allocated; // 0x0C
ULONG Committed; // 0×10
ULONG TagCount; // 0×14
ULONG BlockCount; // 0×18
ULONG Reserved[7]; // 0x1C
PVOID Tags; // 0×38
PVOID Blocks; // 0x3C
} DEBUG_HEAP_INFORMATION, *PDEBUG_HEAP_INFORMATION;
// RtlQueryProcessDebugInformation.DebugInfoClassMask constants
#define PDI_MODULES 0x01
#define PDI_BACKTRACE 0x02
#define PDI_HEAPS 0x04
#define PDI_HEAP_TAGS 0x08
#define PDI_HEAP_BLOCKS 0x10
#define PDI_LOCKS 0x20
extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlQueryProcessDebugInformation( IN ULONG ProcessId, IN ULONG DebugInfoClassMask, IN OUT PDEBUG_BUFFER DebugBuffer);
extern "C" __declspec(dllimport) PDEBUG_BUFFER __stdcall RtlCreateQueryDebugBuffer( IN ULONG Size, IN BOOLEAN EventPair);
extern "C" __declspec(dllimport) NTSTATUS __stdcall RtlDestroyQueryDebugBuffer( IN PDEBUG_BUFFER DebugBuffer);
#include <cstring>
#include <cstdio>
@ -106,8 +51,6 @@ namespace DFHack
sections = 0;
};
HANDLE my_handle;
vector <HANDLE> threads;
vector <HANDLE> stoppedthreads;
uint32_t my_pid;
IMAGE_NT_HEADERS pe_header;
IMAGE_SECTION_HEADER * sections;
@ -138,7 +81,7 @@ Process::Process(VersionInfoFactory * factory)
// read from this process
try
{
uint32_t pe_offset = Process::readDWord(d->base+0x3C);
uint32_t pe_offset = readDWord(d->base+0x3C);
read(d->base + pe_offset, sizeof(d->pe_header), (uint8_t *)&(d->pe_header));
const size_t sectionsSize = sizeof(IMAGE_SECTION_HEADER) * d->pe_header.FileHeader.NumberOfSections;
d->sections = (IMAGE_SECTION_HEADER *) malloc(sectionsSize);
@ -151,24 +94,10 @@ Process::Process(VersionInfoFactory * factory)
VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(d->pe_header.FileHeader.TimeDateStamp);
if(vinfo)
{
vector<uint32_t> threads_ids;
if(!getThreadIDs( threads_ids ))
{
// thread enumeration failed.
return;
}
identified = true;
// give the process a data model and memory layout fixed for the base of first module
my_descriptor = new VersionInfo(*vinfo);
my_descriptor->rebaseTo(getBase());
for(size_t i = 0; i < threads_ids.size();i++)
{
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD) threads_ids[i]);
if(hThread)
d->threads.push_back(hThread);
else
cerr << "Unable to open thread :" << hex << (DWORD) threads_ids[i] << endl;
}
}
}
@ -176,41 +105,10 @@ Process::~Process()
{
// destroy our rebased copy of the memory descriptor
delete my_descriptor;
for(size_t i = 0; i < d->threads.size(); i++)
CloseHandle(d->threads[i]);
if(d->sections != NULL)
free(d->sections);
}
bool Process::getThreadIDs(vector<uint32_t> & threads )
{
HANDLE AllThreads = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( AllThreads == INVALID_HANDLE_VALUE )
{
return false;
}
te32.dwSize = sizeof(THREADENTRY32 );
if( !Thread32First( AllThreads, &te32 ) )
{
CloseHandle( AllThreads );
return false;
}
do
{
if( te32.th32OwnerProcessID == d->my_pid )
{
threads.push_back(te32.th32ThreadID);
}
} while( Thread32Next(AllThreads, &te32 ) );
CloseHandle( AllThreads );
return true;
}
/*
typedef struct _MEMORY_BASIC_INFORMATION
{

@ -43,29 +43,6 @@ namespace DFHack
class VersionInfoFactory;
class PlatformSpecific;
/**
* A type for storing an extended OS Process ID (combines PID and the time the process was started for unique identification)
* \ingroup grp_context
*/
struct ProcessID
{
ProcessID(const uint64_t _time, const uint64_t _pid): time(_time), pid(_pid){};
bool operator==(const ProcessID &other) const
{
return (other.time == time && other.pid == pid);
}
bool operator< (const ProcessID& ms) const
{
if (time < ms.time)
return true;
else if(time == ms.time)
return pid < ms.pid ;
return false;
}
uint64_t time;
uint64_t pid;
};
/**
* Structure describing a section of virtual memory inside a process
* \ingroup grp_context
@ -265,8 +242,6 @@ namespace DFHack
{
return identified;
};
/// find the thread IDs of the process
bool getThreadIDs(std::vector<uint32_t> & threads );
/// get virtual memory ranges of the process (what is mapped where)
void getMemRanges(std::vector<t_memrange> & ranges );

@ -144,21 +144,6 @@ static int lua_Process_isIdentified(lua_State *S)
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);
@ -261,7 +246,6 @@ const luaL_Reg lua_process_func[]=
PROC_FUNC(readCString ),
PROC_FUNC(isSuspended),
PROC_FUNC(isIdentified),
PROC_FUNC(getThreadIDs),
PROC_FUNC(getMemRanges),
PROC_FUNC(getBase),
//PROC_FUNC(getPID), //not implemented
@ -282,4 +266,4 @@ void lua::RegisterProcess(lua::state &st)
lua::RegFunctionsLocal(st, lua_process_func);
st.setglobal("Process");
}
}

@ -1,58 +1,39 @@
class AutoUnsuspend
attr_accessor :running
def initialize
end
def process
return false unless @running
joblist = df.world.job_list.next
count = 0
def process
count = 0
df.world.job_list.each { |job|
if job.job_type == :ConstructBuilding and job.flags.suspend and df.map_tile_at(job).designation.flow_size <= 1
job.flags.suspend = false
count += 1
end
}
if count > 0
puts "Unsuspended #{count} job(s)."
df.process_jobs = true
end
end
while joblist
job = joblist.item
joblist = joblist.next
if job.job_type == :ConstructBuilding
if (job.flags.suspend)
item = job.items[0].item
job.flags.suspend = false
count += 1
end
end
end
def start
@running = true
@onupdate = df.onupdate_register('autounsuspend', 5) { process if @running }
end
puts "Unsuspended #{count} job(s)." unless count == 0
end
def start
@onupdate = df.onupdate_register('autounsuspend', 5) { process }
@running = true
end
def stop
df.onupdate_unregister(@onupdate)
@running = false
end
def status
@running ? 'Running.' : 'Stopped.'
end
end
def stop
@running = false
df.onupdate_unregister(@onupdate)
end
end
case $script_args[0]
when 'start'
$AutoUnsuspend = AutoUnsuspend.new unless $AutoUnsuspend
$AutoUnsuspend ||= AutoUnsuspend.new
$AutoUnsuspend.start
when 'end', 'stop'
$AutoUnsuspend.stop
else
if $AutoUnsuspend
puts $AutoUnsuspend.status
else
puts 'Not loaded.'
end
puts $AutoUnsuspend && $AutoUnsuspend.running ? 'Running.' : 'Stopped.'
end

@ -84,6 +84,7 @@ The special final argument 'magma' will make magma rain on the targets instead.
The special final argument 'butcher' will mark the targets for butchering instead.
Ex: exterminate gob
exterminate gob:male
exterminate elve magma
exterminate him
exterminate pig butcher
@ -115,6 +116,10 @@ when /^undead/i
puts "#{slain} #{count} undeads"
else
if race.index(':')
race, caste = race.split(':')
end
raw_race = df.match_rawname(race, all_races.keys)
if not raw_race
puts "Invalid race, use one of #{all_races.keys.sort.join(' ')}"
@ -123,13 +128,24 @@ else
race_nr = df.world.raws.creatures.all.index { |cr| cr.creature_id == raw_race }
if caste
all_castes = df.world.raws.creatures.all[race_nr].caste.map { |c| c.caste_id }
raw_caste = df.match_rawname(caste, all_castes)
if not raw_caste
puts "Invalid caste, use one of #{all_castes.sort.join(' ')}"
throw :script_finished
end
caste_nr = all_castes.index(raw_caste)
end
count = 0
df.world.units.active.each { |u|
if u.race == race_nr and checkunit[u]
next if caste_nr and u.caste != caste_nr
slayit[u]
count += 1
end
}
puts "#{slain} #{count} #{raw_race}"
puts "#{slain} #{count} #{raw_caste} #{raw_race}"
end