mirror of https://github.com/x64dbg/btparser
WIP: handling vtable generation
This commit is contained in:
parent
b92d01f5c8
commit
8e19f7ce0d
|
@ -6,132 +6,200 @@
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "preprocessor.h"
|
#include "preprocessor.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
bool TestLexer(Lexer & lexer, const std::string & filename)
|
bool TestLexer(Lexer& lexer, const std::string& filename)
|
||||||
{
|
{
|
||||||
if(!lexer.ReadInputFile("tests\\" + filename))
|
if (!lexer.ReadInputFile("tests\\" + filename))
|
||||||
{
|
{
|
||||||
printf("failed to read \"%s\"\n", filename.c_str());
|
printf("failed to read \"%s\"\n", filename.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::string actual;
|
std::string actual;
|
||||||
actual.reserve(65536);
|
actual.reserve(65536);
|
||||||
auto success = lexer.Test([&](const std::string & line)
|
auto success = lexer.Test([&](const std::string& line)
|
||||||
{
|
{
|
||||||
actual.append(line);
|
actual.append(line);
|
||||||
});
|
});
|
||||||
std::string expected;
|
std::string expected;
|
||||||
if(FileHelper::ReadAllText("tests\\exp_lex\\" + filename, expected) && expected == actual)
|
if (FileHelper::ReadAllText("tests\\exp_lex\\" + filename, expected) && expected == actual)
|
||||||
{
|
{
|
||||||
printf("lexer test for \"%s\" success!\n", filename.c_str());
|
printf("lexer test for \"%s\" success!\n", filename.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(success)
|
if (success)
|
||||||
return true;
|
return true;
|
||||||
printf("lexer test for \"%s\" failed...\n", filename.c_str());
|
printf("lexer test for \"%s\" failed...\n", filename.c_str());
|
||||||
FileHelper::WriteAllText("expected.out", expected);
|
FileHelper::WriteAllText("expected.out", expected);
|
||||||
FileHelper::WriteAllText("actual.out", actual);
|
FileHelper::WriteAllText("actual.out", actual);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebugLexer(Lexer & lexer, const std::string & filename, bool output)
|
bool DebugLexer(Lexer& lexer, const std::string& filename, bool output)
|
||||||
{
|
{
|
||||||
if(!lexer.ReadInputFile("tests\\" + filename))
|
if (!lexer.ReadInputFile("tests\\" + filename))
|
||||||
{
|
{
|
||||||
printf("failed to read \"%s\"\n", filename.c_str());
|
printf("failed to read \"%s\"\n", filename.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto success = lexer.Test([](const std::string & line)
|
auto success = lexer.Test([](const std::string& line)
|
||||||
{
|
{
|
||||||
printf("%s", line.c_str());
|
printf("%s", line.c_str());
|
||||||
}, output);
|
}, output);
|
||||||
if(output)
|
if (output)
|
||||||
puts("");
|
puts("");
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateExpected(Lexer & lexer, const std::string & filename)
|
void GenerateExpected(Lexer& lexer, const std::string& filename)
|
||||||
{
|
{
|
||||||
if(!lexer.ReadInputFile("tests\\" + filename))
|
if (!lexer.ReadInputFile("tests\\" + filename))
|
||||||
{
|
{
|
||||||
printf("failed to read \"%s\"\n", filename.c_str());
|
printf("failed to read \"%s\"\n", filename.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string actual;
|
std::string actual;
|
||||||
actual.reserve(65536);
|
actual.reserve(65536);
|
||||||
lexer.Test([&](const std::string & line)
|
lexer.Test([&](const std::string& line)
|
||||||
{
|
{
|
||||||
actual.append(line);
|
actual.append(line);
|
||||||
});
|
});
|
||||||
FileHelper::WriteAllText("tests\\exp_lex\\" + filename, actual);
|
FileHelper::WriteAllText("tests\\exp_lex\\" + filename, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateExpectedTests()
|
void GenerateExpectedTests()
|
||||||
{
|
{
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
for(auto file : testFiles)
|
for (auto file : testFiles)
|
||||||
GenerateExpected(lexer, file);
|
GenerateExpected(lexer, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunLexerTests()
|
void RunLexerTests()
|
||||||
{
|
{
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
for(auto file : testFiles)
|
for (auto file : testFiles)
|
||||||
TestLexer(lexer, file);
|
TestLexer(lexer, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugLexerTests(bool output = true)
|
void DebugLexerTests(bool output = true)
|
||||||
{
|
{
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
for(auto file : testFiles)
|
for (auto file : testFiles)
|
||||||
DebugLexer(lexer, file, output);
|
DebugLexer(lexer, file, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebugParser(const std::string & filename)
|
static std::vector<std::string> SplitNamespace(const std::string& name, std::string& type)
|
||||||
{
|
{
|
||||||
std::string data;
|
auto namespaces = StringUtils::Split(name, ':');
|
||||||
if (!FileHelper::ReadAllText("tests\\" + filename, data))
|
if (namespaces.empty())
|
||||||
{
|
{
|
||||||
printf("Failed to read: %s\n", filename.c_str());
|
type.clear();
|
||||||
return false;
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
type = namespaces.back();
|
||||||
|
namespaces.pop_back();
|
||||||
|
}
|
||||||
|
return namespaces;
|
||||||
|
}
|
||||||
|
|
||||||
std::string pperror;
|
static void HandleVTable(Types::Model& model)
|
||||||
std::unordered_map<std::string, std::string> definitions;
|
{
|
||||||
definitions["WIN32"] = "";
|
std::unordered_set<std::string> classes;
|
||||||
definitions["_MSC_VER"] = "1337";
|
std::unordered_set<std::string> visited;
|
||||||
auto ppData = preprocess(data, pperror, definitions);
|
auto handleType = [&](const Types::QualifiedType& type)
|
||||||
if (!pperror.empty())
|
{
|
||||||
{
|
if (!type.kind.empty())
|
||||||
printf("Preprocess error: %s\n", pperror.c_str());
|
{
|
||||||
return false;
|
const auto& name = type.name;
|
||||||
}
|
const auto& kind = type.kind;
|
||||||
|
if (visited.count(name) != 0)
|
||||||
|
return;
|
||||||
|
visited.insert(name);
|
||||||
|
std::string rettype;
|
||||||
|
auto namespaces = SplitNamespace(name, rettype);
|
||||||
|
if (kind == "class" && rettype[0] == 'I')
|
||||||
|
classes.insert(name);
|
||||||
|
for (const auto& ns : namespaces)
|
||||||
|
{
|
||||||
|
printf("namespace %s {\n", ns.c_str());
|
||||||
|
}
|
||||||
|
printf(" %s %s {\n };\n", kind.c_str(), rettype.c_str());
|
||||||
|
for (const auto& ns : namespaces)
|
||||||
|
printf("}\n");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (const auto& su : model.structUnions)
|
||||||
|
{
|
||||||
|
for (const auto& vf : su.vtable)
|
||||||
|
{
|
||||||
|
handleType(vf.rettype);
|
||||||
|
for (const auto& arg : vf.args)
|
||||||
|
handleType(arg.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto& f : model.functions)
|
||||||
|
{
|
||||||
|
handleType(f.rettype);
|
||||||
|
for (const auto& arg : f.args)
|
||||||
|
handleType(arg.type);
|
||||||
|
}
|
||||||
|
|
||||||
FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData);
|
puts("Used classes:");
|
||||||
|
for (const auto& name : classes)
|
||||||
|
{
|
||||||
|
printf("%s\n", name.c_str());
|
||||||
|
}
|
||||||
|
puts("vtable chuj");
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> errors;
|
bool DebugParser(const std::string& filename)
|
||||||
Types::TypeManager typeManager(sizeof(void*));
|
{
|
||||||
if (!typeManager.ParseTypes(ppData, filename, errors))
|
std::string data;
|
||||||
{
|
if (!FileHelper::ReadAllText("tests\\" + filename, data))
|
||||||
puts("Failed to parse types:");
|
{
|
||||||
for (const auto& error : errors)
|
printf("Failed to read: %s\n", filename.c_str());
|
||||||
puts(error.c_str());
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
puts("ParseFile success!");
|
std::string pperror;
|
||||||
return true;
|
std::unordered_map<std::string, std::string> definitions;
|
||||||
|
definitions["WIN32"] = "";
|
||||||
|
definitions["_MSC_VER"] = "1337";
|
||||||
|
auto ppData = preprocess(data, pperror, definitions);
|
||||||
|
if (!pperror.empty())
|
||||||
|
{
|
||||||
|
printf("Preprocess error: %s\n", pperror.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData);
|
||||||
|
|
||||||
|
std::vector<std::string> errors;
|
||||||
|
Types::Model model;
|
||||||
|
if (!Types::ParseModel(ppData, filename, errors, model))
|
||||||
|
{
|
||||||
|
puts("Failed to parse types:");
|
||||||
|
for (const auto& error : errors)
|
||||||
|
puts(error.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
puts("ParseModel success!");
|
||||||
|
|
||||||
|
HandleVTable(model);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
//GenerateExpectedTests();
|
//GenerateExpectedTests();
|
||||||
auto ticks = GetTickCount();
|
auto ticks = GetTickCount();
|
||||||
DebugParser("cursor.hpp");
|
DebugParser("cursor.hpp");
|
||||||
//Lexer lexer;
|
//Lexer lexer;
|
||||||
//DebugLexer(lexer, "AndroidManifestTemplate.bt", false);
|
//DebugLexer(lexer, "AndroidManifestTemplate.bt", false);
|
||||||
//RunLexerTests();
|
//RunLexerTests();
|
||||||
printf("finished in %ums\n", GetTickCount() - ticks);
|
printf("finished in %ums\n", (unsigned int)(GetTickCount() - ticks));
|
||||||
system("pause");
|
system("pause");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in New Issue