DBG: added SerializableTMap (less code duplication)
This commit is contained in:
parent
94129aa276
commit
5e01b34178
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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.
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue