WIP changes to expression functions

This commit is contained in:
Duncan Ogilvie 2020-06-03 11:49:27 +02:00
parent 6f5e786a54
commit 426f47f89d
7 changed files with 159 additions and 31 deletions

View File

@ -280,7 +280,7 @@ typedef enum
typedef void (*CBPLUGIN)(CBTYPE cbType, void* callbackInfo);
typedef bool (*CBPLUGINCOMMAND)(int argc, char** argv);
typedef void (*CBPLUGINSCRIPT)();
typedef duint(*CBPLUGINEXPRFUNCTION)(int argc, duint* argv, void* userdata);
typedef duint(*CBPLUGINEXPRFUNCTION)(int argc, const duint* argv, void* userdata);
typedef FORMATRESULT(*CBPLUGINFORMATFUNCTION)(char* dest, size_t destCount, int argc, char* argv[], duint value, void* userdata);
typedef bool (*CBPLUGINPREDICATE)(void* userdata);

View File

@ -20,8 +20,50 @@ struct gens<0, S...>
typedef seq<S...> type;
};
template<typename... Ts>
struct front;
template<typename T>
struct front<T>
{
using type = typename T;
};
template<typename T, typename... Ts>
struct front<T, Ts...>
{
using type = typename T;
};
template<>
struct front<>
{
using type = duint;
};
template<typename T>
struct registerHelper;
template<>
struct registerHelper<duint>
{
bool operator()(const String & name, int argc, const ExpressionFunctions::CBEXPRESSIONFUNCTIONINT & cbFunction)
{
return ExpressionFunctions::RegisterInt(name, argc, cbFunction);
}
};
template<>
struct registerHelper<const char*>
{
bool operator()(const String & name, int argc, const ExpressionFunctions::CBEXPRESSIONFUNCTIONSTR & cbFunction)
{
return ExpressionFunctions::RegisterStr(name, argc, cbFunction);
}
};
template<typename T, int ...S, typename... Ts>
static T callFunc(const T* argv, T(*cbFunction)(Ts...), seq<S...>)
static duint callFunc(const T* argv, duint(*cbFunction)(Ts...), seq<S...>)
{
return cbFunction(argv[S]...);
}
@ -30,11 +72,11 @@ template<typename... Ts>
static bool RegisterEasy(const String & name, duint(*cbFunction)(Ts...))
{
auto aliases = StringUtils::Split(name, ',');
auto tempFunc = [cbFunction](int argc, duint * argv, void* userdata)
auto tempFunc = [cbFunction](int argc, const typename front<Ts...>::type * argv, void* userdata) -> duint
{
return callFunc(argv, cbFunction, typename gens<sizeof...(Ts)>::type());
};
if(!ExpressionFunctions::Register(aliases[0], sizeof...(Ts), tempFunc))
if(!registerHelper<typename front<Ts...>::type>()(aliases[0], sizeof...(Ts), tempFunc))
return false;
for(size_t i = 1; i < aliases.size(); i++)
ExpressionFunctions::RegisterAlias(aliases[0], aliases[i]);
@ -68,6 +110,7 @@ void ExpressionFunctions::Init()
RegisterEasy("mod.offset,mod.fileoffset", valvatofileoffset);
RegisterEasy("mod.headerva", modheaderva);
RegisterEasy("mod.isexport", modisexport);
RegisterEasy("mod.fromname", ModBaseFromName);
//Process information
RegisterEasy("peb,PEB", peb);
@ -143,9 +186,12 @@ void ExpressionFunctions::Init()
//Undocumented
RegisterEasy("bpgoto", bpgoto);
//String
RegisterEasy("strcmp", strcmp);
}
bool ExpressionFunctions::Register(const String & name, int argc, const CBEXPRESSIONFUNCTION & cbFunction, void* userdata)
bool ExpressionFunctions::RegisterInt(const String & name, int argc, const CBEXPRESSIONFUNCTIONINT & cbFunction, void* userdata)
{
if(!isValidName(name))
return false;
@ -155,8 +201,28 @@ bool ExpressionFunctions::Register(const String & name, int argc, const CBEXPRES
Function f;
f.name = name;
f.argc = argc;
f.cbFunction = cbFunction;
f.cbFunctionInt = cbFunction;
f.cbFunctionStr = nullptr;
f.userdata = userdata;
f.strFunction = false;
mFunctions[name] = f;
return true;
}
bool ExpressionFunctions::RegisterStr(const String & name, int argc, const CBEXPRESSIONFUNCTIONSTR & cbFunction, void* userdata)
{
if(!isValidName(name))
return false;
EXCLUSIVE_ACQUIRE(LockExpressionFunctions);
if(mFunctions.count(name))
return false;
Function f;
f.name = name;
f.argc = argc;
f.cbFunctionInt = nullptr;
f.cbFunctionStr = cbFunction;
f.userdata = userdata;
f.strFunction = true;
mFunctions[name] = f;
return true;
}
@ -167,8 +233,16 @@ bool ExpressionFunctions::RegisterAlias(const String & name, const String & alia
auto found = mFunctions.find(name);
if(found == mFunctions.end())
return false;
if(!Register(alias, found->second.argc, found->second.cbFunction, found->second.userdata))
return false;
if(found->second.strFunction)
{
if(!RegisterStr(alias, found->second.argc, found->second.cbFunctionStr, found->second.userdata))
return false;
}
else
{
if(!RegisterInt(alias, found->second.argc, found->second.cbFunctionInt, found->second.userdata))
return false;
}
found->second.aliases.push_back(alias);
return true;
}
@ -186,26 +260,40 @@ bool ExpressionFunctions::Unregister(const String & name)
return true;
}
bool ExpressionFunctions::Call(const String & name, std::vector<duint> & argv, duint & result)
bool ExpressionFunctions::CallInt(const String & name, std::vector<duint> & argv, duint & result)
{
SHARED_ACQUIRE(LockExpressionFunctions);
auto found = mFunctions.find(name);
if(found == mFunctions.end())
return false;
const auto & f = found->second;
if(f.argc != int(argv.size()))
if(f.argc != int(argv.size()) || f.strFunction)
return false;
result = f.cbFunction(f.argc, argv.data(), f.userdata);
result = f.cbFunctionInt(f.argc, argv.data(), f.userdata);
return true;
}
bool ExpressionFunctions::GetArgc(const String & name, int & argc)
bool ExpressionFunctions::CallStr(const String & name, std::vector<const char*> & argv, duint & result)
{
SHARED_ACQUIRE(LockExpressionFunctions);
auto found = mFunctions.find(name);
if(found == mFunctions.end())
return false;
const auto & f = found->second;
if(f.argc != int(argv.size()) || !f.strFunction)
return false;
result = f.cbFunctionStr(f.argc, argv.data(), f.userdata);
return true;
}
bool ExpressionFunctions::GetArgc(const String & name, int & argc, bool & strFunction)
{
SHARED_ACQUIRE(LockExpressionFunctions);
auto found = mFunctions.find(name);
if(found == mFunctions.end())
return false;
argc = found->second.argc;
strFunction = found->second.strFunction;
return true;
}

View File

@ -6,23 +6,28 @@
class ExpressionFunctions
{
public:
using CBEXPRESSIONFUNCTION = std::function<duint(int argc, duint* argv, void* userdata)>;
using CBEXPRESSIONFUNCTIONINT = std::function<duint(int argc, const duint* argv, void* userdata)>;
using CBEXPRESSIONFUNCTIONSTR = std::function<duint(int argc, const char** argv, void* userdata)>;
static void Init();
static bool Register(const String & name, int argc, const CBEXPRESSIONFUNCTION & cbFunction, void* userdata = nullptr);
static bool RegisterInt(const String & name, int argc, const CBEXPRESSIONFUNCTIONINT & cbFunction, void* userdata = nullptr);
static bool RegisterStr(const String & name, int argc, const CBEXPRESSIONFUNCTIONSTR & cbFunction, void* userdata = nullptr);
static bool RegisterAlias(const String & name, const String & alias);
static bool Unregister(const String & name);
static bool Call(const String & name, std::vector<duint> & argv, duint & result);
static bool GetArgc(const String & name, int & argc);
static bool CallInt(const String & name, std::vector<duint> & argv, duint & result);
static bool CallStr(const String & name, std::vector<const char*> & argv, duint & result);
static bool GetArgc(const String & name, int & argc, bool & strFunction);
private:
struct Function
{
String name;
int argc = 0;
CBEXPRESSIONFUNCTION cbFunction;
CBEXPRESSIONFUNCTIONINT cbFunctionInt;
CBEXPRESSIONFUNCTIONSTR cbFunctionStr;
void* userdata = nullptr;
std::vector<String> aliases;
bool strFunction = false;
};
static bool isValidName(const String & name);

View File

@ -872,23 +872,45 @@ bool ExpressionParser::Calculate(duint & value, bool signedcalc, bool allowassig
{
const auto & name = token.data();
int argc;
if(!ExpressionFunctions::GetArgc(name, argc))
bool strFunction;
if(!ExpressionFunctions::GetArgc(name, argc, strFunction))
return false;
if(int(stack.size()) < argc)
return false;
std::vector<duint> argv;
argv.resize(argc);
for(auto i = 0; i < argc; i++)
{
duint arg;
if(!stack[stack.size() - 1].DoEvaluate(arg, silent, baseonly))
return false;
stack.pop_back();
argv[argc - i - 1] = arg;
}
duint result;
if(!ExpressionFunctions::Call(name, argv, result))
return false;
if(strFunction)
{
std::vector<const char*> argv;
argv.resize(argc);
for(auto i = 0; i < argc; i++)
{
auto & value = stack[stack.size() - i - 1];
if(value.evaluated)
value.data = StringUtils::sprintf("0x%p", value.value);
argv[argc - i - 1] = value.data.c_str();
}
auto success = ExpressionFunctions::CallStr(name, argv, result);
for(auto i = 0; i < argc; i++)
stack.pop_back();
if(!success)
return false;
}
else
{
std::vector<duint> argv;
argv.resize(argc);
for(auto i = 0; i < argc; i++)
{
duint arg;
if(!stack[stack.size() - 1].DoEvaluate(arg, silent, baseonly))
return false;
stack.pop_back();
argv[argc - i - 1] = arg;
}
if(!ExpressionFunctions::CallInt(name, argv, result))
return false;
}
stack.push_back(EvalValue(result));
}
else

View File

@ -11,6 +11,7 @@
#include "value.h"
#include "TraceRecord.h"
#include "exhandlerinfo.h"
#include <vector>
namespace Exprfunc
{
@ -461,4 +462,14 @@ namespace Exprfunc
return 0;
return getLastExceptionInfo().ExceptionRecord.ExceptionInformation[index];
}
duint strcmp(const char* addrStr, const char* str)
{
duint addr = 0;
if(!convertNumber(addrStr, addr, 16))
return 0;
std::vector<char> cmp(strlen(str) + 1);
DbgMemRead(addr, cmp.data(), cmp.size());
return ::strcmp(cmp.data(), str);
}
}

View File

@ -79,4 +79,6 @@ namespace Exprfunc
duint exflags();
duint exinfocount();
duint exinfo(duint index);
duint strcmp(const char* addr, const char* str);
}

View File

@ -991,7 +991,7 @@ bool pluginexprfuncregister(int pluginHandle, const char* name, int argc, CBPLUG
PLUG_EXPRFUNCTION plugExprfunction;
plugExprfunction.pluginHandle = pluginHandle;
strcpy_s(plugExprfunction.name, name);
if(!ExpressionFunctions::Register(name, argc, cbFunction, userdata))
if(!ExpressionFunctions::RegisterInt(name, argc, cbFunction, userdata))
{
dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN, %s] Expression function \"%s\" failed to register...\n"), plugName.c_str(), name);
return false;