Finish label refactor
This commit is contained in:
parent
fad13af628
commit
f2edbfa95a
|
@ -57,7 +57,7 @@ void BookmarkDelRange(uint Start, uint End)
|
|||
return;
|
||||
|
||||
// Are all bookmarks going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if(Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockBookmarks);
|
||||
|
@ -143,8 +143,10 @@ void BookmarkCacheLoad(JSON Root)
|
|||
// Load the module name
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
if(mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(bookmarkInfo.mod, mod);
|
||||
else
|
||||
bookmarkInfo.mod[0] = '\0';
|
||||
|
||||
// Load address and set auto-generated flag
|
||||
bookmarkInfo.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
|
|
|
@ -80,7 +80,7 @@ void CommentDelRange(uint Start, uint End)
|
|||
return;
|
||||
|
||||
// Are all comments going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if(Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockComments);
|
||||
|
@ -163,12 +163,12 @@ void CommentCacheLoad(JSON Root)
|
|||
json_array_foreach(Object, i, value)
|
||||
{
|
||||
COMMENTSINFO commentInfo;
|
||||
memset(&commentInfo, 0, sizeof(COMMENTSINFO));
|
||||
memset(&commentInfo, 0, sizeof(COMMENTSINFO));
|
||||
|
||||
// Module
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
if(mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(commentInfo.mod, mod);
|
||||
else
|
||||
commentInfo.mod[0] = '\0';
|
||||
|
|
|
@ -8,37 +8,37 @@ std::unordered_map<uint, LABELSINFO> labels;
|
|||
|
||||
bool LabelSet(uint Address, const char* Text, bool Manual)
|
||||
{
|
||||
// CHECK: Exported/Command function
|
||||
if (!DbgIsDebugging())
|
||||
return false;
|
||||
// CHECK: Exported/Command function
|
||||
if (!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// A valid memory address must be supplied
|
||||
if (!MemIsValidReadPtr(Address))
|
||||
return false;
|
||||
// A valid memory address must be supplied
|
||||
if (!MemIsValidReadPtr(Address))
|
||||
return false;
|
||||
|
||||
// Make sure the string is supplied, within bounds, and not a special delimiter
|
||||
if (!Text || Text[0] == '\1' || strlen(Text) >= MAX_LABEL_SIZE - 1)
|
||||
return false;
|
||||
// Make sure the string is supplied, within bounds, and not a special delimiter
|
||||
if (!Text || Text[0] == '\1' || strlen(Text) >= MAX_LABEL_SIZE - 1)
|
||||
return false;
|
||||
|
||||
// Labels cannot be "address" of actual variables
|
||||
if (strstr(Text, "&"))
|
||||
return false;
|
||||
// Labels cannot be "address" of actual variables
|
||||
if (strstr(Text, "&"))
|
||||
return false;
|
||||
|
||||
// Delete the label if no text was supplied
|
||||
// Delete the label if no text was supplied
|
||||
if(Text[0] == '\0')
|
||||
return LabelDelete(Address);
|
||||
|
||||
// Fill out the structure data
|
||||
// Fill out the structure data
|
||||
LABELSINFO labelInfo;
|
||||
labelInfo.manual = Manual;
|
||||
labelInfo.addr = Address - ModBaseFromAddr(Address);
|
||||
strcpy_s(labelInfo.text, Text);
|
||||
labelInfo.manual = Manual;
|
||||
labelInfo.addr = Address - ModBaseFromAddr(Address);
|
||||
strcpy_s(labelInfo.text, Text);
|
||||
ModNameFromAddr(Address, labelInfo.mod, true);
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
|
||||
// Insert label by key
|
||||
const uint key = ModHashFromAddr(Address);
|
||||
// Insert label by key
|
||||
const uint key = ModHashFromAddr(Address);
|
||||
|
||||
if(!labels.insert(std::make_pair(ModHashFromAddr(key), labelInfo)).second)
|
||||
labels[key] = labelInfo;
|
||||
|
@ -48,43 +48,43 @@ bool LabelSet(uint Address, const char* Text, bool Manual)
|
|||
|
||||
bool LabelFromString(const char* Text, uint* Address)
|
||||
{
|
||||
// CHECK: Future? (Not used)
|
||||
// CHECK: Future? (Not used)
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockLabels);
|
||||
SHARED_ACQUIRE(LockLabels);
|
||||
|
||||
for (auto& itr : labels)
|
||||
{
|
||||
// Check if the actual label name matches
|
||||
if (strcmp(itr.second.text, Text))
|
||||
continue;
|
||||
for (auto& itr : labels)
|
||||
{
|
||||
// Check if the actual label name matches
|
||||
if (strcmp(itr.second.text, Text))
|
||||
continue;
|
||||
|
||||
if (Address)
|
||||
*Address = itr.second.addr + ModBaseFromName(itr.second.mod);
|
||||
if (Address)
|
||||
*Address = itr.second.addr + ModBaseFromName(itr.second.mod);
|
||||
|
||||
// Set status to indicate if label was ever found
|
||||
return true;
|
||||
}
|
||||
// Set status to indicate if label was ever found
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LabelGet(uint Address, char* Text)
|
||||
{
|
||||
// CHECK: Export function
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockLabels);
|
||||
SHARED_ACQUIRE(LockLabels);
|
||||
|
||||
// Was the label at this address exist?
|
||||
auto found = labels.find(ModHashFromAddr(Address));
|
||||
// Was the label at this address exist?
|
||||
auto found = labels.find(ModHashFromAddr(Address));
|
||||
|
||||
if(found == labels.end())
|
||||
return false;
|
||||
|
||||
// Copy to user buffer
|
||||
// Copy to user buffer
|
||||
if(Text)
|
||||
strcpy_s(Text, MAX_LABEL_SIZE, found->second.text);
|
||||
|
||||
|
@ -93,63 +93,63 @@ bool LabelGet(uint Address, char* Text)
|
|||
|
||||
bool LabelDelete(uint Address)
|
||||
{
|
||||
// CHECK: Export function
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
return (labels.erase(ModHashFromAddr(Address)) > 0);
|
||||
}
|
||||
|
||||
void LabelDelRange(uint Start, uint End)
|
||||
{
|
||||
// CHECK: Export function
|
||||
if (!DbgIsDebugging())
|
||||
return;
|
||||
// CHECK: Export function
|
||||
if (!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
// Are all comments going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if (Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
labels.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure 'Start' and 'End' reference the same module
|
||||
uint moduleBase = ModBaseFromAddr(Start);
|
||||
// Are all comments going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if (Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
labels.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure 'Start' and 'End' reference the same module
|
||||
uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if (moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
if (moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
for (auto itr = labels.begin(); itr != labels.end();)
|
||||
{
|
||||
// Ignore manually set entries
|
||||
if (itr->second.manual)
|
||||
{
|
||||
itr++;
|
||||
continue;
|
||||
}
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
for (auto itr = labels.begin(); itr != labels.end();)
|
||||
{
|
||||
// Ignore manually set entries
|
||||
if (itr->second.manual)
|
||||
{
|
||||
itr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// [Start, End)
|
||||
if (itr->second.addr >= Start && itr->second.addr < End)
|
||||
itr = labels.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
// [Start, End)
|
||||
if (itr->second.addr >= Start && itr->second.addr < End)
|
||||
itr = labels.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LabelCacheSave(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
|
||||
// Create the sub-root structures in memory
|
||||
const JSON jsonLabels = json_array();
|
||||
const JSON jsonAutoLabels = json_array();
|
||||
// Create the sub-root structures in memory
|
||||
const JSON jsonLabels = json_array();
|
||||
const JSON jsonAutoLabels = json_array();
|
||||
|
||||
// Iterator each label
|
||||
// Iterator each label
|
||||
for(auto& itr : labels)
|
||||
{
|
||||
JSON jsonLabel = json_object();
|
||||
|
@ -157,126 +157,126 @@ void LabelCacheSave(JSON Root)
|
|||
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?
|
||||
// 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
|
||||
// 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);
|
||||
json_decref(jsonLabels);
|
||||
json_decref(jsonAutoLabels);
|
||||
}
|
||||
|
||||
void LabelCacheLoad(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
|
||||
// Inline lambda to parse each JSON entry
|
||||
auto AddLabels = [](const JSON Object, bool Manual)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
// 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));
|
||||
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"));
|
||||
// Module
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if (mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(labelInfo.mod, mod);
|
||||
else
|
||||
labelInfo.mod[0] = '\0';
|
||||
if (mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(labelInfo.mod, mod);
|
||||
else
|
||||
labelInfo.mod[0] = '\0';
|
||||
|
||||
// Address/Manual
|
||||
labelInfo.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
labelInfo.manual = Manual;
|
||||
// Address/Manual
|
||||
labelInfo.addr = (uint)json_hex_value(json_object_get(value, "address"));
|
||||
labelInfo.manual = Manual;
|
||||
|
||||
// Text string
|
||||
const char* text = json_string_value(json_object_get(value, "text"));
|
||||
// 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] = ' ';
|
||||
}
|
||||
if (text)
|
||||
strcpy_s(labelInfo.text, text);
|
||||
else
|
||||
{
|
||||
// Skip empty strings
|
||||
continue;
|
||||
}
|
||||
|
||||
// Finally insert the data
|
||||
const uint key = ModHashFromName(labelInfo.mod) + labelInfo.addr;
|
||||
// Go through the string replacing '&' with spaces
|
||||
for (char *ptr = labelInfo.text; ptr[0] != '\0'; ptr++)
|
||||
{
|
||||
if (ptr[0] == '&')
|
||||
ptr[0] = ' ';
|
||||
}
|
||||
|
||||
labels.insert(std::make_pair(key, labelInfo));
|
||||
}
|
||||
};
|
||||
// Finally insert the data
|
||||
const uint key = ModHashFromName(labelInfo.mod) + labelInfo.addr;
|
||||
|
||||
// Remove previous data
|
||||
labels.clear();
|
||||
labels.insert(std::make_pair(key, labelInfo));
|
||||
}
|
||||
};
|
||||
|
||||
const JSON jsonLabels = json_object_get(Root, "labels");
|
||||
const JSON jsonAutoLabels = json_object_get(Root, "autolabels");
|
||||
// Remove previous data
|
||||
labels.clear();
|
||||
|
||||
// Load user-set labels
|
||||
if (jsonLabels)
|
||||
AddLabels(jsonLabels, true);
|
||||
const JSON jsonLabels = json_object_get(Root, "labels");
|
||||
const JSON jsonAutoLabels = json_object_get(Root, "autolabels");
|
||||
|
||||
// Load auto-set labels
|
||||
if (jsonAutoLabels)
|
||||
AddLabels(jsonAutoLabels, false);
|
||||
// Load user-set labels
|
||||
if (jsonLabels)
|
||||
AddLabels(jsonLabels, true);
|
||||
|
||||
// Load auto-set labels
|
||||
if (jsonAutoLabels)
|
||||
AddLabels(jsonAutoLabels, false);
|
||||
}
|
||||
|
||||
bool LabelEnum(LABELSINFO* List, size_t* Size)
|
||||
{
|
||||
// CHECK: Export function
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// At least 1 parameter is required
|
||||
// At least 1 parameter is required
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
|
||||
// See if the user requested a size
|
||||
// See if the user requested a size
|
||||
if(Size)
|
||||
{
|
||||
*Size = labels.size() * sizeof(LABELSINFO);
|
||||
|
||||
if (!List)
|
||||
return true;
|
||||
|
||||
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++;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
void LabelClear()
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
labels.clear();
|
||||
EXCLUSIVE_ACQUIRE(LockLabels);
|
||||
labels.clear();
|
||||
}
|
|
@ -8,48 +8,47 @@ std::map<DepthModuleRange, LOOPSINFO, DepthModuleRangeCompare> loops;
|
|||
|
||||
bool LoopAdd(uint Start, uint End, bool Manual)
|
||||
{
|
||||
// CHECK: Export function
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// Loop must begin before it ends
|
||||
if (Start > End)
|
||||
return false;
|
||||
// Loop must begin before it ends
|
||||
if (Start > End)
|
||||
return false;
|
||||
|
||||
// Memory addresses must be valid
|
||||
if (!MemIsValidReadPtr(Start) || !MemIsValidReadPtr(End))
|
||||
return false;
|
||||
// Memory addresses must be valid
|
||||
if (!MemIsValidReadPtr(Start) || !MemIsValidReadPtr(End))
|
||||
return false;
|
||||
|
||||
// Check if loop boundaries are in the same module range
|
||||
// Check if loop boundaries are in the same module range
|
||||
const uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if(moduleBase != ModBaseFromAddr(End))
|
||||
return false;
|
||||
|
||||
// Loops cannot overlap other loops
|
||||
int finalDepth = 0;
|
||||
|
||||
// Loops cannot overlap other loops
|
||||
int finalDepth = 0;
|
||||
|
||||
if(LoopOverlaps(0, Start, End, &finalDepth))
|
||||
return false;
|
||||
|
||||
// Fill out loop information structure
|
||||
// Fill out loop information structure
|
||||
LOOPSINFO loopInfo;
|
||||
|
||||
loopInfo.start = Start - moduleBase;
|
||||
loopInfo.end = End - moduleBase;
|
||||
loopInfo.depth = finalDepth;
|
||||
loopInfo.manual = Manual;
|
||||
loopInfo.start = Start - moduleBase;
|
||||
loopInfo.end = End - moduleBase;
|
||||
loopInfo.depth = finalDepth;
|
||||
loopInfo.manual = Manual;
|
||||
ModNameFromAddr(Start, loopInfo.mod, true);
|
||||
|
||||
// Link this to a parent loop if one does exist
|
||||
if(finalDepth)
|
||||
|
||||
// Link this to a parent loop if one does exist
|
||||
if(finalDepth)
|
||||
LoopGet(finalDepth - 1, Start, &loopInfo.parent, 0);
|
||||
else
|
||||
loopInfo.parent = 0;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
|
||||
// Insert into list
|
||||
// Insert into list
|
||||
loops.insert(std::make_pair(DepthModuleRange(finalDepth, ModuleRange(ModHashFromAddr(moduleBase), Range(loopInfo.start, loopInfo.end))), loopInfo));
|
||||
return true;
|
||||
}
|
||||
|
@ -57,29 +56,29 @@ bool LoopAdd(uint Start, uint End, bool Manual)
|
|||
// Get the start/end of a loop at a certain depth and address
|
||||
bool LoopGet(int Depth, uint Address, uint* Start, uint* End)
|
||||
{
|
||||
// CHECK: Exported function
|
||||
// CHECK: Exported function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// Get the virtual address module
|
||||
// Get the virtual address module
|
||||
const uint moduleBase = ModBaseFromAddr(Address);
|
||||
|
||||
// Virtual address to relative address
|
||||
Address -= moduleBase;
|
||||
// Virtual address to relative address
|
||||
Address -= moduleBase;
|
||||
|
||||
SHARED_ACQUIRE(LockLoops);
|
||||
SHARED_ACQUIRE(LockLoops);
|
||||
|
||||
// Search with this address range
|
||||
// Search with this address range
|
||||
auto found = loops.find(DepthModuleRange(Depth, ModuleRange(ModHashFromAddr(moduleBase), Range(Address, Address))));
|
||||
|
||||
if(found == loops.end())
|
||||
return false;
|
||||
|
||||
// Return the loop start
|
||||
// Return the loop start
|
||||
if(Start)
|
||||
*Start = found->second.start + moduleBase;
|
||||
|
||||
// Also the loop end
|
||||
// Also the loop end
|
||||
if(End)
|
||||
*End = found->second.end + moduleBase;
|
||||
|
||||
|
@ -89,48 +88,48 @@ bool LoopGet(int Depth, uint Address, uint* Start, uint* End)
|
|||
//check if a loop overlaps a range, inside is not overlapping
|
||||
bool LoopOverlaps(int Depth, uint Start, uint End, int* FinalDepth)
|
||||
{
|
||||
// CHECK: Export function
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// Determine module addresses and lookup keys
|
||||
const uint moduleBase = ModBaseFromAddr(Start);
|
||||
const uint key = ModHashFromAddr(moduleBase);
|
||||
// Determine module addresses and lookup keys
|
||||
const uint moduleBase = ModBaseFromAddr(Start);
|
||||
const uint key = ModHashFromAddr(moduleBase);
|
||||
|
||||
uint curStart = Start - moduleBase;
|
||||
uint curEnd = End - moduleBase;
|
||||
uint curStart = Start - moduleBase;
|
||||
uint curEnd = End - moduleBase;
|
||||
|
||||
SHARED_ACQUIRE(LockLoops);
|
||||
SHARED_ACQUIRE(LockLoops);
|
||||
|
||||
// Check if the new loop fits in the old loop
|
||||
for(auto& itr : loops)
|
||||
{
|
||||
// Only look in the current module
|
||||
// Only look in the current module
|
||||
if(itr.first.second.first != key)
|
||||
continue;
|
||||
|
||||
// Loop must be at this recursive depth
|
||||
if (itr.second.depth != Depth)
|
||||
continue;
|
||||
// Loop must be at this recursive depth
|
||||
if (itr.second.depth != Depth)
|
||||
continue;
|
||||
|
||||
if(itr.second.start < curStart && itr.second.end > curEnd)
|
||||
return LoopOverlaps(Depth + 1, curStart, curEnd, FinalDepth);
|
||||
}
|
||||
|
||||
// Did the user request t the loop depth?
|
||||
// Did the user request t the loop depth?
|
||||
if(FinalDepth)
|
||||
*FinalDepth = Depth;
|
||||
|
||||
// Check for loop overlaps
|
||||
for (auto& itr : loops)
|
||||
for (auto& itr : loops)
|
||||
{
|
||||
// Only look in the current module
|
||||
if (itr.first.second.first != key)
|
||||
continue;
|
||||
// Only look in the current module
|
||||
if (itr.first.second.first != key)
|
||||
continue;
|
||||
|
||||
// Loop must be at this recursive depth
|
||||
if (itr.second.depth != Depth)
|
||||
continue;
|
||||
// Loop must be at this recursive depth
|
||||
if (itr.second.depth != Depth)
|
||||
continue;
|
||||
|
||||
if(itr.second.start <= curEnd && itr.second.end >= curStart)
|
||||
return true;
|
||||
|
@ -147,81 +146,94 @@ bool LoopDelete(int Depth, uint Address)
|
|||
|
||||
void LoopCacheSave(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
const JSON jsonloops = json_array();
|
||||
const JSON jsonautoloops = json_array();
|
||||
for(auto& itr : loops)
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
|
||||
// Create the root JSON objects
|
||||
const JSON jsonLoops = json_array();
|
||||
const JSON jsonAutoLoops = json_array();
|
||||
|
||||
// Write all entries
|
||||
for(auto& itr : loops)
|
||||
{
|
||||
const LOOPSINFO curLoop = itr.second;
|
||||
JSON curjsonloop = json_object();
|
||||
json_object_set_new(curjsonloop, "module", json_string(curLoop.mod));
|
||||
json_object_set_new(curjsonloop, "start", json_hex(curLoop.start));
|
||||
json_object_set_new(curjsonloop, "end", json_hex(curLoop.end));
|
||||
json_object_set_new(curjsonloop, "depth", json_integer(curLoop.depth));
|
||||
json_object_set_new(curjsonloop, "parent", json_hex(curLoop.parent));
|
||||
if(curLoop.manual)
|
||||
json_array_append_new(jsonloops, curjsonloop);
|
||||
const LOOPSINFO& currentLoop = itr.second;
|
||||
JSON currentJson = json_object();
|
||||
|
||||
json_object_set_new(currentJson, "module", json_string(currentLoop.mod));
|
||||
json_object_set_new(currentJson, "start", json_hex(currentLoop.start));
|
||||
json_object_set_new(currentJson, "end", json_hex(currentLoop.end));
|
||||
json_object_set_new(currentJson, "depth", json_integer(currentLoop.depth));
|
||||
json_object_set_new(currentJson, "parent", json_hex(currentLoop.parent));
|
||||
|
||||
if(currentLoop.manual)
|
||||
json_array_append_new(jsonLoops, currentJson);
|
||||
else
|
||||
json_array_append_new(jsonautoloops, curjsonloop);
|
||||
json_array_append_new(jsonAutoLoops, currentJson);
|
||||
}
|
||||
if(json_array_size(jsonloops))
|
||||
json_object_set(Root, "loops", jsonloops);
|
||||
json_decref(jsonloops);
|
||||
if(json_array_size(jsonautoloops))
|
||||
json_object_set(Root, "autoloops", jsonautoloops);
|
||||
json_decref(jsonautoloops);
|
||||
|
||||
// Append a link to the global root
|
||||
if(json_array_size(jsonLoops))
|
||||
json_object_set(Root, "loops", jsonLoops);
|
||||
|
||||
if(json_array_size(jsonAutoLoops))
|
||||
json_object_set(Root, "autoloops", jsonAutoLoops);
|
||||
|
||||
// Release memory/references
|
||||
json_decref(jsonLoops);
|
||||
json_decref(jsonAutoLoops);
|
||||
}
|
||||
|
||||
void LoopCacheLoad(JSON Root)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
EXCLUSIVE_ACQUIRE(LockLoops);
|
||||
|
||||
// Inline lambda to parse each JSON entry
|
||||
auto AddLoops = [](const JSON Object, bool Manual)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
|
||||
json_array_foreach(Object, i, value)
|
||||
{
|
||||
LOOPSINFO loopInfo;
|
||||
memset(&loopInfo, 0, sizeof(LOOPSINFO));
|
||||
|
||||
// Module name
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
|
||||
if (mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(loopInfo.mod, mod);
|
||||
else
|
||||
loopInfo.mod[0] = '\0';
|
||||
|
||||
// All other variables
|
||||
loopInfo.start = (uint)json_hex_value(json_object_get(value, "start"));
|
||||
loopInfo.end = (uint)json_hex_value(json_object_get(value, "end"));
|
||||
loopInfo.depth = (int)json_integer_value(json_object_get(value, "depth"));
|
||||
loopInfo.parent = (uint)json_hex_value(json_object_get(value, "parent"));
|
||||
loopInfo.manual = Manual;
|
||||
|
||||
// Sanity check: Make sure the loop starts before it ends
|
||||
if (loopInfo.end < loopInfo.start)
|
||||
continue;
|
||||
|
||||
// Insert into global list
|
||||
loops.insert(std::make_pair(DepthModuleRange(loopInfo.depth, ModuleRange(ModHashFromName(loopInfo.mod), Range(loopInfo.start, loopInfo.end))), loopInfo));
|
||||
}
|
||||
};
|
||||
|
||||
// Remove existing entries
|
||||
loops.clear();
|
||||
const JSON jsonloops = json_object_get(Root, "loops");
|
||||
if(jsonloops)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(jsonloops, i, value)
|
||||
{
|
||||
LOOPSINFO curLoop;
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(curLoop.mod, mod);
|
||||
else
|
||||
*curLoop.mod = '\0';
|
||||
curLoop.start = (uint)json_hex_value(json_object_get(value, "start"));
|
||||
curLoop.end = (uint)json_hex_value(json_object_get(value, "end"));
|
||||
curLoop.depth = (int)json_integer_value(json_object_get(value, "depth"));
|
||||
curLoop.parent = (uint)json_hex_value(json_object_get(value, "parent"));
|
||||
if(curLoop.end < curLoop.start)
|
||||
continue; //invalid loop
|
||||
curLoop.manual = true;
|
||||
loops.insert(std::make_pair(DepthModuleRange(curLoop.depth, ModuleRange(ModHashFromName(curLoop.mod), Range(curLoop.start, curLoop.end))), curLoop));
|
||||
}
|
||||
}
|
||||
JSON jsonautoloops = json_object_get(Root, "autoloops");
|
||||
if(jsonautoloops)
|
||||
{
|
||||
size_t i;
|
||||
JSON value;
|
||||
json_array_foreach(jsonautoloops, i, value)
|
||||
{
|
||||
LOOPSINFO curLoop;
|
||||
const char* mod = json_string_value(json_object_get(value, "module"));
|
||||
if(mod && *mod && strlen(mod) < MAX_MODULE_SIZE)
|
||||
strcpy_s(curLoop.mod, mod);
|
||||
else
|
||||
*curLoop.mod = '\0';
|
||||
curLoop.start = (uint)json_hex_value(json_object_get(value, "start"));
|
||||
curLoop.end = (uint)json_hex_value(json_object_get(value, "end"));
|
||||
curLoop.depth = (int)json_integer_value(json_object_get(value, "depth"));
|
||||
curLoop.parent = (uint)json_hex_value(json_object_get(value, "parent"));
|
||||
if(curLoop.end < curLoop.start)
|
||||
continue; //invalid loop
|
||||
curLoop.manual = false;
|
||||
loops.insert(std::make_pair(DepthModuleRange(curLoop.depth, ModuleRange(ModHashFromName(curLoop.mod), Range(curLoop.start, curLoop.end))), curLoop));
|
||||
}
|
||||
}
|
||||
|
||||
const JSON jsonLoops = json_object_get(Root, "loops");
|
||||
const JSON jsonAutoLoops = json_object_get(Root, "autoloops");
|
||||
|
||||
// Load user-set loops
|
||||
if (jsonLoops)
|
||||
AddLoops(jsonLoops, true);
|
||||
|
||||
// Load auto-set loops
|
||||
if (jsonAutoLoops)
|
||||
AddLoops(jsonAutoLoops, false);
|
||||
}
|
||||
|
||||
bool LoopEnum(LOOPSINFO* List, size_t* Size)
|
||||
|
@ -241,14 +253,14 @@ bool LoopEnum(LOOPSINFO* List, size_t* Size)
|
|||
return true;
|
||||
}
|
||||
|
||||
for (auto& itr : loops)
|
||||
for (auto& itr : loops)
|
||||
{
|
||||
*List = itr.second;
|
||||
|
||||
// Adjust the offset to a real virtual address
|
||||
uint modbase = ModBaseFromName(List->mod);
|
||||
List->start += modbase;
|
||||
List->end += modbase;
|
||||
List->start += modbase;
|
||||
List->end += modbase;
|
||||
|
||||
List++;
|
||||
}
|
||||
|
|
|
@ -16,171 +16,174 @@ std::unordered_map<uint, PATCHINFO> patches;
|
|||
|
||||
bool PatchSet(uint Address, unsigned char OldByte, unsigned char NewByte)
|
||||
{
|
||||
// MemIsValidReadPtr also checks if the debugger is actually
|
||||
// debugging
|
||||
// CHECK: Exported function
|
||||
if (!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// Address must be valid
|
||||
if(!MemIsValidReadPtr(Address))
|
||||
return false;
|
||||
|
||||
// Don't patch anything if the new and old values are the same
|
||||
// Don't patch anything if the new and old values are the same
|
||||
if(OldByte == NewByte)
|
||||
return true;
|
||||
|
||||
PATCHINFO newPatch;
|
||||
newPatch.addr = Address - ModBaseFromAddr(Address);
|
||||
newPatch.oldbyte = OldByte;
|
||||
newPatch.newbyte = NewByte;
|
||||
ModNameFromAddr(Address, newPatch.mod, true);
|
||||
newPatch.addr = Address - ModBaseFromAddr(Address);
|
||||
newPatch.oldbyte = OldByte;
|
||||
newPatch.newbyte = NewByte;
|
||||
ModNameFromAddr(Address, newPatch.mod, true);
|
||||
|
||||
// Generate a key for this address
|
||||
// Generate a key for this address
|
||||
const uint key = ModHashFromAddr(Address);
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
|
||||
// Find any patch with this specific address
|
||||
// Find any patch with this specific address
|
||||
auto found = patches.find(key);
|
||||
|
||||
if(found != patches.end())
|
||||
{
|
||||
if(found->second.oldbyte == NewByte)
|
||||
{
|
||||
// The patch was undone here
|
||||
// The patch was undone here
|
||||
patches.erase(found);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep the original byte from the previous patch
|
||||
newPatch.oldbyte = found->second.oldbyte;
|
||||
found->second = newPatch;
|
||||
// Keep the original byte from the previous patch
|
||||
newPatch.oldbyte = found->second.oldbyte;
|
||||
found->second = newPatch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The entry was never found, insert it
|
||||
patches.insert(std::make_pair(key, newPatch));
|
||||
}
|
||||
else
|
||||
{
|
||||
// The entry was never found, insert it
|
||||
patches.insert(std::make_pair(key, newPatch));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PatchGet(uint Address, PATCHINFO* Patch)
|
||||
{
|
||||
// CHECK: Export
|
||||
// CHECK: Export
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockPatches);
|
||||
SHARED_ACQUIRE(LockPatches);
|
||||
|
||||
// Find this specific address in the list
|
||||
// Find this specific address in the list
|
||||
auto found = patches.find(ModHashFromAddr(Address));
|
||||
|
||||
if(found == patches.end())
|
||||
return false;
|
||||
|
||||
// Did the user request an output buffer?
|
||||
if(Patch)
|
||||
// Did the user request an output buffer?
|
||||
if(Patch)
|
||||
{
|
||||
*Patch = found->second;
|
||||
*Patch = found->second;
|
||||
Patch->addr += ModBaseFromAddr(Address);
|
||||
}
|
||||
|
||||
// Return true because the patch was found
|
||||
return true;
|
||||
// Return true because the patch was found
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PatchDelete(uint Address, bool Restore)
|
||||
{
|
||||
// CHECK: Export function
|
||||
// CHECK: Export function
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
|
||||
// Do a list lookup with hash
|
||||
// Do a list lookup with hash
|
||||
auto found = patches.find(ModHashFromAddr(Address));
|
||||
|
||||
if(found == patches.end())
|
||||
return false;
|
||||
|
||||
// Restore the original byte at this address
|
||||
if(Restore)
|
||||
|
||||
// Restore the original byte at this address
|
||||
if(Restore)
|
||||
MemWrite((void*)(found->second.addr + ModBaseFromAddr(Address)), &found->second.oldbyte, sizeof(char), nullptr);
|
||||
|
||||
// Finally remove it from the list
|
||||
// Finally remove it from the list
|
||||
patches.erase(found);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PatchDelRange(uint Start, uint End, bool Restore)
|
||||
{
|
||||
// CHECK: Export call
|
||||
if (!DbgIsDebugging())
|
||||
return;
|
||||
// CHECK: Export call
|
||||
if (!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
// Are all bookmarks going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if (Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
patches.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure 'Start' and 'End' reference the same module
|
||||
uint moduleBase = ModBaseFromAddr(Start);
|
||||
// Are all bookmarks going to be deleted?
|
||||
// 0x00000000 - 0xFFFFFFFF
|
||||
if (Start == 0 && End == ~0)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
patches.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure 'Start' and 'End' reference the same module
|
||||
uint moduleBase = ModBaseFromAddr(Start);
|
||||
|
||||
if (moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
if (moduleBase != ModBaseFromAddr(End))
|
||||
return;
|
||||
|
||||
// VA to RVA in module
|
||||
Start -= moduleBase;
|
||||
End -= moduleBase;
|
||||
// VA to RVA in module
|
||||
Start -= moduleBase;
|
||||
End -= moduleBase;
|
||||
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
for (auto itr = patches.begin(); itr != patches.end();)
|
||||
{
|
||||
// [Start, End)
|
||||
if (itr->second.addr >= Start && itr->second.addr < End)
|
||||
{
|
||||
// Restore the original byte if necessary
|
||||
if (Restore)
|
||||
MemWrite((void*)(itr->second.addr + moduleBase), &itr->second.oldbyte, sizeof(char), nullptr);
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
for (auto itr = patches.begin(); itr != patches.end();)
|
||||
{
|
||||
// [Start, End)
|
||||
if (itr->second.addr >= Start && itr->second.addr < End)
|
||||
{
|
||||
// Restore the original byte if necessary
|
||||
if (Restore)
|
||||
MemWrite((void*)(itr->second.addr + moduleBase), &itr->second.oldbyte, sizeof(char), nullptr);
|
||||
|
||||
itr = patches.erase(itr);
|
||||
}
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
itr = patches.erase(itr);
|
||||
}
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PatchEnum(PATCHINFO* List, size_t* Size)
|
||||
{
|
||||
// CHECK: Exported
|
||||
// CHECK: Exported
|
||||
if(!DbgIsDebugging())
|
||||
return false;
|
||||
|
||||
// At least one parameter is needed
|
||||
// At least one parameter is needed
|
||||
if(!List && !Size)
|
||||
return false;
|
||||
|
||||
SHARED_ACQUIRE(LockPatches);
|
||||
SHARED_ACQUIRE(LockPatches);
|
||||
|
||||
// Did the user request the size?
|
||||
// Did the user request the size?
|
||||
if(Size)
|
||||
{
|
||||
*Size = patches.size() * sizeof(PATCHINFO);
|
||||
|
||||
if (!List)
|
||||
return true;
|
||||
if (!List)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copy each vector entry to a C-style array
|
||||
// Copy each vector entry to a C-style array
|
||||
for(auto& itr : patches)
|
||||
{
|
||||
*List = itr.second;
|
||||
List->addr += ModBaseFromName(itr.second.mod);;
|
||||
List++;
|
||||
*List = itr.second;
|
||||
List->addr += ModBaseFromName(itr.second.mod);;
|
||||
List++;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -188,36 +191,36 @@ bool PatchEnum(PATCHINFO* List, size_t* Size)
|
|||
|
||||
int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Error)
|
||||
{
|
||||
//
|
||||
// This function returns an int based on the number
|
||||
// of patches applied. -1 indicates a failure.
|
||||
//
|
||||
//
|
||||
// This function returns an int based on the number
|
||||
// of patches applied. -1 indicates a failure.
|
||||
//
|
||||
if(Count <= 0)
|
||||
{
|
||||
// Notify the user of the error
|
||||
// Notify the user of the error
|
||||
if(Error)
|
||||
strcpy_s(Error, MAX_ERROR_SIZE, "No patches to apply");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get a copy of the first module name in the array
|
||||
// Get a copy of the first module name in the array
|
||||
char moduleName[MAX_MODULE_SIZE];
|
||||
strcpy_s(moduleName, List[0].mod);
|
||||
|
||||
// Check if all patches are in the same module
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (_stricmp(List[i].mod, moduleName))
|
||||
{
|
||||
if (Error)
|
||||
sprintf_s(Error, MAX_ERROR_SIZE, "not all patches are in module %s", moduleName);
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (_stricmp(List[i].mod, moduleName))
|
||||
{
|
||||
if (Error)
|
||||
sprintf_s(Error, MAX_ERROR_SIZE, "not all patches are in module %s", moduleName);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// See if the module was loaded
|
||||
// See if the module was loaded
|
||||
uint moduleBase = ModBaseFromName(moduleName);
|
||||
|
||||
if(!moduleBase)
|
||||
|
@ -227,9 +230,9 @@ int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Erro
|
|||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the unicode version of the module's path
|
||||
wchar_t originalName[MAX_PATH];
|
||||
|
||||
// Get the unicode version of the module's path
|
||||
wchar_t originalName[MAX_PATH];
|
||||
|
||||
if(!GetModuleFileNameExW(fdProcessInfo->hProcess, (HMODULE)moduleBase, originalName, ARRAYSIZE(originalName)))
|
||||
{
|
||||
|
@ -239,7 +242,7 @@ int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Erro
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Create a temporary backup file
|
||||
// Create a temporary backup file
|
||||
if(!CopyFileW(originalName, StringUtils::Utf8ToUtf16(FileName).c_str(), false))
|
||||
{
|
||||
if(Error)
|
||||
|
@ -252,21 +255,21 @@ int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Erro
|
|||
DWORD loadedSize;
|
||||
HANDLE fileMap;
|
||||
ULONG_PTR fileMapVa;
|
||||
if (!StaticFileLoadW(StringUtils::Utf8ToUtf16(FileName).c_str(), UE_ACCESS_ALL, false, &fileHandle, &loadedSize, &fileMap, &fileMapVa))
|
||||
{
|
||||
strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileLoad failed");
|
||||
return -1;
|
||||
}
|
||||
if (!StaticFileLoadW(StringUtils::Utf8ToUtf16(FileName).c_str(), UE_ACCESS_ALL, false, &fileHandle, &loadedSize, &fileMap, &fileMapVa))
|
||||
{
|
||||
strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileLoad failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Begin iterating all patches, applying them to a file
|
||||
// Begin iterating all patches, applying them to a file
|
||||
int patchCount = 0;
|
||||
|
||||
for(int i = 0; i < Count; i++)
|
||||
{
|
||||
// Convert the virtual address to an offset within disk file data
|
||||
// Convert the virtual address to an offset within disk file data
|
||||
unsigned char* ptr = (unsigned char*)ConvertVAtoFileOffsetEx(fileMapVa, loadedSize, moduleBase, List[i].addr, false, true);
|
||||
|
||||
// Skip patches that do not have a raw address
|
||||
// Skip patches that do not have a raw address
|
||||
if(!ptr)
|
||||
continue;
|
||||
|
||||
|
@ -275,7 +278,7 @@ int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Erro
|
|||
patchCount++;
|
||||
}
|
||||
|
||||
// Unload the file from memory and commit changes to disk
|
||||
// Unload the file from memory and commit changes to disk
|
||||
if(!StaticFileUnloadW(StringUtils::Utf8ToUtf16(FileName).c_str(), true, fileHandle, loadedSize, fileMap, fileMapVa))
|
||||
{
|
||||
if(Error)
|
||||
|
@ -284,33 +287,33 @@ int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Erro
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Zero the error message and return count
|
||||
if (Error)
|
||||
memset(Error, 0, MAX_ERROR_SIZE * sizeof(char));
|
||||
// Zero the error message and return count
|
||||
if (Error)
|
||||
memset(Error, 0, MAX_ERROR_SIZE * sizeof(char));
|
||||
|
||||
return patchCount;
|
||||
}
|
||||
|
||||
void PatchClear(const char* Module)
|
||||
{
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
EXCLUSIVE_ACQUIRE(LockPatches);
|
||||
|
||||
// Was a module specified?
|
||||
if (!Module || Module[0] == '\0')
|
||||
{
|
||||
// No specific entries to delete, so remove all of them
|
||||
patches.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise iterate over each patch and check the owner
|
||||
// module for the address
|
||||
for (auto itr = patches.begin(); itr != patches.end();)
|
||||
{
|
||||
if (!_stricmp(itr->second.mod, Module))
|
||||
itr = patches.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
// Was a module specified?
|
||||
if (!Module || Module[0] == '\0')
|
||||
{
|
||||
// No specific entries to delete, so remove all of them
|
||||
patches.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise iterate over each patch and check the owner
|
||||
// module for the address
|
||||
for (auto itr = patches.begin(); itr != patches.end();)
|
||||
{
|
||||
if (!_stricmp(itr->second.mod, Module))
|
||||
itr = patches.erase(itr);
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue