DBG: very hacky type parser working
This commit is contained in:
parent
943aa09b4f
commit
eea599b0ac
|
@ -4,3 +4,6 @@
|
|||
[submodule "src/gui/Translations"]
|
||||
path = src/gui/Translations
|
||||
url = https://github.com/x64dbg/Translations.git
|
||||
[submodule "src/dbg/btparser"]
|
||||
path = src/dbg/btparser
|
||||
url = https://github.com/x64dbg/btparser
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 87003fef8d08fc8ebdc5a71272e5a75726c2795c
|
|
@ -608,4 +608,24 @@ bool cbInstrLoadTypes(int argc, char* argv[])
|
|||
}
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Types loaded"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cbInstrParseTypes(int argc, char* argv[])
|
||||
{
|
||||
if(IsArgumentsLessThan(argc, 2))
|
||||
return false;
|
||||
auto owner = FileHelper::GetFileName(argv[1]);
|
||||
std::string data;
|
||||
if(!FileHelper::ReadAllText(argv[1], data))
|
||||
{
|
||||
dputs("failed to read file!");
|
||||
return false;
|
||||
}
|
||||
if(!ParseTypes(data, owner))
|
||||
{
|
||||
dputs("ParseTypes failed");
|
||||
return false;
|
||||
}
|
||||
dputs("Types parsed");
|
||||
return true;
|
||||
}
|
|
@ -35,4 +35,5 @@ bool cbInstrVisitType(int argc, char* argv[]);
|
|||
bool cbInstrClearTypes(int argc, char* argv[]);
|
||||
bool cbInstrRemoveType(int argc, char* argv[]);
|
||||
bool cbInstrEnumTypes(int argc, char* argv[]);
|
||||
bool cbInstrLoadTypes(int argc, char* argv[]);
|
||||
bool cbInstrLoadTypes(int argc, char* argv[]);
|
||||
bool cbInstrParseTypes(int argc, char* argv[]);
|
|
@ -585,86 +585,89 @@ static void loadFunctions(const JSON froot, std::vector<Function> & functions)
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
su.name.clear(); //signal error
|
||||
//TODO properly handle errors
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add %s %s;\n"), su.isunion ? "union" : "struct", su.name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//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 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);
|
||||
if(!success)
|
||||
{
|
||||
function.name.clear(); //signal error
|
||||
//TODO properly handle errors
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add function %s %s()\n"), function.rettype.c_str(), function.name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
//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(auto & arg : function.args)
|
||||
{
|
||||
auto success = typeManager.AddArg(function.name, arg.type, arg.name);
|
||||
if(!success)
|
||||
{
|
||||
//TODO properly handle errors
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add argument %s %s.%s;\n"), arg.type.c_str(), function.name.c_str(), arg.name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadTypesJson(const std::string & json, const std::string & owner)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockTypeManager);
|
||||
auto root = json_loads(json.c_str(), 0, 0);
|
||||
if(root)
|
||||
{
|
||||
std::vector<Member> types;
|
||||
loadTypes(json_object_get(root, "types"), types);
|
||||
std::vector<StructUnion> structUnions;
|
||||
loadStructUnions(json_object_get(root, "structs"), false, structUnions);
|
||||
loadStructUnions(json_object_get(root, "unions"), true, structUnions);
|
||||
std::vector<Function> functions;
|
||||
loadFunctions(json_object_get(root, "functions"), functions);
|
||||
Model model;
|
||||
loadTypes(json_object_get(root, "types"), model.types);
|
||||
loadStructUnions(json_object_get(root, "structs"), false, model.structUnions);
|
||||
loadStructUnions(json_object_get(root, "unions"), true, model.structUnions);
|
||||
loadFunctions(json_object_get(root, "functions"), model.functions);
|
||||
|
||||
//Add all base struct/union types first to avoid errors later
|
||||
for(auto & su : structUnions)
|
||||
{
|
||||
auto success = su.isunion ? typeManager.AddUnion(owner, su.name) : typeManager.AddStruct(owner, su.name);
|
||||
if(!success)
|
||||
{
|
||||
su.name.clear(); //signal error
|
||||
//TODO properly handle errors
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add %s %s;\n"), su.isunion ? "union" : "struct", su.name);
|
||||
}
|
||||
}
|
||||
|
||||
//Add simple typedefs
|
||||
for(auto & type : 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, type.name);
|
||||
}
|
||||
}
|
||||
|
||||
//Add base function types to avoid errors later
|
||||
for(auto & function : functions)
|
||||
{
|
||||
auto success = typeManager.AddFunction(owner, function.name, function.rettype, function.callconv, function.noreturn);
|
||||
if(!success)
|
||||
{
|
||||
function.name.clear(); //signal error
|
||||
//TODO properly handle errors
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add function %s %s()\n"), function.rettype, function.name);
|
||||
}
|
||||
}
|
||||
|
||||
//Add struct/union members
|
||||
for(auto & su : 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, su.name, member.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Add function arguments
|
||||
for(auto & function : functions)
|
||||
{
|
||||
if(function.name.empty()) //skip error-signalled functions
|
||||
continue;
|
||||
for(auto & arg : function.args)
|
||||
{
|
||||
auto success = typeManager.AddArg(function.name, arg.type, arg.name);
|
||||
if(!success)
|
||||
{
|
||||
//TODO properly handle errors
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add argument %s %s.%s;\n"), arg.type, function.name, arg.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
LoadModel(owner, model);
|
||||
|
||||
// Free root
|
||||
json_decref(root);
|
||||
|
|
|
@ -119,6 +119,13 @@ namespace Types
|
|||
bool addType(const Type & t);
|
||||
bool visitMember(const Member & root, Visitor & visitor) const;
|
||||
};
|
||||
|
||||
struct Model
|
||||
{
|
||||
std::vector<Member> types;
|
||||
std::vector<StructUnion> structUnions;
|
||||
std::vector<Function> functions;
|
||||
};
|
||||
};
|
||||
|
||||
bool AddType(const std::string & owner, const std::string & type, const std::string & name);
|
||||
|
@ -135,4 +142,5 @@ 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 LoadTypesFile(const std::string & path, const std::string & owner);
|
||||
bool ParseTypes(const std::string & parse, const std::string & owner);
|
|
@ -0,0 +1,255 @@
|
|||
#include "types.h"
|
||||
#include "console.h"
|
||||
|
||||
using namespace Types;
|
||||
|
||||
#include "btparser/btparser/lexer.h"
|
||||
|
||||
void LoadModel(const std::string & owner, Model & model);
|
||||
|
||||
bool ParseTypes(const std::string & parse, const std::string & owner)
|
||||
{
|
||||
Lexer lexer;
|
||||
lexer.SetInputData(parse);
|
||||
std::vector<Lexer::TokenState> tokens;
|
||||
size_t index = 0;
|
||||
auto getToken = [&](size_t i) -> Lexer::TokenState &
|
||||
{
|
||||
if(index >= tokens.size() - 1)
|
||||
i = tokens.size() - 1;
|
||||
return tokens[i];
|
||||
};
|
||||
auto curToken = [&]() -> Lexer::TokenState &
|
||||
{
|
||||
return getToken(index);
|
||||
};
|
||||
auto isToken = [&](Lexer::Token token)
|
||||
{
|
||||
return getToken(index).Token == token;
|
||||
};
|
||||
auto isTokenList = [&](std::initializer_list<Lexer::Token> il)
|
||||
{
|
||||
size_t i = 0;
|
||||
for(auto l : il)
|
||||
if(getToken(index + i++).Token != l)
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
std::string error;
|
||||
if(!lexer.DoLexing(tokens, error))
|
||||
{
|
||||
dputs_untranslated(error.c_str());
|
||||
return false;
|
||||
}
|
||||
Model model;
|
||||
|
||||
auto errLine = [&]()
|
||||
{
|
||||
dprintf("[line %d:%d] ", curToken().CurLine, curToken().LineIndex);
|
||||
};
|
||||
auto eatSemic = [&]()
|
||||
{
|
||||
while(curToken().Token == Lexer::tok_semic)
|
||||
index++;
|
||||
};
|
||||
auto parseTypedef = [&]()
|
||||
{
|
||||
if(isToken(Lexer::tok_typedef))
|
||||
{
|
||||
index++;
|
||||
std::vector<Lexer::TokenState> tdefToks;
|
||||
while(!isToken(Lexer::tok_semic))
|
||||
{
|
||||
if(isToken(Lexer::tok_eof))
|
||||
{
|
||||
errLine();
|
||||
dputs("unexpected eof in typedef");
|
||||
return false;
|
||||
}
|
||||
tdefToks.push_back(curToken());
|
||||
index++;
|
||||
}
|
||||
eatSemic();
|
||||
if(tdefToks.size() >= 2) //at least typedef a b;
|
||||
{
|
||||
Member tm;
|
||||
tm.name = lexer.TokString(tdefToks[tdefToks.size() - 1]);
|
||||
tdefToks.pop_back();
|
||||
for(auto & t : tdefToks)
|
||||
if(!t.IsType() && t.Token != Lexer::tok_op_mul && t.Token != Lexer::tok_identifier)
|
||||
{
|
||||
errLine();
|
||||
dprintf("token %s is not a type...\n", lexer.TokString(t).c_str());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!tm.type.empty() && t.Token != Lexer::tok_op_mul)
|
||||
tm.type.push_back(' ');
|
||||
tm.type += lexer.TokString(t);
|
||||
}
|
||||
//dprintf("typedef %s:%s\n", tm.type.c_str(), tm.name.c_str());
|
||||
model.types.push_back(tm);
|
||||
return true;
|
||||
}
|
||||
errLine();
|
||||
dputs("not enough tokens for typedef");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
auto parseMember = [&](StructUnion & su)
|
||||
{
|
||||
std::vector<Lexer::TokenState> memToks;
|
||||
while(!isToken(Lexer::tok_semic))
|
||||
{
|
||||
if(isToken(Lexer::tok_eof))
|
||||
{
|
||||
errLine();
|
||||
dputs("unexpected eof in member");
|
||||
return false;
|
||||
}
|
||||
memToks.push_back(curToken());
|
||||
index++;
|
||||
}
|
||||
eatSemic();
|
||||
if(memToks.size() >= 2) //at least type name;
|
||||
{
|
||||
Member m;
|
||||
for(size_t i = 0; i < memToks.size(); i++)
|
||||
{
|
||||
const auto & t = memToks[i];
|
||||
if(t.Token == Lexer::tok_subopen)
|
||||
{
|
||||
if(i + 1 >= memToks.size())
|
||||
{
|
||||
errLine();
|
||||
dputs("unexpected end after [");
|
||||
return false;
|
||||
}
|
||||
if(memToks[i + 1].Token != Lexer::tok_number)
|
||||
{
|
||||
errLine();
|
||||
dputs("expected number token");
|
||||
return false;
|
||||
}
|
||||
if(i + 2 >= memToks.size())
|
||||
{
|
||||
errLine();
|
||||
dputs("unexpected end, expected ]");
|
||||
return false;
|
||||
}
|
||||
if(memToks[i + 2].Token != Lexer::tok_subclose)
|
||||
{
|
||||
errLine();
|
||||
dprintf("expected ], got %s\n", lexer.TokString(memToks[i + 2]).c_str());
|
||||
return false;
|
||||
}
|
||||
if(i + 2 != memToks.size() - 1)
|
||||
{
|
||||
errLine();
|
||||
dputs("too many tokens");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if(i + 1 == memToks.size() || memToks[i + 1].Token == Lexer::tok_subopen) //last = name
|
||||
{
|
||||
m.name = lexer.TokString(memToks[i]);
|
||||
}
|
||||
else if(!t.IsType() &&
|
||||
t.Token != Lexer::tok_op_mul &&
|
||||
t.Token != Lexer::tok_identifier)
|
||||
{
|
||||
errLine();
|
||||
dprintf("token %s is not a type...\n", lexer.TokString(t).c_str());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!m.type.empty() && t.Token != Lexer::tok_op_mul)
|
||||
m.type.push_back(' ');
|
||||
m.type += lexer.TokString(t);
|
||||
}
|
||||
}
|
||||
//dprintf("member: %s %s;\n", m.type.c_str(), m.name.c_str());
|
||||
su.members.push_back(m);
|
||||
return true;
|
||||
}
|
||||
errLine();
|
||||
dputs("not enough tokens for member");
|
||||
return false;
|
||||
};
|
||||
auto parseStructUnion = [&]()
|
||||
{
|
||||
if(isToken(Lexer::tok_struct) || isToken(Lexer::tok_union))
|
||||
{
|
||||
StructUnion su;
|
||||
su.isunion = isToken(Lexer::tok_union);
|
||||
index++;
|
||||
if(isTokenList({ Lexer::tok_identifier, Lexer::tok_bropen }))
|
||||
{
|
||||
su.name = lexer.TokString(curToken());
|
||||
index += 2;
|
||||
while(!isToken(Lexer::tok_brclose))
|
||||
{
|
||||
if(isToken(Lexer::tok_eof))
|
||||
{
|
||||
errLine();
|
||||
dprintf("unexpected eof in %s\n", su.isunion ? "union" : "struct");
|
||||
return false;
|
||||
}
|
||||
if(isToken(Lexer::tok_bropen))
|
||||
{
|
||||
errLine();
|
||||
dputs("nested blocks are not allowed!");
|
||||
return false;
|
||||
}
|
||||
if(!parseMember(su))
|
||||
return false;
|
||||
}
|
||||
index++; //eat tok_brclose
|
||||
//dprintf("%s %s, members: %d\n", su.isunion ? "union" : "struct", su.name.c_str(), int(su.members.size()));
|
||||
model.structUnions.push_back(su);
|
||||
if(!isToken(Lexer::tok_semic))
|
||||
{
|
||||
errLine();
|
||||
dputs("expected semicolon!");
|
||||
return false;
|
||||
}
|
||||
eatSemic();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
errLine();
|
||||
dputs("invalid struct token sequence!");
|
||||
return false;
|
||||
}
|
||||
errLine();
|
||||
dprintf("not enough tokens for %s\n", su.isunion ? "union" : "struct");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
while(!isToken(Lexer::tok_eof))
|
||||
{
|
||||
auto curIndex = index;
|
||||
if(!parseTypedef())
|
||||
return false;
|
||||
if(!parseStructUnion())
|
||||
return false;
|
||||
eatSemic();
|
||||
if(curIndex == index)
|
||||
{
|
||||
errLine();
|
||||
dprintf("unexpected token %s\n", lexer.TokString(curToken()).c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LoadModel(owner, model);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -354,6 +354,7 @@ static void registercommands()
|
|||
dbgcmdnew("RemoveType", cbInstrRemoveType, false); //RemoveType
|
||||
dbgcmdnew("EnumTypes", cbInstrEnumTypes, false); //EnumTypes
|
||||
dbgcmdnew("LoadTypes", cbInstrLoadTypes, false); //LoadTypes
|
||||
dbgcmdnew("ParseTypes", cbInstrParseTypes, false); //ParseTypes
|
||||
|
||||
//plugins
|
||||
dbgcmdnew("StartScylla\1scylla\1imprec", cbDebugStartScylla, false); //start scylla
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
<ClCompile Include="assemble.cpp" />
|
||||
<ClCompile Include="bookmark.cpp" />
|
||||
<ClCompile Include="breakpoint.cpp" />
|
||||
<ClCompile Include="btparser\btparser\lexer.cpp" />
|
||||
<ClCompile Include="btparser\btparser\parser.cpp" />
|
||||
<ClCompile Include="command.cpp" />
|
||||
<ClCompile Include="commandline.cpp" />
|
||||
<ClCompile Include="commandparser.cpp" />
|
||||
|
@ -101,6 +103,7 @@
|
|||
<ClCompile Include="threading.cpp" />
|
||||
<ClCompile Include="TraceRecord.cpp" />
|
||||
<ClCompile Include="types.cpp" />
|
||||
<ClCompile Include="typesparser.cpp" />
|
||||
<ClCompile Include="value.cpp" />
|
||||
<ClCompile Include="variable.cpp" />
|
||||
<ClCompile Include="watch.cpp" />
|
||||
|
@ -147,6 +150,11 @@
|
|||
<ClInclude Include="assemble.h" />
|
||||
<ClInclude Include="bookmark.h" />
|
||||
<ClInclude Include="breakpoint.h" />
|
||||
<ClInclude Include="btparser\btparser\ast.h" />
|
||||
<ClInclude Include="btparser\btparser\keywords.h" />
|
||||
<ClInclude Include="btparser\btparser\lexer.h" />
|
||||
<ClInclude Include="btparser\btparser\operators.h" />
|
||||
<ClInclude Include="btparser\btparser\parser.h" />
|
||||
<ClInclude Include="command.h" />
|
||||
<ClInclude Include="commandline.h" />
|
||||
<ClInclude Include="commandparser.h" />
|
||||
|
|
|
@ -87,6 +87,12 @@
|
|||
<Filter Include="Source Files\Commands">
|
||||
<UniqueIdentifier>{c42aba29-6104-475b-9838-ffa2034485aa}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\btparser">
|
||||
<UniqueIdentifier>{3e5a02e2-62ad-4251-a53a-ab3f34fd7dd9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\btparser">
|
||||
<UniqueIdentifier>{d20554d2-b3de-4e73-ac55-217da06783ba}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp">
|
||||
|
@ -410,6 +416,15 @@
|
|||
<ClCompile Include="types.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="btparser\btparser\lexer.cpp">
|
||||
<Filter>Source Files\btparser</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="btparser\btparser\parser.cpp">
|
||||
<Filter>Source Files\btparser</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="typesparser.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dbghelp\dbghelp.h">
|
||||
|
@ -913,5 +928,20 @@
|
|||
<ClInclude Include="types.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="btparser\btparser\ast.h">
|
||||
<Filter>Header Files\btparser</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="btparser\btparser\keywords.h">
|
||||
<Filter>Header Files\btparser</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="btparser\btparser\lexer.h">
|
||||
<Filter>Header Files\btparser</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="btparser\btparser\operators.h">
|
||||
<Filter>Header Files\btparser</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="btparser\btparser\parser.h">
|
||||
<Filter>Header Files\btparser</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue