Improve expression function support
This commit is contained in:
parent
ba12bb6eba
commit
89963dfc1a
|
|
@ -240,13 +240,13 @@ typedef enum
|
|||
{
|
||||
ValueTypeNumber,
|
||||
ValueTypeString,
|
||||
ValueTypeAny
|
||||
ValueTypeAny, // Cannot be used for values, only for argTypes (to accept any type)
|
||||
} ValueType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* ptr;
|
||||
bool isOwner;
|
||||
const char* ptr; // Should be allocated with BridgeAlloc
|
||||
bool isOwner; // When set to true BridgeFree will be called on ptr
|
||||
} StringValue;
|
||||
|
||||
typedef struct
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ void ExpressionFunctions::Init()
|
|||
RegisterEasy("mod.offset,mod.fileoffset", valvatofileoffset);
|
||||
RegisterEasy("mod.headerva", modheaderva);
|
||||
RegisterEasy("mod.isexport", modisexport);
|
||||
ExpressionFunctions::Register("mod.fromname", ValueTypeNumber, { ValueTypeString }, Exprfunc::modbasefromname, nullptr);
|
||||
|
||||
//Process information
|
||||
RegisterEasy("peb,PEB", peb);
|
||||
|
|
@ -108,6 +109,9 @@ void ExpressionFunctions::Init()
|
|||
RegisterEasy("dis.next", disnext);
|
||||
RegisterEasy("dis.prev", disprev);
|
||||
RegisterEasy("dis.iscallsystem", disiscallsystem);
|
||||
ExpressionFunctions::Register("dis.mnemonic", ValueTypeString, { ValueTypeNumber }, Exprfunc::dismnemonic, nullptr);
|
||||
ExpressionFunctions::Register("dis.text", ValueTypeString, { ValueTypeNumber }, Exprfunc::distext, nullptr);
|
||||
ExpressionFunctions::Register("dis.match", ValueTypeNumber, { ValueTypeNumber, ValueTypeString }, Exprfunc::dismatch, nullptr);
|
||||
|
||||
//Trace record
|
||||
RegisterEasy("tr.enabled", trenabled);
|
||||
|
|
@ -148,12 +152,12 @@ void ExpressionFunctions::Init()
|
|||
//Undocumented
|
||||
RegisterEasy("bpgoto", bpgoto);
|
||||
|
||||
ExpressionFunctions::Register("streq", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::strcmp, nullptr);
|
||||
ExpressionFunctions::Register("strstr", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::strstr, nullptr);
|
||||
ExpressionFunctions::Register("strlen", ValueTypeNumber, { ValueTypeString }, Exprfunc::strlen, nullptr);
|
||||
ExpressionFunctions::Register("utf16", ValueTypeString, { ValueTypeNumber }, Exprfunc::utf16, nullptr);
|
||||
// Strings
|
||||
ExpressionFunctions::Register("utf8", ValueTypeString, { ValueTypeNumber }, Exprfunc::utf8, nullptr);
|
||||
ExpressionFunctions::Register("mod.fromname", ValueTypeNumber, { ValueTypeString }, Exprfunc::modbasefromname, nullptr);
|
||||
ExpressionFunctions::Register("utf16", ValueTypeString, { ValueTypeNumber }, Exprfunc::utf16, nullptr);
|
||||
ExpressionFunctions::Register("strstr", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::strstr, nullptr);
|
||||
ExpressionFunctions::Register("streq", ValueTypeNumber, { ValueTypeString, ValueTypeString }, Exprfunc::streq, nullptr);
|
||||
ExpressionFunctions::Register("strlen", ValueTypeNumber, { ValueTypeString }, Exprfunc::strlen, nullptr);
|
||||
}
|
||||
|
||||
bool ExpressionFunctions::Register(const String & name, const ValueType & returnType, const std::vector<ValueType> & argTypes, const CBEXPRESSIONFUNCTION & cbFunction, void* userdata)
|
||||
|
|
|
|||
|
|
@ -903,6 +903,7 @@ bool ExpressionParser::Calculate(duint & value, bool signedcalc, bool allowassig
|
|||
argv.resize(argTypes.size());
|
||||
for(auto i = 0; i < argTypes.size(); i++)
|
||||
{
|
||||
const auto & argType = argTypes[argTypes.size() - i - 1];
|
||||
auto & top = stack[stack.size() - i - 1];
|
||||
ExpressionValue arg;
|
||||
if(top.isString)
|
||||
|
|
@ -921,7 +922,7 @@ bool ExpressionParser::Calculate(duint & value, bool signedcalc, bool allowassig
|
|||
arg = { ValueTypeNumber, result };
|
||||
}
|
||||
|
||||
if(arg.type != argTypes[i] && argTypes[i] != ValueTypeAny)
|
||||
if(arg.type != argType && argType != ValueTypeAny)
|
||||
{
|
||||
if(!silent)
|
||||
{
|
||||
|
|
@ -936,10 +937,36 @@ bool ExpressionParser::Calculate(duint & value, bool signedcalc, bool allowassig
|
|||
}
|
||||
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "invalid"));
|
||||
};
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Expression function %s argument %d type mismatch (expected %s, got %s)!\n"),
|
||||
name.c_str(),
|
||||
String argValueStr;
|
||||
if(arg.type == ValueTypeNumber)
|
||||
{
|
||||
argValueStr = StringUtils::sprintf("0x%p", arg.number);
|
||||
}
|
||||
else if(arg.type == ValueTypeString)
|
||||
{
|
||||
argValueStr = "\"" + StringUtils::Escape(arg.string.ptr) + "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
argValueStr = "???";
|
||||
}
|
||||
String signature = name;
|
||||
signature += "(";
|
||||
for(size_t j = 0; j < argTypes.size(); j++)
|
||||
{
|
||||
if(j > 0)
|
||||
{
|
||||
signature += ", ";
|
||||
}
|
||||
signature += typeName(argTypes[j]);
|
||||
}
|
||||
signature += ")";
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Expression function %s argument %d/%d (%s) type mismatch (expected %s, got %s)!\n"),
|
||||
signature.c_str(),
|
||||
argTypes.size() - i,
|
||||
typeName(argTypes[i]).c_str(),
|
||||
argTypes.size(),
|
||||
argValueStr.c_str(),
|
||||
typeName(argType).c_str(),
|
||||
typeName(arg.type).c_str()
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,50 @@
|
|||
#include "TraceRecord.h"
|
||||
#include "exhandlerinfo.h"
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
|
||||
/// <summary>
|
||||
/// Creates an owning ExpressionValue string
|
||||
/// </summary>
|
||||
static ExpressionValue ValueString(const char* str)
|
||||
{
|
||||
auto len = ::strlen(str);
|
||||
auto buf = (char*)BridgeAlloc(len + 1);
|
||||
memcpy(buf, str, len);
|
||||
|
||||
ExpressionValue value = {};
|
||||
value.type = ValueTypeString;
|
||||
value.string.ptr = buf;
|
||||
value.string.isOwner = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an owning ExpressionValue string
|
||||
/// </summary>
|
||||
static ExpressionValue ValueString(const String & str)
|
||||
{
|
||||
auto len = str.length();
|
||||
auto buf = (char*)BridgeAlloc(len + 1);
|
||||
memcpy(buf, str.c_str(), len);
|
||||
|
||||
ExpressionValue value = {};
|
||||
value.type = ValueTypeString;
|
||||
value.string.ptr = buf;
|
||||
value.string.isOwner = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an owning ExpressionValue number
|
||||
/// </summary>
|
||||
static ExpressionValue ValueNumber(duint number)
|
||||
{
|
||||
ExpressionValue value = {};
|
||||
value.type = ValueTypeNumber;
|
||||
value.number = number;
|
||||
return value;
|
||||
}
|
||||
|
||||
namespace Exprfunc
|
||||
{
|
||||
|
|
@ -84,6 +128,15 @@ namespace Exprfunc
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool modbasefromname(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argc == 1);
|
||||
assert(argv[0].type == ValueTypeString);
|
||||
|
||||
*result = ValueNumber(ModBaseFromName(argv[0].string.ptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
static duint selstart(GUISELECTIONTYPE hWindow)
|
||||
{
|
||||
SELECTIONDATA selection;
|
||||
|
|
@ -306,6 +359,73 @@ namespace Exprfunc
|
|||
return dest && (modsystem(dest) || modsystem(disbranchdest(dest)));
|
||||
}
|
||||
|
||||
bool dismnemonic(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argc == 1);
|
||||
assert(argv[0].type == ValueTypeNumber);
|
||||
|
||||
String mnemonic = "???";
|
||||
auto addr = argv[0].number;
|
||||
unsigned char data[MAX_DISASM_BUFFER];
|
||||
if(MemRead(addr, data, sizeof(data)))
|
||||
{
|
||||
Zydis dis;
|
||||
if(dis.Disassemble(addr, data))
|
||||
{
|
||||
mnemonic = dis.Mnemonic();
|
||||
}
|
||||
}
|
||||
|
||||
*result = ValueString(mnemonic);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool distext(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argc == 1);
|
||||
assert(argv[0].type == ValueTypeNumber);
|
||||
|
||||
std::string text = "???";
|
||||
auto addr = argv[0].number;
|
||||
unsigned char data[MAX_DISASM_BUFFER];
|
||||
if(MemRead(addr, data, sizeof(data)))
|
||||
{
|
||||
Zydis dis;
|
||||
if(dis.Disassemble(addr, data))
|
||||
{
|
||||
text = dis.InstructionText();
|
||||
}
|
||||
}
|
||||
|
||||
*result = ValueString(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dismatch(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argc == 2);
|
||||
assert(argv[0].type == ValueTypeNumber);
|
||||
assert(argv[1].type == ValueTypeString);
|
||||
|
||||
bool matched = false;
|
||||
auto addr = argv[0].number;
|
||||
unsigned char data[MAX_DISASM_BUFFER];
|
||||
if(MemRead(addr, data, sizeof(data)))
|
||||
{
|
||||
Zydis dis;
|
||||
if(dis.Disassemble(addr, data))
|
||||
{
|
||||
auto text = dis.InstructionText();
|
||||
std::smatch m;
|
||||
std::regex re(argv[1].string.ptr);
|
||||
matched = std::regex_search(text, m, re);
|
||||
}
|
||||
}
|
||||
|
||||
*result = ValueNumber(matched);
|
||||
return true;
|
||||
}
|
||||
|
||||
duint trenabled(duint addr)
|
||||
{
|
||||
return TraceRecord.getTraceRecordType(addr) != TraceRecordManager::TraceRecordNone;
|
||||
|
|
@ -478,12 +598,38 @@ namespace Exprfunc
|
|||
return getLastExceptionInfo().ExceptionRecord.ExceptionInformation[index];
|
||||
}
|
||||
|
||||
bool streq(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argc == 1);
|
||||
assert(argv[0].type == ValueTypeString);
|
||||
|
||||
*result = ValueNumber(::strcmp(argv[0].string.ptr, argv[1].string.ptr) == 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strstr(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argc == 1);
|
||||
assert(argv[0].type == ValueTypeString);
|
||||
|
||||
*result = ValueNumber(::strstr(argv[0].string.ptr, argv[1].string.ptr) != nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strlen(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argc == 1);
|
||||
assert(argv[0].type == ValueTypeString);
|
||||
|
||||
*result = ValueNumber(::strlen(argv[0].string.ptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool utf16(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
if(argc > 1 || !argc)
|
||||
return false;
|
||||
|
||||
assert(argc == 1);
|
||||
assert(argv[0].type == ValueTypeNumber);
|
||||
|
||||
duint addr = argv[0].number;
|
||||
|
||||
std::vector<wchar_t> tempStr(MAX_STRING_SIZE + 1);
|
||||
|
|
@ -499,22 +645,16 @@ namespace Exprfunc
|
|||
return false;
|
||||
}
|
||||
|
||||
auto strBuf = BridgeAlloc(utf8Str.size() + 1);
|
||||
memcpy(strBuf, utf8Str.c_str(), utf8Str.size());
|
||||
|
||||
result->type = ValueTypeString;
|
||||
result->string.ptr = (const char*)strBuf;
|
||||
result->string.isOwner = true;
|
||||
*result = ValueString(utf8Str);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool utf8(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
if(argc > 1 || !argc)
|
||||
return false;
|
||||
|
||||
assert(argc == 1);
|
||||
assert(argv[0].type == ValueTypeNumber);
|
||||
|
||||
duint addr = argv[0].number;
|
||||
|
||||
std::vector<char> tempStr(MAX_STRING_SIZE + 1);
|
||||
|
|
@ -524,65 +664,7 @@ namespace Exprfunc
|
|||
return false;
|
||||
}
|
||||
|
||||
auto strlen = ::strlen(tempStr.data());
|
||||
auto strBuf = BridgeAlloc(strlen + 1);
|
||||
memcpy(strBuf, tempStr.data(), strlen + 1);
|
||||
|
||||
result->type = ValueTypeString;
|
||||
result->string.ptr = (const char*)strBuf;
|
||||
result->string.isOwner = true;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool modbasefromname(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
result->type = ValueTypeNumber;
|
||||
result->number = ModBaseFromName(argv[0].string.ptr);
|
||||
|
||||
if(!result->number)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strcmp(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argv[0].type == ValueTypeString);
|
||||
result->type = ValueTypeNumber;
|
||||
result->number = 0;
|
||||
|
||||
if(argc > 2 || argc <= 1)
|
||||
return false;
|
||||
|
||||
result->number = !::strcmp(argv[0].string.ptr, argv[1].string.ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strstr(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argv[0].type == ValueTypeString);
|
||||
result->type = ValueTypeNumber;
|
||||
result->number = 0;
|
||||
|
||||
if(argc > 2 || argc <= 1)
|
||||
return false;
|
||||
|
||||
result->number = ::strstr(argv[0].string.ptr, argv[1].string.ptr) != nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strlen(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata)
|
||||
{
|
||||
assert(argv[0].type == ValueTypeString);
|
||||
result->type = ValueTypeNumber;
|
||||
result->number = 0;
|
||||
|
||||
if(argc != 1)
|
||||
return false;
|
||||
|
||||
result->number = ::strlen(argv[0].string.ptr);
|
||||
*result = ValueString(tempStr.data());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ namespace Exprfunc
|
|||
duint modrva(duint addr);
|
||||
duint modheaderva(duint addr);
|
||||
duint modisexport(duint addr);
|
||||
bool modbasefromname(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
|
||||
duint disasmsel();
|
||||
duint dumpsel();
|
||||
|
|
@ -50,6 +51,9 @@ namespace Exprfunc
|
|||
duint disnext(duint addr);
|
||||
duint disprev(duint addr);
|
||||
duint disiscallsystem(duint addr);
|
||||
bool dismnemonic(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
bool distext(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
bool dismatch(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
|
||||
duint trenabled(duint addr);
|
||||
duint trhitcount(duint addr);
|
||||
|
|
@ -82,10 +86,9 @@ namespace Exprfunc
|
|||
duint exinfocount();
|
||||
duint exinfo(duint index);
|
||||
|
||||
bool strcmp(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
bool streq(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
bool strstr(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
bool strlen(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
bool utf16(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
bool utf8(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
bool modbasefromname(ExpressionValue* result, int argc, const ExpressionValue* argv, void* userdata);
|
||||
}
|
||||
Loading…
Reference in New Issue