From 5e01b341789fa3bcd4be2a5da40e865ea3b7ac9f Mon Sep 17 00:00:00 2001 From: mrexodia Date: Wed, 1 Jun 2016 11:03:54 +0200 Subject: [PATCH] DBG: added SerializableTMap (less code duplication) --- src/dbg/TraceRecord.cpp | 5 +- src/dbg/_scriptapi_argument.cpp | 78 +++++++ src/dbg/_scriptapi_argument.h | 31 +++ src/dbg/_scriptapi_function.cpp | 2 +- src/dbg/addrinfo.h | 2 + src/dbg/argument.cpp | 158 ++++++++++++++ src/dbg/argument.h | 26 +++ src/dbg/bookmark.cpp | 222 +++++-------------- src/dbg/comment.cpp | 258 ++++++---------------- src/dbg/function.cpp | 258 ++++++---------------- src/dbg/function.h | 2 +- src/dbg/label.cpp | 300 ++++++-------------------- src/dbg/label.h | 1 - src/dbg/serializablemap.h | 322 ++++++++++++++++++++++++++++ src/dbg/threading.h | 5 +- src/dbg/x64_dbg_dbg.vcxproj | 5 + src/dbg/x64_dbg_dbg.vcxproj.filters | 15 ++ 17 files changed, 897 insertions(+), 793 deletions(-) create mode 100644 src/dbg/_scriptapi_argument.cpp create mode 100644 src/dbg/_scriptapi_argument.h create mode 100644 src/dbg/argument.cpp create mode 100644 src/dbg/argument.h create mode 100644 src/dbg/serializablemap.h diff --git a/src/dbg/TraceRecord.cpp b/src/dbg/TraceRecord.cpp index df162fa1..326d8d0a 100644 --- a/src/dbg/TraceRecord.cpp +++ b/src/dbg/TraceRecord.cpp @@ -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: diff --git a/src/dbg/_scriptapi_argument.cpp b/src/dbg/_scriptapi_argument.cpp new file mode 100644 index 00000000..cc2ccaa2 --- /dev/null +++ b/src/dbg/_scriptapi_argument.cpp @@ -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 argumentList; + ArgumentGetList(argumentList); + std::vector 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::CopyData(list, argumentScriptList); +} \ No newline at end of file diff --git a/src/dbg/_scriptapi_argument.h b/src/dbg/_scriptapi_argument.h new file mode 100644 index 00000000..00d76542 --- /dev/null +++ b/src/dbg/_scriptapi_argument.h @@ -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 \ No newline at end of file diff --git a/src/dbg/_scriptapi_function.cpp b/src/dbg/_scriptapi_function.cpp index 9370c7f2..790dfb2c 100644 --- a/src/dbg/_scriptapi_function.cpp +++ b/src/dbg/_scriptapi_function.cpp @@ -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) { diff --git a/src/dbg/addrinfo.h b/src/dbg/addrinfo.h index 98374983..44180d3e 100644 --- a/src/dbg/addrinfo.h +++ b/src/dbg/addrinfo.h @@ -53,6 +53,8 @@ struct DepthModuleRangeCompare } }; +#include "serializablemap.h" + //typedefs typedef std::function EXPORTENUMCALLBACK; typedef std::function IMPORTENUMCALLBACK; diff --git a/src/dbg/argument.cpp b/src/dbg/argument.cpp new file mode 100644 index 00000000..1691991c --- /dev/null +++ b/src/dbg/argument.cpp @@ -0,0 +1,158 @@ +#include "argument.h" +#include "module.h" +#include "memory.h" +#include "threading.h" + +struct ArgumentSerializer : JSONWrapper +{ + 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 +{ + 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 & list) +{ + arguments.GetList(list); +} + +bool ArgumentGetInfo(duint Address, ARGUMENTSINFO & info) +{ + return arguments.Get(Arguments::VaKey(Address, Address), info); +} diff --git a/src/dbg/argument.h b/src/dbg/argument.h new file mode 100644 index 00000000..44035334 --- /dev/null +++ b/src/dbg/argument.h @@ -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 & list); +bool ArgumentGetInfo(duint Address, ARGUMENTSINFO & info); + +#endif // _ARGUMENT_H \ No newline at end of file diff --git a/src/dbg/bookmark.cpp b/src/dbg/bookmark.cpp index f6754b05..9a034e76 100644 --- a/src/dbg/bookmark.cpp +++ b/src/dbg/bookmark.cpp @@ -1,14 +1,49 @@ #include "bookmark.h" -#include "threading.h" #include "module.h" #include "memory.h" -std::unordered_map bookmarks; +struct BookmarkSerializer : JSONWrapper +{ + 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 +{ + 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 & 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); } diff --git a/src/dbg/comment.cpp b/src/dbg/comment.cpp index 96fabfc7..c87e344d 100644 --- a/src/dbg/comment.cpp +++ b/src/dbg/comment.cpp @@ -3,12 +3,50 @@ #include "module.h" #include "memory.h" -std::unordered_map comments; +struct CommentSerializer : JSONWrapper +{ + 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 +{ + 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 & 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); } diff --git a/src/dbg/function.cpp b/src/dbg/function.cpp index 9bcde9f5..cb8072a1 100644 --- a/src/dbg/function.cpp +++ b/src/dbg/function.cpp @@ -3,18 +3,62 @@ #include "memory.h" #include "threading.h" -std::map functions; +struct FunctionSerializer : JSONWrapper +{ + 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 +{ + 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 & 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); } diff --git a/src/dbg/function.h b/src/dbg/function.h index 5aa3ab91..84ce7cc5 100644 --- a/src/dbg/function.h +++ b/src/dbg/function.h @@ -22,6 +22,6 @@ void FunctionCacheLoad(JSON Root); bool FunctionEnum(FUNCTIONSINFO* List, size_t* Size); void FunctionClear(); void FunctionGetList(std::vector & list); -bool FunctionGetInfo(duint Address, FUNCTIONSINFO* info); +bool FunctionGetInfo(duint Address, FUNCTIONSINFO & info); #endif // _FUNCTION_H \ No newline at end of file diff --git a/src/dbg/label.cpp b/src/dbg/label.cpp index aa5323b5..b1fb5e8a 100644 --- a/src/dbg/label.cpp +++ b/src/dbg/label.cpp @@ -3,12 +3,50 @@ #include "module.h" #include "memory.h" -std::unordered_map labels; +struct CommentSerializer : JSONWrapper +{ + 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 +{ + 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 & 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 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); } diff --git a/src/dbg/label.h b/src/dbg/label.h index e924d440..4a0ffa6b 100644 --- a/src/dbg/label.h +++ b/src/dbg/label.h @@ -22,6 +22,5 @@ bool LabelEnum(LABELSINFO* List, size_t* Size); void LabelClear(); void LabelGetList(std::vector & list); bool LabelGetInfo(duint Address, LABELSINFO* info); -void LabelEnumCb(std::function cbEnum, const char* module = nullptr); #endif // _LABEL_H \ No newline at end of file diff --git a/src/dbg/serializablemap.h b/src/dbg/serializablemap.h new file mode 100644 index 00000000..4bb4d7bc --- /dev/null +++ b/src/dbg/serializablemap.h @@ -0,0 +1,322 @@ +#include "_global.h" +#include "threading.h" + +template +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 + 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 + void setInt(const char* key, T value) + { + set(key, json_integer(value)); + } + + template + 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 +class SerializableTMap +{ + static_assert(std::is_base_of, TSerializer>::value, "TSerializer is not derived from JSONWrapper"); +public: + using TValuePred = std::function; + + 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 & 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> +using SerializableUnorderedMap = SerializableTMap, TSerializer>; + +template> +using SerializableMap = SerializableTMap, TSerializer>; + +template +struct SerializableModuleRangeMap : SerializableMap +{ + static ModuleRange VaKey(duint start, duint end) + { + auto moduleBase = ModBaseFromAddr(start); + return ModuleRange(ModHashFromAddr(moduleBase), Range(start - moduleBase, end - moduleBase)); + } +}; + +template +struct SerializableModuleHashMap : SerializableUnorderedMap +{ + static duint VaKey(duint addr) + { + return ModHashFromAddr(addr); + } + + void DeleteRange(duint start, duint end, std::function 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); + }); + } + } +}; \ No newline at end of file diff --git a/src/dbg/threading.h b/src/dbg/threading.h index ac3c89b7..058c7812 100644 --- a/src/dbg/threading.h +++ b/src/dbg/threading.h @@ -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 __ThreadLock +#define EXCLUSIVE_ACQUIRE(Index) SectionLocker __ThreadLock #define EXCLUSIVE_REACQUIRE() __ThreadLock.Lock() #define EXCLUSIVE_RELEASE() __ThreadLock.Unlock() -#define SHARED_ACQUIRE(Index) SectionLocker __SThreadLock +#define SHARED_ACQUIRE(Index) SectionLocker __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. diff --git a/src/dbg/x64_dbg_dbg.vcxproj b/src/dbg/x64_dbg_dbg.vcxproj index 0f11eb4e..c2c4d688 100644 --- a/src/dbg/x64_dbg_dbg.vcxproj +++ b/src/dbg/x64_dbg_dbg.vcxproj @@ -23,6 +23,7 @@ + @@ -80,6 +81,7 @@ + @@ -101,6 +103,7 @@ + @@ -152,6 +155,7 @@ + @@ -204,6 +208,7 @@ + diff --git a/src/dbg/x64_dbg_dbg.vcxproj.filters b/src/dbg/x64_dbg_dbg.vcxproj.filters index 5c519962..42ae5113 100644 --- a/src/dbg/x64_dbg_dbg.vcxproj.filters +++ b/src/dbg/x64_dbg_dbg.vcxproj.filters @@ -308,6 +308,12 @@ Source Files\Information + + Source Files\Information + + + Source Files\Interfaces/Exports\_scriptapi + @@ -676,5 +682,14 @@ Header Files\Information + + Header Files\Information + + + Header Files\Information + + + Header Files\Interfaces/Exports\_scriptapi + \ No newline at end of file