Basic support for parsing virtual functions

This commit is contained in:
Duncan Ogilvie 2023-04-06 09:29:09 +02:00
parent 6d3f1f75c4
commit 2973445c5f
8 changed files with 400 additions and 427 deletions

View File

@ -44,3 +44,10 @@ DEF_KEYWORD(double)
DEF_KEYWORD(true)
DEF_KEYWORD(false)
DEF_KEYWORD(nullptr)
DEF_KEYWORD(virtual)
DEF_KEYWORD(private)
DEF_KEYWORD(public)
DEF_KEYWORD(protected)
DEF_KEYWORD(override)
DEF_KEYWORD(class)

View File

@ -258,14 +258,24 @@ Lexer::Token Lexer::getToken(size_t & tokenLineIndex)
}
//identifier/keyword
if(isalpha(mLastChar) || mLastChar == '_') //[a-zA-Z_]
if(isalpha(mLastChar) || mLastChar == '_' || (mLastChar == ':' && peekChar() == ':')) //[a-zA-Z_]
{
tokenLineIndex = mState.LineIndex - 1;
mState.IdentifierStr = mLastChar;
if (mLastChar == ':') //consume the '::'
{
mState.IdentifierStr += ':';
nextChar();
while(isalnum(mLastChar) || mLastChar == '_') //[0-9a-zA-Z_]
}
nextChar();
while(isalnum(mLastChar) || mLastChar == '_' || (mLastChar == ':' && peekChar() == ':')) //[0-9a-zA-Z_]
{
mState.IdentifierStr.push_back(mLastChar);
if(mLastChar == ':') //consume the '::'
{
mState.IdentifierStr += ':';
nextChar();
}
nextChar();
}

View File

@ -110,7 +110,8 @@ bool DebugParser(const std::string & filename)
FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData);
std::vector<std::string> errors;
if (!ParseTypes(ppData, filename, errors))
Types::TypeManager typeManager;
if (!typeManager.ParseTypes(ppData, filename, errors))
{
puts("Failed to parse types:");
for (const auto& error : errors)
@ -126,7 +127,7 @@ int main()
{
//GenerateExpectedTests();
auto ticks = GetTickCount();
DebugParser("simple.bt");
DebugParser("cursor.hpp");
//Lexer lexer;
//DebugLexer(lexer, "AndroidManifestTemplate.bt", false);
//RunLexerTests();

55
btparser/tests/cursor.hpp Normal file
View File

@ -0,0 +1,55 @@
struct TTD::Replay::IReplayEngine
{
virtual void const * TTD::Replay::ReplayEngine::UnsafeAsInterface(struct _GUID const &) const = 0;
virtual void * TTD::Replay::ReplayEngine::UnsafeAsInterface(struct _GUID const &) = 0;
virtual enum Nirvana::GuestAddress TTD::Replay::ReplayEngine::GetPebAddress() const = 0;
virtual struct TTD::SystemInfo const & TTD::Replay::ReplayEngine::GetSystemInfo() const = 0;
virtual struct TTD::Replay::PositionRange const & TTD::Replay::ReplayEngine::GetLifetime() const = 0;
virtual struct TTD::Replay::Position const & TTD::Replay::ReplayEngine::GetLastPosition() const = 0;
virtual struct TTD::Replay::Position const & TTD::Replay::ReplayEngine::GetFirstPosition() const = 0;
virtual enum TTD::Replay::RecordingType TTD::Replay::ReplayEngine::GetRecordingType() const = 0;
virtual struct TTD::Replay::ThreadInfo const & TTD::Replay::ReplayEngine::GetThreadInfo(enum TTD::Replay::UniqueThreadId) const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetThreadCount() const = 0;
virtual struct TTD::Replay::ThreadInfo const * TTD::Replay::ReplayEngine::GetThreadList() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadFirstPositionIndex() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLastPositionIndex() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLifetimeFirstPositionIndex() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLifetimeLastPositionIndex() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetThreadCreatedEventCount() const = 0;
virtual struct TTD::Replay::ThreadCreatedEvent const * TTD::Replay::ReplayEngine::GetThreadCreatedEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetThreadTerminatedEventCount() const = 0;
virtual struct TTD::Replay::ThreadTerminatedEvent const * TTD::Replay::ReplayEngine::GetThreadTerminatedEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetModuleCount() const = 0;
virtual struct TTD::Replay::Module const * TTD::Replay::ReplayEngine::GetModuleList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetModuleInstanceCount() const = 0;
virtual struct TTD::Replay::ModuleInstance const * TTD::Replay::ReplayEngine::GetModuleInstanceList() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetModuleInstanceUnloadIndex() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetModuleLoadedEventCount() const = 0;
virtual struct TTD::Replay::ModuleLoadedEvent const * TTD::Replay::ReplayEngine::GetModuleLoadedEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetModuleUnloadedEventCount() const = 0;
virtual struct TTD::Replay::ModuleUnloadedEvent const * TTD::Replay::ReplayEngine::GetModuleUnloadedEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetExceptionEventCount() const = 0;
virtual struct TTD::Replay::ExceptionEvent const * TTD::Replay::ReplayEngine::GetExceptionEventList() const = 0;
virtual struct TTD::Replay::ExceptionEvent const * TTD::Replay::ReplayEngine::GetExceptionAtOrAfterPosition(struct TTD::Replay::Position const &) const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetKeyframeCount() const = 0;
virtual struct TTD::Replay::Position const * TTD::Replay::ReplayEngine::GetKeyframeList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetRecordClientCount() const = 0;
virtual struct TTD::Replay::RecordClient const * TTD::Replay::ReplayEngine::GetRecordClientList() const = 0;
virtual struct TTD::Replay::RecordClient const & TTD::Replay::ReplayEngine::GetRecordClient(enum TTD::RecordClientId) const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetCustomEventCount() const = 0;
virtual struct TTD::Replay::CustomEvent const * TTD::Replay::ReplayEngine::GetCustomEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetActivityCount() const = 0;
virtual struct TTD::Replay::Activity const * TTD::Replay::ReplayEngine::GetActivityList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetIslandCount() const = 0;
virtual struct TTD::Replay::Island const * TTD::Replay::ReplayEngine::GetIslandList() const = 0;
virtual class TTD::Replay::ICursor * TTD::Replay::ReplayEngine::NewCursor(struct _GUID const &) = 0;
virtual enum TTD::Replay::IndexStatus TTD::Replay::ReplayEngine::BuildIndex(void (*)(void const *, struct TTD::Replay::IndexBuildProgressType const *), void const *, enum TTD::Replay::IndexBuildFlags) = 0;
virtual enum TTD::Replay::IndexStatus TTD::Replay::ReplayEngine::GetIndexStatus() const = 0;
virtual struct TTD::Replay::IndexFileStats TTD::Replay::ReplayEngine::GetIndexFileStats() const = 0;
virtual void TTD::Replay::ReplayEngine::RegisterDebugModeAndLogging(enum TTD::Replay::DebugModeType, class TTD::ErrorReporting *) = 0;
virtual class TTD::Replay::ICursorInternals * TTD::Replay::Cursor::GetInternals() = 0;
virtual class TTD::Replay::IEngineInternals const * TTD::Replay::ReplayEngine::GetInternals() const = 0;
virtual void * TTD::Replay::ReplayEngine::scalar_deleting_dtor(unsigned int) = 0;
virtual void TTD::Replay::ReplayEngine::Destroy() = 0;
virtual bool TTD::Replay::ReplayEngine::Initialize(wchar_t const *) = 0;
};

View File

@ -0,0 +1,55 @@
struct TTD::Replay::IReplayEngine
{
virtual void const * TTD::Replay::ReplayEngine::UnsafeAsInterface(struct _GUID const &) const = 0;
virtual void * TTD::Replay::ReplayEngine::UnsafeAsInterface(struct _GUID const &) = 0;
virtual enum Nirvana::GuestAddress TTD::Replay::ReplayEngine::GetPebAddress() const = 0;
virtual struct TTD::SystemInfo const & TTD::Replay::ReplayEngine::GetSystemInfo() const = 0;
virtual struct TTD::Replay::PositionRange const & TTD::Replay::ReplayEngine::GetLifetime() const = 0;
virtual struct TTD::Replay::Position const & TTD::Replay::ReplayEngine::GetLastPosition() const = 0;
virtual struct TTD::Replay::Position const & TTD::Replay::ReplayEngine::GetFirstPosition() const = 0;
virtual enum TTD::Replay::RecordingType TTD::Replay::ReplayEngine::GetRecordingType() const = 0;
virtual struct TTD::Replay::ThreadInfo const & TTD::Replay::ReplayEngine::GetThreadInfo(enum TTD::Replay::UniqueThreadId) const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetThreadCount() const = 0;
virtual struct TTD::Replay::ThreadInfo const * TTD::Replay::ReplayEngine::GetThreadList() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadFirstPositionIndex() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLastPositionIndex() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLifetimeFirstPositionIndex() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLifetimeLastPositionIndex() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetThreadCreatedEventCount() const = 0;
virtual struct TTD::Replay::ThreadCreatedEvent const * TTD::Replay::ReplayEngine::GetThreadCreatedEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetThreadTerminatedEventCount() const = 0;
virtual struct TTD::Replay::ThreadTerminatedEvent const * TTD::Replay::ReplayEngine::GetThreadTerminatedEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetModuleCount() const = 0;
virtual struct TTD::Replay::Module const * TTD::Replay::ReplayEngine::GetModuleList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetModuleInstanceCount() const = 0;
virtual struct TTD::Replay::ModuleInstance const * TTD::Replay::ReplayEngine::GetModuleInstanceList() const = 0;
virtual uint64_t const * TTD::Replay::ReplayEngine::GetModuleInstanceUnloadIndex() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetModuleLoadedEventCount() const = 0;
virtual struct TTD::Replay::ModuleLoadedEvent const * TTD::Replay::ReplayEngine::GetModuleLoadedEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetModuleUnloadedEventCount() const = 0;
virtual struct TTD::Replay::ModuleUnloadedEvent const * TTD::Replay::ReplayEngine::GetModuleUnloadedEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetExceptionEventCount() const = 0;
virtual struct TTD::Replay::ExceptionEvent const * TTD::Replay::ReplayEngine::GetExceptionEventList() const = 0;
virtual struct TTD::Replay::ExceptionEvent const * TTD::Replay::ReplayEngine::GetExceptionAtOrAfterPosition(struct TTD::Replay::Position const &) const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetKeyframeCount() const = 0;
virtual struct TTD::Replay::Position const * TTD::Replay::ReplayEngine::GetKeyframeList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetRecordClientCount() const = 0;
virtual struct TTD::Replay::RecordClient const * TTD::Replay::ReplayEngine::GetRecordClientList() const = 0;
virtual struct TTD::Replay::RecordClient const & TTD::Replay::ReplayEngine::GetRecordClient(enum TTD::RecordClientId) const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetCustomEventCount() const = 0;
virtual struct TTD::Replay::CustomEvent const * TTD::Replay::ReplayEngine::GetCustomEventList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetActivityCount() const = 0;
virtual struct TTD::Replay::Activity const * TTD::Replay::ReplayEngine::GetActivityList() const = 0;
virtual uint64_t TTD::Replay::ReplayEngine::GetIslandCount() const = 0;
virtual struct TTD::Replay::Island const * TTD::Replay::ReplayEngine::GetIslandList() const = 0;
virtual class TTD::Replay::ICursor * TTD::Replay::ReplayEngine::NewCursor(struct _GUID const &) = 0;
virtual enum TTD::Replay::IndexStatus TTD::Replay::ReplayEngine::BuildIndex(void (*)(void const *, struct TTD::Replay::IndexBuildProgressType const *), void const *, enum TTD::Replay::IndexBuildFlags) = 0;
virtual enum TTD::Replay::IndexStatus TTD::Replay::ReplayEngine::GetIndexStatus() const = 0;
virtual struct TTD::Replay::IndexFileStats TTD::Replay::ReplayEngine::GetIndexFileStats() const = 0;
virtual void TTD::Replay::ReplayEngine::RegisterDebugModeAndLogging(enum TTD::Replay::DebugModeType, class TTD::ErrorReporting *) = 0;
virtual class TTD::Replay::ICursorInternals * TTD::Replay::Cursor::GetInternals() = 0;
virtual class TTD::Replay::IEngineInternals const * TTD::Replay::ReplayEngine::GetInternals() const = 0;
virtual void * TTD::Replay::ReplayEngine::scalar_deleting_dtor(unsigned int) = 0;
virtual void TTD::Replay::ReplayEngine::Destroy() = 0;
virtual bool TTD::Replay::ReplayEngine::Initialize(wchar_t const *) = 0;
};

View File

@ -6,8 +6,6 @@
using namespace Types;
static TypeManager typeManager;
#define EXCLUSIVE_ACQUIRE(x)
#define SHARED_ACQUIRE(x)
@ -300,7 +298,7 @@ static std::string getKind(const Function & f)
}
template<typename K, typename V>
static void enumType(const std::unordered_map<K, V> & map, std::vector<TypeManager::Summary> & types)
static void enumType(const TypeManager& typeManager, const std::unordered_map<K, V> & map, std::vector<TypeManager::Summary> & types)
{
for(auto i = map.begin(); i != map.end(); ++i)
{
@ -308,7 +306,7 @@ static void enumType(const std::unordered_map<K, V> & map, std::vector<TypeManag
s.kind = getKind(i->second);
s.name = i->second.name;
s.owner = i->second.owner;
s.size = SizeofType(s.name);
s.size = typeManager.Sizeof(s.name);
types.push_back(s);
}
}
@ -316,9 +314,9 @@ static void enumType(const std::unordered_map<K, V> & map, std::vector<TypeManag
void TypeManager::Enumerate(std::vector<Summary> & typeList) const
{
typeList.clear();
enumType(types, typeList);
enumType(structs, typeList);
enumType(functions, typeList);
enumType(*this, types, typeList);
enumType(*this, structs, typeList);
enumType(*this, functions, typeList);
//nasty hacks to sort in a nice way
std::sort(typeList.begin(), typeList.end(), [](const Summary & a, const Summary & b)
{
@ -612,342 +610,9 @@ bool TypeManager::GenerateStubs() const
puts("{");
for(const auto& hook : hooks)
{
printf(" HOOK(%s);\n", hook.c_str(), hook.c_str());
printf(" HOOK(%s);\n", hook.c_str());
}
puts("}");
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, const QualifiedType& qtype)
{
EXCLUSIVE_ACQUIRE(LockTypeManager);
return typeManager.AddArg(function, type, name, qtype);
}
bool AppendArg(const std::string & type, const std::string & name, const QualifiedType& qtype)
{
EXCLUSIVE_ACQUIRE(LockTypeManager);
return typeManager.AppendArg(type, name, qtype);
}
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.Enumerate(typeList);
}
#if 0
int json_default_int(const JSON object, const char* key, int defaultVal)
{
auto jint = json_object_get(object, key);
if(jint && json_is_integer(jint))
return int(json_integer_value(jint));
return defaultVal;
}
static void loadTypes(const JSON troot, std::vector<Member> & types)
{
if(!troot)
return;
size_t i;
JSON vali;
Member curType;
json_array_foreach(troot, i, vali)
{
auto type = json_string_value(json_object_get(vali, "type"));
auto name = json_string_value(json_object_get(vali, "name"));
if(!type || !*type || !name || !*name)
continue;
curType.type = type;
curType.name = name;
types.push_back(curType);
}
}
static void loadStructUnions(const JSON suroot, bool isunion, std::vector<StructUnion> & structUnions)
{
if(!suroot)
return;
size_t i;
JSON vali;
StructUnion curSu;
curSu.isunion = isunion;
json_array_foreach(suroot, i, vali)
{
auto suname = json_string_value(json_object_get(vali, "name"));
if(!suname || !*suname)
continue;
curSu.name = suname;
curSu.members.clear();
auto members = json_object_get(vali, "members");
size_t j;
JSON valj;
Member curMember;
json_array_foreach(members, j, valj)
{
auto type = json_string_value(json_object_get(valj, "type"));
auto name = json_string_value(json_object_get(valj, "name"));
if(!type || !*type || !name || !*name)
continue;
curMember.type = type;
curMember.name = name;
curMember.arrsize = json_default_int(valj, "arrsize", 0);
curMember.offset = json_default_int(valj, "offset", -1);
curSu.members.push_back(curMember);
}
structUnions.push_back(curSu);
}
}
static void loadFunctions(const JSON froot, std::vector<Function> & functions)
{
if(!froot)
return;
size_t i;
JSON vali;
Function curFunction;
json_array_foreach(froot, i, vali)
{
auto rettype = json_string_value(json_object_get(vali, "rettype"));
auto fname = json_string_value(json_object_get(vali, "name"));
if(!rettype || !*rettype || !fname || !*fname)
continue;
curFunction.rettype = rettype;
curFunction.name = fname;
curFunction.args.clear();
auto callconv = json_string_value(json_object_get(vali, "callconv"));
curFunction.noreturn = json_boolean_value(json_object_get(vali, "noreturn"));
if(scmp(callconv, "cdecl"))
curFunction.callconv = Cdecl;
else if(scmp(callconv, "stdcall"))
curFunction.callconv = Stdcall;
else if(scmp(callconv, "thiscall"))
curFunction.callconv = Thiscall;
else if(scmp(callconv, "delphi"))
curFunction.callconv = Delphi;
else
curFunction.callconv = Cdecl;
auto args = json_object_get(vali, "args");
size_t j;
JSON valj;
Member curArg;
json_array_foreach(args, j, valj)
{
auto type = json_string_value(json_object_get(valj, "type"));
auto name = json_string_value(json_object_get(valj, "name"));
if(!type || !*type || !name || !*name)
continue;
curArg.type = type;
curArg.name = name;
curFunction.args.push_back(curArg);
}
functions.push_back(curFunction);
}
}
#endif
#define dprintf printf
#define QT_TRANSLATE_NOOP(ctx, s) s
void LoadModel(const std::string & owner, Model & model)
{
//Add all base struct/union types first to avoid errors later
for(auto & su : model.structUnions)
{
auto success = su.isunion ? typeManager.AddUnion(owner, su.name) : typeManager.AddStruct(owner, su.name);
if(!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add %s %s;\n"), su.isunion ? "union" : "struct", su.name.c_str());
su.name.clear(); //signal error
}
}
//Add simple typedefs
for(auto & type : model.types)
{
auto success = typeManager.AddType(owner, type.type, type.name);
if(!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add typedef %s %s;\n"), type.type.c_str(), type.name.c_str());
}
}
//Add enums
for (auto& kv : model.enums)
{
auto& e = kv.first;
const auto& etype = kv.second;
auto success = typeManager.AddEnum(owner, e.name, etype);
if (!success)
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add enum %s;\n"), e.name.c_str());
e.name.clear(); // signal error
}
else
{
for (const auto& v : e.values)
{
if (!typeManager.AddEnumerator(e.name, v.name, v.value))
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add enum member %s.%s = %llu;\n"), e.name.c_str(), v.name.c_str(), v.value);
}
}
}
}
//Add base function types to avoid errors later
for(auto & function : model.functions)
{
auto success = typeManager.AddFunction(owner, function.name, function.rettype, function.callconv, function.noreturn, function.typeonly, function.retqtype);
if(!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add function %s %s()\n"), function.rettype.c_str(), function.name.c_str());
function.name.clear(); //signal error
}
}
//Add struct/union members
for(auto & su : model.structUnions)
{
if(su.name.empty()) //skip error-signalled structs/unions
continue;
for(auto & member : su.members)
{
auto success = typeManager.AddMember(su.name, member.type, member.name, member.arrsize, member.offset);
if(!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add member %s %s.%s;\n"), member.type.c_str(), su.name.c_str(), member.name.c_str());
}
}
}
//Add function arguments
for(auto & function : model.functions)
{
if(function.name.empty()) //skip error-signalled functions
continue;
for (size_t i = 0; i < function.args.size(); i++)
{
auto& arg = function.args[i];
if (arg.name.empty())
arg.name = "__unnamed_arg_" + std::to_string(i);
auto success = typeManager.AddArg(function.name, arg.type, arg.name, arg.qtype);
if(!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add argument %s[%zu]: %s %s;\n"), function.name.c_str(), i, arg.type.c_str(), arg.name.c_str());
}
}
}
}
#if 0
bool LoadTypesJson(const std::string & json, const std::string & owner)
{
EXCLUSIVE_ACQUIRE(LockTypeManager);
auto root = json_loads(json.c_str(), 0, 0);
if(root)
{
Model model;
loadTypes(json_object_get(root, "types"), model.types);
loadTypes(json_object_get(root, ArchValue("types32", "types64")), model.types);
loadStructUnions(json_object_get(root, "structs"), false, model.structUnions);
loadStructUnions(json_object_get(root, ArchValue("structs32", "structs64")), false, model.structUnions);
loadStructUnions(json_object_get(root, "unions"), true, model.structUnions);
loadStructUnions(json_object_get(root, ArchValue("unions32", "unions64")), true, model.structUnions);
loadFunctions(json_object_get(root, "functions"), model.functions);
loadFunctions(json_object_get(root, ArchValue("functions32", "functions64")), model.functions);
LoadModel(owner, model);
// Free root
json_decref(root);
}
else
return false;
return true;
}
bool LoadTypesFile(const std::string & path, const std::string & owner)
{
std::string json;
if(!FileHelper::ReadAllText(path, json))
return false;
return LoadTypesJson(json, owner);
}
#endif
std::string StructUnionPtrType(const std::string & pointto)
{
return typeManager.StructUnionPtrType(pointto);
}
bool GenerateStubs()
{
return typeManager.GenerateStubs();
}

View File

@ -81,29 +81,6 @@ namespace Types
int offset = -1; //Member offset (only stored for reference)
};
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;
};
struct EnumValue
{
std::string name;
uint64_t value = 0;
};
struct Enum
{
std::string owner; // Enum owner
std::string name; // Enum name
std::vector<EnumValue> values; // Enum values
Primitive type; // Enum value type
};
enum CallingConvention
{
DefaultDecl,
@ -125,6 +102,38 @@ namespace Types
std::vector<Member> args; //Function arguments
};
struct StructUnion
{
std::string owner; //StructUnion owner
std::string name; //StructUnion identifier
std::vector<Member> members; //StructUnion members
std::vector<Function> vtable;
bool isunion = false; //Is this a union?
int size = 0;
};
struct EnumValue
{
std::string name;
uint64_t value = 0;
};
struct Enum
{
std::string owner; // Enum owner
std::string name; // Enum name
std::vector<EnumValue> values; // Enum values
Primitive type; // Enum value type
};
struct Model
{
std::vector<Member> types;
std::vector<std::pair<Enum, std::string>> enums;
std::vector<StructUnion> structUnions;
std::vector<Function> functions;
};
struct TypeManager
{
struct Visitor
@ -163,6 +172,8 @@ namespace Types
bool RemoveType(const std::string & type);
void Enumerate(std::vector<Summary> & typeList) const;
std::string StructUnionPtrType(const std::string & pointto) const;
bool ParseTypes(const std::string& code, const std::string& owner, std::vector<std::string>& errors);
bool GenerateStubs() const;
private:
@ -184,31 +195,5 @@ namespace Types
bool addType(const Type & t);
bool visitMember(const Member & root, Visitor & visitor) const;
};
struct Model
{
std::vector<Member> types;
std::vector<std::pair<Enum, std::string>> enums;
std::vector<StructUnion> structUnions;
std::vector<Function> functions;
};
};
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, const Types::QualifiedType& qtype);
bool AppendArg(const std::string & type, const std::string & name, const Types::QualifiedType& qtype);
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);
bool LoadTypesJson(const std::string & json, const std::string & owner);
bool LoadTypesFile(const std::string & path, const std::string & owner);
bool ParseTypes(const std::string & code, const std::string & owner, std::vector<std::string> & errors);
std::string StructUnionPtrType(const std::string & pointto);
bool GenerateStubs();

View File

@ -5,7 +5,8 @@ using namespace Types;
#include "lexer.h"
void LoadModel(const std::string& owner, Model& model);
#define dprintf printf
#define QT_TRANSLATE_NOOP(ctx, s) s
struct Parser
{
@ -41,6 +42,21 @@ struct Parser
return getToken(index).Token == token;
}
bool isStructLike()
{
auto tok = getToken(index).Token;
switch (tok)
{
case Lexer::tok_struct:
case Lexer::tok_union:
case Lexer::tok_enum:
case Lexer::tok_class:
return true;
default:
return false;
}
}
bool isTokenList(std::initializer_list<Lexer::Token> il)
{
size_t i = 0;
@ -119,7 +135,7 @@ struct Parser
return false;
}
}
else if (t.Is(Lexer::tok_op_mul))
else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and))
{
if (type.empty())
{
@ -177,20 +193,31 @@ struct Parser
return false;
}
if (!isToken(Lexer::tok_op_mul))
if (!isToken(Lexer::tok_op_mul) && !isToken(Lexer::tok_op_and))
{
errLine(curToken(), "expected * in function pointer type");
return false;
}
index++;
if (!isToken(Lexer::tok_identifier)) // TODO: support unnamed function pointers
if (!isToken(Lexer::tok_identifier))
{
if (isToken(Lexer::tok_parclose))
{
// unnamed function pointer
fn.name = "";
}
else
{
errLine(curToken(), "expected identifier in function pointer type");
return false;
}
}
else
{
fn.name = lexer.TokString(curToken());
index++;
}
if (!isToken(Lexer::tok_parclose))
{
@ -237,6 +264,19 @@ struct Parser
return false;
}
if (isStructLike())
{
if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier)
{
index++;
}
else
{
errLine(curToken(), "unsupported struct/union/enum in function argument");
return false;
}
}
const auto& t = curToken();
if (t.IsType() || t.Is(Lexer::tok_identifier) || t.Is(Lexer::tok_const))
{
@ -245,7 +285,7 @@ struct Parser
// Primitive type
tlist.push_back(t);
}
else if (t.Is(Lexer::tok_op_mul))
else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and))
{
// Pointer to the type on the left
if (tlist.empty())
@ -396,7 +436,7 @@ struct Parser
return false;
}
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union) || isToken(Lexer::tok_enum))
if (isStructLike())
{
if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier)
{
@ -416,7 +456,7 @@ struct Parser
// Primitive type / name
tlist.push_back(t);
}
else if (t.Is(Lexer::tok_op_mul))
else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and))
{
// Pointer to the type on the left
if (tlist.empty())
@ -425,7 +465,7 @@ struct Parser
return false;
}
if (sawPointer && tlist.back().Token != Lexer::tok_op_mul)
if (sawPointer && tlist.back().Token != Lexer::tok_op_mul && tlist.back().Token != Lexer::tok_op_and)
{
errLine(curToken(), "unexpected * in member");
return false;
@ -511,12 +551,27 @@ struct Parser
tlist.pop_back();
// Remove the pointer from the type
while (!tlist.empty() && tlist.back().Token == Lexer::tok_op_mul)
while (!tlist.empty() && (tlist.back().Token == Lexer::tok_op_mul || tlist.back().Token == Lexer::tok_op_and))
tlist.pop_back();
sawPointer = false;
m = Member();
}
else if (t.Is(Lexer::tok_virtual))
{
// Parse a virtual function declaration
index++;
// Parse the function declaration
Function vfunction;
if (!parseFunctionTop(vfunction, true))
return false;
su.vtable.push_back(vfunction);
}
else if (t.Is(Lexer::tok_brclose) && tlist.empty())
{
return true;
}
else
{
__debugbreak();
@ -539,7 +594,7 @@ struct Parser
bool parseStructUnion()
{
auto startToken = curToken();
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union))
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_class) || isToken(Lexer::tok_union))
{
StructUnion su;
su.isunion = isToken(Lexer::tok_union);
@ -745,7 +800,7 @@ struct Parser
return false;
}
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union) || isToken(Lexer::tok_enum))
if (isStructLike())
{
if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier)
{
@ -765,7 +820,7 @@ struct Parser
index++;
tlist.push_back(t);
}
else if (t.Token == Lexer::tok_op_mul)
else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and))
{
// Pointer to the type on the left
if (tlist.empty())
@ -774,7 +829,7 @@ struct Parser
return false;
}
if (sawPointer && tlist.back().Token != Lexer::tok_op_mul)
if (sawPointer && tlist.back().Token != Lexer::tok_op_mul && tlist.back().Token != Lexer::tok_op_and)
{
errLine(curToken(), "unexpected * in member");
return false;
@ -832,8 +887,10 @@ struct Parser
return true;
}
bool parseFunctionTop()
bool parseFunctionTop(Function& fn, bool isVirtual)
{
fn = {};
bool sawPointer = false;
std::vector<Lexer::TokenState> tlist;
while (!isToken(Lexer::tok_semic))
@ -844,7 +901,7 @@ struct Parser
return false;
}
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union) || isToken(Lexer::tok_enum))
if (isStructLike())
{
if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier)
{
@ -864,7 +921,7 @@ struct Parser
// Primitive type / name
tlist.push_back(t);
}
else if (t.Is(Lexer::tok_op_mul))
else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and))
{
// Pointer to the type on the left
if (tlist.empty())
@ -873,7 +930,7 @@ struct Parser
return false;
}
if (sawPointer && tlist.back().Token != Lexer::tok_op_mul)
if (sawPointer && tlist.back().Token != Lexer::tok_op_mul && tlist.back().Token != Lexer::tok_op_and)
{
errLine(curToken(), "unexpected * in function");
return false;
@ -889,21 +946,63 @@ struct Parser
index++;
// Function pointer type
Function fn;
if (!parseFunction(tlist, fn, false))
{
return false;
}
if (!isToken(Lexer::tok_semic))
{
if (isVirtual)
{
auto endToken = curToken();
while (true)
{
auto tEnd = curToken();
if (tEnd.Is(Lexer::tok_eof))
{
errLine(curToken(), "unexpected eof after virtual function");
return false;
}
if (tEnd.Is(Lexer::tok_const) || tEnd.Is(Lexer::tok_override))
{
index++;
continue;
}
if (tEnd.Is(Lexer::tok_semic))
{
break;
}
if (tEnd.Is(Lexer::tok_assign))
{
index++;
tEnd = curToken();
if (!tEnd.Is(Lexer::tok_number) || tEnd.NumberVal != 0)
{
errLine(endToken, "expected = 0 after virtual function type");
return false;
}
index++;
break;
}
else
{
errLine(endToken, "expected = 0 after virtual function type");
return false;
}
}
}
if (!isToken(Lexer::tok_semic))
{
errLine(curToken(), "expected ; after function type");
return false;
}
}
eatSemic();
model.functions.push_back(fn);
return true;
}
else
@ -914,7 +1013,103 @@ struct Parser
return false;
}
bool operator()()
void LoadModel(TypeManager typeManager, const std::string& owner, Model& model)
{
//Add all base struct/union types first to avoid errors later
for (auto& su : model.structUnions)
{
auto success = su.isunion ? typeManager.AddUnion(owner, su.name) : typeManager.AddStruct(owner, su.name);
if (!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add %s %s;\n"), su.isunion ? "union" : "struct", su.name.c_str());
su.name.clear(); //signal error
}
}
//Add simple typedefs
for (auto& type : model.types)
{
auto success = typeManager.AddType(owner, type.type, type.name);
if (!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add typedef %s %s;\n"), type.type.c_str(), type.name.c_str());
}
}
//Add enums
for (auto& kv : model.enums)
{
auto& e = kv.first;
const auto& etype = kv.second;
auto success = typeManager.AddEnum(owner, e.name, etype);
if (!success)
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add enum %s;\n"), e.name.c_str());
e.name.clear(); // signal error
}
else
{
for (const auto& v : e.values)
{
if (!typeManager.AddEnumerator(e.name, v.name, v.value))
{
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add enum member %s.%s = %llu;\n"), e.name.c_str(), v.name.c_str(), v.value);
}
}
}
}
//Add base function types to avoid errors later
for (auto& function : model.functions)
{
auto success = typeManager.AddFunction(owner, function.name, function.rettype, function.callconv, function.noreturn, function.typeonly, function.retqtype);
if (!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add function %s %s()\n"), function.rettype.c_str(), function.name.c_str());
function.name.clear(); //signal error
}
}
//Add struct/union members
for (auto& su : model.structUnions)
{
if (su.name.empty()) //skip error-signalled structs/unions
continue;
for (auto& member : su.members)
{
auto success = typeManager.AddMember(su.name, member.type, member.name, member.arrsize, member.offset);
if (!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add member %s %s.%s;\n"), member.type.c_str(), su.name.c_str(), member.name.c_str());
}
}
}
//Add function arguments
for (auto& function : model.functions)
{
if (function.name.empty()) //skip error-signalled functions
continue;
for (size_t i = 0; i < function.args.size(); i++)
{
auto& arg = function.args[i];
if (arg.name.empty())
arg.name = "__unnamed_arg_" + std::to_string(i);
auto success = typeManager.AddArg(function.name, arg.type, arg.name, arg.qtype);
if (!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add argument %s[%zu]: %s %s;\n"), function.name.c_str(), i, arg.type.c_str(), arg.name.c_str());
}
}
}
}
bool operator()(TypeManager& typeManager)
{
std::string error;
if (!lexer.DoLexing(tokens, error))
@ -935,19 +1130,19 @@ struct Parser
eatSemic();
if (curIndex == index)
{
if (!parseFunctionTop())
Function fn;
if (!parseFunctionTop(fn, false))
return false;
else
continue;
model.functions.push_back(fn);
}
}
LoadModel(owner, model);
LoadModel(typeManager, owner, model);
return true;
}
};
bool ParseTypes(const std::string& code, const std::string& owner, std::vector<std::string>& errors)
bool TypeManager::ParseTypes(const std::string& code, const std::string& owner, std::vector<std::string>& errors)
{
return Parser(code, owner, errors)();
return Parser(code, owner, errors)(*this);
}