DBG: basic of the type system working
This commit is contained in:
parent
16bf75a15b
commit
022bceb8f7
|
|
@ -25,13 +25,12 @@
|
|||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <tlhelp32.h>
|
||||
#include "..\dbg_types.h"
|
||||
#include "..\dbg_assert.h"
|
||||
#include "..\bridge\bridgemain.h"
|
||||
#include "jansson\jansson.h"
|
||||
#include "jansson\jansson_x64dbg.h"
|
||||
#include "yara\yara.h"
|
||||
#include "DeviceNameResolver\DeviceNameResolver.h"
|
||||
#include "../dbg_types.h"
|
||||
#include "../dbg_assert.h"
|
||||
#include "../bridge\bridgemain.h"
|
||||
#include "jansson/jansson.h"
|
||||
#include "jansson/jansson_x64dbg.h"
|
||||
#include "DeviceNameResolver/DeviceNameResolver.h"
|
||||
#include "handle.h"
|
||||
#include "stringutils.h"
|
||||
#include "dbghelp_safe.h"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "debugger.h"
|
||||
#include "filehelper.h"
|
||||
#include "label.h"
|
||||
#include "yara/yara.h"
|
||||
|
||||
static int maxFindResults = 5000;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
#include "console.h"
|
||||
#include "encodemap.h"
|
||||
#include "value.h"
|
||||
#include "types.h"
|
||||
#include "memory.h"
|
||||
|
||||
using namespace Types;
|
||||
|
||||
static CMDRESULT cbInstrDataGeneric(ENCODETYPE type, int argc, char* argv[])
|
||||
{
|
||||
|
|
@ -120,4 +124,470 @@ CMDRESULT cbInstrDataJunk(int argc, char* argv[])
|
|||
CMDRESULT cbInstrDataMiddle(int argc, char* argv[])
|
||||
{
|
||||
return cbInstrDataGeneric(enc_middle, argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
#define towner "cmd"
|
||||
|
||||
CMDRESULT cbInstrAddType(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 3))
|
||||
return STATUS_ERROR;
|
||||
if(!AddType(towner, argv[1], argv[2]))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "AddType failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf_untranslated("typedef %s %s;\n", argv[2], argv[1]);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrAddStruct(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 2))
|
||||
return STATUS_ERROR;
|
||||
if(!AddStruct(towner, argv[1]))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "AddStruct failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf_untranslated("struct %s;\n", argv[1]);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrAddUnion(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 2))
|
||||
return STATUS_ERROR;
|
||||
if(!AddUnion(towner, argv[1]))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "AddUnion failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf_untranslated("union %s;\n", argv[1]);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrAddMember(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 4))
|
||||
return STATUS_ERROR;
|
||||
auto parent = argv[1];
|
||||
auto type = argv[2];
|
||||
auto name = argv[3];
|
||||
int arrsize = 0, offset = -1;
|
||||
if(argc > 3)
|
||||
{
|
||||
duint value;
|
||||
if(!valfromstring(argv[4], &value, false))
|
||||
return STATUS_ERROR;
|
||||
arrsize = int(value);
|
||||
if(argc > 4)
|
||||
{
|
||||
if(!valfromstring(argv[5], &value, false))
|
||||
return STATUS_ERROR;
|
||||
offset = int(value);
|
||||
}
|
||||
}
|
||||
if(!AddMember(parent, type, name, arrsize, offset))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "AddMember failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf_untranslated("%s: %s %s", parent, type, name);
|
||||
if(arrsize > 0)
|
||||
dprintf_untranslated("[%d]", arrsize);
|
||||
if(offset >= 0)
|
||||
dprintf_untranslated(" (offset: %d)", offset);
|
||||
dputs_untranslated(";");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrAppendMember(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 3))
|
||||
return STATUS_ERROR;
|
||||
auto type = argv[1];
|
||||
auto name = argv[2];
|
||||
int arrsize = 0, offset = -1;
|
||||
if(argc > 3)
|
||||
{
|
||||
duint value;
|
||||
if(!valfromstring(argv[3], &value, false))
|
||||
return STATUS_ERROR;
|
||||
arrsize = int(value);
|
||||
if(argc > 4)
|
||||
{
|
||||
if(!valfromstring(argv[4], &value, false))
|
||||
return STATUS_ERROR;
|
||||
offset = int(value);
|
||||
}
|
||||
}
|
||||
if(!AppendMember(type, name, arrsize, offset))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "AppendMember failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf_untranslated("%s %s", type, name);
|
||||
if(arrsize > 0)
|
||||
dprintf_untranslated("[%d]", arrsize);
|
||||
if(offset >= 0)
|
||||
dprintf_untranslated(" (offset: %d)", offset);
|
||||
dputs_untranslated(";");
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrAddFunction(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 3))
|
||||
return STATUS_ERROR;
|
||||
auto name = argv[1];
|
||||
auto rettype = argv[2];
|
||||
auto callconv = Cdecl;
|
||||
auto noreturn = false;
|
||||
if(argc > 3)
|
||||
{
|
||||
if(scmp(argv[3], "cdecl"))
|
||||
callconv = Cdecl;
|
||||
else if(scmp(argv[3], "stdcall"))
|
||||
callconv = Stdcall;
|
||||
else if(scmp(argv[3], "thiscall"))
|
||||
callconv = Thiscall;
|
||||
else if(scmp(argv[3], "delphi"))
|
||||
callconv = Delphi;
|
||||
else
|
||||
{
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Unknown calling convention \"%s\"\n"), argv[3]);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if(argc > 4)
|
||||
{
|
||||
duint value;
|
||||
if(!valfromstring(argv[4], &value, false))
|
||||
return STATUS_ERROR;
|
||||
noreturn = value != 0;
|
||||
}
|
||||
}
|
||||
if(!AddFunction(towner, name, rettype, callconv, noreturn))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "AddFunction failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf_untranslated("%s %s();\n", rettype, name);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrAddArg(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 4))
|
||||
return STATUS_ERROR;
|
||||
if(!AddArg(argv[1], argv[2], argv[3]))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "AddArg failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf_untranslated("%s: %s %s;\n", argv[1], argv[2], argv[3]);
|
||||
return STATUS_CONTINUE;
|
||||
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrAppendArg(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 3))
|
||||
return STATUS_ERROR;
|
||||
if(!AppendArg(argv[1], argv[2]))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "AppendArg failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf_untranslated("%s %s;\n", argv[1], argv[2]);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrSizeofType(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 2))
|
||||
return STATUS_ERROR;
|
||||
auto size = SizeofType(argv[1]);
|
||||
if(!size)
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "SizeofType failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf_untranslated("sizeof(%s) = %d\n", argv[1], size);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
struct PrintVisitor : TypeManager::Visitor
|
||||
{
|
||||
explicit PrintVisitor(duint data = 0, int maxPtrDepth = 0)
|
||||
: mAddr(data), mMaxPtrDepth(maxPtrDepth) { }
|
||||
|
||||
template<typename T>
|
||||
static String basicPrint(void* data, const char* format)
|
||||
{
|
||||
return StringUtils::sprintf(format, *(T*)data);
|
||||
}
|
||||
|
||||
bool visitType(const Member & member, const Type & type) override
|
||||
{
|
||||
String valueStr;
|
||||
Memory<unsigned char*> data(type.size);
|
||||
if(mAddr)
|
||||
{
|
||||
if(MemRead(mAddr + mOffset, data(), data.size()))
|
||||
{
|
||||
valueStr.assign(" = ");
|
||||
switch(type.primitive)
|
||||
{
|
||||
case Int8:
|
||||
valueStr += basicPrint<char>(data(), "%c");
|
||||
break;
|
||||
case Uint8:
|
||||
valueStr += basicPrint<unsigned char>(data(), "0x%02X");
|
||||
break;
|
||||
case Int16:
|
||||
valueStr += basicPrint<short>(data(), "%d");
|
||||
break;
|
||||
case Uint16:
|
||||
valueStr += basicPrint<short>(data(), "%u");
|
||||
break;
|
||||
case Int32:
|
||||
valueStr += basicPrint<int>(data(), "%d");
|
||||
break;
|
||||
case Uint32:
|
||||
valueStr += basicPrint<unsigned int>(data(), "%u");
|
||||
break;
|
||||
case Int64:
|
||||
valueStr += basicPrint<long long>(data(), "%lld");
|
||||
break;
|
||||
case Uint64:
|
||||
valueStr += basicPrint<unsigned long long>(data(), "%llu");
|
||||
break;
|
||||
case Dsint:
|
||||
#ifdef _WIN64
|
||||
valueStr += basicPrint<dsint>(data(), "%lld");
|
||||
#else
|
||||
valueStr += basicPrint<dsint>(data(), "%d");
|
||||
#endif //_WIN64
|
||||
break;
|
||||
case Duint:
|
||||
#ifdef _WIN64
|
||||
valueStr += basicPrint<duint>(data(), "%llu");
|
||||
#else
|
||||
valueStr += basicPrint<duint>(data(), "%u");
|
||||
#endif //_WIN64
|
||||
break;
|
||||
case Float:
|
||||
valueStr += basicPrint<float>(data(), "%f");
|
||||
break;
|
||||
case Double:
|
||||
valueStr += basicPrint<double>(data(), "%f");
|
||||
break;
|
||||
case Pointer:
|
||||
valueStr += basicPrint<void*>(data(), "0x%p");
|
||||
break;
|
||||
case PtrString:
|
||||
{
|
||||
valueStr += basicPrint<char*>(data(), "0x%p");
|
||||
Memory<char*> strdata(MAX_STRING_SIZE + 1);
|
||||
if(MemRead(*(duint*)data(), strdata(), strdata.size() - 1))
|
||||
{
|
||||
valueStr += " \"";
|
||||
valueStr += strdata();
|
||||
valueStr.push_back('\"');
|
||||
}
|
||||
else
|
||||
valueStr += " ???";
|
||||
}
|
||||
break;
|
||||
|
||||
case PtrWString:
|
||||
{
|
||||
valueStr += basicPrint<wchar_t*>(data(), "0x%p");
|
||||
Memory<wchar_t*> strdata(MAX_STRING_SIZE * 2 + 2);
|
||||
if(MemRead(*(duint*)data(), strdata(), strdata.size() - 2))
|
||||
{
|
||||
valueStr += " L\"";
|
||||
valueStr += StringUtils::Utf16ToUtf8(strdata());
|
||||
valueStr.push_back('\"');
|
||||
}
|
||||
else
|
||||
valueStr += " ???";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
valueStr = " ???";
|
||||
}
|
||||
indent();
|
||||
auto ptype = mParents.empty() ? Parent::Struct : parent().type;
|
||||
if(ptype == Parent::Array)
|
||||
dprintf_untranslated("%s[%u]%s;", member.name.c_str(), parent().index++, valueStr.c_str());
|
||||
else
|
||||
dprintf_untranslated("%s %s%s;", type.name.c_str(), member.name.c_str(), valueStr.c_str());
|
||||
dputs_untranslated(type.pointto.empty() || mPtrDepth >= mMaxPtrDepth ? "" : " {");
|
||||
if(ptype != Parent::Union)
|
||||
mOffset += type.size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visitStructUnion(const Member & member, const StructUnion & type) override
|
||||
{
|
||||
indent();
|
||||
dprintf_untranslated("%s %s {\n", type.isunion ? "union" : "struct", type.name.c_str());
|
||||
mParents.push_back(Parent(type.isunion ? Parent::Union : Parent::Struct));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visitArray(const Member & member) override
|
||||
{
|
||||
indent();
|
||||
dprintf_untranslated("%s %s[%d] {\n", member.type.c_str(), member.name.c_str(), member.arrsize);
|
||||
mParents.push_back(Parent(Parent::Array));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visitPtr(const Member & member, const Type & type) override
|
||||
{
|
||||
auto offset = mOffset;
|
||||
auto res = visitType(member, type); //print the pointer value
|
||||
if(mPtrDepth >= mMaxPtrDepth)
|
||||
return false;
|
||||
duint value = 0;
|
||||
if(!mAddr || !MemRead(mAddr + offset, &value, sizeof(value)))
|
||||
return false;
|
||||
mParents.push_back(Parent(Parent::Pointer));
|
||||
parent().offset = mOffset;
|
||||
parent().addr = mAddr;
|
||||
mOffset = 0;
|
||||
mAddr = value;
|
||||
mPtrDepth++;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool visitBack(const Member & member) override
|
||||
{
|
||||
if(parent().type == Parent::Pointer)
|
||||
{
|
||||
mOffset = parent().offset;
|
||||
mAddr = parent().addr;
|
||||
mPtrDepth--;
|
||||
}
|
||||
mParents.pop_back();
|
||||
indent();
|
||||
if(parent().type == Parent::Array)
|
||||
dprintf_untranslated("};\n");
|
||||
else
|
||||
dprintf_untranslated("} %s;\n", member.name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Parent
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
Struct,
|
||||
Union,
|
||||
Array,
|
||||
Pointer
|
||||
};
|
||||
|
||||
Type type;
|
||||
unsigned int index = 0;
|
||||
duint addr = 0;
|
||||
duint offset = 0;
|
||||
|
||||
explicit Parent(Type type)
|
||||
: type(type) { }
|
||||
};
|
||||
|
||||
Parent & parent()
|
||||
{
|
||||
return mParents[mParents.size() - 1];
|
||||
}
|
||||
|
||||
void indent() const
|
||||
{
|
||||
if(mAddr)
|
||||
dprintf_untranslated("%p ", mAddr + mOffset);
|
||||
for(auto i = 0; i < int(mParents.size()) * 2; i++)
|
||||
dprintf_untranslated(" ");
|
||||
}
|
||||
|
||||
std::vector<Parent> mParents;
|
||||
duint mOffset = 0;
|
||||
duint mAddr = 0;
|
||||
int mPtrDepth = 0;
|
||||
int mMaxPtrDepth = 0;
|
||||
};
|
||||
|
||||
CMDRESULT cbInstrVisitType(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 2))
|
||||
return STATUS_ERROR;
|
||||
auto type = argv[1];
|
||||
auto name = "visit";
|
||||
duint addr = 0;
|
||||
auto maxPtrDepth = 0;
|
||||
if(argc > 2)
|
||||
{
|
||||
if(!valfromstring(argv[2], &addr, false))
|
||||
return STATUS_ERROR;
|
||||
if(argc > 3)
|
||||
{
|
||||
duint value;
|
||||
if(!valfromstring(argv[3], &value, false))
|
||||
return STATUS_ERROR;
|
||||
maxPtrDepth = int(value);
|
||||
if(argc > 4)
|
||||
name = argv[4];
|
||||
}
|
||||
}
|
||||
PrintVisitor visitor(addr, maxPtrDepth);
|
||||
if(!VisitType(type, name, visitor))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "VisitType failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrClearTypes(int argc, char* argv[])
|
||||
{
|
||||
auto owner = towner;
|
||||
if(argc > 1)
|
||||
owner = argv[1];
|
||||
ClearTypes(owner);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrRemoveType(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 2))
|
||||
return STATUS_ERROR;
|
||||
if(!RemoveType(argv[1]))
|
||||
{
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "RemoveType failed"));
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Type %s removed\n"), argv[1]);
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrEnumTypes(int argc, char* argv[])
|
||||
{
|
||||
std::vector<TypeManager::Summary> typeList;
|
||||
EnumTypes(typeList);
|
||||
for(auto & type : typeList)
|
||||
{
|
||||
if(type.owner.empty())
|
||||
type.owner.assign("x64dbg");
|
||||
dprintf_untranslated("%s: %s %s, sizeof(%s) = %d\n", type.owner.c_str(), type.kind.c_str(), type.name.c_str(), type.name.c_str(), type.size);
|
||||
}
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,4 +20,18 @@ CMDRESULT cbInstrDataAscii(int argc, char* argv[]);
|
|||
CMDRESULT cbInstrDataUnicode(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrDataCode(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrDataJunk(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrDataMiddle(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrDataMiddle(int argc, char* argv[]);
|
||||
|
||||
CMDRESULT cbInstrAddType(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAddStruct(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAddUnion(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAddMember(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAppendMember(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAddFunction(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAddArg(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAppendArg(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrSizeofType(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrVisitType(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrClearTypes(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrRemoveType(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrEnumTypes(int argc, char* argv[]);
|
||||
|
|
@ -69,6 +69,7 @@ enum SectionLock
|
|||
LockHistory,
|
||||
LockSymbolCache,
|
||||
LockLineCache,
|
||||
LockTypeManager,
|
||||
|
||||
// Number of elements in this enumeration. Must always be the last
|
||||
// index.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,427 @@
|
|||
#include "types.h"
|
||||
#include "stringutils.h"
|
||||
#include "threading.h"
|
||||
|
||||
using namespace Types;
|
||||
|
||||
static TypeManager typeManager;
|
||||
|
||||
TypeManager::TypeManager()
|
||||
{
|
||||
auto p = [this](const std::string & n, Primitive p, int size)
|
||||
{
|
||||
primitivesizes[p] = size;
|
||||
auto splits = StringUtils::Split(n, ',');
|
||||
for(const auto & split : splits)
|
||||
addType("", p, split);
|
||||
};
|
||||
p("int8_t,int8,char,byte,bool,signed char", Int8, sizeof(char));
|
||||
p("uint8_t,uint8,uchar,unsigned char,ubyte", Uint8, sizeof(unsigned char));
|
||||
p("int16_t,int16,wchar_t,char16_t,short", Int16, sizeof(short));
|
||||
p("uint16_t,uint16,ushort,unsigned short", Int16, sizeof(unsigned short));
|
||||
p("int32_t,int32,int,long", Int32, sizeof(int));
|
||||
p("uint32_t,uint32,unsigned int,unsigned long", Uint32, sizeof(unsigned int));
|
||||
p("int64_t,int64,long long", Int64, sizeof(long long));
|
||||
p("uint64_t,uint64,unsigned long long", Uint64, sizeof(unsigned long long));
|
||||
p("dsint", Dsint, sizeof(void*));
|
||||
p("duint,size_t", Duint, sizeof(void*));
|
||||
p("float", Float, sizeof(float));
|
||||
p("double", Double, sizeof(double));
|
||||
p("ptr,void*", Pointer, sizeof(void*));
|
||||
p("char*,const char*", PtrString, sizeof(char*));
|
||||
p("wchar_t*,const wchar_t*", PtrWString, sizeof(wchar_t*));
|
||||
}
|
||||
|
||||
bool TypeManager::AddType(const std::string & owner, const std::string & type, const std::string & name)
|
||||
{
|
||||
if(owner.empty())
|
||||
return false;
|
||||
validPtr(type);
|
||||
auto found = types.find(type);
|
||||
if(found == types.end())
|
||||
return false;
|
||||
return addType(owner, found->second.primitive, name);
|
||||
}
|
||||
|
||||
bool TypeManager::AddStruct(const std::string & owner, const std::string & name)
|
||||
{
|
||||
StructUnion s;
|
||||
s.name = name;
|
||||
s.owner = owner;
|
||||
return addStructUnion(s);
|
||||
}
|
||||
|
||||
bool TypeManager::AddUnion(const std::string & owner, const std::string & name)
|
||||
{
|
||||
StructUnion u;
|
||||
u.owner = owner;
|
||||
u.name = name;
|
||||
u.isunion = true;
|
||||
return addStructUnion(u);
|
||||
}
|
||||
|
||||
bool TypeManager::AddMember(const std::string & parent, const std::string & type, const std::string & name, int arrsize, int offset)
|
||||
{
|
||||
if(!isDefined(type) && !validPtr(type))
|
||||
return false;
|
||||
auto found = structs.find(parent);
|
||||
if(arrsize < 0 || found == structs.end() || !isDefined(type) || name.empty() || type.empty() || type == parent)
|
||||
return false;
|
||||
auto & s = found->second;
|
||||
|
||||
for(const auto & member : s.members)
|
||||
if(member.name == name)
|
||||
return false;
|
||||
|
||||
auto typeSize = Sizeof(type);
|
||||
if(arrsize)
|
||||
typeSize *= arrsize;
|
||||
|
||||
Member m;
|
||||
m.name = name;
|
||||
m.arrsize = arrsize;
|
||||
m.type = type;
|
||||
|
||||
if(offset >= 0) //user-defined offset
|
||||
{
|
||||
if(offset < s.size)
|
||||
return false;
|
||||
if(offset > s.size)
|
||||
{
|
||||
Member pad;
|
||||
pad.type = "char";
|
||||
pad.arrsize = offset - s.size;
|
||||
char padname[32] = "";
|
||||
sprintf_s(padname, "padding%d", pad.arrsize);
|
||||
pad.name = padname;
|
||||
s.members.push_back(m);
|
||||
s.size += pad.arrsize;
|
||||
}
|
||||
}
|
||||
|
||||
s.members.push_back(m);
|
||||
|
||||
if(s.isunion)
|
||||
{
|
||||
if(typeSize > s.size)
|
||||
s.size = typeSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
s.size += typeSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeManager::AppendMember(const std::string & type, const std::string & name, int arrsize, int offset)
|
||||
{
|
||||
return AddMember(laststruct, type, name, arrsize, offset);
|
||||
}
|
||||
|
||||
bool TypeManager::AddFunction(const std::string & owner, const std::string & name, const std::string & rettype, CallingConvention callconv, bool noreturn)
|
||||
{
|
||||
auto found = functions.find(name);
|
||||
if(found != functions.end() || name.empty() || owner.empty())
|
||||
return false;
|
||||
lastfunction = name;
|
||||
Function f;
|
||||
f.owner = owner;
|
||||
f.name = name;
|
||||
f.rettype = rettype;
|
||||
f.callconv = callconv;
|
||||
f.noreturn = noreturn;
|
||||
functions.insert({f.name, f});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeManager::AddArg(const std::string & function, const std::string & type, const std::string & name)
|
||||
{
|
||||
if(!isDefined(type) && !validPtr(type))
|
||||
return false;
|
||||
auto found = functions.find(function);
|
||||
if(found == functions.end() || function.empty() || name.empty() || !isDefined(type))
|
||||
return false;
|
||||
lastfunction = function;
|
||||
Member arg;
|
||||
arg.name = name;
|
||||
arg.type = type;
|
||||
found->second.args.push_back(arg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeManager::AppendArg(const std::string & type, const std::string & name)
|
||||
{
|
||||
return AddArg(lastfunction, type, name);
|
||||
}
|
||||
|
||||
int TypeManager::Sizeof(const std::string & type) const
|
||||
{
|
||||
auto foundT = types.find(type);
|
||||
if(foundT != types.end())
|
||||
return foundT->second.size;
|
||||
auto foundS = structs.find(type);
|
||||
if(foundS != structs.end())
|
||||
return foundS->second.size;
|
||||
auto foundF = functions.find(type);
|
||||
if(foundF != functions.end())
|
||||
{
|
||||
const auto foundP = primitivesizes.find(Pointer);
|
||||
if(foundP != primitivesizes.end())
|
||||
return foundP->second;
|
||||
return sizeof(void*);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool TypeManager::Visit(const std::string & type, const std::string & name, Visitor & visitor) const
|
||||
{
|
||||
Member m;
|
||||
m.name = name;
|
||||
m.type = type;
|
||||
return visitMember(m, visitor);
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
static void filterOwnerMap(std::unordered_map<K, V> & map, const std::string & owner)
|
||||
{
|
||||
for(auto i = map.begin(); i != map.end();)
|
||||
{
|
||||
auto j = i++;
|
||||
if(j->second.owner.empty())
|
||||
continue;
|
||||
if(owner.empty() || j->second.owner == owner)
|
||||
map.erase(j);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeManager::Clear(const std::string & owner)
|
||||
{
|
||||
laststruct.clear();
|
||||
lastfunction.clear();
|
||||
filterOwnerMap(types, owner);
|
||||
filterOwnerMap(structs, owner);
|
||||
filterOwnerMap(functions, owner);
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
static bool removeType(std::unordered_map<K, V> & map, const std::string & type)
|
||||
{
|
||||
auto found = map.find(type);
|
||||
if(found == map.end())
|
||||
return false;
|
||||
if(found->second.owner.empty())
|
||||
return false;
|
||||
map.erase(found);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeManager::RemoveType(const std::string & type)
|
||||
{
|
||||
return removeType(types, type) || removeType(structs, type) || removeType(functions, type);
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
static void enumType(const std::unordered_map<K, V> & map, const std::string & kind, std::vector<TypeManager::Summary> & types)
|
||||
{
|
||||
for(auto i = map.begin(); i != map.end(); ++i)
|
||||
{
|
||||
TypeManager::Summary s;
|
||||
s.kind = kind;
|
||||
s.name = i->second.name;
|
||||
s.owner = i->second.owner;
|
||||
s.size = SizeofType(s.name);
|
||||
types.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeManager::Enum(std::vector<Summary> & typeList) const
|
||||
{
|
||||
typeList.clear();
|
||||
enumType(types, "typedef", typeList);
|
||||
enumType(structs, "structunion", typeList);
|
||||
enumType(functions, "function", typeList);
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
static bool mapContains(const std::unordered_map<K, V> & map, const K & k)
|
||||
{
|
||||
return map.find(k) != map.end();
|
||||
}
|
||||
|
||||
bool TypeManager::isDefined(const std::string & id) const
|
||||
{
|
||||
return mapContains(types, id) || mapContains(structs, id);
|
||||
}
|
||||
|
||||
bool TypeManager::validPtr(const std::string & id)
|
||||
{
|
||||
if(id[id.length() - 1] == '*')
|
||||
{
|
||||
auto type = id.substr(0, id.length() - 1);
|
||||
if(!isDefined(type))
|
||||
return false;
|
||||
std::string owner("ptr");
|
||||
auto foundT = types.find(type);
|
||||
if(foundT != types.end())
|
||||
owner = foundT->second.owner;
|
||||
auto foundS = structs.find(type);
|
||||
if(foundS != structs.end())
|
||||
owner = foundS->second.owner;
|
||||
return addType(owner, Pointer, id, type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TypeManager::addStructUnion(const StructUnion & s)
|
||||
{
|
||||
laststruct = s.name;
|
||||
if(s.owner.empty() || s.name.empty() || isDefined(s.name))
|
||||
return false;
|
||||
structs.insert({s.name, s});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeManager::addType(const Type & t)
|
||||
{
|
||||
if(t.name.empty() || isDefined(t.name))
|
||||
return false;
|
||||
types.insert({t.name, t});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TypeManager::addType(const std::string & owner, Primitive primitive, const std::string & name, const std::string & pointto)
|
||||
{
|
||||
if(name.empty() || isDefined(name))
|
||||
return false;
|
||||
Type t;
|
||||
t.owner = owner;
|
||||
t.name = name;
|
||||
t.primitive = primitive;
|
||||
t.size = primitivesizes[primitive];
|
||||
t.pointto = pointto;
|
||||
return addType(t);
|
||||
}
|
||||
|
||||
bool TypeManager::visitMember(const Member & root, Visitor & visitor) const
|
||||
{
|
||||
auto foundT = types.find(root.type);
|
||||
if(foundT != types.end())
|
||||
{
|
||||
const auto & t = foundT->second;
|
||||
if(!t.pointto.empty())
|
||||
{
|
||||
if(!isDefined(t.pointto))
|
||||
return false;
|
||||
if(visitor.visitPtr(root, t)) //allow the visitor to bail out
|
||||
{
|
||||
if(!Visit(t.pointto, "*" + root.name, visitor))
|
||||
return false;
|
||||
return visitor.visitBack(root);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return visitor.visitType(root, t);
|
||||
}
|
||||
auto foundS = structs.find(root.type);
|
||||
if(foundS != structs.end())
|
||||
{
|
||||
const auto & s = foundS->second;
|
||||
if(!visitor.visitStructUnion(root, s))
|
||||
return false;
|
||||
for(const auto & child : s.members)
|
||||
{
|
||||
if(child.arrsize)
|
||||
{
|
||||
if(!visitor.visitArray(child))
|
||||
return false;
|
||||
for(auto i = 0; i < child.arrsize; i++)
|
||||
if(!visitMember(child, visitor))
|
||||
return false;
|
||||
if(!visitor.visitBack(child))
|
||||
return false;
|
||||
}
|
||||
else if(!visitMember(child, visitor))
|
||||
return false;
|
||||
}
|
||||
return visitor.visitBack(root);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AddType(const std::string & owner, const std::string & type, const std::string & name)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.AddType(owner, type, name);
|
||||
}
|
||||
|
||||
bool AddStruct(const std::string & owner, const std::string & name)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.AddStruct(owner, name);
|
||||
}
|
||||
|
||||
bool AddUnion(const std::string & owner, const std::string & name)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.AddUnion(owner, name);
|
||||
}
|
||||
|
||||
bool AddMember(const std::string & parent, const std::string & type, const std::string & name, int arrsize, int offset)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.AddMember(parent, type, name, arrsize, offset);
|
||||
}
|
||||
|
||||
bool AppendMember(const std::string & type, const std::string & name, int arrsize, int offset)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.AppendMember(type, name, arrsize, offset);
|
||||
}
|
||||
|
||||
bool AddFunction(const std::string & owner, const std::string & name, const std::string & rettype, Types::CallingConvention callconv, bool noreturn)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.AddFunction(owner, name, rettype, callconv, noreturn);
|
||||
}
|
||||
|
||||
bool AddArg(const std::string & function, const std::string & type, const std::string & name)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.AddArg(function, type, name);
|
||||
}
|
||||
|
||||
bool AppendArg(const std::string & type, const std::string & name)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.AppendArg(type, name);
|
||||
}
|
||||
|
||||
int SizeofType(const std::string & type)
|
||||
{
|
||||
SHARED_ACQUIRE(LockTypeManager);
|
||||
return typeManager.Sizeof(type);
|
||||
}
|
||||
|
||||
bool VisitType(const std::string & type, const std::string & name, Types::TypeManager::Visitor & visitor)
|
||||
{
|
||||
SHARED_ACQUIRE(LockTypeManager);
|
||||
return typeManager.Visit(type, name, visitor);
|
||||
}
|
||||
|
||||
void ClearTypes(const std::string & owner)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.Clear(owner);
|
||||
}
|
||||
|
||||
bool RemoveType(const std::string & type)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
return typeManager.RemoveType(type);
|
||||
}
|
||||
|
||||
void EnumTypes(std::vector<Types::TypeManager::Summary> & typeList)
|
||||
{
|
||||
SHARED_ACQUIRE(LockTypeManager);
|
||||
return typeManager.Enum(typeList);
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Types
|
||||
{
|
||||
enum Primitive
|
||||
{
|
||||
Int8,
|
||||
Uint8,
|
||||
Int16,
|
||||
Uint16,
|
||||
Int32,
|
||||
Uint32,
|
||||
Int64,
|
||||
Uint64,
|
||||
Dsint,
|
||||
Duint,
|
||||
Float,
|
||||
Double,
|
||||
Pointer,
|
||||
PtrString, //char* (null-terminated)
|
||||
PtrWString //wchar_t* (null-terminated)
|
||||
};
|
||||
|
||||
struct Type
|
||||
{
|
||||
std::string owner; //Type owner
|
||||
std::string name; //Type identifier.
|
||||
std::string pointto; //Type identifier of *Type
|
||||
Primitive primitive; //Primitive type.
|
||||
int size = 0; //Size in bytes.
|
||||
};
|
||||
|
||||
struct Member
|
||||
{
|
||||
std::string name; //Member identifier
|
||||
std::string type; //Type.name
|
||||
int arrsize = 0; //Number of elements if Member is an array
|
||||
};
|
||||
|
||||
struct StructUnion
|
||||
{
|
||||
std::string owner; //StructUnion owner
|
||||
std::string name; //StructUnion identifier
|
||||
std::vector<Member> members; //StructUnion members
|
||||
bool isunion = false; //Is this a union?
|
||||
int size = 0;
|
||||
};
|
||||
|
||||
enum CallingConvention
|
||||
{
|
||||
Cdecl,
|
||||
Stdcall,
|
||||
Thiscall,
|
||||
Delphi
|
||||
};
|
||||
|
||||
struct Function
|
||||
{
|
||||
std::string owner; //Function owner
|
||||
std::string name; //Function identifier
|
||||
std::string rettype; //Function return type
|
||||
CallingConvention callconv; //Function calling convention
|
||||
bool noreturn; //Function does not return (ExitProcess, _exit)
|
||||
std::vector<Member> args; //Function arguments
|
||||
};
|
||||
|
||||
struct TypeManager
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
virtual ~Visitor() { }
|
||||
virtual bool visitType(const Member & member, const Type & type) = 0;
|
||||
virtual bool visitStructUnion(const Member & member, const StructUnion & type) = 0;
|
||||
virtual bool visitArray(const Member & member) = 0;
|
||||
virtual bool visitPtr(const Member & member, const Type & type) = 0;
|
||||
virtual bool visitBack(const Member & member) = 0;
|
||||
};
|
||||
|
||||
struct Summary
|
||||
{
|
||||
std::string kind;
|
||||
std::string name;
|
||||
std::string owner;
|
||||
int size;
|
||||
};
|
||||
|
||||
explicit TypeManager();
|
||||
bool AddType(const std::string & owner, const std::string & type, const std::string & name);
|
||||
bool AddStruct(const std::string & owner, const std::string & name);
|
||||
bool AddUnion(const std::string & owner, const std::string & name);
|
||||
bool AddMember(const std::string & parent, const std::string & type, const std::string & name, int arrsize = 0, int offset = -1);
|
||||
bool AppendMember(const std::string & type, const std::string & name, int arrsize = 0, int offset = -1);
|
||||
bool AddFunction(const std::string & owner, const std::string & name, const std::string & rettype, CallingConvention callconv = Cdecl, bool noreturn = false);
|
||||
bool AddArg(const std::string & function, const std::string & type, const std::string & name);
|
||||
bool AppendArg(const std::string & type, const std::string & name);
|
||||
int Sizeof(const std::string & type) const;
|
||||
bool Visit(const std::string & type, const std::string & name, Visitor & visitor) const;
|
||||
void Clear(const std::string & owner = "");
|
||||
bool RemoveType(const std::string & type);
|
||||
void Enum(std::vector<Summary> & typeList) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<Primitive, int> primitivesizes;
|
||||
std::unordered_map<std::string, Type> types;
|
||||
std::unordered_map<std::string, StructUnion> structs;
|
||||
std::unordered_map<std::string, Function> functions;
|
||||
std::string laststruct;
|
||||
std::string lastfunction;
|
||||
|
||||
bool isDefined(const std::string & id) const;
|
||||
bool validPtr(const std::string & id);
|
||||
bool addStructUnion(const StructUnion & s);
|
||||
bool addType(const std::string & owner, Primitive primitive, const std::string & name, const std::string & pointto = "");
|
||||
bool addType(const Type & t);
|
||||
bool visitMember(const Member & root, Visitor & visitor) const;
|
||||
};
|
||||
};
|
||||
|
||||
bool AddType(const std::string & owner, const std::string & type, const std::string & name);
|
||||
bool AddStruct(const std::string & owner, const std::string & name);
|
||||
bool AddUnion(const std::string & owner, const std::string & name);
|
||||
bool AddMember(const std::string & parent, const std::string & type, const std::string & name, int arrsize = 0, int offset = -1);
|
||||
bool AppendMember(const std::string & type, const std::string & name, int arrsize = 0, int offset = -1);
|
||||
bool AddFunction(const std::string & owner, const std::string & name, const std::string & rettype, Types::CallingConvention callconv = Types::Cdecl, bool noreturn = false);
|
||||
bool AddArg(const std::string & function, const std::string & type, const std::string & name);
|
||||
bool AppendArg(const std::string & type, const std::string & name);
|
||||
int SizeofType(const std::string & type);
|
||||
bool VisitType(const std::string & type, const std::string & name, Types::TypeManager::Visitor & visitor);
|
||||
void ClearTypes(const std::string & owner = "");
|
||||
bool RemoveType(const std::string & type);
|
||||
void EnumTypes(std::vector<Types::TypeManager::Summary> & typeList);
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include "datainst_helper.h"
|
||||
#include "exception.h"
|
||||
#include "expressionfunctions.h"
|
||||
#include "yara/yara.h"
|
||||
|
||||
static MESSAGE_STACK* gMsgStack = 0;
|
||||
static HANDLE hCommandLoopThread = 0;
|
||||
|
|
@ -341,6 +342,20 @@ static void registercommands()
|
|||
dbgcmdnew("DataJunk", cbInstrDataJunk, true); //mark as Junk
|
||||
dbgcmdnew("DataMiddle", cbInstrDataMiddle, true); //mark as Middle
|
||||
|
||||
dbgcmdnew("AddType", cbInstrAddType, false); //AddType
|
||||
dbgcmdnew("AddStruct", cbInstrAddStruct, false); //AddStruct
|
||||
dbgcmdnew("AddUnion", cbInstrAddUnion, false); //AddUnion
|
||||
dbgcmdnew("AddMember", cbInstrAddMember, false); //AddMember
|
||||
dbgcmdnew("AppendMember", cbInstrAppendMember, false); //AppendMember
|
||||
dbgcmdnew("AddFunction", cbInstrAddFunction, false); //AddFunction
|
||||
dbgcmdnew("AddArg", cbInstrAddArg, false); //AddArg
|
||||
dbgcmdnew("AppendArg", cbInstrAppendArg, false); //AppendArg
|
||||
dbgcmdnew("SizeofType", cbInstrSizeofType, false); //SizeofType
|
||||
dbgcmdnew("VisitType", cbInstrVisitType, false); //VisitType
|
||||
dbgcmdnew("ClearTypes", cbInstrClearTypes, false); //ClearTypes
|
||||
dbgcmdnew("RemoveType", cbInstrRemoveType, false); //RemoveType
|
||||
dbgcmdnew("EnumTypes", cbInstrEnumTypes, false); //EnumTypes
|
||||
|
||||
//plugins
|
||||
dbgcmdnew("StartScylla\1scylla\1imprec", cbDebugStartScylla, false); //start scylla
|
||||
dbgcmdnew("plugload\1pluginload\1loadplugin", cbInstrPluginLoad, false); //load plugin
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@
|
|||
<ClCompile Include="thread.cpp" />
|
||||
<ClCompile Include="threading.cpp" />
|
||||
<ClCompile Include="TraceRecord.cpp" />
|
||||
<ClCompile Include="types.cpp" />
|
||||
<ClCompile Include="value.cpp" />
|
||||
<ClCompile Include="variable.cpp" />
|
||||
<ClCompile Include="watch.cpp" />
|
||||
|
|
@ -223,6 +224,7 @@
|
|||
<ClInclude Include="taskthread.h" />
|
||||
<ClInclude Include="tcpconnections.h" />
|
||||
<ClInclude Include="TraceRecord.h" />
|
||||
<ClInclude Include="types.h" />
|
||||
<ClInclude Include="watch.h" />
|
||||
<ClInclude Include="xrefs.h" />
|
||||
<ClInclude Include="yara\yara\integers.h" />
|
||||
|
|
|
|||
|
|
@ -407,6 +407,9 @@
|
|||
<ClCompile Include="x64dbg.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="types.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dbghelp\dbghelp.h">
|
||||
|
|
@ -907,5 +910,8 @@
|
|||
<ClInclude Include="x64dbg.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="types.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
Reference in New Issue