2021-09-08 15:18:24 +02:00
|
|
|
#include <hex/pattern_language/pattern_language.hpp>
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
#include <hex/helpers/file.hpp>
|
2021-01-22 18:01:39 +01:00
|
|
|
#include <hex/providers/provider.hpp>
|
2021-09-21 21:29:18 +02:00
|
|
|
#include <hex/helpers/logger.hpp>
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
#include <hex/pattern_language/preprocessor.hpp>
|
|
|
|
#include <hex/pattern_language/lexer.hpp>
|
|
|
|
#include <hex/pattern_language/parser.hpp>
|
|
|
|
#include <hex/pattern_language/validator.hpp>
|
|
|
|
#include <hex/pattern_language/evaluator.hpp>
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
namespace hex::pl {
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-09-06 20:35:38 +02:00
|
|
|
class PatternData;
|
|
|
|
|
2021-01-23 14:00:09 +01:00
|
|
|
PatternLanguage::PatternLanguage() {
|
2021-01-22 18:01:39 +01:00
|
|
|
this->m_preprocessor = new Preprocessor();
|
2022-02-01 22:09:44 +01:00
|
|
|
this->m_lexer = new Lexer();
|
|
|
|
this->m_parser = new Parser();
|
|
|
|
this->m_validator = new Validator();
|
|
|
|
this->m_evaluator = new Evaluator();
|
2021-01-23 14:00:09 +01:00
|
|
|
|
2022-01-30 17:49:18 +01:00
|
|
|
this->m_preprocessor->addDefaultPragmaHandlers();
|
|
|
|
|
2021-01-23 14:00:09 +01:00
|
|
|
this->m_preprocessor->addPragmaHandler("endian", [this](std::string value) {
|
|
|
|
if (value == "big") {
|
2021-10-06 15:19:32 +02:00
|
|
|
this->m_evaluator->setDefaultEndian(std::endian::big);
|
2021-01-23 14:00:09 +01:00
|
|
|
return true;
|
|
|
|
} else if (value == "little") {
|
2021-10-06 15:19:32 +02:00
|
|
|
this->m_evaluator->setDefaultEndian(std::endian::little);
|
2021-01-23 14:00:09 +01:00
|
|
|
return true;
|
|
|
|
} else if (value == "native") {
|
2021-10-06 15:19:32 +02:00
|
|
|
this->m_evaluator->setDefaultEndian(std::endian::native);
|
2021-01-23 14:00:09 +01:00
|
|
|
return true;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-07 13:20:33 +01:00
|
|
|
|
|
|
|
this->m_preprocessor->addPragmaHandler("eval_depth", [this](std::string value) {
|
|
|
|
auto limit = strtol(value.c_str(), nullptr, 0);
|
|
|
|
|
|
|
|
if (limit <= 0)
|
|
|
|
return false;
|
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
this->m_evaluator->setEvaluationDepth(limit);
|
2021-09-22 00:45:04 +02:00
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
this->m_preprocessor->addPragmaHandler("array_limit", [this](const std::string &value) {
|
2021-09-22 00:45:04 +02:00
|
|
|
auto limit = strtol(value.c_str(), nullptr, 0);
|
|
|
|
|
|
|
|
if (limit <= 0)
|
|
|
|
return false;
|
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
this->m_evaluator->setArrayLimit(limit);
|
2021-03-07 13:20:33 +01:00
|
|
|
return true;
|
|
|
|
});
|
2021-04-13 21:49:31 +02:00
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
this->m_preprocessor->addPragmaHandler("pattern_limit", [this](const std::string &value) {
|
|
|
|
auto limit = strtol(value.c_str(), nullptr, 0);
|
|
|
|
|
|
|
|
if (limit <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
this->m_evaluator->setPatternLimit(limit);
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
2021-10-07 11:34:46 +02:00
|
|
|
this->m_preprocessor->addPragmaHandler("loop_limit", [this](const std::string &value) {
|
|
|
|
auto limit = strtol(value.c_str(), nullptr, 0);
|
|
|
|
|
|
|
|
if (limit <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
this->m_evaluator->setLoopLimit(limit);
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
this->m_preprocessor->addPragmaHandler("base_address", [](const std::string &value) {
|
2021-04-13 21:49:31 +02:00
|
|
|
auto baseAddress = strtoull(value.c_str(), nullptr, 0);
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
ImHexApi::Provider::get()->setBaseAddress(baseAddress);
|
2021-04-13 21:49:31 +02:00
|
|
|
return true;
|
|
|
|
});
|
2021-01-22 18:01:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PatternLanguage::~PatternLanguage() {
|
|
|
|
delete this->m_preprocessor;
|
|
|
|
delete this->m_lexer;
|
|
|
|
delete this->m_parser;
|
|
|
|
delete this->m_validator;
|
|
|
|
}
|
|
|
|
|
2022-01-24 20:53:17 +01:00
|
|
|
std::optional<std::vector<ASTNode *>> PatternLanguage::parseString(const std::string &code) {
|
2021-12-18 22:56:36 +01:00
|
|
|
auto preprocessedCode = this->m_preprocessor->preprocess(code);
|
|
|
|
if (!preprocessedCode.has_value()) {
|
|
|
|
this->m_currError = this->m_preprocessor->getError();
|
2022-01-30 12:43:43 +01:00
|
|
|
return std::nullopt;
|
2021-12-18 22:56:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto tokens = this->m_lexer->lex(preprocessedCode.value());
|
|
|
|
if (!tokens.has_value()) {
|
|
|
|
this->m_currError = this->m_lexer->getError();
|
2022-01-30 12:43:43 +01:00
|
|
|
return std::nullopt;
|
2021-12-18 22:56:36 +01:00
|
|
|
}
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-12-18 22:56:36 +01:00
|
|
|
auto ast = this->m_parser->parse(tokens.value());
|
|
|
|
if (!ast.has_value()) {
|
|
|
|
this->m_currError = this->m_parser->getError();
|
2022-01-30 12:43:43 +01:00
|
|
|
return std::nullopt;
|
2021-12-18 22:56:36 +01:00
|
|
|
}
|
|
|
|
|
2022-01-31 14:37:12 +01:00
|
|
|
if (!this->m_validator->validate(*ast)) {
|
|
|
|
this->m_currError = this->m_validator->getError();
|
|
|
|
|
|
|
|
for (auto &node : *ast)
|
|
|
|
delete node;
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
2021-12-18 22:56:36 +01:00
|
|
|
return ast;
|
|
|
|
}
|
|
|
|
|
2022-02-06 00:18:04 +01:00
|
|
|
bool PatternLanguage::executeString(prv::Provider *provider, const std::string &code, const std::map<std::string, Token::Literal> &envVars, const std::map<std::string, Token::Literal> &inVariables, bool checkResult) {
|
2022-02-01 18:09:40 +01:00
|
|
|
this->m_running = true;
|
|
|
|
ON_SCOPE_EXIT { this->m_running = false; };
|
|
|
|
|
2021-01-22 18:01:39 +01:00
|
|
|
this->m_currError.reset();
|
|
|
|
this->m_evaluator->getConsole().clear();
|
2021-01-23 14:00:09 +01:00
|
|
|
this->m_evaluator->setProvider(provider);
|
2021-10-02 15:22:38 +02:00
|
|
|
this->m_evaluator->setDefaultEndian(std::endian::native);
|
|
|
|
this->m_evaluator->setEvaluationDepth(32);
|
|
|
|
this->m_evaluator->setArrayLimit(0x1000);
|
|
|
|
this->m_evaluator->setPatternLimit(0x2000);
|
2021-10-07 11:34:46 +02:00
|
|
|
this->m_evaluator->setLoopLimit(0x1000);
|
2021-12-18 22:56:36 +01:00
|
|
|
this->m_evaluator->setInVariables(inVariables);
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-12-10 11:55:27 +01:00
|
|
|
for (const auto &[name, value] : envVars)
|
|
|
|
this->m_evaluator->setEnvVariable(name, value);
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
for (auto &node : this->m_currAST)
|
|
|
|
delete node;
|
|
|
|
this->m_currAST.clear();
|
|
|
|
|
2021-12-18 22:56:36 +01:00
|
|
|
auto ast = this->parseString(code);
|
|
|
|
if (!ast)
|
2022-02-01 18:09:40 +01:00
|
|
|
return false;
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
this->m_currAST = ast.value();
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
auto patterns = this->m_evaluator->evaluate(ast.value());
|
|
|
|
if (!patterns.has_value()) {
|
|
|
|
this->m_currError = this->m_evaluator->getConsole().getLastHardError();
|
2022-02-01 18:09:40 +01:00
|
|
|
return false;
|
2021-01-22 18:01:39 +01:00
|
|
|
}
|
|
|
|
|
2022-02-06 00:18:04 +01:00
|
|
|
if (auto mainResult = this->m_evaluator->getMainResult(); checkResult && mainResult.has_value()) {
|
|
|
|
auto returnCode = Token::literalToSigned(*mainResult);
|
|
|
|
|
|
|
|
if (returnCode != 0) {
|
|
|
|
auto errorMessage = hex::format("non-success value returned from main: {}", returnCode);
|
|
|
|
|
|
|
|
this->m_evaluator->getConsole().log(LogConsole::Level::Error, errorMessage);
|
|
|
|
this->m_currError = PatternLanguageError(0, errorMessage);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
this->m_patterns = std::move(patterns.value());
|
|
|
|
|
|
|
|
return true;
|
2021-01-22 18:01:39 +01:00
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
bool PatternLanguage::executeFile(prv::Provider *provider, const fs::path &path, const std::map<std::string, Token::Literal> &envVars, const std::map<std::string, Token::Literal> &inVariables) {
|
2021-09-08 15:18:24 +02:00
|
|
|
File file(path, File::Mode::Read);
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2022-02-06 00:18:04 +01:00
|
|
|
return this->executeString(provider, file.readString(), envVars, inVariables, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<bool, std::optional<Token::Literal>> PatternLanguage::executeFunction(prv::Provider *provider, const std::string &code) {
|
|
|
|
|
|
|
|
auto functionContent = hex::format("fn main() {{ {0} }};", code);
|
|
|
|
|
|
|
|
auto success = this->executeString(provider, functionContent, {}, {}, false);
|
|
|
|
auto result = this->m_evaluator->getMainResult();
|
|
|
|
|
|
|
|
return { success, result };
|
2021-01-22 18:01:39 +01:00
|
|
|
}
|
|
|
|
|
2021-10-07 11:34:46 +02:00
|
|
|
void PatternLanguage::abort() {
|
|
|
|
this->m_evaluator->abort();
|
|
|
|
}
|
|
|
|
|
2022-01-24 20:53:17 +01:00
|
|
|
const std::vector<ASTNode *> &PatternLanguage::getCurrentAST() const {
|
2021-12-18 22:56:36 +01:00
|
|
|
return this->m_currAST;
|
|
|
|
}
|
|
|
|
|
2022-01-24 20:53:17 +01:00
|
|
|
[[nodiscard]] std::map<std::string, Token::Literal> PatternLanguage::getOutVariables() const {
|
2021-12-18 22:56:36 +01:00
|
|
|
return this->m_evaluator->getOutVariables();
|
|
|
|
}
|
|
|
|
|
2021-01-22 18:01:39 +01:00
|
|
|
|
2022-01-24 20:53:17 +01:00
|
|
|
const std::vector<std::pair<LogConsole::Level, std::string>> &PatternLanguage::getConsoleLog() {
|
2021-01-22 18:01:39 +01:00
|
|
|
return this->m_evaluator->getConsole().getLog();
|
|
|
|
}
|
|
|
|
|
2022-01-31 14:37:12 +01:00
|
|
|
const std::optional<PatternLanguageError> &PatternLanguage::getError() {
|
2021-01-22 18:01:39 +01:00
|
|
|
return this->m_currError;
|
|
|
|
}
|
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
u32 PatternLanguage::getCreatedPatternCount() {
|
|
|
|
return this->m_evaluator->getPatternCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 PatternLanguage::getMaximumPatternCount() {
|
|
|
|
return this->m_evaluator->getPatternLimit();
|
|
|
|
}
|
|
|
|
|
2021-12-19 12:32:15 +01:00
|
|
|
|
|
|
|
void PatternLanguage::allowDangerousFunctions(bool allow) {
|
|
|
|
this->m_evaluator->allowDangerousFunctions(allow);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PatternLanguage::hasDangerousFunctionBeenCalled() const {
|
|
|
|
return this->m_evaluator->hasDangerousFunctionBeenCalled();
|
|
|
|
}
|
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
void PatternLanguage::reset() {
|
|
|
|
for (auto &pattern : this->m_patterns)
|
|
|
|
delete pattern;
|
|
|
|
this->m_patterns.clear();
|
|
|
|
|
|
|
|
this->m_currAST.clear();
|
|
|
|
}
|
|
|
|
|
2021-01-22 18:01:39 +01:00
|
|
|
}
|