1
0
Fork 0

DBG: very hacky type parser working

This commit is contained in:
mrexodia 2016-11-22 00:10:21 +01:00
parent 943aa09b4f
commit eea599b0ac
No known key found for this signature in database
GPG Key ID: FC89E0AAA0C1AAD8
10 changed files with 405 additions and 75 deletions

3
.gitmodules vendored
View File

@ -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

1
src/dbg/btparser Submodule

@ -0,0 +1 @@
Subproject commit 87003fef8d08fc8ebdc5a71272e5a75726c2795c

View File

@ -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;
}

View File

@ -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[]);

View File

@ -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);

View File

@ -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);

255
src/dbg/typesparser.cpp Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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" />

View File

@ -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>