1
0
Fork 0
x64dbg/src/dbg/xrefs.cpp

160 lines
4.3 KiB
C++

#include "xrefs.h"
#include "addrinfo.h"
struct XREFSINFO : AddrInfo
{
XREFTYPE type;
std::unordered_map<duint, XREF_RECORD> references;
};
struct XrefSerializer : AddrInfoSerializer<XREFSINFO>
{
bool Save(const XREFSINFO & value) override
{
AddrInfoSerializer::Save(value);
auto references = json_array();
for(const auto & itr : value.references)
{
auto reference = json_object();
json_object_set_new(reference, "addr", json_hex(itr.second.addr));
json_object_set_new(reference, "type", json_hex(itr.second.type));
json_array_append_new(references, reference);
}
set("references", references);
return true;
}
bool Load(XREFSINFO & value) override
{
if(!AddrInfoSerializer::Load(value))
return false;
auto references = get("references");
if(!references)
return false;
value.type = XREF_DATA;
size_t i;
JSON reference;
json_array_foreach(references, i, reference)
{
XREF_RECORD record;
record.addr = duint(json_hex_value(json_object_get(reference, "addr")));
record.type = XREFTYPE(json_hex_value(json_object_get(reference, "type")));
value.type = max(record.type, value.type);
value.references.insert({ record.addr, record });
}
return true;
}
};
struct Xrefs : AddrInfoHashMap<LockCrossReferences, XREFSINFO, XrefSerializer>
{
const char* jsonKey() const override
{
return "xrefs";
}
};
static Xrefs xrefs;
bool XrefAdd(duint Address, duint From)
{
XREFSINFO info;
if(!MemIsValidReadPtr(From) || !xrefs.PrepareValue(info, Address, false))
return false;
// Fail if boundary exceeds module size
auto moduleBase = ModBaseFromAddr(Address);
if(moduleBase != ModBaseFromAddr(From))
return false;
BASIC_INSTRUCTION_INFO instInfo;
DbgDisasmFastAt(From, &instInfo);
XREF_RECORD xrefRecord;
xrefRecord.addr = From - moduleBase;
if(instInfo.call)
xrefRecord.type = XREF_CALL;
else if(instInfo.branch)
xrefRecord.type = XREF_JMP;
else
xrefRecord.type = XREF_DATA;
EXCLUSIVE_ACQUIRE(LockCrossReferences);
auto & mapData = xrefs.GetDataUnsafe();
auto key = Xrefs::VaKey(Address);
auto found = mapData.find(key);
if(found == mapData.end())
{
info.type = xrefRecord.type;
info.references.insert({ xrefRecord.addr, xrefRecord });
mapData.insert({ key, info });
}
else
{
found->second.references.insert({ xrefRecord.addr, xrefRecord });
found->second.type = max(found->second.type, xrefRecord.type);
}
return true;
}
bool XrefGet(duint Address, XREF_INFO* List)
{
SHARED_ACQUIRE(LockCrossReferences);
auto & mapData = xrefs.GetDataUnsafe();
auto found = mapData.find(Xrefs::VaKey(Address));
if(found == mapData.end())
return false;
if(List->refcount != found->second.references.size())
return false;
auto moduleBase = ModBaseFromAddr(Address);
auto ptr = List->references;
for(const auto & itr : found->second.references)
{
*ptr = itr.second;
ptr->addr += moduleBase;
++ptr;
}
return true;
}
duint XrefGetCount(duint Address)
{
SHARED_ACQUIRE(LockCrossReferences);
auto & mapData = xrefs.GetDataUnsafe();
auto found = mapData.find(Xrefs::VaKey(Address));
return found == mapData.end() ? 0 : found->second.references.size();
}
XREFTYPE XrefGetType(duint Address)
{
SHARED_ACQUIRE(LockCrossReferences);
auto & mapData = xrefs.GetDataUnsafe();
auto found = mapData.find(Xrefs::VaKey(Address));
return found == mapData.end() ? XREF_NONE : found->second.type;
}
bool XrefDeleteAll(duint Address)
{
return xrefs.Delete(Xrefs::VaKey(Address));
}
void XrefDelRange(duint Start, duint End)
{
xrefs.DeleteRange(Start, End, false);
}
void XrefCacheSave(JSON Root)
{
xrefs.CacheSave(Root);
}
void XrefCacheLoad(JSON Root)
{
xrefs.CacheLoad(Root);
}
void XrefClear()
{
xrefs.Clear();
}