1
0
Fork 0

Improve expression function support

This commit is contained in:
Duncan Ogilvie 2022-04-11 00:56:47 +02:00
parent ba12bb6eba
commit 89963dfc1a
5 changed files with 201 additions and 85 deletions

View File

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

View File

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

View File

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

View File

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

View File

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