summaryrefslogtreecommitdiff
path: root/Database
diff options
context:
space:
mode:
authorunknown <Pixel@.(none)>2009-09-16 22:24:08 -0700
committerunknown <Pixel@.(none)>2009-09-16 22:24:08 -0700
commit6a653b35990e9a642dd4af9b8ee5742d5a84956c (patch)
tree31dac2b537af43584bbc6237df824cad7dba1a00 /Database
parent2142bda77399a49f0a6684cccb4bb3420c2a10df (diff)
Adding basic Database structure.
Diffstat (limited to 'Database')
-rw-r--r--Database/database-types.h47
-rw-r--r--Database/internals/database-internal.cpp27
-rw-r--r--Database/internals/database-internal.h39
-rw-r--r--Database/internals/database-references.cpp47
-rw-r--r--Database/internals/database-references.h58
-rw-r--r--Database/internals/database-segment.cpp119
-rw-r--r--Database/internals/database-segment.h72
7 files changed, 409 insertions, 0 deletions
diff --git a/Database/database-types.h b/Database/database-types.h
new file mode 100644
index 0000000..95c5ebd
--- /dev/null
+++ b/Database/database-types.h
@@ -0,0 +1,47 @@
+#ifndef __DATABASE_TYPES_H__
+#define __DATABASE_TYPES_H__
+
+/** The basic tags that describe the bytes of the database. The tag "CODE_FIRST_BYTE" is
+ * mainly for multi-bytes instructions, in order to help the UI displaying
+ * properly the instructions.
+ */
+
+enum basic_tags_t {
+ TAG_UNKNOWN = 0,
+ TAG_CODE,
+ TAG_DATA,
+ TAG_CODE_FIRST_BYTE,
+};
+
+/** The 8-bits tag for a byte. The certitude part
+ * A non-hollow database will be as big (at least) as the input file: in-memory-RLE is probably a good idea.
+ */
+struct memory_tags_t {
+ unsigned short basic_tags: 2;
+ /** -1..30, 30 being "user hinted", 29 being "external reference" (entry point, exported symbol, ...)
+ * and -1 means something's fishy with that tag, and that it is probably completely wrong.
+ * Certitude will grow down with distance from a certain piece of info when the crawler goes away jumping around.
+ */
+ unsigned short certitude: 6;
+};
+
+/** An absolute pointer can reference a segment from its ID, and a pointer within the segment.
+ */
+
+typedef union {
+ Uint64 raw_ptr;
+ struct {
+ Uint32 segment_id;
+ Uint32 ptr;
+ };
+} absolute_ptr;
+
+/** A function description.
+ */
+
+struct function_t {
+ absolute_ptr start;
+ Uint32 size;
+};
+
+#endif
diff --git a/Database/internals/database-internal.cpp b/Database/internals/database-internal.cpp
new file mode 100644
index 0000000..0c90b71
--- /dev/null
+++ b/Database/internals/database-internal.cpp
@@ -0,0 +1,27 @@
+#include "database-internal.h"
+
+DatabaseCell::DatabaseCell(Cpu * cpu, Uint64 cpu_base, absolute_ptr origin, Uint32 size, Uint32 extra_size, DatabaseCell * prev, Database * parent) : cpu(cpu), next(0), prev(prev), parent(parent) {
+ prev->next = this;
+ parent->setEnd(this);
+ if (origin) {
+ Segment * origin_seg = parent->GetSegment(SEGID(origin));
+ segment = new Segment(size, cpu_base, parent->GetNextSegId(), extra_size, origin_seg->getPristineMemory() + SEGOFFSET(origin));
+ } else {
+ segment = new Segment(size, cpu_base, parent->GetNextSegId(), extra_size);
+ }
+}
+
+DatabaseCell::~DatabaseCell() {
+ if (parent->getEnd() == this)
+ parent->setEnd(prev);
+
+ if (parent->getStart() == this)
+ parent->setStart(next);
+
+ if (next)
+ next->prev = prev;
+ if (prev)
+ prev->next = next;
+
+ delete segment;
+}
diff --git a/Database/internals/database-internal.h b/Database/internals/database-internal.h
new file mode 100644
index 0000000..75e82c9
--- /dev/null
+++ b/Database/internals/database-internal.h
@@ -0,0 +1,39 @@
+#ifndef __DATABASE_INTERNAL_H__
+#define __DATABASE_INTERNAL_H__
+
+#include "database-segment.h"
+#include "database-types.h"
+
+class Database;
+class Cpu;
+
+/** A database element. Basically, the database is a collection of segments, associated with information.
+ * This class could have been merged with Segment's, but in an effort to split the segment, that only
+ * contains the raw memory, and the various data associated with it, this glue element exists. It'll also
+ * construct a linked list for the database.
+ */
+
+class DatabaseCell : public Base {
+ public:
+ /** The constructor of a DatabaseCell. Note that if you specify the origin parameter,
+ * it'll create a sub-segment based on the first one. Note also that this doesn't support
+ * the patching system, yet.
+ */
+ DatabaseCell(Cpu * cpu, Uint64 cpu_base, absolute_ptr origin, Uint32 size, Uint32 extra_size, DatabaseCell * prev);
+ ~DatabaseCell();
+ Uint32 getID() { return segment->GetID(); }
+ void LoadMemory(Handle * src) { segment->LoadMemory(src); }
+ Segment * getSegment() { return segment; }
+ Cpu * getCpu() { return cpu; }
+ Uint64 getCpuBase() { return segment->getCpuBase(); }
+ absolute_ptr getOrigin() { return origin; }
+
+ private:
+ Segment * segment;
+ Cpu * cpu;
+ absolute_ptr origin; // a data segment can come from within another one
+ DatabaseCell * next, * prev;
+ Database * parent;
+};
+
+#endif
diff --git a/Database/internals/database-references.cpp b/Database/internals/database-references.cpp
new file mode 100644
index 0000000..8520f16
--- /dev/null
+++ b/Database/internals/database-references.cpp
@@ -0,0 +1,47 @@
+#include "database-references.h"
+
+RefFrom::RefFrom(RefTo * refTo, SegmentRefData * data) : refTo(refTo), data(data) {
+ assert(refto);
+ assert(data);
+
+ next = data->getRefFrom();
+ prev = 0;
+ data->firstRefFrom = this;
+ if (next)
+ next->prev = this;
+}
+
+RefFrom::~RefFrom() {
+ if (next)
+ next->prev = prev;
+ if (prev)
+ prev->next = next;
+ else
+ data->setFirstRefFrom(next);
+}
+
+RefTo::RefTo(absolute_ptr ptr, SegmentRefData * data, Database * database) : data(data) {
+ assert(database);
+ Segment * destSeg = database->getSegment(ptr.segment_id);
+ assert(destSeg);
+ refFrom = new RefFrom(this, destSeg->getSegmentRefData(ptr.ptr);
+
+ RefTo * t = data->getRefTo();
+ if (t) {
+ delete t;
+ data->setRefTo(this);
+ }
+}
+
+RefTo::~RefTo() {
+ data->refTo = 0;
+ delete refFrom;
+}
+
+SegmentRefData::SegmentRefData(Uint32 ptr, Segment * seg) : ptr(ptr), seg(seg) {
+ seg->setSegmentRefData(ptr, this);
+}
+
+SegmentRefData::~SegmentRefData() {
+ seg->setSegmentRefData(ptr, 0);
+}
diff --git a/Database/internals/database-references.h b/Database/internals/database-references.h
new file mode 100644
index 0000000..65e4cdf
--- /dev/null
+++ b/Database/internals/database-references.h
@@ -0,0 +1,58 @@
+#ifndef __DATABASE_REFERENCES_H__
+#define __DATABASE_REFERENCES_H__
+
+class SegmentData;
+class RefFrom;
+class RefTo;
+
+/** The reference system, where the database will be able to hold references from and to memory pointers.
+ */
+
+class RefFrom : public Base {
+ public:
+ RefFrom(RefTo * refTo, SegmentRefData * data);
+ ~RefFrom()
+ SegmentRefData * getRefSegData() { return refTo->getSegRefData(); }
+ SegmentRefData * getSegRefData() { return data; }
+ RefFrom * getNext() { return next; }
+ private:
+ RefTo * refTo;
+ RefFrom * next, * prev;
+ SegmentRefData * data;
+};
+
+class RefTo : public Base {
+ public:
+ RefTo(Uint32 ptr, SegmentRefData * data);
+ ~RefTo();
+ SegmentRefData * getRefSegData() { return refFrom->getSegRefData(); }
+ SegmentRefData * getSegRefData() { return data; }
+ private:
+ RefFrom * refFrom;
+ SegmentRefData * data;
+};
+
+class SegmentRefData : public Base {
+ public:
+ SegmentRefData(Uint32 ptr, Segment * seg);
+ ~SegmentRefData()
+ Uint32 getPtr() { return ptr; }
+ Segment * getSegment() { return seg; }
+ SegmentRefData * getSegmentRefData(Uint32 ptr) { return seg->getSegmentRefData(ptr); }
+
+ RefTo * getRefTo() { return refTo; }
+ RefFrom * getRefFrom() { return firstRefFrom; }
+
+ void setRefTo(RefTo * newRefTo) { refTo = newRefTo; checkDestroy(); }
+ void setFirstRefFrom(RefFrom * newFirstRefFrom) { firstRefFrom = newFirstRefFrom; checkDestroy(); }
+
+ private:
+ RefTo * refTo;
+ RefFrom * firstRefFrom;
+
+ Uint32 ptr;
+ Segment * seg;
+ void checkDestroy() { if (!refTo && !firstRefFrom) delete this; }
+};
+
+#endif
diff --git a/Database/internals/database-segment.cpp b/Database/internals/database-segment.cpp
new file mode 100644
index 0000000..4b94000
--- /dev/null
+++ b/Database/internals/database-segment.cpp
@@ -0,0 +1,119 @@
+#include "database-segment.h"
+
+Segment::Segment(Uint32 size, Uint32 id, Uint64 cpu_base, Uint32 extra_size, const Byte * data) : patches(0), plainmemory(0), size(size), extra_size(extra_size), id(id), cpu_base(cpu_base) {
+ Uint64 fullsize = size + extra_size;
+
+ assert(size);
+
+ if (data) {
+ plainmemory = (Byte *) data;
+ loaded = true;
+ allocated = false
+ } else {
+ plainmemory = Allocator<Byte>::alloc(size);
+ loaded = false;
+ allocated = true;
+ }
+ tags = Allocator<memory_tags_t>::alloc(fullsize);
+ refData = Allocator<SegmentRefData *>::alloc(fullsize);
+}
+
+Segment::~Segment() {
+ if (allocated)
+ Allocator<Byte>::free(plainmemory);
+ if (patches)
+ Allocator<Byte>::free(patches);
+ if (patchesmemory)
+ Allocator<Byte>::free(patchesmap);
+ Allocator<memory_tags_t>::free(tags);
+ Allocator<SegmentRefData *>::free(refData);
+}
+
+short Segment::Read(Uint32 ptr) {
+ if (ptr >= size) {
+ LOG(CONSOLE, ERROR, "Out of bound read attempt in segment %i at %08X\n", id, ptr);
+ return -1;
+ }
+ if (IsPatched(ptr))
+ return patches[ptr];
+ return plainmemory[ptr];
+}
+
+short Segment::RawRead(Uint32 ptr) {
+ if (ptr >= size) {
+ LOG(CONSOLE, ERROR, "Out of bound rawread attempt in segment %i at %08X\n", id, ptr);
+ return -1;
+ }
+ return plainmemory[ptr];
+}
+
+void Segment::Patch(Uint32 ptr, Byte val) {
+ if (!patchesmap) {
+ patches = Allocator<Byte>::alloc(size);
+ patchesmap = Allocator<Byte>::alloc((size << 3) + ((size & 7) ? 1 : 0));
+ }
+ if (ptr >= size) {
+ LOG(CONSOLE, ERROR, "Out of bound patch attempt in segment %i at %08X\n", id, ptr);
+ return;
+ }
+ patches[ptr] = val;
+ patchesmap[ptr / 8] |= (1 << ptr % 8);
+}
+
+void Segment::Restore(Uint32 ptr) {
+ if (!patchesmap)
+ return;
+ if (ptr >= size) {
+ LOG(CONSOLE, ERROR, "Out of bound patch attempt in segment %i at %08X\n", id, ptr);
+ return;
+ }
+ patchesmap[ptr / 8] &= ~(1 << (ptr % 8));
+}
+
+bool Segment::IsPatched(Uint32 ptr) {
+ if (!patchesmap)
+ return false;
+ return patchesmap[ptr / 8] & (1 << (ptr % 8));
+}
+
+void Segment::LoadMemory(Handle * src) {
+ if (loaded) {
+ LOG(CONSOLE, WARNING, "Memory segment already loaded, second attempt ignored.");
+ return;
+ }
+
+ src->Read(plainmemory, size);
+}
+
+void setTag(Uint32 ptr, memory_tags_t tag) {
+ if (ptr >= (size + extra_size)) {
+ LOG(CONSOLE, ERROR, "Out of bound setTag attempt in segment %i at %08X\n", id, ptr);
+ return;
+ }
+ tags[ptr] = tag;
+}
+
+memory_tags_t getTag(Uint32 ptr) {
+ if (ptr >= (size + extra_size)) {
+ memory_tags_t z = { 0, 0 };
+ LOG(CONSOLE, ERROR, "Out of bound getTag attempt in segment %i at %08X\n", id, ptr);
+ return z;
+ }
+ return tags[ptr];
+}
+
+SegmentRefData * Segment::getSegmentRefData(Uint32 ptr) {
+ if (ptr >= (size + extra_size)) {
+ LOG(CONSOLE, ERROR, "Out of bound getSegmentRefData attempt in segment %i at %08X\n", id, ptr);
+ return 0;
+ }
+ return refData[ptr];
+}
+
+void Segment::setSegmentRefData(Uint32 ptr, SegmentRefData * data) {
+ if (ptr >= (size + extra_size)) {
+ LOG(CONSOLE, ERROR, "Out of bound setSegmentRefData attempt in segment %i at %08X\n", id, ptr);
+ return;
+ }
+ refData[ptr] = data;
+}
diff --git a/Database/internals/database-segment.h b/Database/internals/database-segment.h
new file mode 100644
index 0000000..72086a7
--- /dev/null
+++ b/Database/internals/database-segment.h
@@ -0,0 +1,72 @@
+#ifndef __DATABASE_SEGMENT_H__
+#define __DATABASE_SEGMENT_H__
+
+#include "database-types.h"
+
+class SegmentRefData;
+
+/**
+ * The Segment class that holds the memory and patches for a memory segment.
+ *
+ * This class will passively hold the memory for a segment memory. The tags
+ * corresponding to each byte are also stored there. The patches are optionnal,
+ * and will only be allocated if a patch is actually done.
+ *
+ * TODO: do in-memory hollow structure for the tags.
+ */
+
+class Segment : public Base {
+ public:
+ /**
+ * Main constructor.
+ *
+ * @param size is the real data size of this segment.
+ * @param id is the static id for that data segment.
+ * @param cpu_base is the base absolute physical address for that segment in the cpu's flat memory.
+ * @param extra_size gives the size of the uninitialized memory at the end of the segment, typically the bss part.
+ * @param data optionally holds the memory to use for this segment. If it's provided, the caller MUST NOT free it, as it's going to be used directly.
+ */
+ Segment(Uint32 size, Uint32 id, Uint64 cpu_base, Uint32 extra_size = 0, const Byte * data = 0);
+ ~Segment();
+ Uint32 getId() { return id; }
+ /** Will return the byte for that pointer in the segment. May be patched.
+ * @param ptr is the pointer for the byte to be retrieved.
+ * @return the byte read, or -1 if it's inside the BSS part, or outside the whole segment.
+ */
+ short Read(Uint32 ptr);
+ /** Will return the byte for that pointer in the segment. Will NOT be patched.
+ * @param ptr is the pointer for the byte to be retrieved.
+ * @return the byte read, or -1 if it's inside the BSS part, or outside the whole segment.
+ */
+ short RawRead(Uint32 ptr);
+ /** In case you need to read the (unpatched) memory block.
+ * @return the memory block of the segment.
+ */
+ const Byte * getPristineMemory() { return plainmemory; }
+ void Patch(Uint32 ptr, Byte val);
+ void Restore(Uint32 ptr);
+ bool IsPatched(Uint32 ptr);
+ bool IsLoaded() { return loaded; }
+ /** Will load the memory segment with the provided Handle; will
+ * only work if you didn't provide data during the constructor.
+ * @see Segment()
+ */
+ void LoadMemory(Handle * src);
+ void setTag(Uint32 ptr, memory_tags_t tag);
+ memory_tags_t getTag(Uint32 ptr);
+ Uint32 getSize() { return size; }
+ Uint64 getFullSize() { return size + extra_size; }
+ Uint64 getCpuBase() { return cpu_base; }
+ SegmentRefData * getSegmentRefData(Uint32 ptr);
+ void setSegmentRefData(Uint32 ptr, SegmentRefData * data);
+ private:
+ Byte * plainmemory, * patches, * patchesmap;
+ SegmentRefData ** refData;
+ memory_tags_t * tags;
+ bool loaded, allocated;
+ Uint32 size, extra_size;
+ Uint32 id;
+ Uint64 cpu_base;
+}
+
+#endif