diff --git a/x64_dbg_dbg/_exports.cpp b/x64_dbg_dbg/_exports.cpp index f150d3e5..f7c9a109 100644 --- a/x64_dbg_dbg/_exports.cpp +++ b/x64_dbg_dbg/_exports.cpp @@ -138,12 +138,12 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, ADDR } if(addrinfo->flags & flagbookmark) { - addrinfo->isbookmark = bookmarkget(addr); + addrinfo->isbookmark = BookmarkGet(addr); retval = true; } if(addrinfo->flags & flagfunction) { - if(functionget(addr, &addrinfo->function.start, &addrinfo->function.end)) + if(FunctionGet(addr, &addrinfo->function.start, &addrinfo->function.end)) retval = true; } if(addrinfo->flags & flagloop) @@ -306,9 +306,9 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoset(duint addr, ADDRINFO* addrinfo) if(addrinfo->flags & flagbookmark) //set bookmark { if(addrinfo->isbookmark) - retval = bookmarkset(addr, true); + retval = BookmarkSet(addr, true); else - retval = bookmarkdel(addr); + retval = BookmarkDelete(addr); } return retval; } @@ -614,7 +614,7 @@ extern "C" DLL_EXPORT uint _dbg_getbranchdestination(uint addr) extern "C" DLL_EXPORT bool _dbg_functionoverlaps(uint start, uint end) { - return functionoverlaps(start, end); + return FunctionOverlaps(start, end); } extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* param2) @@ -805,28 +805,28 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par case DBG_FUNCTION_GET: { FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1; - return (uint)functionget(info->addr, &info->start, &info->end); + return (uint)FunctionGet(info->addr, &info->start, &info->end); } break; case DBG_FUNCTION_OVERLAPS: { FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1; - return (uint)functionoverlaps(info->start, info->end); + return (uint)FunctionOverlaps(info->start, info->end); } break; case DBG_FUNCTION_ADD: { FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1; - return (uint)functionadd(info->start, info->end, info->manual); + return (uint)FunctionAdd(info->start, info->end, info->manual); } break; case DBG_FUNCTION_DEL: { FUNCTION_LOOP_INFO* info = (FUNCTION_LOOP_INFO*)param1; - return (uint)functiondel(info->addr); + return (uint)FunctionDelete(info->addr); } break; @@ -899,25 +899,25 @@ extern "C" DLL_EXPORT uint _dbg_sendmessage(DBGMSG type, void* param1, void* par case DBG_SET_AUTO_BOOKMARK_AT: { - return (uint)bookmarkset((uint)param1, false); + return (uint)BookmarkSet((uint)param1, false); } break; case DBG_DELETE_AUTO_BOOKMARK_RANGE: { - bookmarkdelrange((uint)param1, (uint)param2); + BookmarkDelRange((uint)param1, (uint)param2); } break; case DBG_SET_AUTO_FUNCTION_AT: { - return (uint)functionadd((uint)param1, (uint)param2, false); + return (uint)FunctionAdd((uint)param1, (uint)param2, false); } break; case DBG_DELETE_AUTO_FUNCTION_RANGE: { - functiondelrange((uint)param1, (uint)param2); + FunctionDelRange((uint)param1, (uint)param2); } break; diff --git a/x64_dbg_dbg/addrinfo.cpp b/x64_dbg_dbg/addrinfo.cpp index ed4bb65c..52a51d9a 100644 --- a/x64_dbg_dbg/addrinfo.cpp +++ b/x64_dbg_dbg/addrinfo.cpp @@ -23,8 +23,8 @@ void dbsave() JSON root = json_object(); commentcachesave(root); labelcachesave(root); - bookmarkcachesave(root); - functioncachesave(root); + BookmarkCacheSave(root); + FunctionCacheSave(root); loopcachesave(root); BpCacheSave(root); WString wdbpath = StringUtils::Utf8ToUtf16(dbpath); @@ -84,8 +84,8 @@ void dbload() } commentcacheload(root); labelcacheload(root); - bookmarkcacheload(root); - functioncacheload(root); + BookmarkCacheLoad(root); + FunctionCacheLoad(root); loopcacheload(root); BpCacheLoad(root); json_decref(root); //free root @@ -97,8 +97,8 @@ void dbclose() dbsave(); commentclear(); labelclear(); - bookmarkclear(); - functionclear(); + BookmarkClear(); + FunctionClear(); loopclear(); BpClear(); patchclear(); diff --git a/x64_dbg_dbg/bookmark.cpp b/x64_dbg_dbg/bookmark.cpp index 5ea6268f..6db5e1a9 100644 --- a/x64_dbg_dbg/bookmark.cpp +++ b/x64_dbg_dbg/bookmark.cpp @@ -66,12 +66,13 @@ void BookmarkDelRange(uint Start, uint End) } else { - // Make sure 'start' and 'end' reference the same module + // Make sure 'Start' and 'End' reference the same module uint moduleBase = ModBaseFromAddr(Start); if(moduleBase != ModBaseFromAddr(End)) return; + // Virtual -> relative offset Start -= moduleBase; End -= moduleBase; diff --git a/x64_dbg_dbg/debugger_commands.cpp b/x64_dbg_dbg/debugger_commands.cpp index 2e93d8b7..c3d23861 100644 --- a/x64_dbg_dbg/debugger_commands.cpp +++ b/x64_dbg_dbg/debugger_commands.cpp @@ -813,8 +813,8 @@ CMDRESULT cbDebugBenchmark(int argc, char* argv[]) { commentset(i, "test", false); labelset(i, "test", false); - bookmarkset(i, false); - functionadd(i, i, false); + BookmarkSet(i, false); + FunctionAdd(i, i, false); } dprintf("%ums\n", GetTickCount() - ticks); return STATUS_CONTINUE; diff --git a/x64_dbg_dbg/function.cpp b/x64_dbg_dbg/function.cpp index e24c01e5..090b3c58 100644 --- a/x64_dbg_dbg/function.cpp +++ b/x64_dbg_dbg/function.cpp @@ -8,185 +8,256 @@ typedef std::map FunctionsInfo; static FunctionsInfo functions; -bool functionadd(uint start, uint end, bool manual) +bool FunctionAdd(uint Start, uint End, bool Manual) { - if(!DbgIsDebugging() or end < start or !memisvalidreadptr(fdProcessInfo->hProcess, start)) + // CHECK: Export/Command function + if(!DbgIsDebugging()) return false; - const uint modbase = ModBaseFromAddr(start); - if(modbase != ModBaseFromAddr(end)) //the function boundaries are not in the same module + + // Make sure memory is readable + if(!memisvalidreadptr(fdProcessInfo->hProcess, Start)) return false; - if(functionoverlaps(start, end)) + + // Fail if boundary exceeds module size + const uint moduleBase = ModBaseFromAddr(Start); + + if(moduleBase != ModBaseFromAddr(End)) return false; + + // Fail if 'Start' and 'End' are incompatible + if(Start > End || FunctionOverlaps(Start, End)) + return false; + FUNCTIONSINFO function; - ModNameFromAddr(start, function.mod, true); - function.start = start - modbase; - function.end = end - modbase; - function.manual = manual; - CriticalSectionLocker locker(LockFunctions); - functions.insert(std::make_pair(ModuleRange(ModHashFromAddr(modbase), Range(function.start, function.end)), function)); + ModNameFromAddr(Start, function.mod, true); + function.start = Start - moduleBase; + function.end = End - moduleBase; + function.manual = Manual; + + // Insert to global table + EXCLUSIVE_ACQUIRE(LockFunctions); + + functions.insert(std::make_pair(ModuleRange(ModHashFromAddr(moduleBase), Range(function.start, function.end)), function)); return true; } -bool functionget(uint addr, uint* start, uint* end) +bool FunctionGet(uint Address, uint* Start, uint* End) { + // CHECK: Exported function if(!DbgIsDebugging()) return false; - uint modbase = ModBaseFromAddr(addr); - CriticalSectionLocker locker(LockFunctions); - const FunctionsInfo::iterator found = functions.find(ModuleRange(ModHashFromAddr(modbase), Range(addr - modbase, addr - modbase))); - if(found == functions.end()) //not found + + const uint modbase = ModBaseFromAddr(Address); + + // Lookup by module hash, then function range + SHARED_ACQUIRE(LockFunctions); + + auto found = functions.find(ModuleRange(ModHashFromAddr(modbase), Range(Address - modbase, Address - modbase))); + + // Was this range found? + if(found == functions.end()) return false; - if(start) - *start = found->second.start + modbase; - if(end) - *end = found->second.end + modbase; + + if(Start) + *Start = found->second.start + modbase; + + if(End) + *End = found->second.end + modbase; + return true; } -bool functionoverlaps(uint start, uint end) -{ - if(!DbgIsDebugging() or end < start) - return false; - const uint modbase = ModBaseFromAddr(start); - CriticalSectionLocker locker(LockFunctions); - return (functions.count(ModuleRange(ModHashFromAddr(modbase), Range(start - modbase, end - modbase))) > 0); -} - -bool functiondel(uint addr) +bool FunctionOverlaps(uint Start, uint End) { + // CHECK: Exported function if(!DbgIsDebugging()) return false; - const uint modbase = ModBaseFromAddr(addr); - CriticalSectionLocker locker(LockFunctions); - return (functions.erase(ModuleRange(ModHashFromAddr(modbase), Range(addr - modbase, addr - modbase))) > 0); + + // A function can't end before it begins + if(Start > End) + return false; + + const uint moduleBase = ModBaseFromAddr(Start); + + SHARED_ACQUIRE(LockFunctions); + return (functions.count(ModuleRange(ModHashFromAddr(moduleBase), Range(Start - moduleBase, End - moduleBase))) > 0); } -void functiondelrange(uint start, uint end) +bool FunctionDelete(uint Address) { + // CHECK: Exported function + if(!DbgIsDebugging()) + return false; + + const uint moduleBase = ModBaseFromAddr(Address); + + EXCLUSIVE_ACQUIRE(LockFunctions); + return (functions.erase(ModuleRange(ModHashFromAddr(moduleBase), Range(Address - moduleBase, Address - moduleBase))) > 0); +} + +void FunctionDelRange(uint Start, uint End) +{ + // CHECK: Exported function if(!DbgIsDebugging()) return; - bool bDelAll = (start == 0 && end == ~0); //0x00000000-0xFFFFFFFF - uint modbase = ModBaseFromAddr(start); - if(modbase != ModBaseFromAddr(end)) - return; - start -= modbase; - end -= modbase; - CriticalSectionLocker locker(LockFunctions); - FunctionsInfo::iterator i = functions.begin(); - while(i != functions.end()) + + // Should all functions be deleted? + if(Start == 0x00000000 && End == 0xFFFFFFFF) { - if(i->second.manual) //ignore manual + EXCLUSIVE_ACQUIRE(LockFunctions); + functions.clear(); + } + else + { + uint moduleBase = ModBaseFromAddr(Start); + + // The start and end address must be in the same module + if(moduleBase != ModBaseFromAddr(End)) + return; + + // Convert these to a relative offset + Start -= moduleBase; + End -= moduleBase; + + EXCLUSIVE_ACQUIRE(LockFunctions); + for(auto itr = functions.begin(); itr != functions.end();) { - i++; - continue; + // Ignore manually set entries + if(itr->second.manual) + { + itr++; + continue; + } + + // [Start, End] + if(itr->second.end >= Start && itr->second.start <= End) + itr = functions.erase(itr); + else + itr++; } - if(bDelAll or !(i->second.start <= end and i->second.end >= start)) - functions.erase(i++); - else - i++; } } -void functioncachesave(JSON root) +void FunctionCacheSave(JSON Root) { - CriticalSectionLocker locker(LockFunctions); - const JSON jsonfunctions = json_array(); - const JSON jsonautofunctions = json_array(); - for(FunctionsInfo::iterator i = functions.begin(); i != functions.end(); ++i) + EXCLUSIVE_ACQUIRE(LockFunctions); + + // Allocate JSON object array + const JSON jsonFunctions = json_array(); + const JSON jsonAutoFunctions = json_array(); + + for(auto & i : functions) { - const FUNCTIONSINFO curFunction = i->second; - JSON curjsonfunction = json_object(); - json_object_set_new(curjsonfunction, "module", json_string(curFunction.mod)); - json_object_set_new(curjsonfunction, "start", json_hex(curFunction.start)); - json_object_set_new(curjsonfunction, "end", json_hex(curFunction.end)); - if(curFunction.manual) - json_array_append_new(jsonfunctions, curjsonfunction); + 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)); + + if(i.second.manual) + json_array_append_new(jsonFunctions, currentFunction); else - json_array_append_new(jsonautofunctions, curjsonfunction); + json_array_append_new(jsonAutoFunctions, currentFunction); } - if(json_array_size(jsonfunctions)) - json_object_set(root, "functions", jsonfunctions); - json_decref(jsonfunctions); - if(json_array_size(jsonautofunctions)) - json_object_set(root, "autofunctions", jsonautofunctions); - json_decref(jsonautofunctions); + + 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); } -void functioncacheload(JSON root) +void FunctionCacheLoad(JSON Root) { - CriticalSectionLocker locker(LockFunctions); + EXCLUSIVE_ACQUIRE(LockFunctions); + + // Delete existing entries functions.clear(); - const JSON jsonfunctions = json_object_get(root, "functions"); - if(jsonfunctions) + + // Inline lambda to enumerate all JSON array indices + auto InsertFunctions = [](const JSON Object, bool Manual) { size_t i; JSON value; - json_array_foreach(jsonfunctions, i, value) + json_array_foreach(Object, i, value) { - FUNCTIONSINFO curFunction; + FUNCTIONSINFO function; + + // Copy module name const char* mod = json_string_value(json_object_get(value, "module")); + if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE) - strcpy_s(curFunction.mod, mod); + strcpy_s(function.mod, mod); else - *curFunction.mod = '\0'; - curFunction.start = (uint)json_hex_value(json_object_get(value, "start")); - curFunction.end = (uint)json_hex_value(json_object_get(value, "end")); - if(curFunction.end < curFunction.start) - continue; //invalid function - curFunction.manual = true; - const uint key = ModHashFromName(curFunction.mod); - functions.insert(std::make_pair(ModuleRange(ModHashFromName(curFunction.mod), Range(curFunction.start, curFunction.end)), curFunction)); + function.mod[0] = '\0'; + + // Function address + function.start = (uint)json_hex_value(json_object_get(value, "start")); + function.end = (uint)json_hex_value(json_object_get(value, "end")); + function.manual = Manual; + + // Sanity check + if(function.end < function.start) + continue; + + const uint key = ModHashFromName(function.mod); + functions.insert(std::make_pair(ModuleRange(ModHashFromName(function.mod), Range(function.start, function.end)), function)); } - } - JSON jsonautofunctions = json_object_get(root, "autofunctions"); - if(jsonautofunctions) - { - size_t i; - JSON value; - json_array_foreach(jsonautofunctions, i, value) - { - FUNCTIONSINFO curFunction; - const char* mod = json_string_value(json_object_get(value, "module")); - if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE) - strcpy_s(curFunction.mod, mod); - else - *curFunction.mod = '\0'; - curFunction.start = (uint)json_hex_value(json_object_get(value, "start")); - curFunction.end = (uint)json_hex_value(json_object_get(value, "end")); - if(curFunction.end < curFunction.start) - continue; //invalid function - curFunction.manual = true; - const uint key = ModHashFromName(curFunction.mod); - functions.insert(std::make_pair(ModuleRange(ModHashFromName(curFunction.mod), Range(curFunction.start, curFunction.end)), curFunction)); - } - } + }; + + const JSON jsonFunctions = json_object_get(Root, "functions"); + const JSON jsonAutoFunctions = json_object_get(Root, "autofunctions"); + + if(jsonFunctions) + InsertFunctions(jsonFunctions, true); + + if(jsonAutoFunctions) + InsertFunctions(jsonAutoFunctions, false); } -bool functionenum(FUNCTIONSINFO* functionlist, size_t* cbsize) +bool FunctionEnum(FUNCTIONSINFO* List, size_t* Size) { + // CHECK: Exported function if(!DbgIsDebugging()) return false; - if(!functionlist && !cbsize) + + // If a list isn't passed and the size not requested, fail + if(!List && !Size) return false; - CriticalSectionLocker locker(LockFunctions); - if(!functionlist && cbsize) + + SHARED_ACQUIRE(LockFunctions); + + // Did the caller request the buffer size needed? + if(Size) { - *cbsize = functions.size() * sizeof(FUNCTIONSINFO); - return true; + *Size = functions.size() * sizeof(FUNCTIONSINFO); + + if(!List) + return true; } - int j = 0; - for(FunctionsInfo::iterator i = functions.begin(); i != functions.end(); ++i, j++) + + // Fill out the buffer + for(auto & itr : functions) { - functionlist[j] = i->second; - uint modbase = ModBaseFromName(functionlist[j].mod); - functionlist[j].start += modbase; - functionlist[j].end += modbase; + // Adjust for relative to virtual addresses + uint moduleBase = ModBaseFromName(itr.second.mod); + + *List = itr.second; + List->start += moduleBase; + List->end += moduleBase; + + List++; } + return true; } -void functionclear() +void FunctionClear() { - CriticalSectionLocker locker(LockFunctions); - FunctionsInfo().swap(functions); + EXCLUSIVE_ACQUIRE(LockFunctions); + functions.clear(); } \ No newline at end of file diff --git a/x64_dbg_dbg/function.h b/x64_dbg_dbg/function.h index 53f4adda..41afb223 100644 --- a/x64_dbg_dbg/function.h +++ b/x64_dbg_dbg/function.h @@ -1,5 +1,4 @@ -#ifndef _FUNCTION_H -#define _FUNCTION_H +#pragma once #include "addrinfo.h" @@ -11,14 +10,12 @@ struct FUNCTIONSINFO bool manual; }; -bool functionadd(uint start, uint end, bool manual); -bool functionget(uint addr, uint* start, uint* end); -bool functionoverlaps(uint start, uint end); -bool functiondel(uint addr); -void functiondelrange(uint start, uint end); -void functioncachesave(JSON root); -void functioncacheload(JSON root); -bool functionenum(FUNCTIONSINFO* functionlist, size_t* cbsize); -void functionclear(); - -#endif //_FUNCTION_H \ No newline at end of file +bool FunctionAdd(uint Start, uint End, bool Manual); +bool FunctionGet(uint Address, uint* Start, uint* End); +bool FunctionOverlaps(uint Start, uint End); +bool FunctionDelete(uint Address); +void FunctionDelRange(uint Start, uint End); +void FunctionCacheSave(JSON Root); +void FunctionCacheLoad(JSON Root); +bool FunctionEnum(FUNCTIONSINFO* List, size_t* Size); +void FunctionClear(); \ No newline at end of file diff --git a/x64_dbg_dbg/instruction.cpp b/x64_dbg_dbg/instruction.cpp index f9cba729..a48047b5 100644 --- a/x64_dbg_dbg/instruction.cpp +++ b/x64_dbg_dbg/instruction.cpp @@ -368,7 +368,7 @@ CMDRESULT cbInstrBookmarkSet(int argc, char* argv[]) uint addr = 0; if(!valfromstring(argv[1], &addr, false)) return STATUS_ERROR; - if(!bookmarkset(addr, true)) + if(!BookmarkSet(addr, true)) { dputs("failed to set bookmark!"); return STATUS_ERROR; @@ -387,7 +387,7 @@ CMDRESULT cbInstrBookmarkDel(int argc, char* argv[]) uint addr = 0; if(!valfromstring(argv[1], &addr, false)) return STATUS_ERROR; - if(!bookmarkdel(addr)) + if(!BookmarkDelete(addr)) { dputs("failed to delete bookmark!"); return STATUS_ERROR; @@ -454,7 +454,7 @@ CMDRESULT cbFunctionAdd(int argc, char* argv[]) uint end = 0; if(!valfromstring(argv[1], &start, false) or !valfromstring(argv[2], &end, false)) return STATUS_ERROR; - if(!functionadd(start, end, true)) + if(!FunctionAdd(start, end, true)) { dputs("failed to add function"); return STATUS_ERROR; @@ -474,7 +474,7 @@ CMDRESULT cbFunctionDel(int argc, char* argv[]) uint addr = 0; if(!valfromstring(argv[1], &addr, false)) return STATUS_ERROR; - if(!functiondel(addr)) + if(!FunctionDelete(addr)) { dputs("failed to delete function"); return STATUS_ERROR; @@ -1339,14 +1339,14 @@ CMDRESULT cbInstrBookmarkList(int argc, char* argv[]) GuiReferenceAddColumn(0, "Disassembly"); GuiReferenceReloadData(); size_t cbsize; - bookmarkenum(0, &cbsize); + BookmarkEnum(0, &cbsize); if(!cbsize) { dputs("no bookmarks"); return STATUS_CONTINUE; } Memory bookmarks(cbsize, "cbInstrBookmarkList:bookmarks"); - bookmarkenum(bookmarks, 0); + BookmarkEnum(bookmarks, 0); int count = (int)(cbsize / sizeof(BOOKMARKSINFO)); for(int i = 0; i < count; i++) { @@ -1374,14 +1374,14 @@ CMDRESULT cbInstrFunctionList(int argc, char* argv[]) GuiReferenceAddColumn(0, "Label/Comment"); GuiReferenceReloadData(); size_t cbsize; - functionenum(0, &cbsize); + FunctionEnum(0, &cbsize); if(!cbsize) { dputs("no functions"); return STATUS_CONTINUE; } Memory functions(cbsize, "cbInstrFunctionList:functions"); - functionenum(functions, 0); + FunctionEnum(functions, 0); int count = (int)(cbsize / sizeof(FUNCTIONSINFO)); for(int i = 0; i < count; i++) { diff --git a/x64_dbg_dbg/module.cpp b/x64_dbg_dbg/module.cpp index 4adc07e3..f3186c0b 100644 --- a/x64_dbg_dbg/module.cpp +++ b/x64_dbg_dbg/module.cpp @@ -105,7 +105,6 @@ bool ModUnload(uint base) void ModClear() { - // Remove all modules in the list EXCLUSIVE_ACQUIRE(LockModules); modinfo.clear(); EXCLUSIVE_RELEASE(); @@ -141,13 +140,9 @@ bool ModNameFromAddr(uint addr, char* modname, bool extension) if(!module) return false; - // Zero buffer first - memset(modname, 0, MAX_MODULE_SIZE); + // Copy initial module name + strcpy_s(modname, MAX_MODULE_SIZE, module->name); - // Append the module path/name - strcat_s(modname, MAX_MODULE_SIZE, module->name); - - // Append the extension if(extension) strcat_s(modname, MAX_MODULE_SIZE, module->extension);