DBG: add support for customized string formatting (closes #1336)
This commit is contained in:
parent
fa84346445
commit
5796891771
|
@ -157,3 +157,13 @@ duint _plugin_hash(const void* data, duint size)
|
|||
{
|
||||
return murmurhash(data, int(size));
|
||||
}
|
||||
|
||||
PLUG_IMPEXP bool _plugin_registerformatfunction(int pluginHandle, const char* type, CBPLUGINFORMATFUNCTION cbFunction, void* userdata)
|
||||
{
|
||||
return pluginformatfuncregister(pluginHandle, type, cbFunction, userdata);
|
||||
}
|
||||
|
||||
PLUG_IMPEXP bool _plugin_unregisterformatfunction(int pluginHandle, const char* type)
|
||||
{
|
||||
return pluginformatfuncunregister(pluginHandle, type);
|
||||
}
|
||||
|
|
|
@ -264,6 +264,7 @@ 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 bool(*CBPLUGINFORMATFUNCTION)(char* dest, size_t destCount, int argc, char* argv[], duint value, void* userdata);
|
||||
|
||||
//exports
|
||||
#ifdef __cplusplus
|
||||
|
@ -297,6 +298,8 @@ PLUG_IMPEXP bool _plugin_unregisterexprfunction(int pluginHandle, const char* na
|
|||
PLUG_IMPEXP bool _plugin_unload(const char* pluginName);
|
||||
PLUG_IMPEXP bool _plugin_load(const char* pluginName);
|
||||
PLUG_IMPEXP duint _plugin_hash(const void* data, duint size);
|
||||
PLUG_IMPEXP bool _plugin_registerformatfunction(int pluginHandle, const char* type, CBPLUGINFORMATFUNCTION cbFunction, void* userdata);
|
||||
PLUG_IMPEXP bool _plugin_unregisterformatfunction(int pluginHandle, const char* type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
#include "formatfunctions.h"
|
||||
#include "threading.h"
|
||||
#include "value.h"
|
||||
#include "memory.h"
|
||||
|
||||
std::unordered_map<String, FormatFunctions::Function> FormatFunctions::mFunctions;
|
||||
|
||||
void FormatFunctions::Init()
|
||||
{
|
||||
Register("mem", [](char* dest, size_t destCount, int argc, char* argv[], duint addr, void* userdata)
|
||||
{
|
||||
duint size;
|
||||
if(argc < 2 || !valfromstring(argv[1], &size) || size > 128)
|
||||
return false;
|
||||
std::vector<unsigned char> data(size);
|
||||
if(!MemRead(addr, data.data(), data.size()))
|
||||
return false;
|
||||
strncpy_s(dest, destCount, StringUtils::ToHex(data.data(), data.size()).c_str(), _TRUNCATE);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool FormatFunctions::Register(const String & type, const CBFORMATFUNCTION & cbFunction, void* userdata)
|
||||
{
|
||||
if(!isValidName(type))
|
||||
return false;
|
||||
EXCLUSIVE_ACQUIRE(LockFormatFunctions);
|
||||
if(mFunctions.count(type))
|
||||
return false;
|
||||
Function f;
|
||||
f.type = type;
|
||||
f.cbFunction = cbFunction;
|
||||
f.userdata = userdata;
|
||||
mFunctions[type] = f;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FormatFunctions::RegisterAlias(const String & name, const String & alias)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockFormatFunctions);
|
||||
auto found = mFunctions.find(name);
|
||||
if(found == mFunctions.end())
|
||||
return false;
|
||||
if(!Register(alias, found->second.cbFunction, found->second.userdata))
|
||||
return false;
|
||||
found->second.aliases.push_back(alias);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FormatFunctions::Unregister(const String & name)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockFormatFunctions);
|
||||
auto found = mFunctions.find(name);
|
||||
if(found == mFunctions.end())
|
||||
return false;
|
||||
auto aliases = found->second.aliases;
|
||||
mFunctions.erase(found);
|
||||
for(const auto & alias : found->second.aliases)
|
||||
Unregister(alias);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FormatFunctions::Call(std::vector<char> & dest, const String & type, std::vector<String> & argv, duint value)
|
||||
{
|
||||
SHARED_ACQUIRE(LockFormatFunctions);
|
||||
auto found = mFunctions.find(type);
|
||||
if(found == mFunctions.end())
|
||||
return false;
|
||||
std::vector<char*> argvn(argv.size());
|
||||
for(size_t i = 0; i < argv.size(); i++)
|
||||
argvn[i] = (char*)argv[i].c_str();
|
||||
const auto & f = found->second;
|
||||
return f.cbFunction(dest.data(), dest.size(), int(argv.size()), argvn.data(), value, f.userdata);
|
||||
}
|
||||
|
||||
bool FormatFunctions::isValidName(const String & name)
|
||||
{
|
||||
if(!name.length())
|
||||
return false;
|
||||
if(!(name[0] == '_' || isalpha(name[0])))
|
||||
return false;
|
||||
for(const auto & ch : name)
|
||||
if(!(isalnum(ch) || ch == '_' || ch == '.'))
|
||||
return false;
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "_global.h"
|
||||
#include "_plugins.h"
|
||||
|
||||
class FormatFunctions
|
||||
{
|
||||
public:
|
||||
using CBFORMATFUNCTION = std::function<bool(char* dest, size_t destCount, int argc, char* argv[], duint value, void* userdata)>;
|
||||
|
||||
static void Init();
|
||||
static bool Register(const String & type, const CBFORMATFUNCTION & cbFunction, void* userdata = nullptr);
|
||||
static bool RegisterAlias(const String & type, const String & alias);
|
||||
static bool Unregister(const String & type);
|
||||
static bool Call(std::vector<char> & dest, const String & type, std::vector<String> & argv, duint value);
|
||||
|
||||
private:
|
||||
struct Function
|
||||
{
|
||||
String type;
|
||||
CBFORMATFUNCTION cbFunction;
|
||||
void* userdata;
|
||||
std::vector<String> aliases;
|
||||
};
|
||||
|
||||
static bool isValidName(const String & name);
|
||||
|
||||
static std::unordered_map<String, Function> mFunctions;
|
||||
};
|
|
@ -9,6 +9,7 @@
|
|||
#include "debugger.h"
|
||||
#include "threading.h"
|
||||
#include "expressionfunctions.h"
|
||||
#include "formatfunctions.h"
|
||||
|
||||
/**
|
||||
\brief List of plugins.
|
||||
|
@ -45,6 +46,11 @@ static std::vector<PLUG_MENU> pluginMenuList;
|
|||
*/
|
||||
static std::vector<PLUG_EXPRFUNCTION> pluginExprfunctionList;
|
||||
|
||||
/**
|
||||
\brief List of plugin formatfunctions.
|
||||
*/
|
||||
static std::vector<PLUG_FORMATFUNCTION> pluginFormatfunctionList;
|
||||
|
||||
/**
|
||||
\brief Loads a plugin from the plugin directory.
|
||||
\param pluginName Name of the plugin.
|
||||
|
@ -893,3 +899,36 @@ bool pluginexprfuncunregister(int pluginHandle, const char* name)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pluginformatfuncregister(int pluginHandle, const char* type, CBPLUGINFORMATFUNCTION cbFunction, void* userdata)
|
||||
{
|
||||
PLUG_FORMATFUNCTION plugFormatfunction;
|
||||
plugFormatfunction.pluginHandle = pluginHandle;
|
||||
strcpy_s(plugFormatfunction.name, type);
|
||||
if(!FormatFunctions::Register(type, cbFunction, userdata))
|
||||
return false;
|
||||
EXCLUSIVE_ACQUIRE(LockPluginFormatfunctionList);
|
||||
pluginFormatfunctionList.push_back(plugFormatfunction);
|
||||
EXCLUSIVE_RELEASE();
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] Format function \"%s\" registered!\n"), type);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pluginformatfuncunregister(int pluginHandle, const char* type)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockPluginFormatfunctionList);
|
||||
for(auto it = pluginFormatfunctionList.begin(); it != pluginFormatfunctionList.end(); ++it)
|
||||
{
|
||||
const auto & currentFormatfunction = *it;
|
||||
if(currentFormatfunction.pluginHandle == pluginHandle && !strcmp(currentFormatfunction.name, type))
|
||||
{
|
||||
pluginFormatfunctionList.erase(it);
|
||||
EXCLUSIVE_RELEASE();
|
||||
if(!FormatFunctions::Unregister(type))
|
||||
return false;
|
||||
dprintf(QT_TRANSLATE_NOOP("DBG", "[PLUGIN] Format function \"%s\" unregistered!\n"), type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,12 @@ struct PLUG_EXPRFUNCTION
|
|||
char name[deflen];
|
||||
};
|
||||
|
||||
struct PLUG_FORMATFUNCTION
|
||||
{
|
||||
int pluginHandle;
|
||||
char name[deflen];
|
||||
};
|
||||
|
||||
//plugin management functions
|
||||
bool pluginload(const char* pluginname, bool loadall = false);
|
||||
bool pluginunload(const char* pluginname, bool unloadall = false);
|
||||
|
@ -81,5 +87,7 @@ void pluginmenusetname(int pluginHandle, int hMenu, const char* name);
|
|||
void pluginmenuentrysetname(int pluginHandle, int hEntry, const char* name);
|
||||
bool pluginexprfuncregister(int pluginHandle, const char* name, int argc, CBPLUGINEXPRFUNCTION cbFunction, void* userdata);
|
||||
bool pluginexprfuncunregister(int pluginHandle, const char* name);
|
||||
bool pluginformatfuncregister(int pluginHandle, const char* type, CBPLUGINFORMATFUNCTION cbFunction, void* userdata);
|
||||
bool pluginformatfuncunregister(int pluginHandle, const char* type);
|
||||
|
||||
#endif // _PLUGIN_LOADER_H
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "symbolinfo.h"
|
||||
#include "module.h"
|
||||
#include "disasm_fast.h"
|
||||
#include "formatfunctions.h"
|
||||
|
||||
namespace ValueType
|
||||
{
|
||||
|
@ -93,11 +94,12 @@ static String printValue(FormatValueType value, ValueType::ValueType type)
|
|||
return result;
|
||||
}
|
||||
|
||||
static const char* getArgExpressionType(const String & formatString, ValueType::ValueType & type)
|
||||
static const char* getArgExpressionType(const String & formatString, ValueType::ValueType & type, String & complexArgs)
|
||||
{
|
||||
auto hasExplicitType = false;
|
||||
size_t toSkip = 0;
|
||||
type = ValueType::Hex;
|
||||
if(formatString.size() > 2 && !isdigit(formatString[0]) && formatString[1] == ':')
|
||||
complexArgs.clear();
|
||||
if(formatString.size() > 2 && !isdigit(formatString[0]) && formatString[1] == ':') //simple type
|
||||
{
|
||||
switch(formatString[0])
|
||||
{
|
||||
|
@ -128,19 +130,25 @@ static const char* getArgExpressionType(const String & formatString, ValueType::
|
|||
default: //invalid format
|
||||
return nullptr;
|
||||
}
|
||||
hasExplicitType = true;
|
||||
toSkip = 2; //skip '?:'
|
||||
}
|
||||
auto expression = formatString.c_str();
|
||||
if(hasExplicitType)
|
||||
expression += 2;
|
||||
else
|
||||
type = ValueType::Hex;
|
||||
return expression;
|
||||
else if(formatString.size() > 3 && (formatString[0] == ';' || formatString[0] == '@')) //complex type
|
||||
{
|
||||
for(toSkip = 1; toSkip < formatString.length(); toSkip++)
|
||||
if(formatString[toSkip] == '@')
|
||||
{
|
||||
toSkip++;
|
||||
break;
|
||||
}
|
||||
complexArgs = formatString.substr(1, toSkip - 2);
|
||||
}
|
||||
return formatString.c_str() + toSkip;
|
||||
}
|
||||
|
||||
static unsigned int getArgNumType(const String & formatString, ValueType::ValueType & type)
|
||||
{
|
||||
auto expression = getArgExpressionType(formatString, type);
|
||||
String complexArgs;
|
||||
auto expression = getArgExpressionType(formatString, type, complexArgs);
|
||||
unsigned int argnum = 0;
|
||||
if(!expression || sscanf(expression, "%u", &argnum) != 1)
|
||||
type = ValueType::Unknown;
|
||||
|
@ -205,11 +213,27 @@ String stringformat(String format, const FormatValueVector & values)
|
|||
return output;
|
||||
}
|
||||
|
||||
static String printComplexValue(FormatValueType value, const String & complexArgs)
|
||||
{
|
||||
auto split = StringUtils::Split(complexArgs, ';');
|
||||
duint valuint;
|
||||
if(!split.empty() && valfromstring(value, &valuint))
|
||||
{
|
||||
std::vector<char> dest(MAX_SETTING_SIZE, '\0'); //TODO: check performance, could be made static
|
||||
if(FormatFunctions::Call(dest, split[0], split, valuint))
|
||||
return String(dest.data());
|
||||
}
|
||||
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "[Formatting Error]"));
|
||||
}
|
||||
|
||||
static String handleFormatStringInline(const String & formatString)
|
||||
{
|
||||
auto type = ValueType::Unknown;
|
||||
auto value = getArgExpressionType(formatString, type);
|
||||
if(value && *value)
|
||||
String complexArgs;
|
||||
auto value = getArgExpressionType(formatString, type, complexArgs);
|
||||
if(!complexArgs.empty())
|
||||
return printComplexValue(value, complexArgs);
|
||||
else if(value && *value)
|
||||
return printValue(value, type);
|
||||
return GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "[Formatting Error]"));
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ enum SectionLock
|
|||
LockPluginCommandList,
|
||||
LockPluginMenuList,
|
||||
LockPluginExprfunctionList,
|
||||
LockPluginFormatfunctionList,
|
||||
LockSehCache,
|
||||
LockMnemonicHelp,
|
||||
LockTraceRecord,
|
||||
|
@ -71,6 +72,7 @@ enum SectionLock
|
|||
LockLineCache,
|
||||
LockTypeManager,
|
||||
LockModuleHashes,
|
||||
LockFormatFunctions,
|
||||
|
||||
// Number of elements in this enumeration. Must always be the last
|
||||
// index.
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "datainst_helper.h"
|
||||
#include "exception.h"
|
||||
#include "expressionfunctions.h"
|
||||
#include "formatfunctions.h"
|
||||
#include "yara/yara.h"
|
||||
|
||||
static MESSAGE_STACK* gMsgStack = 0;
|
||||
|
@ -684,6 +685,8 @@ extern "C" DLL_EXPORT const char* _dbg_dbginit()
|
|||
dputs(QT_TRANSLATE_NOOP("DBG", "Registering GUI command handler..."));
|
||||
ExpressionFunctions::Init();
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Registering expression functions..."));
|
||||
FormatFunctions::Init();
|
||||
dputs(QT_TRANSLATE_NOOP("DBG", "Registering format functions..."));
|
||||
SCRIPTTYPEINFO info;
|
||||
strcpy_s(info.name, GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "Default")));
|
||||
info.id = 0;
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
<ClCompile Include="disasm_helper.cpp" />
|
||||
<ClCompile Include="expressionfunctions.cpp" />
|
||||
<ClCompile Include="exprfunc.cpp" />
|
||||
<ClCompile Include="formatfunctions.cpp" />
|
||||
<ClCompile Include="handles.cpp" />
|
||||
<ClCompile Include="exception.cpp" />
|
||||
<ClCompile Include="exhandlerinfo.cpp" />
|
||||
|
@ -194,6 +195,7 @@
|
|||
<ClInclude Include="expressionfunctions.h" />
|
||||
<ClInclude Include="exprfunc.h" />
|
||||
<ClInclude Include="filemap.h" />
|
||||
<ClInclude Include="formatfunctions.h" />
|
||||
<ClInclude Include="handles.h" />
|
||||
<ClInclude Include="exception.h" />
|
||||
<ClInclude Include="exhandlerinfo.h" />
|
||||
|
|
|
@ -425,6 +425,9 @@
|
|||
<ClCompile Include="typesparser.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="formatfunctions.cpp">
|
||||
<Filter>Source Files\Core</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dbghelp\dbghelp.h">
|
||||
|
@ -949,5 +952,8 @@
|
|||
<ClInclude Include="filemap.h">
|
||||
<Filter>Header Files\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="formatfunctions.h">
|
||||
<Filter>Header Files\Core</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue