1
0
Fork 0

DBG: add support for customized string formatting (closes #1336)

This commit is contained in:
mrexodia 2017-03-11 05:41:25 +01:00
parent fa84346445
commit 5796891771
No known key found for this signature in database
GPG Key ID: FC89E0AAA0C1AAD8
11 changed files with 225 additions and 13 deletions

View File

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

View File

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

View File

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

29
src/dbg/formatfunctions.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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