dfhack/tools/playground/incrementalsearch.cpp

650 lines
20 KiB
C++

// this is an incremental search tool. It only works on Linux.
// here be dragons... and ugly code :P
#include <iostream>
#include <climits>
#include <vector>
#include <map>
#include <ctime>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
#ifndef LINUX_BUILD
#define WINVER 0x0500
// this one prevents windows from infecting the global namespace with filth
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
2010-05-25 22:48:23 -06:00
#include <DFHack.h>
2010-06-01 21:39:55 -06:00
#include "SegmentedFinder.h"
inline void printRange(DFHack::t_memrange * tpr)
{
2010-06-01 21:39:55 -06:00
std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl;
}
2010-06-05 16:56:09 -06:00
string rdWinString( char * offset, SegmentedFinder & sf )
{
char * start_offset = offset + 4;
uint32_t length = *(uint32_t *)(offset + 20);
uint32_t capacity = *(uint32_t *)(offset + 24);
char * temp = new char[capacity+1];
// read data from inside the string structure
if(capacity < 16)
{
memcpy(temp, start_offset,capacity);
//read(start_offset, capacity, (uint8_t *)temp);
}
else // read data from what the offset + 4 dword points to
{
start_offset = sf.Translate<char>(*(uint32_t*)start_offset);
memcpy(temp, start_offset,capacity);
}
temp[length] = 0;
string ret = temp;
delete temp;
return ret;
}
2010-06-01 21:39:55 -06:00
bool getRanges(DFHack::Process * p, vector <DFHack::t_memrange>& selected_ranges)
{
vector <DFHack::t_memrange> ranges;
selected_ranges.clear();
p->getMemRanges(ranges);
cout << "Which range to search? (default is 1-4)" << endl;
for(int i = 0; i< ranges.size();i++)
{
2010-06-01 21:39:55 -06:00
cout << dec << "(" << i << ") ";
printRange(&(ranges[i]));
}
2010-06-01 21:39:55 -06:00
int start, end;
while(1)
{
2010-06-01 21:39:55 -06:00
string select;
cout << ">>";
std::getline(cin, select);
if(select.empty())
{
2010-06-01 21:39:55 -06:00
// empty input, assume default. observe the length of the memory range vector
// these are hardcoded values, intended for my convenience only
if(p->getDescriptor()->getOS() == DFHack::memory_info::OS_WINDOWS)
{
2010-06-01 21:39:55 -06:00
start = min(11, (int)ranges.size());
end = min(14, (int)ranges.size());
}
2010-06-01 21:39:55 -06:00
else if(p->getDescriptor()->getOS() == DFHack::memory_info::OS_LINUX)
{
start = min(11, (int)ranges.size());
end = min(14, (int)ranges.size());
}
else
{
2010-06-01 21:39:55 -06:00
start = 1;
end = 1;
}
2010-06-01 21:39:55 -06:00
break;
}
2010-06-01 21:39:55 -06:00
// I like the C variants here. much less object clutter
else if(sscanf(select.c_str(), "%d-%d", &start, &end) == 2)
{
2010-06-01 21:39:55 -06:00
start = min(start, (int)ranges.size());
end = min(end, (int)ranges.size());
break;
}
2010-06-01 21:39:55 -06:00
else
{
2010-06-01 21:39:55 -06:00
continue;
}
2010-06-01 21:39:55 -06:00
break;
}
2010-06-01 21:39:55 -06:00
end++;
cout << "selected ranges:" <<endl;
2010-06-05 16:56:09 -06:00
vector <DFHack::t_memrange>::iterator it;
it = ranges.begin() + start;
while (it != ranges.begin() + end)
{
2010-06-05 16:56:09 -06:00
// check if readable
if((*it).read)
{
selected_ranges.push_back(*it);
printRange(&*it);
}
it++;
}
2010-06-01 21:39:55 -06:00
}
bool getNumber (string prompt, int & output, int def, bool pdef = true)
{
cout << prompt;
if(pdef)
cout << " default=" << def << endl;
while (1)
{
2010-06-01 21:39:55 -06:00
string select;
cout << ">>";
std::getline(cin, select);
if(select.empty())
{
2010-06-01 21:39:55 -06:00
output = def;
break;
}
2010-06-01 21:39:55 -06:00
else if( sscanf(select.c_str(), "%d", &output) == 1 )
{
2010-06-01 21:39:55 -06:00
break;
}
2010-06-01 21:39:55 -06:00
else
2010-05-30 19:04:18 -06:00
{
2010-06-01 21:39:55 -06:00
continue;
2010-05-30 19:04:18 -06:00
}
}
2010-06-01 21:39:55 -06:00
return true;
}
2010-06-01 21:39:55 -06:00
bool getString (string prompt, string & output)
{
2010-06-01 21:39:55 -06:00
cout << prompt;
cout << ">>";
string select;
std::getline(cin, select);
if(select.empty())
{
2010-06-01 21:39:55 -06:00
return false;
}
2010-06-01 21:39:55 -06:00
else
{
2010-06-01 21:39:55 -06:00
output = select;
return true;
}
}
2010-06-01 21:39:55 -06:00
template <class T>
bool Incremental ( vector <uint64_t> &found, const char * what, T& output,
const char *singular = "address", const char *plural = "addresses" )
{
2010-06-01 21:39:55 -06:00
string select;
if(found.empty())
{
2010-06-03 18:51:09 -06:00
cout << "search ready - insert " << what << ", 'p' for results, 'p #' to limit number of results" << endl;
2010-06-01 21:39:55 -06:00
}
else if( found.size() == 1)
{
2010-06-03 18:51:09 -06:00
cout << "Found single "<< singular <<"!" << endl;
2010-06-01 21:39:55 -06:00
cout << hex << "0x" << found[0] << endl;
}
else
{
cout << "Found " << dec << found.size() << " " << plural <<"." << endl;
}
incremental_more:
cout << ">>";
std::getline(cin, select);
2010-06-03 18:51:09 -06:00
size_t num = 0;
if( sscanf(select.c_str(),"p %d", &num) && num > 0)
{
cout << "Found "<< plural <<":" << endl;
for(int i = 0; i < min(found.size(), num);i++)
{
cout << hex << "0x" << found[i] << endl;
}
goto incremental_more;
}
else if(select == "p")
2010-06-01 21:39:55 -06:00
{
cout << "Found "<< plural <<":" << endl;
for(int i = 0; i < found.size();i++)
{
cout << hex << "0x" << found[i] << endl;
}
goto incremental_more;
}
else if(select.empty())
{
return false;
2010-06-01 21:39:55 -06:00
}
else
{
stringstream ss (stringstream::in | stringstream::out);
ss << select;
2010-06-03 18:51:09 -06:00
ss >> hex >> output;
2010-06-01 21:39:55 -06:00
if(ss.fail())
{
2010-06-03 18:51:09 -06:00
ss >> dec >> output;
if(ss.fail())
{
cout << "not a valid value for type: " << what << endl;
goto incremental_more;
}
2010-06-01 21:39:55 -06:00
}
return true;
2010-06-01 21:39:55 -06:00
}
}
2010-06-03 18:51:09 -06:00
void FindIntegers(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
2010-06-01 21:39:55 -06:00
// input / validation of variable size
int size;
do
{
getNumber("Select variable size (1,2,4 bytes)",size, 4);
} while (size != 1 && size != 2 && size != 4);
// input / validation of variable alignment (default is to use the same alignment as size)
int alignment;
do
{
getNumber("Select variable alignment (1,2,4 bytes)",alignment, size);
} while (alignment != 1 && alignment != 2 && alignment != 4);
uint32_t test1;
vector <uint64_t> found;
found.reserve(100);
2010-06-01 21:39:55 -06:00
while(Incremental(found, "integer",test1))
{
2010-06-01 21:39:55 -06:00
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
switch(size)
{
2010-06-01 21:39:55 -06:00
case 1:
sf.Find<uint8_t,uint8_t>(test1,alignment,found, equalityP<uint8_t>);
break;
case 2:
sf.Find<uint16_t,uint16_t>(test1,alignment,found, equalityP<uint16_t>);
break;
case 4:
sf.Find<uint32_t,uint32_t>(test1,alignment,found, equalityP<uint32_t>);
break;
}
2010-06-01 21:39:55 -06:00
DF->Detach();
}
}
2010-06-03 18:51:09 -06:00
void FindVectorByLength(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges )
2010-05-23 15:06:10 -06:00
{
2010-06-01 21:39:55 -06:00
int element_size;
do
{
getNumber("Select searched vector item size in bytes",element_size, 4);
} while (element_size < 1);
2010-05-23 15:06:10 -06:00
uint32_t length;
vector <uint64_t> found;
found.reserve(100);
2010-06-01 21:39:55 -06:00
while (Incremental(found, "vector length",length,"vector","vectors"))
2010-05-23 15:06:10 -06:00
{
2010-06-01 21:39:55 -06:00
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Find<int ,vecTriplet>(0,4,found,vectorAll);
sf.Find<uint32_t,vecTriplet>(length * element_size,4,found,vectorLength<uint32_t>);
DF->Detach();
2010-05-23 15:06:10 -06:00
}
}
2010-06-03 18:51:09 -06:00
void FindVectorByObjectRawname(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
2010-05-26 09:54:30 -06:00
{
vector <uint64_t> found;
string select;
2010-06-01 21:39:55 -06:00
while (Incremental(found, "raw name",select,"vector","vectors"))
2010-05-26 09:54:30 -06:00
{
2010-06-01 21:39:55 -06:00
// clear the list of found addresses -- this is a one-shot
found.clear();
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Find<int ,vecTriplet>(0,4,found, vectorAll);
sf.Find<const char * ,vecTriplet>(select.c_str(),4,found, vectorString);
DF->Detach();
2010-05-26 09:54:30 -06:00
}
}
2010-06-03 18:51:09 -06:00
void FindVectorByFirstObjectRawname(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> found;
string select;
while (Incremental(found, "raw name",select,"vector","vectors"))
{
// clear the list of found addresses -- this is a one-shot
found.clear();
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Find<int ,vecTriplet>(0,4,found, vectorAll);
sf.Find<const char * ,vecTriplet>(select.c_str(),4,found, vectorStringFirst);
DF->Detach();
}
}
struct VectorSizeFunctor : public binary_function<uint64_t, uint64_t, bool>
{
VectorSizeFunctor(SegmentedFinder & sf):sf_(sf){}
bool operator()( uint64_t lhs, uint64_t rhs)
{
vecTriplet* left = sf_.Translate<vecTriplet>(lhs);
vecTriplet* right = sf_.Translate<vecTriplet>(rhs);
return ((left->finish - left->start) < (right->finish - right->start));
}
SegmentedFinder & sf_;
};
void FindVectorByBounds(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> found;
uint32_t select;
while (Incremental(found, "address between vector.start and vector.end",select,"vector","vectors"))
{
// clear the list of found addresses -- this is a one-shot
found.clear();
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Find<int ,vecTriplet>(0,4,found, vectorAll);
sf.Find<uint32_t ,vecTriplet>(select,4,found, vectorAddrWithin);
// sort by size of vector
std::sort(found.begin(), found.end(), VectorSizeFunctor(sf));
DF->Detach();
}
}
void FindPtrVectorsByObjectAddress(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> found;
uint32_t select;
while (Incremental(found, "object address",select,"vector","vectors"))
{
// clear the list of found addresses -- this is a one-shot
found.clear();
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Find<int ,vecTriplet>(0,4,found, vectorAll);
sf.Find<uint32_t ,vecTriplet>(select,4,found, vectorOfPtrWithin);
DF->Detach();
}
}
void FindStrings(DFHack::ContextManager & DFMgr, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> found;
string select;
2010-06-01 21:39:55 -06:00
while (Incremental(found,"string",select,"string","strings"))
{
2010-06-01 21:39:55 -06:00
DFMgr.Refresh();
DFHack::Context * DF = DFMgr.getSingleContext();
DF->Attach();
SegmentedFinder sf(ranges,DF);
sf.Find< const char * ,uint32_t>(select.c_str(),1,found, findString);
DF->Detach();
}
}
2010-06-05 16:56:09 -06:00
void printFound(vector <uint64_t> &found, const char * what)
{
cout << what << ":" << endl;
for(int i = 0; i < found.size();i++)
{
cout << hex << "0x" << found[i] << endl;
}
}
void printFoundStrVec(vector <uint64_t> &found, const char * what, SegmentedFinder & s)
{
cout << what << ":" << endl;
for(int i = 0; i < found.size();i++)
{
cout << hex << "0x" << found[i] << endl;
cout << "--------------------------" << endl;
vecTriplet * vt = s.Translate<vecTriplet>(found[i]);
if(vt)
{
int j = 0;
for(uint32_t idx = vt->start; idx < vt->finish; idx += sizeof(uint32_t))
{
uint32_t object_ptr;
// deref ptr idx, get ptr to object
if(!s.Read(idx,object_ptr))
{
cout << "BAD!" << endl;
break;
}
// deref ptr to first object, get ptr to string
uint32_t string_ptr;
if(!s.Read(object_ptr,string_ptr))
{
cout << "BAD!" << endl;
break;
}
// get string location in our local cache
char * str = s.Translate<char>(string_ptr);
if(!str)
{
cout << "BAD!" << endl;
break;
}
cout << dec << j << ": " << str << endl;
j++;
}
}
else
{
cout << "BAD!" << endl;
break;
}
cout << "--------------------------" << endl;
}
}
2010-06-01 21:39:55 -06:00
void automatedLangtables(DFHack::Context * DF, vector <DFHack::t_memrange>& ranges)
{
vector <uint64_t> allVectors;
2010-06-05 16:56:09 -06:00
vector <uint64_t> filtVectors;
2010-06-01 21:39:55 -06:00
vector <uint64_t> to_filter;
2010-06-05 16:56:09 -06:00
cout << "stealing memory..." << endl;
SegmentedFinder sf(ranges, DF);
cout << "looking for vectors..." << endl;
sf.Find<int ,vecTriplet>(0,4,allVectors, vectorAll);
// trim vectors. anything with > 10000 entries is not interesting
for(uint64_t i = 0; i < allVectors.size();i++)
{
vecTriplet* vtrip = sf.Translate<vecTriplet>(allVectors[i]);
if(vtrip)
{
uint64_t length = (vtrip->finish - vtrip->start) / 4;
if(length < 10000 )
{
filtVectors.push_back(allVectors[i]);
}
}
}
cout << "-------------------" << endl;
cout << "!!LANGUAGE TABLES!!" << endl;
cout << "-------------------" << endl;
2010-06-01 21:39:55 -06:00
uint64_t kulet_vector;
uint64_t word_table_offset;
uint64_t DWARF_vector;
uint64_t DWARF_object;
// find lang vector (neutral word table)
2010-06-05 16:56:09 -06:00
to_filter = filtVectors;
2010-06-03 18:51:09 -06:00
sf.Find<const char * ,vecTriplet>("ABBEY",4,to_filter, vectorStringFirst);
2010-06-01 21:39:55 -06:00
uint64_t lang_addr = to_filter[0];
// find dwarven language word table
2010-06-05 16:56:09 -06:00
to_filter = filtVectors;
2010-06-03 18:51:09 -06:00
sf.Find<const char * ,vecTriplet>("kulet",4,to_filter, vectorStringFirst);
2010-06-01 21:39:55 -06:00
kulet_vector = to_filter[0];
// find vector of languages
2010-06-05 16:56:09 -06:00
to_filter = filtVectors;
2010-06-03 18:51:09 -06:00
sf.Find<const char * ,vecTriplet>("DWARF",4,to_filter, vectorStringFirst);
2010-06-01 21:39:55 -06:00
// verify
for(int i = 0; i < to_filter.size(); i++)
{
vecTriplet * vec = sf.Translate<vecTriplet>(to_filter[i]);
if(((vec->finish - vec->start) / 4) == 4) // verified
{
2010-06-01 21:39:55 -06:00
DWARF_vector = to_filter[i];
DWARF_object = sf.Read<uint32_t>(vec->start);
// compute word table offset from dwarf word table and dwarf language object addresses
word_table_offset = kulet_vector - DWARF_object;
break;
}
}
2010-06-01 21:39:55 -06:00
cout << "translation vector: " << hex << "0x" << DWARF_vector << endl;
cout << "lang vector: " << hex << "0x" << lang_addr << endl;
cout << "word table offset: " << hex << "0x" << word_table_offset << endl;
2010-06-05 16:56:09 -06:00
cout << "-------------" << endl;
cout << "!!MATERIALS!!" << endl;
cout << "-------------" << endl;
// inorganics vector
to_filter = filtVectors;
//sf.Find<uint32_t,vecTriplet>(257 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Find<const char * ,vecTriplet>("IRON",4,to_filter, vectorStringFirst);
sf.Find<const char * ,vecTriplet>("RAW_ADAMANTINE",4,to_filter, vectorString);
sf.Find<const char * ,vecTriplet>("BLOODSTONE",4,to_filter, vectorString);
printFound(to_filter,"inorganics");
// organics vector
to_filter = filtVectors;
sf.Find<uint32_t,vecTriplet>(52 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Find<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",4,to_filter, vectorStringFirst);
printFound(to_filter,"organics");
// tree vector
to_filter = filtVectors;
sf.Find<uint32_t,vecTriplet>(31 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Find<const char * ,vecTriplet>("MANGROVE",4,to_filter, vectorStringFirst);
printFound(to_filter,"trees");
// plant vector
to_filter = filtVectors;
sf.Find<uint32_t,vecTriplet>(21 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Find<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",4,to_filter, vectorStringFirst);
printFound(to_filter,"plants");
// color descriptors
//AMBER, 112
to_filter = filtVectors;
sf.Find<uint32_t,vecTriplet>(112 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Find<const char * ,vecTriplet>("AMBER",4,to_filter, vectorStringFirst);
printFound(to_filter,"color descriptors");
if(!to_filter.empty())
{
uint64_t vec = to_filter[0];
vecTriplet *vtColors = sf.Translate<vecTriplet>(vec);
uint32_t colorObj = sf.Read<uint32_t>(vtColors->start);
cout << "Amber color:" << hex << "0x" << colorObj << endl;
// TODO: find string 'amber', the floats
}
// all descriptors
//AMBER, 338
to_filter = filtVectors;
sf.Find<uint32_t,vecTriplet>(338 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Find<const char * ,vecTriplet>("AMBER",4,to_filter, vectorStringFirst);
printFound(to_filter,"all descriptors");
// creature type
//ELEPHANT, ?? (demons abound)
to_filter = filtVectors;
//sf.Find<uint32_t,vecTriplet>(338 * 4,4,to_filter,vectorLength<uint32_t>);
sf.Find<const char * ,vecTriplet>("ELEPHANT",4,to_filter, vectorString);
sf.Find<const char * ,vecTriplet>("CAT",4,to_filter, vectorString);
sf.Find<const char * ,vecTriplet>("DWARF",4,to_filter, vectorString);
sf.Find<const char * ,vecTriplet>("WAMBLER_FLUFFY",4,to_filter, vectorString);
sf.Find<const char * ,vecTriplet>("TOAD",4,to_filter, vectorString);
sf.Find<const char * ,vecTriplet>("DEMON_1",4,to_filter, vectorString);
vector <uint64_t> toad_first = to_filter;
vector <uint64_t> elephant_first = to_filter;
sf.Find<const char * ,vecTriplet>("TOAD",4,toad_first, vectorStringFirst);
sf.Find<const char * ,vecTriplet>("ELEPHANT",4,elephant_first, vectorStringFirst);
printFound(toad_first,"toad-first creature types");
printFound(elephant_first,"elephant-first creature types");
printFound(to_filter,"all creature types");
}
int main (void)
{
string select;
2010-05-23 15:06:10 -06:00
DFHack::ContextManager DFMgr("Memory.xml");
DFHack::Context * DF = DFMgr.getSingleContext();
try
{
2010-05-23 15:06:10 -06:00
DF->Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
2010-05-23 15:06:10 -06:00
DFHack::Process * p = DF->getProcess();
vector <DFHack::t_memrange> selected_ranges;
2010-06-01 21:39:55 -06:00
getRanges(p,selected_ranges);
2010-06-01 21:39:55 -06:00
string prompt =
"Select search type: 1=number(default), 2=vector by length, 3=vector>object>string,\n"
2010-06-05 16:56:09 -06:00
" 4=string, 5=automated offset search, 6=vector by address in its array,\n"
2010-06-01 21:39:55 -06:00
" 7=pointer vector by address of an object, 8=vector>first object>string\n";
2010-05-23 15:06:10 -06:00
int mode;
2010-06-01 21:39:55 -06:00
do
{
2010-06-01 21:39:55 -06:00
getNumber(prompt,mode, 1, false);
} while (mode < 1 || mode > 8 );
switch (mode)
{
2010-06-03 18:51:09 -06:00
case 1:
FindIntegers(DFMgr, selected_ranges);
2010-06-01 21:39:55 -06:00
break;
2010-06-03 18:51:09 -06:00
case 2:
FindVectorByLength(DFMgr, selected_ranges);
2010-06-01 21:39:55 -06:00
break;
2010-06-03 18:51:09 -06:00
case 3:
FindVectorByObjectRawname(DFMgr, selected_ranges);
2010-06-01 21:39:55 -06:00
break;
2010-06-03 18:51:09 -06:00
case 4:
FindStrings(DFMgr, selected_ranges);
2010-06-01 21:39:55 -06:00
break;
case 5:
automatedLangtables(DF,selected_ranges);
break;
case 6:
2010-06-03 18:51:09 -06:00
FindVectorByBounds(DFMgr,selected_ranges);
break;
2010-06-01 21:39:55 -06:00
case 7:
2010-06-03 18:51:09 -06:00
FindPtrVectorsByObjectAddress(DFMgr,selected_ranges);
break;
2010-06-01 21:39:55 -06:00
case 8:
2010-06-03 18:51:09 -06:00
FindVectorByFirstObjectRawname(DFMgr, selected_ranges);
break;
2010-06-01 21:39:55 -06:00
default:
cout << "not implemented :(" << endl;
}
#ifndef LINUX_BUILD
2010-05-23 15:06:10 -06:00
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}