1
0
Fork 0

DBG: added SerializableTMap (less code duplication)

This commit is contained in:
mrexodia 2016-06-01 11:03:54 +02:00
parent 94129aa276
commit 5e01b34178
No known key found for this signature in database
GPG Key ID: D72F9A4FAA0073B4
17 changed files with 897 additions and 793 deletions

View File

@ -298,7 +298,8 @@ void TraceRecordManager::saveToDb(JSON root)
efree(temp, "TraceRecordManager::saveToDb");
json_array_append_new(jsonTraceRecords, jsonObj);
}
json_object_set_new(root, "tracerecord", jsonTraceRecords);
if(json_array_size(jsonTraceRecords))
json_object_set_new(root, "tracerecord", jsonTraceRecords);
json_decref(jsonTraceRecords);
}
@ -320,7 +321,7 @@ void TraceRecordManager::loadFromDb(JSON root)
TraceRecordPage currentPage;
size_t size;
currentPage.dataType = (TraceRecordType)json_hex_value(json_object_get(value, "type"));
currentPage.rva = json_hex_value(json_object_get(value, "rva"));
currentPage.rva = (duint)json_hex_value(json_object_get(value, "rva"));
switch(currentPage.dataType)
{
case TraceRecordType::TraceRecordBitExec:

View File

@ -0,0 +1,78 @@
#include "_scriptapi_argument.h"
#include "_scriptapi_module.h"
#include "argument.h"
SCRIPT_EXPORT bool Script::Argument::Add(duint start, duint end, bool manual, duint instructionCount)
{
return ArgumentAdd(start, end, manual, instructionCount);
}
SCRIPT_EXPORT bool Script::Argument::Add(const ArgumentInfo* info)
{
if(!info)
return false;
auto base = Module::BaseFromName(info->mod);
if(!base)
return false;
return Add(base + info->rvaStart, base + info->rvaEnd, info->manual, info->instructioncount);
}
SCRIPT_EXPORT bool Script::Argument::Get(duint addr, duint* start, duint* end, duint* instructionCount)
{
return ArgumentGet(addr, start, end, instructionCount);
}
SCRIPT_EXPORT bool Script::Argument::GetInfo(duint addr, ArgumentInfo* info)
{
ARGUMENTSINFO argument;
if(!ArgumentGetInfo(addr, argument))
return false;
if(info)
{
strcpy_s(info->mod, argument.mod);
info->rvaStart = argument.start;
info->rvaEnd = argument.end;
info->manual = argument.manual;
info->instructioncount = argument.instructioncount;
}
return true;
}
SCRIPT_EXPORT bool Script::Argument::Overlaps(duint start, duint end)
{
return ArgumentOverlaps(start, end);
}
SCRIPT_EXPORT bool Script::Argument::Delete(duint address)
{
return ArgumentDelete(address);
}
SCRIPT_EXPORT void Script::Argument::DeleteRange(duint start, duint end, bool deleteManual)
{
ArgumentDelRange(start, end, deleteManual);
}
SCRIPT_EXPORT void Script::Argument::Clear()
{
ArgumentClear();
}
SCRIPT_EXPORT bool Script::Argument::GetList(ListOf(ArgumentInfo) list)
{
std::vector<ARGUMENTSINFO> argumentList;
ArgumentGetList(argumentList);
std::vector<ArgumentInfo> argumentScriptList;
argumentScriptList.reserve(argumentList.size());
for(const auto & argument : argumentList)
{
ArgumentInfo scriptArgument;
strcpy_s(scriptArgument.mod, argument.mod);
scriptArgument.rvaStart = argument.start;
scriptArgument.rvaEnd = argument.end;
scriptArgument.manual = argument.manual;
scriptArgument.instructioncount = argument.instructioncount;
argumentScriptList.push_back(scriptArgument);
}
return BridgeList<ArgumentInfo>::CopyData(list, argumentScriptList);
}

View File

@ -0,0 +1,31 @@
#ifndef _SCRIPTAPI_ARGUMENT_H
#define _SCRIPTAPI_ARGUMENT_H
#include "_scriptapi.h"
namespace Script
{
namespace Argument
{
struct ArgumentInfo
{
char mod[MAX_MODULE_SIZE];
duint rvaStart;
duint rvaEnd;
bool manual;
duint instructioncount;
};
SCRIPT_EXPORT bool Add(duint start, duint end, bool manual, duint instructionCount = 0);
SCRIPT_EXPORT bool Add(const ArgumentInfo* info);
SCRIPT_EXPORT bool Get(duint addr, duint* start = nullptr, duint* end = nullptr, duint* instructionCount = nullptr);
SCRIPT_EXPORT bool GetInfo(duint addr, ArgumentInfo* info);
SCRIPT_EXPORT bool Overlaps(duint start, duint end);
SCRIPT_EXPORT bool Delete(duint address);
SCRIPT_EXPORT void DeleteRange(duint start, duint end, bool deleteManual = false);
SCRIPT_EXPORT void Clear();
SCRIPT_EXPORT bool GetList(ListOf(ArgumentInfo) list); //caller has the responsibility to free the list
}; //Argument
}; //Script
#endif //_SCRIPTAPI_ARGUMENT_H

View File

@ -25,7 +25,7 @@ SCRIPT_EXPORT bool Script::Function::Get(duint addr, duint* start, duint* end, d
SCRIPT_EXPORT bool Script::Function::GetInfo(duint addr, FunctionInfo* info)
{
FUNCTIONSINFO function;
if(!FunctionGetInfo(addr, &function))
if(!FunctionGetInfo(addr, function))
return false;
if(info)
{

View File

@ -53,6 +53,8 @@ struct DepthModuleRangeCompare
}
};
#include "serializablemap.h"
//typedefs
typedef std::function<void (duint base, const char* mod, const char* name, duint addr)> EXPORTENUMCALLBACK;
typedef std::function<void (duint base, duint addr, char* name, char* moduleName)> IMPORTENUMCALLBACK;

158
src/dbg/argument.cpp Normal file
View File

@ -0,0 +1,158 @@
#include "argument.h"
#include "module.h"
#include "memory.h"
#include "threading.h"
struct ArgumentSerializer : JSONWrapper<ARGUMENTSINFO>
{
bool Save(const ARGUMENTSINFO & value) override
{
setString("module", value.mod);
setHex("start", value.start);
setHex("end", value.end);
setHex("icount", value.instructioncount);
setBool("manual", value.manual);
return true;
}
bool Load(ARGUMENTSINFO & value) override
{
return getString("module", value.mod) &&
getHex("start", value.start) &&
getHex("end", value.end) &&
getBool("manual", value.manual) &&
getHex("icount", value.instructioncount) &&
value.end >= value.start;
}
};
struct Arguments : SerializableModuleRangeMap<LockArguments, ARGUMENTSINFO, ArgumentSerializer>
{
void AdjustValue(ARGUMENTSINFO & value) const override
{
auto base = ModBaseFromName(value.mod);
value.start += base;
value.end += base;
}
protected:
const char* jsonKey() const override
{
return "arguments";
}
ModuleRange makeKey(const ARGUMENTSINFO & value) const override
{
return ModuleRange(ModHashFromName(value.mod), Range(value.start, value.end));
}
};
static Arguments arguments;
bool ArgumentAdd(duint Start, duint End, bool Manual, duint InstructionCount)
{
// Make sure memory is readable
if(!MemIsValidReadPtr(Start))
return false;
// Fail if boundary exceeds module size
auto moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return false;
// Fail if 'Start' and 'End' are incompatible
if(Start > End || ArgumentOverlaps(Start, End))
return false;
ARGUMENTSINFO argument;
ModNameFromAddr(Start, argument.mod, true);
argument.start = Start - moduleBase;
argument.end = End - moduleBase;
argument.manual = Manual;
argument.instructioncount = InstructionCount;
return arguments.Add(argument);
}
bool ArgumentGet(duint Address, duint* Start, duint* End, duint* InstrCount)
{
ARGUMENTSINFO argument;
if(!arguments.Get(Arguments::VaKey(Address, Address), argument))
return false;
arguments.AdjustValue(argument);
if(Start)
*Start = argument.start;
if(End)
*End = argument.end;
if(InstrCount)
*InstrCount = argument.instructioncount;
return true;
}
bool ArgumentOverlaps(duint Start, duint End)
{
// A argument can't end before it begins
if(Start > End)
return false;
return arguments.Contains(Arguments::VaKey(Start, End));
}
bool ArgumentDelete(duint Address)
{
return arguments.Delete(Arguments::VaKey(Address, Address));
}
void ArgumentDelRange(duint Start, duint End, bool DeleteManual)
{
// Should all arguments be deleted?
// 0x00000000 - 0xFFFFFFFF
if(Start == 0 && End == ~0)
{
ArgumentClear();
}
else
{
// The start and end address must be in the same module
auto moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return;
// Convert these to a relative offset
Start -= moduleBase;
End -= moduleBase;
arguments.DeleteWhere([ = ](const ARGUMENTSINFO & value)
{
if(!DeleteManual && value.manual)
return false;
return value.end >= Start && value.start <= End;
});
}
}
void ArgumentCacheSave(JSON Root)
{
arguments.CacheSave(Root);
}
void ArgumentCacheLoad(JSON Root)
{
arguments.CacheLoad(Root);
}
void ArgumentClear()
{
arguments.Clear();
}
void ArgumentGetList(std::vector<ARGUMENTSINFO> & list)
{
arguments.GetList(list);
}
bool ArgumentGetInfo(duint Address, ARGUMENTSINFO & info)
{
return arguments.Get(Arguments::VaKey(Address, Address), info);
}

26
src/dbg/argument.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _ARGUMENT_H
#define _ARGUMENT_H
#include "addrinfo.h"
struct ARGUMENTSINFO
{
char mod[MAX_MODULE_SIZE];
duint start;
duint end;
bool manual;
duint instructioncount;
};
bool ArgumentAdd(duint Start, duint End, bool Manual, duint InstructionCount = 0);
bool ArgumentGet(duint Address, duint* Start = nullptr, duint* End = nullptr, duint* InstrCount = nullptr);
bool ArgumentOverlaps(duint Start, duint End);
bool ArgumentDelete(duint Address);
void ArgumentDelRange(duint Start, duint End, bool DeleteManual = false);
void ArgumentCacheSave(JSON Root);
void ArgumentCacheLoad(JSON Root);
void ArgumentClear();
void ArgumentGetList(std::vector<ARGUMENTSINFO> & list);
bool ArgumentGetInfo(duint Address, ARGUMENTSINFO & info);
#endif // _ARGUMENT_H

View File

@ -1,14 +1,49 @@
#include "bookmark.h"
#include "threading.h"
#include "module.h"
#include "memory.h"
std::unordered_map<duint, BOOKMARKSINFO> bookmarks;
struct BookmarkSerializer : JSONWrapper<BOOKMARKSINFO>
{
bool Save(const BOOKMARKSINFO & value) override
{
setString("module", value.mod);
setHex("address", value.addr);
setBool("manual", value.manual);
return true;
}
bool Load(BOOKMARKSINFO & value) override
{
value.manual = true;
getBool("manual", value.manual); //legacy support
return getString("module", value.mod) &&
getHex("address", value.addr);
}
};
struct Bookmarks : SerializableModuleHashMap<LockBookmarks, BOOKMARKSINFO, BookmarkSerializer>
{
void AdjustValue(BOOKMARKSINFO & value) const override
{
value.addr += ModBaseFromName(value.mod);
}
protected:
const char* jsonKey() const override
{
return "bookmarks";
}
duint makeKey(const BOOKMARKSINFO & value) const override
{
return ModHashFromName(value.mod) + value.addr;
}
};
static Bookmarks bookmarks;
bool BookmarkSet(duint Address, bool Manual)
{
ASSERT_DEBUGGING("Export call");
// Validate the incoming address
if(!MemIsValidReadPtr(Address))
return false;
@ -18,202 +53,59 @@ bool BookmarkSet(duint Address, bool Manual)
bookmark.addr = Address - ModBaseFromAddr(Address);
bookmark.manual = Manual;
// Exclusive lock to insert new data
EXCLUSIVE_ACQUIRE(LockBookmarks);
if(!bookmarks.insert(std::make_pair(ModHashFromAddr(Address), bookmark)).second)
{
EXCLUSIVE_RELEASE();
return BookmarkDelete(Address);
}
return true;
auto key = Bookmarks::VaKey(Address);
if(bookmarks.Contains(key))
return bookmarks.Delete(key);
return bookmarks.Add(bookmark);
}
bool BookmarkGet(duint Address)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockBookmarks);
return (bookmarks.count(ModHashFromAddr(Address)) > 0);
return bookmarks.Contains(Bookmarks::VaKey(Address));
}
bool BookmarkDelete(duint Address)
{
ASSERT_DEBUGGING("Export call");
EXCLUSIVE_ACQUIRE(LockBookmarks);
return (bookmarks.erase(ModHashFromAddr(Address)) > 0);
return bookmarks.Delete(Bookmarks::VaKey(Address));
}
void BookmarkDelRange(duint Start, duint End, bool Manual)
{
ASSERT_DEBUGGING("Export call");
// Are all bookmarks going to be deleted?
// 0x00000000 - 0xFFFFFFFF
if(Start == 0 && End == ~0)
bookmarks.DeleteRange(Start, End, [Manual](duint start, duint end, const BOOKMARKSINFO & value)
{
BookmarkClear();
}
else
{
// Make sure 'Start' and 'End' reference the same module
duint moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return;
// Virtual -> relative offset
Start -= moduleBase;
End -= moduleBase;
EXCLUSIVE_ACQUIRE(LockBookmarks);
for(auto itr = bookmarks.begin(); itr != bookmarks.end();)
{
const auto & currentBookmark = itr->second;
// Ignore non-matching entries
if(Manual ? !currentBookmark.manual : currentBookmark.manual)
{
++itr;
continue;
}
// [Start, End)
if(currentBookmark.addr >= Start && currentBookmark.addr < End)
itr = bookmarks.erase(itr);
else
++itr;
}
}
if(Manual ? !value.manual : value.manual) //ignore non-matching entries
return false;
return value.addr >= start && value.addr < end;
});
}
void BookmarkCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBookmarks);
const JSON jsonBookmarks = json_array();
const JSON jsonAutoBookmarks = json_array();
// Save to the JSON root
for(auto & itr : bookmarks)
{
JSON currentBookmark = json_object();
json_object_set_new(currentBookmark, "module", json_string(itr.second.mod));
json_object_set_new(currentBookmark, "address", json_hex(itr.second.addr));
if(itr.second.manual)
json_array_append_new(jsonBookmarks, currentBookmark);
else
json_array_append_new(jsonAutoBookmarks, currentBookmark);
}
if(json_array_size(jsonBookmarks))
json_object_set(Root, "bookmarks", jsonBookmarks);
if(json_array_size(jsonAutoBookmarks))
json_object_set(Root, "autobookmarks", jsonAutoBookmarks);
json_decref(jsonBookmarks);
json_decref(jsonAutoBookmarks);
bookmarks.CacheSave(Root);
}
void BookmarkCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockBookmarks);
// Inline lambda to parse each JSON entry
auto AddBookmarks = [](const JSON Object, bool Manual)
{
size_t i;
JSON value;
json_array_foreach(Object, i, value)
{
BOOKMARKSINFO bookmarkInfo;
memset(&bookmarkInfo, 0, sizeof(BOOKMARKSINFO));
// Load the module name
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(bookmarkInfo.mod, mod);
// Load address and set auto-generated flag
bookmarkInfo.addr = (duint)json_hex_value(json_object_get(value, "address"));
bookmarkInfo.manual = Manual;
const duint key = ModHashFromName(bookmarkInfo.mod) + bookmarkInfo.addr;
bookmarks.insert(std::make_pair(key, bookmarkInfo));
}
};
// Remove existing entries
bookmarks.clear();
const JSON jsonBookmarks = json_object_get(Root, "bookmarks");
const JSON jsonAutoBookmarks = json_object_get(Root, "autobookmarks");
// Load user-set bookmarks
if(jsonBookmarks)
AddBookmarks(jsonBookmarks, true);
// Load auto-set bookmarks
if(jsonAutoBookmarks)
AddBookmarks(jsonAutoBookmarks, false);
bookmarks.CacheLoad(Root);
bookmarks.CacheLoad(Root, false, "auto"); //legacy support
}
bool BookmarkEnum(BOOKMARKSINFO* List, size_t* Size)
{
// The array container must be set, or the size must be set, or both
ASSERT_FALSE(!List && !Size);
SHARED_ACQUIRE(LockBookmarks);
// Return the size if set
if(Size)
{
*Size = bookmarks.size() * sizeof(BOOKMARKSINFO);
if(!List)
return true;
}
// Copy struct and adjust the relative offset to a virtual address
for(auto & itr : bookmarks)
{
*List = itr.second;
List->addr += ModBaseFromName(List->mod);
List++;
}
return true;
return bookmarks.Enum(List, Size);
}
void BookmarkClear()
{
EXCLUSIVE_ACQUIRE(LockBookmarks);
bookmarks.clear();
bookmarks.Clear();
}
void BookmarkGetList(std::vector<BOOKMARKSINFO> & list)
{
SHARED_ACQUIRE(LockBookmarks);
list.clear();
list.reserve(bookmarks.size());
for(const auto & itr : bookmarks)
list.push_back(itr.second);
bookmarks.GetList(list);
}
bool BookmarkGetInfo(duint Address, BOOKMARKSINFO* info)
{
SHARED_ACQUIRE(LockBookmarks);
auto found = bookmarks.find(Address);
if(found == bookmarks.end())
return false;
if(info)
memcpy(info, &found->second, sizeof(BOOKMARKSINFO));
return true;
return bookmarks.GetInfo(Bookmarks::VaKey(Address), info);
}

View File

@ -3,12 +3,50 @@
#include "module.h"
#include "memory.h"
std::unordered_map<duint, COMMENTSINFO> comments;
struct CommentSerializer : JSONWrapper<COMMENTSINFO>
{
bool Save(const COMMENTSINFO & value) override
{
setString("module", value.mod);
setHex("address", value.addr);
setString("text", value.text);
setBool("manual", value.manual);
return true;
}
bool Load(COMMENTSINFO & value) override
{
value.manual = true;
getBool("manual", value.manual); //legacy support
return getString("module", value.mod) &&
getHex("address", value.addr) &&
getString("text", value.text);
}
};
struct Comments : SerializableModuleHashMap<LockComments, COMMENTSINFO, CommentSerializer>
{
void AdjustValue(COMMENTSINFO & value) const override
{
value.addr += ModBaseFromName(value.mod);
}
protected:
const char* jsonKey() const override
{
return "comments";
}
duint makeKey(const COMMENTSINFO & value) const override
{
return ModHashFromName(value.mod) + value.addr;
}
};
static Comments comments;
bool CommentSet(duint Address, const char* Text, bool Manual)
{
ASSERT_DEBUGGING("Export call");
// A valid memory address must be supplied
if(!MemIsValidReadPtr(Address))
return false;
@ -32,237 +70,63 @@ bool CommentSet(duint Address, const char* Text, bool Manual)
comment.manual = Manual;
comment.addr = Address - ModBaseFromAddr(Address);
// Key generated from module hash
const duint key = ModHashFromAddr(Address);
EXCLUSIVE_ACQUIRE(LockComments);
// Insert if possible, otherwise replace
if(!comments.insert(std::make_pair(key, comment)).second)
comments[key] = comment;
return true;
return comments.Add(comment);
}
bool CommentGet(duint Address, char* Text)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockComments);
// Get an existing comment and copy the string buffer
auto found = comments.find(ModHashFromAddr(Address));
// Was it found?
if(found == comments.end())
COMMENTSINFO comment;
if(!comments.Get(Comments::VaKey(Address), comment))
return false;
if(Text)
{
if(found->second.manual) //autocomment
strcpy_s(Text, MAX_COMMENT_SIZE, found->second.text);
else
sprintf_s(Text, MAX_COMMENT_SIZE, "\1%s", found->second.text);
}
if(comment.manual)
strcpy_s(Text, MAX_COMMENT_SIZE, comment.text);
else
sprintf_s(Text, MAX_COMMENT_SIZE, "\1%s", comment.text);
return true;
}
bool CommentDelete(duint Address)
{
ASSERT_DEBUGGING("Export call");
EXCLUSIVE_ACQUIRE(LockComments);
return (comments.erase(ModHashFromAddr(Address)) > 0);
return comments.Delete(Comments::VaKey(Address));
}
void CommentDelRange(duint Start, duint End, bool Manual)
{
ASSERT_DEBUGGING("Export call");
// Are all comments going to be deleted?
// 0x00000000 - 0xFFFFFFFF
if(Start == 0 && End == ~0)
comments.DeleteRange(Start, End, [Manual](duint start, duint end, const COMMENTSINFO & value)
{
CommentClear();
}
else
{
// Make sure 'Start' and 'End' reference the same module
duint moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return;
// Virtual -> relative offset
Start -= moduleBase;
End -= moduleBase;
EXCLUSIVE_ACQUIRE(LockComments);
for(auto itr = comments.begin(); itr != comments.end();)
{
const auto & currentComment = itr->second;
// Ignore non-matching entries
if(Manual ? !currentComment.manual : currentComment.manual)
{
++itr;
continue;
}
// [Start, End)
if(currentComment.addr >= Start && currentComment.addr < End)
itr = comments.erase(itr);
else
++itr;
}
}
if(Manual ? !value.manual : value.manual) //ignore non-matching entries
return false;
return value.addr >= start && value.addr < end;
});
}
void CommentCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockComments);
const JSON jsonComments = json_array();
const JSON jsonAutoComments = json_array();
// Build the JSON array
for(auto & itr : comments)
{
JSON currentComment = json_object();
json_object_set_new(currentComment, "module", json_string(itr.second.mod));
json_object_set_new(currentComment, "address", json_hex(itr.second.addr));
json_object_set_new(currentComment, "text", json_string(itr.second.text));
if(itr.second.manual)
json_array_append_new(jsonComments, currentComment);
else
json_array_append_new(jsonAutoComments, currentComment);
}
// Save to the JSON root
if(json_array_size(jsonComments))
json_object_set(Root, "comments", jsonComments);
if(json_array_size(jsonAutoComments))
json_object_set(Root, "autocomments", jsonAutoComments);
json_decref(jsonComments);
json_decref(jsonAutoComments);
comments.CacheSave(Root);
}
void CommentCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockComments);
// Inline lambda to parse each JSON entry
auto AddComments = [](const JSON Object, bool Manual)
{
size_t i;
JSON value;
json_array_foreach(Object, i, value)
{
COMMENTSINFO commentInfo;
memset(&commentInfo, 0, sizeof(COMMENTSINFO));
// Module
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(commentInfo.mod, mod);
// Address/Manual
commentInfo.addr = (duint)json_hex_value(json_object_get(value, "address"));
commentInfo.manual = Manual;
// String value
const char* text = json_string_value(json_object_get(value, "text"));
if(text)
strcpy_s(commentInfo.text, text);
else
{
// Skip blank comments
continue;
}
const duint key = ModHashFromName(commentInfo.mod) + commentInfo.addr;
comments.insert(std::make_pair(key, commentInfo));
}
};
// Remove existing entries
comments.clear();
const JSON jsonComments = json_object_get(Root, "comments");
const JSON jsonAutoComments = json_object_get(Root, "autocomments");
// Load user-set comments
if(jsonComments)
AddComments(jsonComments, true);
// Load auto-set comments
if(jsonAutoComments)
AddComments(jsonAutoComments, false);
comments.CacheLoad(Root);
comments.CacheLoad(Root, false, "auto"); //legacy support
}
bool CommentEnum(COMMENTSINFO* List, size_t* Size)
{
ASSERT_DEBUGGING("Command function call");
// At least 1 parameter must be supplied
ASSERT_FALSE(!List && !Size);
SHARED_ACQUIRE(LockComments);
// Check if the user requested size only
if(Size)
{
*Size = comments.size() * sizeof(COMMENTSINFO);
if(!List)
return true;
}
// Populate the returned array
for(auto & itr : comments)
{
*List = itr.second;
List->addr += ModBaseFromName(List->mod);
List++;
}
return true;
return comments.Enum(List, Size);
}
void CommentClear()
{
EXCLUSIVE_ACQUIRE(LockComments);
comments.clear();
comments.Clear();
}
void CommentGetList(std::vector<COMMENTSINFO> & list)
{
SHARED_ACQUIRE(LockComments);
list.clear();
list.reserve(comments.size());
for(const auto & itr : comments)
list.push_back(itr.second);
comments.GetList(list);
}
bool CommentGetInfo(duint Address, COMMENTSINFO* info)
{
SHARED_ACQUIRE(LockComments);
// Get an existing comment and copy the string buffer
auto found = comments.find(ModHashFromAddr(Address));
// Was it found?
if(found == comments.end())
return false;
if(info)
memcpy(info, &found->second, sizeof(COMMENTSINFO));
return true;
return comments.GetInfo(Comments::VaKey(Address), info);
}

View File

@ -3,18 +3,62 @@
#include "memory.h"
#include "threading.h"
std::map<ModuleRange, FUNCTIONSINFO, ModuleRangeCompare> functions;
struct FunctionSerializer : JSONWrapper<FUNCTIONSINFO>
{
bool Save(const FUNCTIONSINFO & value) override
{
setString("module", value.mod);
setHex("start", value.start);
setHex("end", value.end);
setHex("icount", value.instructioncount);
setBool("manual", value.manual);
return true;
}
bool Load(FUNCTIONSINFO & value) override
{
//legacy support
value.manual = true;
getBool("manual", value.manual);
return getString("module", value.mod) &&
getHex("start", value.start) &&
getHex("end", value.end) &&
getHex("icount", value.instructioncount) &&
value.end >= value.start;
}
};
struct Functions : SerializableModuleRangeMap<LockFunctions, FUNCTIONSINFO, FunctionSerializer>
{
void AdjustValue(FUNCTIONSINFO & value) const override
{
auto base = ModBaseFromName(value.mod);
value.start += base;
value.end += base;
}
protected:
const char* jsonKey() const override
{
return "functions";
}
ModuleRange makeKey(const FUNCTIONSINFO & value) const override
{
return ModuleRange(ModHashFromName(value.mod), Range(value.start, value.end));
}
};
static Functions functions;
bool FunctionAdd(duint Start, duint End, bool Manual, duint InstructionCount)
{
ASSERT_DEBUGGING("Export call");
// Make sure memory is readable
if(!MemIsValidReadPtr(Start))
return false;
// Fail if boundary exceeds module size
const duint moduleBase = ModBaseFromAddr(Start);
auto moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return false;
@ -30,68 +74,39 @@ bool FunctionAdd(duint Start, duint End, bool Manual, duint InstructionCount)
function.manual = Manual;
function.instructioncount = InstructionCount;
// Insert to global table
EXCLUSIVE_ACQUIRE(LockFunctions);
functions.insert(std::make_pair(ModuleRange(ModHashFromAddr(moduleBase), Range(function.start, function.end)), function));
return true;
return functions.Add(function);
}
bool FunctionGet(duint Address, duint* Start, duint* End, duint* InstrCount)
{
ASSERT_DEBUGGING("Export call");
const duint moduleBase = ModBaseFromAddr(Address);
// Lookup by module hash, then function range
SHARED_ACQUIRE(LockFunctions);
auto found = functions.find(ModuleRange(ModHashFromAddr(moduleBase), Range(Address - moduleBase, Address - moduleBase)));
// Was this range found?
if(found == functions.end())
FUNCTIONSINFO function;
if(!functions.Get(Functions::VaKey(Address, Address), function))
return false;
functions.AdjustValue(function);
if(Start)
*Start = found->second.start + moduleBase;
*Start = function.start;
if(End)
*End = found->second.end + moduleBase;
*End = function.end;
if(InstrCount)
*InstrCount = found->second.instructioncount;
*InstrCount = function.instructioncount;
return true;
}
bool FunctionOverlaps(duint Start, duint End)
{
ASSERT_DEBUGGING("Export call");
// A function can't end before it begins
if(Start > End)
return false;
const duint moduleBase = ModBaseFromAddr(Start);
SHARED_ACQUIRE(LockFunctions);
return (functions.count(ModuleRange(ModHashFromAddr(moduleBase), Range(Start - moduleBase, End - moduleBase))) > 0);
return functions.Contains(Functions::VaKey(Start, End));
}
bool FunctionDelete(duint Address)
{
ASSERT_DEBUGGING("Export call");
const duint moduleBase = ModBaseFromAddr(Address);
EXCLUSIVE_ACQUIRE(LockFunctions);
return (functions.erase(ModuleRange(ModHashFromAddr(moduleBase), Range(Address - moduleBase, Address - moduleBase))) > 0);
return functions.Delete(Functions::VaKey(Address, Address));
}
void FunctionDelRange(duint Start, duint End, bool DeleteManual)
{
ASSERT_DEBUGGING("Export call");
// Should all functions be deleted?
// 0x00000000 - 0xFFFFFFFF
if(Start == 0 && End == ~0)
@ -101,7 +116,7 @@ void FunctionDelRange(duint Start, duint End, bool DeleteManual)
else
{
// The start and end address must be in the same module
duint moduleBase = ModBaseFromAddr(Start);
auto moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return;
@ -110,173 +125,42 @@ void FunctionDelRange(duint Start, duint End, bool DeleteManual)
Start -= moduleBase;
End -= moduleBase;
EXCLUSIVE_ACQUIRE(LockFunctions);
for(auto itr = functions.begin(); itr != functions.end();)
functions.DeleteWhere([ = ](const FUNCTIONSINFO & value)
{
const auto & currentFunction = itr->second;
// Ignore manually set entries
if(!DeleteManual && currentFunction.manual)
{
++itr;
continue;
}
// [Start, End]
if(currentFunction.end >= Start && currentFunction.start <= End)
itr = functions.erase(itr);
else
++itr;
}
if(!DeleteManual && value.manual)
return false;
return value.end >= Start && value.start <= End;
});
}
}
void FunctionCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockFunctions);
// Allocate JSON object array
const JSON jsonFunctions = json_array();
const JSON jsonAutoFunctions = json_array();
for(auto & i : functions)
{
JSON currentFunction = json_object();
json_object_set_new(currentFunction, "module", json_string(i.second.mod));
json_object_set_new(currentFunction, "start", json_hex(i.second.start));
json_object_set_new(currentFunction, "end", json_hex(i.second.end));
json_object_set_new(currentFunction, "icount", json_hex(i.second.instructioncount));
if(i.second.manual)
json_array_append_new(jsonFunctions, currentFunction);
else
json_array_append_new(jsonAutoFunctions, currentFunction);
}
if(json_array_size(jsonFunctions))
json_object_set(Root, "functions", jsonFunctions);
if(json_array_size(jsonAutoFunctions))
json_object_set(Root, "autofunctions", jsonAutoFunctions);
// Decrease reference count to avoid leaking memory
json_decref(jsonFunctions);
json_decref(jsonAutoFunctions);
functions.CacheSave(Root);
}
void FunctionCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockFunctions);
// Delete existing entries
functions.clear();
// Inline lambda to enumerate all JSON array indices
auto InsertFunctions = [](const JSON Object, bool Manual)
{
size_t i;
JSON value;
json_array_foreach(Object, i, value)
{
FUNCTIONSINFO functionInfo;
memset(&functionInfo, 0, sizeof(FUNCTIONSINFO));
// Copy module name
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(functionInfo.mod, mod);
// Function address
functionInfo.start = (duint)json_hex_value(json_object_get(value, "start"));
functionInfo.end = (duint)json_hex_value(json_object_get(value, "end"));
functionInfo.manual = Manual;
functionInfo.instructioncount = (duint)json_hex_value(json_object_get(value, "icount"));
// Sanity check
if(functionInfo.end < functionInfo.start)
continue;
const duint key = ModHashFromName(functionInfo.mod);
functions.insert(std::make_pair(ModuleRange(key, Range(functionInfo.start, functionInfo.end)), functionInfo));
}
};
const JSON jsonFunctions = json_object_get(Root, "functions");
const JSON jsonAutoFunctions = json_object_get(Root, "autofunctions");
// Manual
if(jsonFunctions)
InsertFunctions(jsonFunctions, true);
// Auto
if(jsonAutoFunctions)
InsertFunctions(jsonAutoFunctions, false);
functions.CacheLoad(Root);
functions.CacheLoad(Root, false, "auto"); //legacy support
}
bool FunctionEnum(FUNCTIONSINFO* List, size_t* Size)
{
ASSERT_DEBUGGING("Export call");
// If a list isn't passed and the size not requested, fail
ASSERT_FALSE(!List && !Size);
SHARED_ACQUIRE(LockFunctions);
// Did the caller request the buffer size needed?
if(Size)
{
*Size = functions.size() * sizeof(FUNCTIONSINFO);
if(!List)
return true;
}
// Fill out the buffer
for(auto & itr : functions)
{
// Adjust for relative to virtual addresses
duint moduleBase = ModBaseFromName(itr.second.mod);
*List = itr.second;
List->start += moduleBase;
List->end += moduleBase;
List++;
}
return true;
return functions.Enum(List, Size);
}
void FunctionClear()
{
EXCLUSIVE_ACQUIRE(LockFunctions);
functions.clear();
functions.Clear();
}
void FunctionGetList(std::vector<FUNCTIONSINFO> & list)
{
SHARED_ACQUIRE(LockFunctions);
list.clear();
list.reserve(functions.size());
for(const auto & itr : functions)
list.push_back(itr.second);
functions.GetList(list);
}
bool FunctionGetInfo(duint Address, FUNCTIONSINFO* info)
bool FunctionGetInfo(duint Address, FUNCTIONSINFO & info)
{
auto moduleBase = ModBaseFromAddr(Address);
// Lookup by module hash, then function range
SHARED_ACQUIRE(LockFunctions);
auto found = functions.find(ModuleRange(ModHashFromAddr(moduleBase), Range(Address - moduleBase, Address - moduleBase)));
// Was this range found?
if(found == functions.end())
return false;
if(info)
memcpy(info, &found->second, sizeof(FUNCTIONSINFO));
return true;
return functions.Get(Functions::VaKey(Address, Address), info);
}

View File

@ -22,6 +22,6 @@ void FunctionCacheLoad(JSON Root);
bool FunctionEnum(FUNCTIONSINFO* List, size_t* Size);
void FunctionClear();
void FunctionGetList(std::vector<FUNCTIONSINFO> & list);
bool FunctionGetInfo(duint Address, FUNCTIONSINFO* info);
bool FunctionGetInfo(duint Address, FUNCTIONSINFO & info);
#endif // _FUNCTION_H

View File

@ -3,12 +3,50 @@
#include "module.h"
#include "memory.h"
std::unordered_map<duint, LABELSINFO> labels;
struct CommentSerializer : JSONWrapper<LABELSINFO>
{
bool Save(const LABELSINFO & value) override
{
setString("module", value.mod);
setHex("address", value.addr);
setString("text", value.text);
setBool("manual", value.manual);
return true;
}
bool Load(LABELSINFO & value) override
{
value.manual = true;
getBool("manual", value.manual); //legacy support
return getString("module", value.mod) &&
getHex("address", value.addr) &&
getString("text", value.text);
}
};
struct Labels : SerializableModuleHashMap<LockComments, LABELSINFO, CommentSerializer>
{
void AdjustValue(LABELSINFO & value) const override
{
value.addr += ModBaseFromName(value.mod);
}
protected:
const char* jsonKey() const override
{
return "labels";
}
duint makeKey(const LABELSINFO & value) const override
{
return ModHashFromName(value.mod) + value.addr;
}
};
static Labels labels;
bool LabelSet(duint Address, const char* Text, bool Manual)
{
ASSERT_DEBUGGING("Exported/Command function");
// A valid memory address must be supplied
if(!MemIsValidReadPtr(Address))
return false;
@ -35,285 +73,73 @@ bool LabelSet(duint Address, const char* Text, bool Manual)
strcpy_s(labelInfo.text, Text);
ModNameFromAddr(Address, labelInfo.mod, true);
EXCLUSIVE_ACQUIRE(LockLabels);
// Insert label by key
const duint key = ModHashFromAddr(Address);
if(!labels.insert(std::make_pair(ModHashFromAddr(key), labelInfo)).second)
labels[key] = labelInfo;
return true;
return labels.Add(labelInfo);
}
bool LabelFromString(const char* Text, duint* Address)
{
ASSERT_DEBUGGING("Future(?): Currently not used");
SHARED_ACQUIRE(LockLabels);
for(auto & itr : labels)
return labels.GetWhere([&](const LABELSINFO & value)
{
// Check if the actual label name matches
if(strcmp(itr.second.text, Text))
continue;
if(strcmp(value.text, Text))
return false;
if(Address)
*Address = itr.second.addr + ModBaseFromName(itr.second.mod);
// Set status to indicate if label was ever found
*Address = value.addr + ModBaseFromName(value.mod);
return true;
}
return false;
});
}
bool LabelGet(duint Address, char* Text)
{
ASSERT_DEBUGGING("Export call");
SHARED_ACQUIRE(LockLabels);
// Was the label at this address exist?
auto found = labels.find(ModHashFromAddr(Address));
if(found == labels.end())
LABELSINFO label;
if(!labels.Get(Labels::VaKey(Address), label))
return false;
// Copy to user buffer
if(Text)
strcpy_s(Text, MAX_LABEL_SIZE, found->second.text);
strcpy_s(Text, MAX_LABEL_SIZE, label.text);
return true;
}
bool LabelDelete(duint Address)
{
ASSERT_DEBUGGING("Export call");
EXCLUSIVE_ACQUIRE(LockLabels);
return (labels.erase(ModHashFromAddr(Address)) > 0);
return labels.Delete(Labels::VaKey(Address));
}
void LabelDelRange(duint Start, duint End, bool Manual)
{
ASSERT_DEBUGGING("Export call");
// Are all comments going to be deleted?
// 0x00000000 - 0xFFFFFFFF
if(Start == 0 && End == ~0)
labels.DeleteRange(Start, End, [Manual](duint start, duint end, const LABELSINFO & value)
{
LabelClear();
}
else
{
// Make sure 'Start' and 'End' reference the same module
duint moduleBase = ModBaseFromAddr(Start);
if(moduleBase != ModBaseFromAddr(End))
return;
// Virtual -> relative offset
Start -= moduleBase;
End -= moduleBase;
EXCLUSIVE_ACQUIRE(LockLabels);
for(auto itr = labels.begin(); itr != labels.end();)
{
const auto & currentLabel = itr->second;
// Ignore non-matching entries
if(Manual ? !currentLabel.manual : currentLabel.manual)
{
++itr;
continue;
}
// [Start, End)
if(currentLabel.addr >= Start && currentLabel.addr < End)
itr = labels.erase(itr);
else
++itr;
}
}
if(Manual ? !value.manual : value.manual) //ignore non-matching entries
return false;
return value.addr >= start && value.addr < end;
});
}
void LabelCacheSave(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockLabels);
// Create the sub-root structures in memory
const JSON jsonLabels = json_array();
const JSON jsonAutoLabels = json_array();
// Iterator each label
for(auto & itr : labels)
{
JSON jsonLabel = json_object();
json_object_set_new(jsonLabel, "module", json_string(itr.second.mod));
json_object_set_new(jsonLabel, "address", json_hex(itr.second.addr));
json_object_set_new(jsonLabel, "text", json_string(itr.second.text));
// Was the label manually added?
if(itr.second.manual)
json_array_append_new(jsonLabels, jsonLabel);
else
json_array_append_new(jsonAutoLabels, jsonLabel);
}
// Apply the object to the global root
if(json_array_size(jsonLabels))
json_object_set(Root, "labels", jsonLabels);
if(json_array_size(jsonAutoLabels))
json_object_set(Root, "autolabels", jsonAutoLabels);
json_decref(jsonLabels);
json_decref(jsonAutoLabels);
labels.CacheSave(Root);
}
void LabelCacheLoad(JSON Root)
{
EXCLUSIVE_ACQUIRE(LockLabels);
// Inline lambda to parse each JSON entry
auto AddLabels = [](const JSON Object, bool Manual)
{
size_t i;
JSON value;
json_array_foreach(Object, i, value)
{
LABELSINFO labelInfo;
memset(&labelInfo, 0, sizeof(LABELSINFO));
// Module
const char* mod = json_string_value(json_object_get(value, "module"));
if(mod && strlen(mod) < MAX_MODULE_SIZE)
strcpy_s(labelInfo.mod, mod);
// Address/Manual
labelInfo.addr = (duint)json_hex_value(json_object_get(value, "address"));
labelInfo.manual = Manual;
// Text string
const char* text = json_string_value(json_object_get(value, "text"));
if(text)
strcpy_s(labelInfo.text, text);
else
{
// Skip empty strings
continue;
}
// Go through the string replacing '&' with spaces
for(char* ptr = labelInfo.text; ptr[0] != '\0'; ptr++)
{
if(ptr[0] == '&')
ptr[0] = ' ';
}
// Finally insert the data
const duint key = ModHashFromName(labelInfo.mod) + labelInfo.addr;
labels.insert(std::make_pair(key, labelInfo));
}
};
// Remove previous data
labels.clear();
const JSON jsonLabels = json_object_get(Root, "labels");
const JSON jsonAutoLabels = json_object_get(Root, "autolabels");
// Load user-set labels
if(jsonLabels)
AddLabels(jsonLabels, true);
// Load auto-set labels
if(jsonAutoLabels)
AddLabels(jsonAutoLabels, false);
labels.CacheLoad(Root);
labels.CacheLoad(Root, false, "auto"); //legacy support
}
bool LabelEnum(LABELSINFO* List, size_t* Size)
{
ASSERT_DEBUGGING("Export call");
// At least 1 parameter is required
if(!List && !Size)
return false;
EXCLUSIVE_ACQUIRE(LockLabels);
// See if the user requested a size
if(Size)
{
*Size = labels.size() * sizeof(LABELSINFO);
if(!List)
return true;
}
// Fill out the return list while converting the offset
// to a virtual address
for(auto & itr : labels)
{
*List = itr.second;
List->addr += ModBaseFromName(itr.second.mod);
List++;
}
return true;
return labels.Enum(List, Size);
}
void LabelClear()
{
EXCLUSIVE_ACQUIRE(LockLabels);
labels.clear();
labels.Clear();
}
void LabelGetList(std::vector<LABELSINFO> & list)
{
SHARED_ACQUIRE(LockLabels);
list.clear();
list.reserve(labels.size());
for(const auto & itr : labels)
list.push_back(itr.second);
labels.GetList(list);
}
bool LabelGetInfo(duint Address, LABELSINFO* info)
{
SHARED_ACQUIRE(LockLabels);
// Was the label at this address exist?
auto found = labels.find(ModHashFromAddr(Address));
if(found == labels.end())
return false;
// Copy to user buffer
if(info)
memcpy(info, &found->second, sizeof(LABELSINFO));
return true;
}
void LabelEnumCb(std::function<void(const LABELSINFO & info)> cbEnum, const char* module)
{
SHARED_ACQUIRE(LockLabels);
for(auto i = labels.begin(); i != labels.end();)
{
auto j = i;
++i; // Increment here, because the callback might remove the current entry
if(module && module[0] != '\0')
{
if(strcmp(j->second.mod, module) != 0)
continue;
}
SHARED_RELEASE();
cbEnum(j->second);
SHARED_REACQUIRE();
}
return labels.GetInfo(Address, info);
}

View File

@ -22,6 +22,5 @@ bool LabelEnum(LABELSINFO* List, size_t* Size);
void LabelClear();
void LabelGetList(std::vector<LABELSINFO> & list);
bool LabelGetInfo(duint Address, LABELSINFO* info);
void LabelEnumCb(std::function<void(const LABELSINFO & info)> cbEnum, const char* module = nullptr);
#endif // _LABEL_H

322
src/dbg/serializablemap.h Normal file
View File

@ -0,0 +1,322 @@
#include "_global.h"
#include "threading.h"
template<class TValue>
class JSONWrapper
{
public:
virtual ~JSONWrapper()
{
}
void SetJson(JSON json)
{
mJson = json;
}
virtual bool Save(const TValue & value) = 0;
virtual bool Load(TValue & value) = 0;
protected:
void setString(const char* key, const char* value)
{
set(key, json_string(value));
}
template<size_t TSize>
bool getString(const char* key, char(&_Dest)[TSize]) const
{
auto str = json_string_value(json_object_get(mJson, key));
if(str && strlen(str) < TSize)
{
strcpy_s(_Dest, str);
return true;
}
return false;
}
void setHex(const char* key, duint value)
{
set(key, json_hex(value));
}
bool getHex(const char* key, duint & value) const
{
auto jsonValue = get(key);
if(!jsonValue)
return false;
value = duint(json_hex_value(jsonValue));
return true;
}
void setBool(const char* key, bool value)
{
set(key, json_boolean(value));
}
bool getBool(const char* key, bool & value) const
{
auto jsonValue = get(key);
if(!jsonValue)
return false;
value = json_boolean_value(jsonValue);
return true;
}
template<typename T>
void setInt(const char* key, T value)
{
set(key, json_integer(value));
}
template<typename T>
bool getInt(const char* key, T & value)
{
auto jsonValue = get(key);
if(!jsonValue)
return false;
value = T(json_integer_value(jsonValue));
return true;
}
private:
// ReSharper disable once CppMemberFunctionMayBeConst
void set(const char* key, JSON value)
{
json_object_set_new(mJson, key, value);
}
JSON get(const char* key) const
{
return json_object_get(mJson, key);
}
JSON mJson = nullptr;
};
template<SectionLock TLock, class TKey, class TValue, class TMap, class TSerializer>
class SerializableTMap
{
static_assert(std::is_base_of<JSONWrapper<TValue>, TSerializer>::value, "TSerializer is not derived from JSONWrapper<TValue>");
public:
using TValuePred = std::function<bool(const TValue & value)>;
virtual ~SerializableTMap()
{
}
bool Add(const TValue & value)
{
EXCLUSIVE_ACQUIRE(TLock);
return addNoLock(value);
}
bool Get(const TKey & key, TValue & value) const
{
SHARED_ACQUIRE(TLock);
auto found = mMap.find(key);
if(found == mMap.end())
return false;
value = found->second;
return true;
}
bool Contains(const TKey & key) const
{
SHARED_ACQUIRE(TLock);
return mMap.count(key) > 0;
}
bool Delete(const TKey & key)
{
EXCLUSIVE_ACQUIRE(TLock);
return mMap.erase(key) > 0;
}
void DeleteWhere(TValuePred predicate)
{
EXCLUSIVE_ACQUIRE(TLock);
for(auto itr = mMap.begin(); itr != mMap.end();)
{
if(predicate(itr->second))
itr = mMap.erase(itr);
else
++itr;
}
}
bool GetWhere(TValuePred predicate, TValue & value)
{
return getWhere(predicate, &value);
}
bool GetWhere(TValuePred predicate)
{
return getWhere(predicate, nullptr);
}
void Clear()
{
EXCLUSIVE_ACQUIRE(TLock);
mMap.clear();
}
void CacheSave(JSON root) const
{
SHARED_ACQUIRE(TLock);
auto jsonValues = json_array();
TSerializer serializer;
for(const auto & itr : mMap)
{
auto jsonValue = json_object();
serializer.SetJson(jsonValue);
if(serializer.Save(itr.second))
json_array_append_new(jsonValues, jsonValue);
else
json_decref(jsonValue);
}
if(json_array_size(jsonValues))
json_object_set(root, jsonKey(), jsonValues);
json_decref(jsonValues);
}
void CacheLoad(JSON root, bool clear = true, const char* keyprefix = nullptr)
{
if(clear)
Clear();
EXCLUSIVE_ACQUIRE(TLock);
auto jsonValues = json_object_get(root, keyprefix ? (keyprefix + String(jsonKey())).c_str() : jsonKey());
if(!jsonValues)
return;
size_t i;
JSON jsonValue;
TSerializer deserializer;
json_array_foreach(jsonValues, i, jsonValue)
{
deserializer.SetJson(jsonValue);
TValue value;
if(deserializer.Load(value))
addNoLock(value);
}
}
void GetList(std::vector<TValue> & values) const
{
SHARED_ACQUIRE(TLock);
values.clear();
values.reserve(mMap.size());
for(const auto & itr : mMap)
values.push_back(itr.second);
}
bool Enum(TValue* list, size_t* size) const
{
if(!list && !size)
return false;
SHARED_ACQUIRE(TLock);
if(size)
{
*size = mMap.size() * sizeof(TValue);
if(!list)
return true;
}
for(auto & itr : mMap)
{
*list = itr.second;
AdjustValue(*list);
++list;
}
return true;
}
bool GetInfo(const TKey & key, TValue* valuePtr) const
{
TValue value;
if(!Get(key, value))
return false;
if(valuePtr)
*valuePtr = value;
return true;
}
virtual void AdjustValue(TValue & value) const = 0;
protected:
virtual const char* jsonKey() const = 0;
virtual TKey makeKey(const TValue & value) const = 0;
private:
TMap mMap;
bool addNoLock(const TValue & value)
{
mMap[makeKey(value)] = value;
return true;
}
bool getWhere(TValuePred predicate, TValue* value)
{
SHARED_ACQUIRE(TLock);
for(const auto & itr : mMap)
{
if(!predicate(itr.second))
continue;
if(value)
*value = itr.second;
return true;
}
return false;
}
};
template<SectionLock TLock, class TKey, class TValue, class TSerializer, class THash = std::hash<TKey>>
using SerializableUnorderedMap = SerializableTMap<TLock, TKey, TValue, std::unordered_map<TKey, TValue, THash>, TSerializer>;
template<SectionLock TLock, class TKey, class TValue, class TSerializer, class TCompare = std::less<TKey>>
using SerializableMap = SerializableTMap<TLock, TKey, TValue, std::map<TKey, TValue, TCompare>, TSerializer>;
template<SectionLock TLock, class TValue, class TSerializer>
struct SerializableModuleRangeMap : SerializableMap<TLock, ModuleRange, TValue, TSerializer, ModuleRangeCompare>
{
static ModuleRange VaKey(duint start, duint end)
{
auto moduleBase = ModBaseFromAddr(start);
return ModuleRange(ModHashFromAddr(moduleBase), Range(start - moduleBase, end - moduleBase));
}
};
template<SectionLock TLock, class TValue, class TSerializer>
struct SerializableModuleHashMap : SerializableUnorderedMap<TLock, duint, TValue, TSerializer>
{
static duint VaKey(duint addr)
{
return ModHashFromAddr(addr);
}
void DeleteRange(duint start, duint end, std::function<bool(duint start, duint end, const TValue & value)> inRange)
{
// Are all comments going to be deleted?
// 0x00000000 - 0xFFFFFFFF
if(start == 0 && end == ~0)
{
Clear();
}
else
{
// Make sure 'Start' and 'End' reference the same module
duint moduleBase = ModBaseFromAddr(start);
if(moduleBase != ModBaseFromAddr(end))
return;
// Virtual -> relative offset
start -= moduleBase;
end -= moduleBase;
DeleteWhere([start, end, inRange](const TValue & value)
{
return inRange(start, end, value);
});
}
}
};

View File

@ -25,11 +25,11 @@ void waitdeinitialize();
// Win Vista and newer: (Faster) SRW locks used
// Win 2003 and older: (Slower) Critical sections used
//
#define EXCLUSIVE_ACQUIRE(Index) SectionLocker<SectionLock::##Index, false> __ThreadLock
#define EXCLUSIVE_ACQUIRE(Index) SectionLocker<Index, false> __ThreadLock
#define EXCLUSIVE_REACQUIRE() __ThreadLock.Lock()
#define EXCLUSIVE_RELEASE() __ThreadLock.Unlock()
#define SHARED_ACQUIRE(Index) SectionLocker<SectionLock::##Index, true> __SThreadLock
#define SHARED_ACQUIRE(Index) SectionLocker<Index, true> __SThreadLock
#define SHARED_REACQUIRE() __SThreadLock.Lock()
#define SHARED_RELEASE() __SThreadLock.Unlock()
@ -57,6 +57,7 @@ enum SectionLock
LockMnemonicHelp,
LockTraceRecord,
LockDebugStartStop,
LockArguments,
// Number of elements in this enumeration. Must always be the last
// index.

View File

@ -23,6 +23,7 @@
<ClCompile Include="analysis.cpp" />
<ClCompile Include="AnalysisPass.cpp" />
<ClCompile Include="analysis_nukem.cpp" />
<ClCompile Include="argument.cpp" />
<ClCompile Include="assemble.cpp" />
<ClCompile Include="bookmark.cpp" />
<ClCompile Include="breakpoint.cpp" />
@ -80,6 +81,7 @@
<ClCompile Include="_dbgfunctions.cpp" />
<ClCompile Include="_global.cpp" />
<ClCompile Include="_plugins.cpp" />
<ClCompile Include="_scriptapi_argument.cpp" />
<ClCompile Include="_scriptapi_assembler.cpp" />
<ClCompile Include="_scriptapi_bookmark.cpp" />
<ClCompile Include="_scriptapi_comment.cpp" />
@ -101,6 +103,7 @@
<ClInclude Include="analysis.h" />
<ClInclude Include="AnalysisPass.h" />
<ClInclude Include="analysis_nukem.h" />
<ClInclude Include="argument.h" />
<ClInclude Include="assemble.h" />
<ClInclude Include="BasicBlock.h" />
<ClInclude Include="bookmark.h" />
@ -152,6 +155,7 @@
<ClInclude Include="patternfind.h" />
<ClInclude Include="plugin_loader.h" />
<ClInclude Include="reference.h" />
<ClInclude Include="serializablemap.h" />
<ClInclude Include="tcpconnections.h" />
<ClInclude Include="TraceRecord.h" />
<ClInclude Include="yara\yara\stream.h" />
@ -204,6 +208,7 @@
<ClInclude Include="_global.h" />
<ClInclude Include="_plugins.h" />
<ClInclude Include="_plugin_types.h" />
<ClInclude Include="_scriptapi_argument.h" />
<ClInclude Include="_scriptapi_assembler.h" />
<ClInclude Include="_scriptapi_bookmark.h" />
<ClInclude Include="_scriptapi_comment.h" />

View File

@ -308,6 +308,12 @@
<ClCompile Include="tcpconnections.cpp">
<Filter>Source Files\Information</Filter>
</ClCompile>
<ClCompile Include="argument.cpp">
<Filter>Source Files\Information</Filter>
</ClCompile>
<ClCompile Include="_scriptapi_argument.cpp">
<Filter>Source Files\Interfaces/Exports\_scriptapi</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="x64_dbg.h">
@ -676,5 +682,14 @@
<ClInclude Include="tcpconnections.h">
<Filter>Header Files\Information</Filter>
</ClInclude>
<ClInclude Include="argument.h">
<Filter>Header Files\Information</Filter>
</ClInclude>
<ClInclude Include="serializablemap.h">
<Filter>Header Files\Information</Filter>
</ClInclude>
<ClInclude Include="_scriptapi_argument.h">
<Filter>Header Files\Interfaces/Exports\_scriptapi</Filter>
</ClInclude>
</ItemGroup>
</Project>