summaryrefslogtreecommitdiff
path: root/needs_porting/SegmentedFinder.h
diff options
context:
space:
mode:
authorPetr Mrázek2012-03-01 00:01:24 +0100
committerPetr Mrázek2012-03-01 00:01:24 +0100
commit07b4044336176e8277f3adaa2e03c406e77b6b76 (patch)
tree9019b2ea3ff92b8c77dc464c46d8026d63bbd7ac /needs_porting/SegmentedFinder.h
parent1f2782d5b86ee62d821ec0c7e33833048fc06b20 (diff)
downloaddfhack-07b4044336176e8277f3adaa2e03c406e77b6b76.tar.gz
dfhack-07b4044336176e8277f3adaa2e03c406e77b6b76.tar.bz2
dfhack-07b4044336176e8277f3adaa2e03c406e77b6b76.tar.xz
Nuke more!
Diffstat (limited to 'needs_porting/SegmentedFinder.h')
-rw-r--r--needs_porting/SegmentedFinder.h543
1 files changed, 543 insertions, 0 deletions
diff --git a/needs_porting/SegmentedFinder.h b/needs_porting/SegmentedFinder.h
new file mode 100644
index 00000000..b3fe5aec
--- /dev/null
+++ b/needs_porting/SegmentedFinder.h
@@ -0,0 +1,543 @@
+#ifndef SEGMENTED_FINDER_H
+#define SEGMENTED_FINDER_H
+#include <malloc.h>
+#include <iosfwd>
+#include <iterator>
+
+class SegmentedFinder;
+class SegmentFinder
+{
+ public:
+ SegmentFinder(DFHack::t_memrange & mr, DFHack::Context * DF, SegmentedFinder * SF)
+ {
+ _DF = DF;
+ mr_ = mr;
+ valid=false;
+ if(mr.valid)
+ {
+ mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start);
+ _SF = SF;
+ try
+ {
+ DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer);
+ valid = true;
+ }
+ catch (DFHack::Error::MemoryAccessDenied &)
+ {
+ free(mr_.buffer);
+ valid = false;
+ mr.valid = false; // mark the range passed in as bad
+ cout << "Range 0x" << hex << mr_.start << " - 0x" << mr_.end;
+
+ if (strlen(mr_.name) != 0)
+ cout << " (" << mr_.name << ")";
+
+ cout << dec << " not readable." << endl;
+ cout << "Skipping this range on future scans." << endl;
+ }
+ }
+ }
+ ~SegmentFinder()
+ {
+ if(valid)
+ free(mr_.buffer);
+ }
+ bool isValid()
+ {
+ return valid;
+ }
+ template <class needleType, class hayType, typename comparator >
+ bool Find (needleType needle, const uint8_t increment , vector <uint64_t> &newfound, comparator oper)
+ {
+ if(!valid) return !newfound.empty();
+ //loop
+ for(uint64_t offset = 0; offset < (mr_.end - mr_.start) - sizeof(hayType); offset += increment)
+ {
+ if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) )
+ newfound.push_back(mr_.start + offset);
+ }
+ return !newfound.empty();
+ }
+
+ template < class needleType, class hayType, typename comparator >
+ uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
+ {
+ if(!valid) return 0;
+ uint64_t stopper = min((mr_.end - mr_.start) - sizeof(hayType), (start - mr_.start) - sizeof(hayType) + length);
+ //loop
+ for(uint64_t offset = start - mr_.start; offset < stopper; offset +=1)
+ {
+ if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) )
+ return mr_.start + offset;
+ }
+ return 0;
+ }
+
+ template <class needleType, class hayType, typename comparator >
+ bool Filter (needleType needle, vector <uint64_t> &found, vector <uint64_t> &newfound, comparator oper)
+ {
+ if(!valid) return !newfound.empty();
+ for( uint64_t i = 0; i < found.size(); i++)
+ {
+ if(mr_.isInRange(found[i]))
+ {
+ uint64_t corrected = found[i] - mr_.start;
+ if( oper(_SF,(hayType *)(mr_.buffer + corrected), needle) )
+ newfound.push_back(found[i]);
+ }
+ }
+ return !newfound.empty();
+ }
+ private:
+ friend class SegmentedFinder;
+ SegmentedFinder * _SF;
+ DFHack::Context * _DF;
+ DFHack::t_memrange mr_;
+ bool valid;
+};
+
+class SegmentedFinder
+{
+ public:
+ SegmentedFinder(vector <DFHack::t_memrange>& ranges, DFHack::Context * DF)
+ {
+ _DF = DF;
+ for(size_t i = 0; i < ranges.size(); i++)
+ {
+ segments.push_back(new SegmentFinder(ranges[i], DF, this));
+ }
+ }
+ ~SegmentedFinder()
+ {
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ delete segments[i];
+ }
+ }
+ SegmentFinder * getSegmentForAddress (uint64_t addr)
+ {
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ if(segments[i]->mr_.isInRange(addr))
+ {
+ return segments[i];
+ }
+ }
+ return 0;
+ }
+ template <class needleType, class hayType, typename comparator >
+ bool Find (const needleType needle, const uint8_t increment, vector <uint64_t> &found, comparator oper)
+ {
+ found.clear();
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ segments[i]->Find<needleType,hayType,comparator>(needle, increment, found, oper);
+ }
+ return !(found.empty());
+ }
+
+ template < class needleType, class hayType, typename comparator >
+ uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
+ {
+ SegmentFinder * sf = getSegmentForAddress(start);
+ if(sf)
+ {
+ return sf->FindInRange<needleType,hayType,comparator>(needle, oper, start, length);
+ }
+ return 0;
+ }
+
+ template <class needleType, class hayType, typename comparator >
+ bool Filter (const needleType needle, vector <uint64_t> &found, comparator oper)
+ {
+ vector <uint64_t> newfound;
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ segments[i]->Filter<needleType,hayType,comparator>(needle, found, newfound, oper);
+ }
+ found.clear();
+ found = newfound;
+ return !(found.empty());
+ }
+
+ template <class needleType, class hayType, typename comparator >
+ bool Incremental (needleType needle, const uint8_t increment ,vector <uint64_t> &found, comparator oper)
+ {
+ if(found.empty())
+ {
+ return Find <needleType, hayType, comparator>(needle,increment,found,oper);
+ }
+ else
+ {
+ return Filter <needleType, hayType, comparator>(needle,found,oper);
+ }
+ }
+
+ template <typename T>
+ T * Translate(uint64_t address)
+ {
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ if(segments[i]->mr_.isInRange(address))
+ {
+ return (T *) (segments[i]->mr_.buffer + address - segments[i]->mr_.start);
+ }
+ }
+ return 0;
+ }
+
+ template <typename T>
+ T Read(uint64_t address)
+ {
+ return *Translate<T>(address);
+ }
+
+ template <typename T>
+ bool Read(uint64_t address, T& target)
+ {
+ T * test = Translate<T>(address);
+ if(test)
+ {
+ target = *test;
+ return true;
+ }
+ return false;
+ }
+ private:
+ DFHack::Context * _DF;
+ vector <SegmentFinder *> segments;
+};
+
+template <typename T>
+bool equalityP (SegmentedFinder* s, T *x, T y)
+{
+ return (*x) == y;
+}
+
+struct vecTriplet
+{
+ uint32_t start;
+ uint32_t finish;
+ uint32_t alloc_finish;
+};
+
+template <typename Needle>
+bool vectorLength (SegmentedFinder* s, vecTriplet *x, Needle &y)
+{
+ if(x->start <= x->finish && x->finish <= x->alloc_finish)
+ if((x->finish - x->start) == y)
+ return true;
+ return false;
+}
+
+// find a vector of 32bit pointers, where an object pointed to has a string 'y' as the first member
+bool vectorString (SegmentedFinder* s, vecTriplet *x, const char *y)
+{
+ uint32_t object_ptr;
+ // iterate over vector of pointers
+ for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t))
+ {
+ // deref ptr idx, get ptr to object
+ if(!s->Read(idx,object_ptr))
+ {
+ return false;
+ }
+ // deref ptr to first object, get ptr to string
+ uint32_t string_ptr;
+ if(!s->Read(object_ptr,string_ptr))
+ return false;
+ // get string location in our local cache
+ char * str = s->Translate<char>(string_ptr);
+ if(!str)
+ return false;
+ if(strcmp(y, str) == 0)
+ return true;
+ }
+ return false;
+}
+
+// find a vector of 32bit pointers, where the first object pointed to has a string 'y' as the first member
+bool vectorStringFirst (SegmentedFinder* s, vecTriplet *x, const char *y)
+{
+ uint32_t object_ptr;
+ uint32_t idx = x->start;
+ // deref ptr idx, get ptr to object
+ if(!s->Read(idx,object_ptr))
+ {
+ return false;
+ }
+ // deref ptr to first object, get ptr to string
+ uint32_t string_ptr;
+ if(!s->Read(object_ptr,string_ptr))
+ return false;
+ // get string location in our local cache
+ char * str = s->Translate<char>(string_ptr);
+ if(!str)
+ return false;
+ if(strcmp(y, str) == 0)
+ return true;
+ return false;
+}
+
+// test if the address is between vector.start and vector.finish
+// not very useful alone, but could be a good step to filter some things
+bool vectorAddrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address)
+{
+ if(address < x->finish && address >= x->start)
+ return true;
+ return false;
+}
+
+// test if an object address is within the vector of pointers
+//
+bool vectorOfPtrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address)
+{
+ uint32_t object_ptr;
+ for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t))
+ {
+ if(!s->Read(idx,object_ptr))
+ {
+ return false;
+ }
+ if(object_ptr == address)
+ return true;
+ }
+ return false;
+}
+
+bool vectorAll (SegmentedFinder* s, vecTriplet *x, int )
+{
+ if(x->start <= x->finish && x->finish <= x->alloc_finish)
+ {
+ if(s->getSegmentForAddress(x->start) == s->getSegmentForAddress(x->finish)
+ && s->getSegmentForAddress(x->finish) == s->getSegmentForAddress(x->alloc_finish))
+ return true;
+ }
+ return false;
+}
+
+class Bytestreamdata
+{
+ public:
+ void * object;
+ uint32_t length;
+ uint32_t allocated;
+ uint32_t n_used;
+};
+
+class Bytestream
+{
+public:
+ Bytestream(void * obj, uint32_t len, bool alloc = false)
+ {
+ d = new Bytestreamdata();
+ d->allocated = alloc;
+ d->object = obj;
+ d->length = len;
+ d->n_used = 1;
+ constant = false;
+ }
+ Bytestream()
+ {
+ d = new Bytestreamdata();
+ d->allocated = false;
+ d->object = 0;
+ d->length = 0;
+ d->n_used = 1;
+ constant = false;
+ }
+ Bytestream( Bytestream & bs)
+ {
+ d =bs.d;
+ d->n_used++;
+ constant = false;
+ }
+ Bytestream( const Bytestream & bs)
+ {
+ d =bs.d;
+ d->n_used++;
+ constant = true;
+ }
+ ~Bytestream()
+ {
+ d->n_used --;
+ if(d->allocated && d->object && d->n_used == 0)
+ {
+ free (d->object);
+ free (d);
+ }
+ }
+ bool Allocate(size_t bytes)
+ {
+ if(constant)
+ return false;
+ if(d->allocated)
+ {
+ d->object = realloc(d->object, bytes);
+ }
+ else
+ {
+ d->object = malloc( bytes );
+ }
+
+ if(d->object)
+ {
+ d->allocated = bytes;
+ return true;
+ }
+ else
+ {
+ d->allocated = 0;
+ return false;
+ }
+ }
+ template < class T >
+ bool insert( T what )
+ {
+ if(constant)
+ return false;
+ if(d->length+sizeof(T) >= d->allocated)
+ Allocate((d->length+sizeof(T)) * 2);
+ (*(T *)( (uint64_t)d->object + d->length)) = what;
+ d->length += sizeof(T);
+ return true;
+ }
+ Bytestreamdata * d;
+ bool constant;
+};
+std::ostream& operator<< ( std::ostream& out, Bytestream& bs )
+{
+ if(bs.d->object)
+ {
+ out << "bytestream " << dec << bs.d->length << "/" << bs.d->allocated << " bytes" << endl;
+ for(size_t i = 0; i < bs.d->length; i++)
+ {
+ out << hex << (int) ((uint8_t *) bs.d->object)[i] << " ";
+ }
+ out << endl;
+ }
+ else
+ {
+ out << "empty bytestresm" << endl;
+ }
+ return out;
+}
+
+std::istream& operator>> ( std::istream& out, Bytestream& bs )
+{
+ string read;
+ while(!out.eof())
+ {
+ string tmp;
+ out >> tmp;
+ read.append(tmp);
+ }
+ cout << read << endl;
+ bs.d->length = 0;
+ size_t first = read.find_first_of("\"");
+ size_t last = read.find_last_of("\"");
+ size_t start = first + 1;
+ if(first == read.npos)
+ {
+ std::transform(read.begin(), read.end(), read.begin(), (int(*)(int)) tolower);
+ bs.Allocate(read.size()); // overkill. size / 2 should be good, but this is safe
+ int state = 0;
+ char big = 0;
+ char small = 0;
+ string::iterator it = read.begin();
+ // iterate through string, construct a bytestream out of 00-FF bytes
+ while(it != read.end())
+ {
+ char reads = *it;
+ if((reads >='0' && reads <= '9'))
+ {
+ if(state == 0)
+ {
+ big = reads - '0';
+ state = 1;
+ }
+ else if(state == 1)
+ {
+ small = reads - '0';
+ state = 0;
+ bs.insert<char>(big*16 + small);
+ }
+ }
+ if((reads >= 'a' && reads <= 'f'))
+ {
+ if(state == 0)
+ {
+ big = reads - 'a' + 10;
+ state = 1;
+ }
+ else if(state == 1)
+ {
+ small = reads - 'a' + 10;
+ state = 0;
+ bs.insert<char>(big*16 + small);
+ }
+ }
+ it++;
+ }
+ // we end in state= 1. should we add or should we trim... or throw errors?
+ // I decided on adding
+ if (state == 1)
+ {
+ small = 0;
+ bs.insert<char>(big*16 + small);
+ }
+ }
+ else
+ {
+ if(last == first)
+ {
+ // only one "
+ last = read.size();
+ }
+ size_t length = last - start;
+ // construct bytestream out of stuff between ""
+ bs.d->length = length;
+ if(length)
+ {
+ // todo: Bytestream should be able to handle this without external code
+ bs.Allocate(length);
+ bs.d->length = length;
+ const char* strstart = read.c_str();
+ memcpy(bs.d->object, strstart + start, length);
+ }
+ else
+ {
+ bs.d->object = 0;
+ }
+ }
+ cout << bs;
+ return out;
+}
+
+bool findBytestream (SegmentedFinder* s, void *addr, Bytestream compare )
+{
+ if(memcmp(addr, compare.d->object, compare.d->length) == 0)
+ return true;
+ return false;
+}
+
+bool findString (SegmentedFinder* s, uint32_t *addr, const char * compare )
+{
+ // read string pointer, translate to local scheme
+ char *str = s->Translate<char>(*addr);
+ // verify
+ if(!str)
+ return false;
+ if(strcmp(str, compare) == 0)
+ return true;
+ return false;
+}
+
+bool findStrBuffer (SegmentedFinder* s, uint32_t *addr, const char * compare )
+{
+ if(memcmp((const char *)addr, compare, strlen(compare)) == 0)
+ return true;
+ return false;
+}
+
+#endif // SEGMENTED_FINDER_H