DBG+BRIDGE+GUI+LAUNCER: manually merged pull request #705 (thanks to @wynick27)
This commit is contained in:
parent
a89c93c425
commit
ee3e030886
|
|
@ -737,6 +737,37 @@ BRIDGE_IMPEXP bool DbgLoopDel(int depth, duint addr)
|
|||
return true;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP size_t DbgGetXrefCountAt(duint addr)
|
||||
{
|
||||
return _dbg_sendmessage(DBG_GET_XREF_COUNT_AT, (void*)addr, 0);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP XREFTYPE DbgGetXrefTypeAt(duint addr)
|
||||
{
|
||||
return (XREFTYPE)_dbg_sendmessage(DBG_GET_XREF_TYPE_AT, (void*)addr, 0);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP bool DbgXrefAdd(duint addr, duint from, bool iscall)
|
||||
{
|
||||
if(!_dbg_sendmessage(DBG_XREF_ADD, (void*)addr, (void*)from))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP bool DbgXrefDelAll(duint addr)
|
||||
{
|
||||
if(!_dbg_sendmessage(DBG_XREF_DEL_ALL, (void*)addr, 0))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP bool DbgXrefGet(duint addr, XREF_INFO* info)
|
||||
{
|
||||
if(!_dbg_sendmessage(DBG_XREF_GET, (void*)addr, info))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME all
|
||||
BRIDGE_IMPEXP bool DbgIsRunLocked()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -129,6 +129,15 @@ typedef enum
|
|||
LOOP_END
|
||||
} LOOPTYPE;
|
||||
|
||||
//order by most important type last
|
||||
typedef enum
|
||||
{
|
||||
XREF_NONE,
|
||||
XREF_DATA,
|
||||
XREF_JMP,
|
||||
XREF_CALL
|
||||
} XREFTYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ARG_NONE,
|
||||
|
|
@ -188,6 +197,11 @@ typedef enum
|
|||
DBG_DELETE_COMMENT_RANGE, // param1=duint start, param2=duint end
|
||||
DBG_DELETE_LABEL_RANGE, // param1=duint start, param2=duint end
|
||||
DBG_DELETE_BOOKMARK_RANGE, // param1=duint start, param2=duint end
|
||||
DBG_GET_XREF_COUNT_AT, // param1=duint addr, param2=unused
|
||||
DBG_GET_XREF_TYPE_AT, // param1=duint addr, param2=unused
|
||||
DBG_XREF_ADD, // param1=duint addr, param2=duint from
|
||||
DBG_XREF_DEL_ALL, // param1=duint addr, param2=unused
|
||||
DBG_XREF_GET, // param1=duint addr, param2=XREF_INFO* info
|
||||
} DBGMSG;
|
||||
|
||||
typedef enum
|
||||
|
|
@ -649,6 +663,19 @@ typedef struct
|
|||
int depth;
|
||||
} FUNCTION_LOOP_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
duint addr;
|
||||
XREFTYPE type;
|
||||
} XREF_RECORD;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
XREF_RECORD* references;
|
||||
size_t refcount;
|
||||
} XREF_INFO;
|
||||
|
||||
//Debugger functions
|
||||
BRIDGE_IMPEXP const char* DbgInit();
|
||||
BRIDGE_IMPEXP void DbgExit();
|
||||
|
|
@ -710,6 +737,11 @@ BRIDGE_IMPEXP bool DbgLoopGet(int depth, duint addr, duint* start, duint* end);
|
|||
BRIDGE_IMPEXP bool DbgLoopOverlaps(int depth, duint start, duint end);
|
||||
BRIDGE_IMPEXP bool DbgLoopAdd(duint start, duint end);
|
||||
BRIDGE_IMPEXP bool DbgLoopDel(int depth, duint addr);
|
||||
BRIDGE_IMPEXP bool DbgXrefAdd(duint addr, duint from, bool iscall);
|
||||
BRIDGE_IMPEXP bool DbgXrefDelAll(duint addr);
|
||||
BRIDGE_IMPEXP bool DbgXrefGet(duint addr, XREF_INFO* info);
|
||||
BRIDGE_IMPEXP size_t DbgGetXrefCountAt(duint addr);
|
||||
BRIDGE_IMPEXP XREFTYPE DbgGetXrefTypeAt(duint addr);
|
||||
BRIDGE_IMPEXP bool DbgIsRunLocked();
|
||||
BRIDGE_IMPEXP bool DbgIsBpDisabled(duint addr);
|
||||
BRIDGE_IMPEXP bool DbgSetAutoCommentAt(duint addr, const char* text);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "x64_dbg.h"
|
||||
#include "threading.h"
|
||||
#include "stringformat.h"
|
||||
#include "xrefs.h"
|
||||
|
||||
static bool bOnlyCipAutoComments = false;
|
||||
|
||||
|
|
@ -1000,6 +1001,50 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
|
|||
}
|
||||
break;
|
||||
|
||||
case DBG_GET_XREF_COUNT_AT:
|
||||
{
|
||||
return XrefGetCount((duint)param1);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_XREF_GET:
|
||||
{
|
||||
if(!param2)
|
||||
return false;
|
||||
XREF_INFO* info = (XREF_INFO*)param2;
|
||||
duint address = (duint)param1;
|
||||
info->refcount = XrefGetCount(address);
|
||||
|
||||
if(info->refcount == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->references = (XREF_RECORD*)BridgeAlloc(sizeof(XREF_RECORD) * info->refcount);
|
||||
return XrefGet(address, info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_XREF_ADD:
|
||||
{
|
||||
return XrefAdd((duint)param1, (duint)param2);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_XREF_DEL_ALL:
|
||||
{
|
||||
return XrefDeleteAll((duint)param1);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_GET_XREF_TYPE_AT:
|
||||
{
|
||||
return XrefGetType((duint)param1);
|
||||
}
|
||||
break;
|
||||
|
||||
case DBG_GET_STRING_AT:
|
||||
{
|
||||
auto addr = duint(param1);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ typedef std::pair<int, ModuleRange> DepthModuleRange; //depth + modulerange
|
|||
|
||||
struct RangeCompare
|
||||
{
|
||||
bool operator()(const Range & a, const Range & b) //a before b?
|
||||
bool operator()(const Range & a, const Range & b) const //a before b?
|
||||
{
|
||||
return a.second < b.first;
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ struct RangeCompare
|
|||
|
||||
struct OverlappingRangeCompare
|
||||
{
|
||||
bool operator()(const Range & a, const Range & b) //a before b?
|
||||
bool operator()(const Range & a, const Range & b) const //a before b?
|
||||
{
|
||||
return a.second < b.first || a.second < b.second;
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ struct OverlappingRangeCompare
|
|||
|
||||
struct ModuleRangeCompare
|
||||
{
|
||||
bool operator()(const ModuleRange & a, const ModuleRange & b)
|
||||
bool operator()(const ModuleRange & a, const ModuleRange & b) const
|
||||
{
|
||||
if(a.first < b.first) //module hash is smaller
|
||||
return true;
|
||||
|
|
@ -39,7 +39,7 @@ struct ModuleRangeCompare
|
|||
|
||||
struct DepthModuleRangeCompare
|
||||
{
|
||||
bool operator()(const DepthModuleRange & a, const DepthModuleRange & b)
|
||||
bool operator()(const DepthModuleRange & a, const DepthModuleRange & b) const
|
||||
{
|
||||
if(a.first < b.first) //module depth is smaller
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "database.h"
|
||||
#include "threading.h"
|
||||
#include "filehelper.h"
|
||||
#include "xrefs.h"
|
||||
#include "TraceRecord.h"
|
||||
|
||||
/**
|
||||
|
|
@ -50,6 +51,7 @@ void DbSave(DbLoadSaveType saveType)
|
|||
BookmarkCacheSave(root);
|
||||
FunctionCacheSave(root);
|
||||
LoopCacheSave(root);
|
||||
XrefCacheSave(root);
|
||||
TraceRecord.saveToDb(root);
|
||||
BpCacheSave(root);
|
||||
|
||||
|
|
@ -160,9 +162,11 @@ void DbLoad(DbLoadSaveType loadType)
|
|||
BookmarkCacheLoad(root);
|
||||
FunctionCacheLoad(root);
|
||||
LoopCacheLoad(root);
|
||||
XrefCacheLoad(root);
|
||||
TraceRecord.loadFromDb(root);
|
||||
BpCacheLoad(root);
|
||||
|
||||
|
||||
// Load notes
|
||||
const char* text = json_string_value(json_object_get(root, "notes"));
|
||||
GuiSetDebuggeeNotes(text);
|
||||
|
|
@ -183,6 +187,7 @@ void DbClose()
|
|||
BookmarkClear();
|
||||
FunctionClear();
|
||||
LoopClear();
|
||||
XrefClear();
|
||||
BpClear();
|
||||
PatchClear();
|
||||
GuiSetDebuggeeNotes("");
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "mnemonichelp.h"
|
||||
#include "error.h"
|
||||
#include "recursiveanalysis.h"
|
||||
#include "xrefsanalysis.h"
|
||||
|
||||
static bool bRefinit = false;
|
||||
static int maxFindResults = 5000;
|
||||
|
|
@ -2171,6 +2172,19 @@ CMDRESULT cbInstrAnalrecur(int argc, char* argv[])
|
|||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrAnalxrefs(int argc, char* argv[])
|
||||
{
|
||||
SELECTIONDATA sel;
|
||||
GuiSelectionGet(GUI_DISASSEMBLY, &sel);
|
||||
duint size = 0;
|
||||
auto base = MemFindBaseAddr(sel.start, &size);
|
||||
XrefsAnalysis anal(base, size);
|
||||
anal.Analyse();
|
||||
anal.SetMarkers();
|
||||
GuiUpdateAllViews();
|
||||
return STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
CMDRESULT cbInstrVirtualmod(int argc, char* argv[])
|
||||
{
|
||||
if(argc < 3)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ CMDRESULT cbInstrCapstone(int argc, char* argv[]);
|
|||
CMDRESULT cbInstrAnalyseNukem(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAnalyse(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAnalrecur(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrAnalxrefs(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrVisualize(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrMeminfo(int argc, char* argv[]);
|
||||
CMDRESULT cbInstrCfanalyse(int argc, char* argv[]);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "_global.h"
|
||||
#include "threading.h"
|
||||
#include "module.h"
|
||||
|
||||
template<class TValue>
|
||||
class JSONWrapper
|
||||
|
|
@ -79,7 +80,6 @@ protected:
|
|||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// ReSharper disable once CppMemberFunctionMayBeConst
|
||||
void set(const char* key, JSON value)
|
||||
{
|
||||
|
|
@ -239,6 +239,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
TMap & GetDataUnsafe()
|
||||
{
|
||||
return mMap;
|
||||
}
|
||||
|
||||
virtual void AdjustValue(TValue & value) const = 0;
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ enum SectionLock
|
|||
LockSehCache,
|
||||
LockMnemonicHelp,
|
||||
LockTraceRecord,
|
||||
LockCrossReferences,
|
||||
LockDebugStartStop,
|
||||
LockArguments,
|
||||
|
||||
|
|
|
|||
|
|
@ -274,6 +274,7 @@ static void registercommands()
|
|||
dbgcmdnew("handleclose", cbHandleClose, true); //close remote handle
|
||||
dbgcmdnew("briefcheck", cbInstrBriefcheck, true); //check if mnemonic briefs are missing
|
||||
dbgcmdnew("analrecur\1analr", cbInstrAnalrecur, true); //analyze a single function
|
||||
dbgcmdnew("analxrefs\1analx", cbInstrAnalxrefs, true); //analyze xrefs
|
||||
}
|
||||
|
||||
static bool cbCommandProvider(char* cmd, int maxlen)
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@
|
|||
<ClCompile Include="value.cpp" />
|
||||
<ClCompile Include="variable.cpp" />
|
||||
<ClCompile Include="x64_dbg.cpp" />
|
||||
<ClCompile Include="xrefs.cpp" />
|
||||
<ClCompile Include="xrefsanalysis.cpp" />
|
||||
<ClCompile Include="_exports.cpp" />
|
||||
<ClCompile Include="_dbgfunctions.cpp" />
|
||||
<ClCompile Include="_global.cpp" />
|
||||
|
|
@ -160,6 +162,8 @@
|
|||
<ClInclude Include="serializablemap.h" />
|
||||
<ClInclude Include="tcpconnections.h" />
|
||||
<ClInclude Include="TraceRecord.h" />
|
||||
<ClInclude Include="xrefs.h" />
|
||||
<ClInclude Include="xrefsanalysis.h" />
|
||||
<ClInclude Include="yara\yara\stream.h" />
|
||||
<ClInclude Include="_scriptapi.h" />
|
||||
<ClInclude Include="simplescript.h" />
|
||||
|
|
|
|||
|
|
@ -308,6 +308,9 @@
|
|||
<ClCompile Include="tcpconnections.cpp">
|
||||
<Filter>Source Files\Information</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="xrefs.cpp">
|
||||
<Filter>Source Files\Information</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="argument.cpp">
|
||||
<Filter>Source Files\Information</Filter>
|
||||
</ClCompile>
|
||||
|
|
@ -317,6 +320,9 @@
|
|||
<ClCompile Include="recursiveanalysis.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="xrefsanalysis.cpp">
|
||||
<Filter>Source Files\Analysis</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="x64_dbg.h">
|
||||
|
|
@ -685,6 +691,9 @@
|
|||
<ClInclude Include="tcpconnections.h">
|
||||
<Filter>Header Files\Information</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="xrefs.h">
|
||||
<Filter>Header Files\Information</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="argument.h">
|
||||
<Filter>Header Files\Information</Filter>
|
||||
</ClInclude>
|
||||
|
|
@ -697,5 +706,8 @@
|
|||
<ClInclude Include="recursiveanalysis.h">
|
||||
<Filter>Header Files\Analysis</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="xrefsanalysis.h">
|
||||
<Filter>Header Files\Analysis</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
#include "xrefs.h"
|
||||
#include "module.h"
|
||||
#include "memory.h"
|
||||
#include "threading.h"
|
||||
|
||||
struct XREFSINFO
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
duint address;
|
||||
XREFTYPE type;
|
||||
std::unordered_map<duint, XREF_RECORD> references;
|
||||
};
|
||||
|
||||
struct XrefSerializer : JSONWrapper<XREFSINFO>
|
||||
{
|
||||
bool Save(const XREFSINFO & value) override
|
||||
{
|
||||
setString("module", value.mod);
|
||||
setHex("address", value.address);
|
||||
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(!getString("module", value.mod) ||
|
||||
!getHex("address", value.address))
|
||||
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 : SerializableModuleHashMap<LockCrossReferences, XREFSINFO, XrefSerializer>
|
||||
{
|
||||
void AdjustValue(XREFSINFO & value) const override
|
||||
{
|
||||
value.address += ModBaseFromName(value.mod);
|
||||
}
|
||||
|
||||
protected:
|
||||
const char* jsonKey() const override
|
||||
{
|
||||
return "xrefs";
|
||||
}
|
||||
|
||||
duint makeKey(const XREFSINFO & value) const override
|
||||
{
|
||||
return ModHashFromName(value.mod) + value.address;
|
||||
}
|
||||
};
|
||||
|
||||
static Xrefs xrefs;
|
||||
|
||||
bool XrefAdd(duint Address, duint From)
|
||||
{
|
||||
// Make sure memory is readable
|
||||
if(!MemIsValidReadPtr(Address) || !MemIsValidReadPtr(From))
|
||||
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())
|
||||
{
|
||||
XREFSINFO info;
|
||||
ModNameFromAddr(Address, info.mod, true);
|
||||
info.address = Address - moduleBase;
|
||||
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, [](duint start, duint end, const XREFSINFO & value)
|
||||
{
|
||||
return value.address >= start && value.address <= end;
|
||||
});
|
||||
}
|
||||
|
||||
void XrefCacheSave(JSON Root)
|
||||
{
|
||||
xrefs.CacheSave(Root);
|
||||
}
|
||||
|
||||
void XrefCacheLoad(JSON Root)
|
||||
{
|
||||
xrefs.CacheLoad(Root);
|
||||
}
|
||||
|
||||
void XrefClear()
|
||||
{
|
||||
xrefs.Clear();
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _XREFS_H
|
||||
#define _XREFS_H
|
||||
|
||||
#include "_global.h"
|
||||
|
||||
|
||||
|
||||
bool XrefAdd(duint Address, duint From);
|
||||
bool XrefGet(duint Address, XREF_INFO* List);
|
||||
duint XrefGetCount(duint Address);
|
||||
XREFTYPE XrefGetType(duint Address);
|
||||
bool XrefDeleteAll(duint Address);
|
||||
void XrefDelRange(duint Start, duint End);
|
||||
void XrefCacheSave(JSON Root);
|
||||
void XrefCacheLoad(JSON Root);
|
||||
void XrefClear();
|
||||
|
||||
#endif // _FUNCTION_H
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#include "xrefsanalysis.h"
|
||||
#include "xrefs.h"
|
||||
#include "console.h"
|
||||
|
||||
void XrefsAnalysis::Analyse()
|
||||
{
|
||||
dputs("Starting xref analysis...");
|
||||
auto ticks = GetTickCount();
|
||||
|
||||
for(auto addr = mBase; addr < mBase + mSize;)
|
||||
{
|
||||
if(!mCp.Disassemble(addr, translateAddr(addr)))
|
||||
{
|
||||
addr++;
|
||||
continue;
|
||||
}
|
||||
addr += mCp.Size();
|
||||
|
||||
XREF xref;
|
||||
xref.addr = 0;
|
||||
xref.from = mCp.Address();
|
||||
for(auto i = 0; i < mCp.OpCount(); i++)
|
||||
{
|
||||
duint dest = mCp.ResolveOpValue(i, [](x86_reg)->size_t
|
||||
{
|
||||
return 0;
|
||||
});
|
||||
if(inRange(dest))
|
||||
{
|
||||
xref.addr = dest;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(xref.addr)
|
||||
mXrefs.push_back(xref);
|
||||
}
|
||||
|
||||
dprintf("%u xrefs found in %ums!\n", mXrefs.size(), GetTickCount() - ticks);
|
||||
}
|
||||
|
||||
void XrefsAnalysis::SetMarkers()
|
||||
{
|
||||
XrefDelRange(mBase, mBase + mSize - 1);
|
||||
for(const auto & xref : mXrefs)
|
||||
XrefAdd(xref.addr, xref.from);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "analysis.h"
|
||||
|
||||
class XrefsAnalysis : public Analysis
|
||||
{
|
||||
public:
|
||||
XrefsAnalysis(duint base, duint size)
|
||||
: Analysis(base, size)
|
||||
{
|
||||
}
|
||||
|
||||
void Analyse() override;
|
||||
void SetMarkers() override;
|
||||
|
||||
private:
|
||||
struct XREF
|
||||
{
|
||||
duint addr;
|
||||
duint from;
|
||||
};
|
||||
|
||||
std::vector<XREF> mXrefs;
|
||||
};
|
||||
|
|
@ -46,10 +46,13 @@ Disassembly::Disassembly(QWidget* parent) : AbstractTableView(parent)
|
|||
|
||||
backgroundColor = ConfigColor("DisassemblyBackgroundColor");
|
||||
|
||||
mXrefInfo.refcount = 0;
|
||||
|
||||
// Slots
|
||||
connect(Bridge::getBridge(), SIGNAL(repaintGui()), this, SLOT(reloadData()));
|
||||
connect(Bridge::getBridge(), SIGNAL(updateDump()), this, SLOT(reloadData()));
|
||||
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(debugStateChangedSlot(DBGSTATE)));
|
||||
connect(this, SIGNAL(selectionChanged(dsint)), this, SLOT(selectionChangedSlot(dsint)));
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
|
@ -58,6 +61,8 @@ Disassembly::~Disassembly()
|
|||
{
|
||||
delete mMemPage;
|
||||
delete mDisasm;
|
||||
if(mXrefInfo.refcount != 0)
|
||||
BridgeFree(mXrefInfo.references);
|
||||
}
|
||||
|
||||
void Disassembly::updateColors()
|
||||
|
|
@ -368,8 +373,33 @@ QString Disassembly::paintContent(QPainter* painter, dsint rowBase, int rowOffse
|
|||
}
|
||||
int funcsize = paintFunctionGraphic(painter, x, y, funcType, false);
|
||||
|
||||
painter->setPen(mFunctionPen);
|
||||
|
||||
XREFTYPE refType = DbgGetXrefTypeAt(cur_addr);
|
||||
QString indicator;
|
||||
if(refType == XREF_JMP)
|
||||
{
|
||||
indicator = ">";
|
||||
}
|
||||
else if(refType == XREF_CALL)
|
||||
{
|
||||
indicator = "$";
|
||||
}
|
||||
else if(funcType != FUNC_NONE)
|
||||
{
|
||||
indicator = ".";
|
||||
}
|
||||
else
|
||||
{
|
||||
indicator = " ";
|
||||
}
|
||||
|
||||
int charwidth = getCharWidth();
|
||||
painter->drawText(QRect(x + funcsize, y , charwidth , h), Qt::AlignVCenter | Qt::AlignLeft, indicator);
|
||||
funcsize += charwidth;
|
||||
|
||||
//draw jump arrows
|
||||
int jumpsize = paintJumpsGraphic(painter, x + funcsize, y - 1, wRVA); //jump line
|
||||
int jumpsize = paintJumpsGraphic(painter, x + funcsize, y - 1, wRVA, mInstBuffer.at(rowOffset).branchType != Instruction_t::BranchType::None); //jump line
|
||||
|
||||
//draw bytes
|
||||
RichTextPainter::List richBytes;
|
||||
|
|
@ -806,13 +836,17 @@ dsint Disassembly::sliderMovedHook(int type, dsint value, dsint delta)
|
|||
*
|
||||
* @return Nothing.
|
||||
*/
|
||||
int Disassembly::paintJumpsGraphic(QPainter* painter, int x, int y, dsint addr)
|
||||
int Disassembly::paintJumpsGraphic(QPainter* painter, int x, int y, dsint addr, bool isjmp)
|
||||
{
|
||||
dsint selHeadRVA = mSelection.fromIndex;
|
||||
dsint rva = addr;
|
||||
duint curVa = rvaToVa(addr);
|
||||
duint selVa = rvaToVa(mSelection.firstSelectedIndex);
|
||||
Instruction_t instruction = DisassembleAt(selHeadRVA);
|
||||
auto branchType = instruction.branchType;
|
||||
|
||||
bool showXref = false;
|
||||
|
||||
GraphicDump_t wPict = GD_Nothing;
|
||||
|
||||
if(branchType != Instruction_t::None)
|
||||
|
|
@ -844,21 +878,124 @@ int Disassembly::paintJumpsGraphic(QPainter* painter, int x, int y, dsint addr)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if(mXrefInfo.refcount > 0)
|
||||
{
|
||||
duint max = selVa, min = selVa;
|
||||
showXref = true;
|
||||
int jmpcount = 0;
|
||||
for(int i = 0; i < mXrefInfo.refcount; i++)
|
||||
{
|
||||
if(mXrefInfo.references[i].type != XREF_JMP)
|
||||
continue;
|
||||
jmpcount++;
|
||||
if(curVa == mXrefInfo.references[i].addr)
|
||||
wPict = GD_VertHori;
|
||||
if(mXrefInfo.references[i].addr > max)
|
||||
max = mXrefInfo.references[i].addr;
|
||||
if(mXrefInfo.references[i].addr < min)
|
||||
min = mXrefInfo.references[i].addr;
|
||||
}
|
||||
if(jmpcount)
|
||||
{
|
||||
if(curVa == selVa)
|
||||
{
|
||||
if(max == selVa)
|
||||
{
|
||||
wPict = GD_HeadFromTop;
|
||||
}
|
||||
else if(min == selVa)
|
||||
{
|
||||
wPict = GD_HeadFromBottom;
|
||||
}
|
||||
else if(max > selVa && min < selVa)
|
||||
{
|
||||
wPict = GD_HeadFromBoth;
|
||||
}
|
||||
|
||||
bool bIsExecute = DbgIsJumpGoingToExecute(rvaToVa(instruction.rva));
|
||||
}
|
||||
else if(curVa < selVa && curVa == min)
|
||||
{
|
||||
wPict = GD_FootToBottom;
|
||||
}
|
||||
else if(curVa > selVa && curVa == max)
|
||||
{
|
||||
wPict = GD_FootToTop;
|
||||
}
|
||||
if(wPict == GD_Nothing && curVa > min && curVa < max)
|
||||
wPict = GD_Vert;
|
||||
}
|
||||
}
|
||||
|
||||
if(branchType == Instruction_t::Unconditional) //unconditional
|
||||
GraphicJumpDirection_t curInstDir = GJD_Nothing;
|
||||
|
||||
if(isjmp)
|
||||
{
|
||||
duint curInstDestination = DbgGetBranchDestination(curVa);
|
||||
if(curInstDestination == 0 || curVa == curInstDestination)
|
||||
{
|
||||
curInstDir = GJD_Nothing;
|
||||
}
|
||||
else if(curInstDestination < curVa)
|
||||
{
|
||||
curInstDir = GJD_Up;
|
||||
}
|
||||
else
|
||||
{
|
||||
curInstDir = GJD_Down;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
painter->setPen(mConditionalTruePen);
|
||||
if(curInstDir == GJD_Up)
|
||||
{
|
||||
QPoint wPoints[] =
|
||||
{
|
||||
QPoint(x , y + getRowHeight() / 2 + 1),
|
||||
QPoint(x + 2, y + getRowHeight() / 2 - 1),
|
||||
QPoint(x + 4, y + getRowHeight() / 2 + 1),
|
||||
};
|
||||
|
||||
painter->drawPolyline(wPoints, 3);
|
||||
}
|
||||
else if(curInstDir == GJD_Down)
|
||||
{
|
||||
QPoint wPoints[] =
|
||||
{
|
||||
QPoint(x , y + getRowHeight() / 2 - 1),
|
||||
QPoint(x + 2, y + getRowHeight() / 2 + 1),
|
||||
QPoint(x + 4, y + getRowHeight() / 2 - 1),
|
||||
};
|
||||
|
||||
painter->drawPolyline(wPoints, 3);
|
||||
}
|
||||
|
||||
x += 8;
|
||||
|
||||
if(showXref)
|
||||
{
|
||||
painter->setPen(mUnconditionalPen);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(bIsExecute)
|
||||
painter->setPen(mConditionalTruePen);
|
||||
bool bIsExecute = DbgIsJumpGoingToExecute(rvaToVa(instruction.rva));
|
||||
|
||||
|
||||
if(branchType == Instruction_t::Unconditional) //unconditional
|
||||
{
|
||||
painter->setPen(mUnconditionalPen);
|
||||
}
|
||||
else
|
||||
painter->setPen(mConditionalFalsePen);
|
||||
{
|
||||
if(bIsExecute)
|
||||
painter->setPen(mConditionalTruePen);
|
||||
else
|
||||
painter->setPen(mConditionalFalsePen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(wPict == GD_Vert)
|
||||
{
|
||||
painter->drawLine(x, y, x, y + getRowHeight());
|
||||
|
|
@ -899,8 +1036,26 @@ int Disassembly::paintJumpsGraphic(QPainter* painter, int x, int y, dsint addr)
|
|||
painter->drawLine(x, y, x, y + getRowHeight() / 2);
|
||||
painter->drawPolyline(wPoints, 3);
|
||||
}
|
||||
else if(wPict == GD_HeadFromBoth)
|
||||
{
|
||||
QPoint wPoints[] =
|
||||
{
|
||||
QPoint(x + 3, y + getRowHeight() / 2 - 2),
|
||||
QPoint(x + 5, y + getRowHeight() / 2),
|
||||
QPoint(x + 3, y + getRowHeight() / 2 + 2),
|
||||
};
|
||||
|
||||
return 7;
|
||||
painter->drawLine(x, y + getRowHeight() / 2, x + 5, y + getRowHeight() / 2);
|
||||
painter->drawLine(x, y, x, y + getRowHeight());
|
||||
painter->drawPolyline(wPoints, 3);
|
||||
}
|
||||
else if(wPict == GD_VertHori)
|
||||
{
|
||||
painter->drawLine(x, y + getRowHeight() / 2, x + 5, y + getRowHeight() / 2);
|
||||
painter->drawLine(x, y, x, y + getRowHeight());
|
||||
}
|
||||
|
||||
return 15;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
|
|
@ -1186,6 +1341,18 @@ dsint Disassembly::getSelectionEnd()
|
|||
return mSelection.toIndex;
|
||||
}
|
||||
|
||||
void Disassembly::selectionChangedSlot(dsint Va)
|
||||
{
|
||||
if(mXrefInfo.refcount != 0)
|
||||
{
|
||||
BridgeFree(mXrefInfo.references);
|
||||
mXrefInfo.refcount = 0;
|
||||
}
|
||||
if(DbgIsDebugging())
|
||||
DbgXrefGet(Va, &mXrefInfo);
|
||||
}
|
||||
|
||||
|
||||
void Disassembly::selectNext(bool expand)
|
||||
{
|
||||
dsint wAddr;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public:
|
|||
dsint sliderMovedHook(int type, dsint value, dsint delta);
|
||||
|
||||
// Jumps Graphic
|
||||
int paintJumpsGraphic(QPainter* painter, int x, int y, dsint addr);
|
||||
int paintJumpsGraphic(QPainter* painter, int x, int y, dsint addr, bool isjmp);
|
||||
|
||||
// Function Graphic
|
||||
|
||||
|
|
@ -104,10 +104,12 @@ signals:
|
|||
public slots:
|
||||
void disassembleAt(dsint parVA, dsint parCIP);
|
||||
void debugStateChangedSlot(DBGSTATE state);
|
||||
void selectionChangedSlot(dsint parVA);
|
||||
|
||||
private:
|
||||
enum GuiState_t {NoState, MultiRowsSelectionState};
|
||||
enum GraphicDump_t {GD_Nothing, GD_FootToTop, GD_FootToBottom, GD_HeadFromTop, GD_HeadFromBottom, GD_Vert}; // GD_FootToTop = '- , GD_FootToBottom = ,- , GD_HeadFromTop = '-> , GD_HeadFromBottom = ,-> , GD_Vert = |
|
||||
enum GraphicDump_t {GD_Nothing, GD_FootToTop, GD_FootToBottom, GD_HeadFromTop, GD_HeadFromBottom, GD_HeadFromBoth, GD_Vert, GD_VertHori}; // GD_FootToTop = '- , GD_FootToBottom = ,- , GD_HeadFromTop = '-> , GD_HeadFromBottom = ,-> , GD_HeadFromBoth = |-> , GD_Vert = | , GD_VertHori = |-
|
||||
enum GraphicJumpDirection_t {GJD_Nothing, GJD_Up, GJD_Down };
|
||||
|
||||
typedef struct _SelectionData_t
|
||||
{
|
||||
|
|
@ -199,6 +201,7 @@ protected:
|
|||
bool mHighlightingMode;
|
||||
MemoryPage* mMemPage;
|
||||
bool mShowMnemonicBrief;
|
||||
XREF_INFO mXrefInfo;
|
||||
};
|
||||
|
||||
#endif // DISASSEMBLY_H
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "AssembleDialog.h"
|
||||
#include "StringUtil.h"
|
||||
#include "Breakpoints.h"
|
||||
#include "XrefBrowseDialog.h"
|
||||
|
||||
CPUDisassembly::CPUDisassembly(CPUWidget* parent) : Disassembly(parent)
|
||||
{
|
||||
|
|
@ -431,6 +432,10 @@ void CPUDisassembly::setupRightClickContextMenu()
|
|||
gotoMenu->addAction(makeShortcutAction(QIcon(":/icons/images/bottom.png"), tr("End of Page"), SLOT(gotoEndSlot()), "ActionGotoEnd"));
|
||||
mMenuBuilder->addMenu(makeMenu(QIcon(":/icons/images/goto.png"), tr("Go to")), gotoMenu);
|
||||
mMenuBuilder->addSeparator();
|
||||
mMenuBuilder->addAction(makeShortcutAction(QIcon(":/icons/images/xrefs.png"), tr("xrefs..."), SLOT(gotoXrefSlot()), "ActionXrefs"), [this](QMenu*)
|
||||
{
|
||||
return mXrefInfo.refcount > 0;
|
||||
});
|
||||
|
||||
MenuBuilder* searchMenu = new MenuBuilder(this);
|
||||
MenuBuilder* mSearchRegionMenu = new MenuBuilder(this);
|
||||
|
|
@ -897,6 +902,14 @@ void CPUDisassembly::gotoEndSlot()
|
|||
DbgCmdExec(QString().sprintf("disasm \"%p\"", dest).toUtf8().constData());
|
||||
}
|
||||
|
||||
void CPUDisassembly::gotoXrefSlot()
|
||||
{
|
||||
if(!DbgIsDebugging() || !mXrefInfo.refcount)
|
||||
return;
|
||||
XrefBrowseDialog xrefDlg(this, getSelectedVa());
|
||||
xrefDlg.exec();
|
||||
}
|
||||
|
||||
void CPUDisassembly::followActionSlot()
|
||||
{
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ public slots:
|
|||
void followActionSlot();
|
||||
void gotoPreviousSlot();
|
||||
void gotoNextSlot();
|
||||
void gotoXrefSlot();
|
||||
void findReferencesSlot();
|
||||
void findConstantSlot();
|
||||
void findStringsSlot();
|
||||
|
|
|
|||
|
|
@ -1,180 +1,180 @@
|
|||
#include <QTextCodec>
|
||||
|
||||
#include "HexLineEdit.h"
|
||||
#include "ui_HexLineEdit.h"
|
||||
#include "Bridge.h"
|
||||
|
||||
HexLineEdit::HexLineEdit(QWidget* parent) :
|
||||
QLineEdit(parent),
|
||||
ui(new Ui::HexLineEdit)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// setup data
|
||||
mData = QByteArray();
|
||||
mEncoding = Encoding::Ascii;
|
||||
mKeepSize = false;
|
||||
mOverwriteMode = false;
|
||||
|
||||
//setup text fields
|
||||
QFont font("Monospace", 8, QFont::Normal, false);
|
||||
font.setFixedPitch(true);
|
||||
font.setStyleHint(QFont::Monospace);
|
||||
setFont(font);
|
||||
|
||||
connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(updateData(const QString &)));
|
||||
}
|
||||
|
||||
HexLineEdit::~HexLineEdit()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void HexLineEdit::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
// Switch between insert/overwrite mode
|
||||
if(event->key() == Qt::Key_Insert && (event->modifiers() == Qt::NoModifier))
|
||||
{
|
||||
mOverwriteMode = !mOverwriteMode;
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
if(mOverwriteMode)
|
||||
{
|
||||
if(!event->text().isEmpty() && event->text().at(0).isPrint())
|
||||
{
|
||||
QString keyText;
|
||||
switch(mEncoding)
|
||||
{
|
||||
case Encoding::Ascii:
|
||||
keyText = event->text().toLatin1();
|
||||
break;
|
||||
case Encoding::Unicode:
|
||||
keyText = event->text();
|
||||
break;
|
||||
}
|
||||
|
||||
del();
|
||||
insert(keyText);
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QLineEdit::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void HexLineEdit::setData(const QByteArray & data)
|
||||
{
|
||||
QString text;
|
||||
switch(mEncoding)
|
||||
{
|
||||
case Encoding::Ascii:
|
||||
for(int i = 0; i < data.size(); i++)
|
||||
{
|
||||
QChar ch(data.constData()[i]);
|
||||
if(ch.isPrint())
|
||||
text += ch.toLatin1();
|
||||
else
|
||||
text += '.';
|
||||
}
|
||||
break;
|
||||
|
||||
case Encoding::Unicode:
|
||||
for(int i = 0, j = 0; i < data.size(); i += sizeof(wchar_t), j++)
|
||||
{
|
||||
QChar wch(((wchar_t*)data.constData())[j]);
|
||||
if(wch.isPrint())
|
||||
text += wch;
|
||||
else
|
||||
text += '.';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mData = toEncodedData(text);
|
||||
setText(text);
|
||||
}
|
||||
|
||||
QByteArray HexLineEdit::data()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
void HexLineEdit::setEncoding(const HexLineEdit::Encoding encoding)
|
||||
{
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
||||
HexLineEdit::Encoding HexLineEdit::encoding()
|
||||
{
|
||||
return mEncoding;
|
||||
}
|
||||
|
||||
void HexLineEdit::setKeepSize(const bool enabled)
|
||||
{
|
||||
mKeepSize = enabled;
|
||||
if(enabled)
|
||||
{
|
||||
int dataSize = mData.size();
|
||||
int charSize;
|
||||
switch(mEncoding)
|
||||
{
|
||||
case Encoding::Ascii:
|
||||
charSize = sizeof(char);
|
||||
break;
|
||||
|
||||
case Encoding::Unicode:
|
||||
charSize = sizeof(wchar_t);
|
||||
break;
|
||||
}
|
||||
|
||||
setMaxLength((dataSize / charSize) + (dataSize % charSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
setMaxLength(32767);
|
||||
}
|
||||
}
|
||||
|
||||
bool HexLineEdit::keepSize()
|
||||
{
|
||||
return mKeepSize;
|
||||
}
|
||||
|
||||
void HexLineEdit::setOverwriteMode(bool overwriteMode)
|
||||
{
|
||||
mOverwriteMode = overwriteMode;
|
||||
}
|
||||
|
||||
bool HexLineEdit::overwriteMode()
|
||||
{
|
||||
return mOverwriteMode;
|
||||
}
|
||||
|
||||
void HexLineEdit::updateData(const QString & arg1)
|
||||
{
|
||||
Q_UNUSED(arg1);
|
||||
|
||||
mData = toEncodedData(text());
|
||||
emit dataEdited();
|
||||
}
|
||||
|
||||
QByteArray HexLineEdit::toEncodedData(const QString & text)
|
||||
{
|
||||
QByteArray data;
|
||||
switch(mEncoding)
|
||||
{
|
||||
case Encoding::Ascii:
|
||||
for(int i = 0; i < text.length(); i++)
|
||||
data.append(text[i].toLatin1());
|
||||
break;
|
||||
|
||||
case Encoding::Unicode:
|
||||
data = QTextCodec::codecForName("UTF-16")->makeEncoder(QTextCodec::IgnoreHeader)->fromUnicode(text);
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
#include <QTextCodec>
|
||||
|
||||
#include "HexLineEdit.h"
|
||||
#include "ui_HexLineEdit.h"
|
||||
#include "Bridge.h"
|
||||
|
||||
HexLineEdit::HexLineEdit(QWidget* parent) :
|
||||
QLineEdit(parent),
|
||||
ui(new Ui::HexLineEdit)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// setup data
|
||||
mData = QByteArray();
|
||||
mEncoding = Encoding::Ascii;
|
||||
mKeepSize = false;
|
||||
mOverwriteMode = false;
|
||||
|
||||
//setup text fields
|
||||
QFont font("Monospace", 8, QFont::Normal, false);
|
||||
font.setFixedPitch(true);
|
||||
font.setStyleHint(QFont::Monospace);
|
||||
setFont(font);
|
||||
|
||||
connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(updateData(const QString &)));
|
||||
}
|
||||
|
||||
HexLineEdit::~HexLineEdit()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void HexLineEdit::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
// Switch between insert/overwrite mode
|
||||
if(event->key() == Qt::Key_Insert && (event->modifiers() == Qt::NoModifier))
|
||||
{
|
||||
mOverwriteMode = !mOverwriteMode;
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
if(mOverwriteMode)
|
||||
{
|
||||
if(!event->text().isEmpty() && event->text().at(0).isPrint())
|
||||
{
|
||||
QString keyText;
|
||||
switch(mEncoding)
|
||||
{
|
||||
case Encoding::Ascii:
|
||||
keyText = event->text().toLatin1();
|
||||
break;
|
||||
case Encoding::Unicode:
|
||||
keyText = event->text();
|
||||
break;
|
||||
}
|
||||
|
||||
del();
|
||||
insert(keyText);
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QLineEdit::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void HexLineEdit::setData(const QByteArray & data)
|
||||
{
|
||||
QString text;
|
||||
switch(mEncoding)
|
||||
{
|
||||
case Encoding::Ascii:
|
||||
for(int i = 0; i < data.size(); i++)
|
||||
{
|
||||
QChar ch(data.constData()[i]);
|
||||
if(ch.isPrint())
|
||||
text += ch.toLatin1();
|
||||
else
|
||||
text += '.';
|
||||
}
|
||||
break;
|
||||
|
||||
case Encoding::Unicode:
|
||||
for(int i = 0, j = 0; i < data.size(); i += sizeof(wchar_t), j++)
|
||||
{
|
||||
QChar wch(((wchar_t*)data.constData())[j]);
|
||||
if(wch.isPrint())
|
||||
text += wch;
|
||||
else
|
||||
text += '.';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mData = toEncodedData(text);
|
||||
setText(text);
|
||||
}
|
||||
|
||||
QByteArray HexLineEdit::data()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
void HexLineEdit::setEncoding(const HexLineEdit::Encoding encoding)
|
||||
{
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
||||
HexLineEdit::Encoding HexLineEdit::encoding()
|
||||
{
|
||||
return mEncoding;
|
||||
}
|
||||
|
||||
void HexLineEdit::setKeepSize(const bool enabled)
|
||||
{
|
||||
mKeepSize = enabled;
|
||||
if(enabled)
|
||||
{
|
||||
int dataSize = mData.size();
|
||||
int charSize;
|
||||
switch(mEncoding)
|
||||
{
|
||||
case Encoding::Ascii:
|
||||
charSize = sizeof(char);
|
||||
break;
|
||||
|
||||
case Encoding::Unicode:
|
||||
charSize = sizeof(wchar_t);
|
||||
break;
|
||||
}
|
||||
|
||||
setMaxLength((dataSize / charSize) + (dataSize % charSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
setMaxLength(32767);
|
||||
}
|
||||
}
|
||||
|
||||
bool HexLineEdit::keepSize()
|
||||
{
|
||||
return mKeepSize;
|
||||
}
|
||||
|
||||
void HexLineEdit::setOverwriteMode(bool overwriteMode)
|
||||
{
|
||||
mOverwriteMode = overwriteMode;
|
||||
}
|
||||
|
||||
bool HexLineEdit::overwriteMode()
|
||||
{
|
||||
return mOverwriteMode;
|
||||
}
|
||||
|
||||
void HexLineEdit::updateData(const QString & arg1)
|
||||
{
|
||||
Q_UNUSED(arg1);
|
||||
|
||||
mData = toEncodedData(text());
|
||||
emit dataEdited();
|
||||
}
|
||||
|
||||
QByteArray HexLineEdit::toEncodedData(const QString & text)
|
||||
{
|
||||
QByteArray data;
|
||||
switch(mEncoding)
|
||||
{
|
||||
case Encoding::Ascii:
|
||||
for(int i = 0; i < text.length(); i++)
|
||||
data.append(text[i].toLatin1());
|
||||
break;
|
||||
|
||||
case Encoding::Unicode:
|
||||
data = QTextCodec::codecForName("UTF-16")->makeEncoder(QTextCodec::IgnoreHeader)->fromUnicode(text);
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,57 @@
|
|||
#ifndef HEXLINEEDITT_H
|
||||
#define HEXLINEEDITT_H
|
||||
|
||||
#include <QLineEdit>
|
||||
#include "Configuration.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class HexLineEdit;
|
||||
}
|
||||
|
||||
class HexLineEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Encoding
|
||||
{
|
||||
Ascii,
|
||||
Unicode
|
||||
};
|
||||
|
||||
explicit HexLineEdit(QWidget* parent = 0);
|
||||
~HexLineEdit();
|
||||
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
void setData(const QByteArray & data);
|
||||
QByteArray data();
|
||||
|
||||
void setEncoding(const Encoding encoding);
|
||||
Encoding encoding();
|
||||
|
||||
void setKeepSize(const bool enabled);
|
||||
bool keepSize();
|
||||
|
||||
void setOverwriteMode(bool overwriteMode);
|
||||
bool overwriteMode();
|
||||
|
||||
signals:
|
||||
void dataEdited();
|
||||
|
||||
private slots:
|
||||
void updateData(const QString & arg1);
|
||||
|
||||
private:
|
||||
Ui::HexLineEdit* ui;
|
||||
|
||||
QByteArray mData;
|
||||
Encoding mEncoding;
|
||||
bool mKeepSize;
|
||||
bool mOverwriteMode;
|
||||
|
||||
QByteArray toEncodedData(const QString & text);
|
||||
};
|
||||
|
||||
#endif // HEXLINEEDITT_H
|
||||
#ifndef HEXLINEEDITT_H
|
||||
#define HEXLINEEDITT_H
|
||||
|
||||
#include <QLineEdit>
|
||||
#include "Configuration.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class HexLineEdit;
|
||||
}
|
||||
|
||||
class HexLineEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Encoding
|
||||
{
|
||||
Ascii,
|
||||
Unicode
|
||||
};
|
||||
|
||||
explicit HexLineEdit(QWidget* parent = 0);
|
||||
~HexLineEdit();
|
||||
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
void setData(const QByteArray & data);
|
||||
QByteArray data();
|
||||
|
||||
void setEncoding(const Encoding encoding);
|
||||
Encoding encoding();
|
||||
|
||||
void setKeepSize(const bool enabled);
|
||||
bool keepSize();
|
||||
|
||||
void setOverwriteMode(bool overwriteMode);
|
||||
bool overwriteMode();
|
||||
|
||||
signals:
|
||||
void dataEdited();
|
||||
|
||||
private slots:
|
||||
void updateData(const QString & arg1);
|
||||
|
||||
private:
|
||||
Ui::HexLineEdit* ui;
|
||||
|
||||
QByteArray mData;
|
||||
Encoding mEncoding;
|
||||
bool mKeepSize;
|
||||
bool mOverwriteMode;
|
||||
|
||||
QByteArray toEncodedData(const QString & text);
|
||||
};
|
||||
|
||||
#endif // HEXLINEEDITT_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
#include "XrefBrowseDialog.h"
|
||||
#include "ui_XrefBrowseDialog.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
XrefBrowseDialog::XrefBrowseDialog(QWidget* parent, duint address) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::XrefBrowseDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::MSWindowsFixedSizeDialogHint);
|
||||
setWindowIcon(QIcon(":/icons/images/xrefs.png"));
|
||||
mAddress = address;
|
||||
if(DbgXrefGet(address, &mXrefInfo))
|
||||
{
|
||||
char disasm[GUI_MAX_DISASSEMBLY_SIZE] = "";
|
||||
setWindowTitle(QString(tr("xrefs at %1")).arg(ToHexString(address)));
|
||||
for(int i = 0; i < mXrefInfo.refcount; i++)
|
||||
{
|
||||
GuiGetDisassembly(mXrefInfo.references[i].addr, disasm);
|
||||
ui->listWidget->addItem(disasm);
|
||||
}
|
||||
mPrevSelectionSize = 0;
|
||||
ui->listWidget->setCurrentRow(0);
|
||||
}
|
||||
}
|
||||
|
||||
void XrefBrowseDialog::changeAddress(duint address)
|
||||
{
|
||||
DbgCmdExec(QString().sprintf("disasm \"%p\"", address).toUtf8().constData());
|
||||
}
|
||||
|
||||
XrefBrowseDialog::~XrefBrowseDialog()
|
||||
{
|
||||
delete ui;
|
||||
if(mXrefInfo.refcount)
|
||||
BridgeFree(mXrefInfo.references);
|
||||
}
|
||||
|
||||
void XrefBrowseDialog::on_listWidget_itemDoubleClicked(QListWidgetItem*)
|
||||
{
|
||||
accept();
|
||||
}
|
||||
|
||||
void XrefBrowseDialog::on_listWidget_itemSelectionChanged()
|
||||
{
|
||||
if(ui->listWidget->selectedItems().size() != mPrevSelectionSize)
|
||||
{
|
||||
duint address;
|
||||
if(mPrevSelectionSize == 0)
|
||||
address = mXrefInfo.references[ui->listWidget->currentRow()].addr;
|
||||
else
|
||||
address = mAddress;
|
||||
|
||||
changeAddress(address);
|
||||
}
|
||||
mPrevSelectionSize = ui->listWidget->selectedItems().size();
|
||||
}
|
||||
|
||||
void XrefBrowseDialog::on_listWidget_currentRowChanged(int row)
|
||||
{
|
||||
if(ui->listWidget->selectedItems().size() != 0)
|
||||
{
|
||||
duint address = mXrefInfo.references[row].addr;
|
||||
changeAddress(address);
|
||||
}
|
||||
}
|
||||
|
||||
void XrefBrowseDialog::on_XrefBrowseDialog_rejected()
|
||||
{
|
||||
DbgCmdExec(QString().sprintf("disasm \"%p\"", mAddress).toUtf8().constData());
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef XREFBROWSEDIALOG_H
|
||||
#define XREFBROWSEDIALOG_H
|
||||
|
||||
#include "Bridge.h"
|
||||
#include <QDialog>
|
||||
#include <QListWidgetItem>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class XrefBrowseDialog;
|
||||
}
|
||||
|
||||
class XrefBrowseDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit XrefBrowseDialog(QWidget* parent, duint address);
|
||||
~XrefBrowseDialog();
|
||||
|
||||
private slots:
|
||||
void on_listWidget_itemDoubleClicked(QListWidgetItem* item);
|
||||
void on_listWidget_itemSelectionChanged();
|
||||
void on_listWidget_currentRowChanged(int currentRow);
|
||||
void on_XrefBrowseDialog_rejected();
|
||||
|
||||
private:
|
||||
Ui::XrefBrowseDialog* ui;
|
||||
XREF_INFO mXrefInfo;
|
||||
duint mAddress;
|
||||
int mPrevSelectionSize;
|
||||
void changeAddress(duint address);
|
||||
};
|
||||
|
||||
#endif // XREFBROWSEDIALOG_H
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>XrefBrowseDialog</class>
|
||||
<widget class="QDialog" name="XrefBrowseDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>328</width>
|
||||
<height>426</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Courier New</family>
|
||||
</font>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>XrefBrowseDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>227</x>
|
||||
<y>408</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>XrefBrowseDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>295</x>
|
||||
<y>414</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -305,6 +305,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
defaultShortcuts.insert("ActionFindReferencesToSelectedAddress", Shortcut(tr("Actions -> Find References to Selected Address"), "Ctrl+R"));
|
||||
defaultShortcuts.insert("ActionFindPattern", Shortcut(tr("Actions -> Find Pattern"), "Ctrl+B"));
|
||||
defaultShortcuts.insert("ActionFindReferences", Shortcut(tr("Actions -> Find References"), "Ctrl+R"));
|
||||
defaultShortcuts.insert("ActionXrefs", Shortcut(tr("Actions -> xrefs..."), "X"));
|
||||
defaultShortcuts.insert("ActionHelpOnMnemonic", Shortcut(tr("Actions -> Help on Mnemonic"), "Ctrl+F1"));
|
||||
defaultShortcuts.insert("ActionToggleMnemonicBrief", Shortcut(tr("Actions -> Toggle Mnemonic Brief"), "Ctrl+Shift+F1"));
|
||||
defaultShortcuts.insert("ActionHighlightingMode", Shortcut(tr("Actions -> Highlighting Mode"), "Ctrl+H"));
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 685 B |
|
|
@ -97,5 +97,6 @@
|
|||
<file>images/handles.png</file>
|
||||
<file>images/dump.png</file>
|
||||
<file>images/analyzesinglefunction.png</file>
|
||||
<file>images/xrefs.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
|||
|
|
@ -151,7 +151,8 @@ SOURCES += \
|
|||
Src/Gui/EditFloatRegister.cpp \
|
||||
Src/Utils/HexValidator.cpp \
|
||||
Src/Utils/LongLongValidator.cpp \
|
||||
Src/Utils/MiscUtil.cpp
|
||||
Src/Utils/MiscUtil.cpp \
|
||||
Src/Gui/XrefBrowseDialog.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
|
|
@ -243,7 +244,8 @@ HEADERS += \
|
|||
Src/Gui/EditFloatRegister.h \
|
||||
Src/Utils/HexValidator.h \
|
||||
Src/Utils/LongLongValidator.h \
|
||||
Src/Utils/MiscUtil.h
|
||||
Src/Utils/MiscUtil.h \
|
||||
Src/Gui/XrefBrowseDialog.h
|
||||
|
||||
FORMS += \
|
||||
Src/Gui/MainWindow.ui \
|
||||
|
|
@ -272,7 +274,8 @@ FORMS += \
|
|||
Src/Gui/AssembleDialog.ui \
|
||||
Src/Gui/EditBreakpointDialog.ui \
|
||||
Src/Gui/CPUArgumentWidget.ui \
|
||||
Src/Gui/EditFloatRegister.ui
|
||||
Src/Gui/EditFloatRegister.ui \
|
||||
Src/Gui/XrefBrowseDialog.ui
|
||||
|
||||
TRANSLATIONS = \
|
||||
Translations/x64dbg_zh_CN.ts
|
||||
|
|
|
|||
|
|
@ -23,10 +23,16 @@
|
|||
<ResourceCompile Include="..\exe\resource.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
<ResourceCompile Include="..\exe\icon.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\exe\resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\exe\icon.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
Reference in New Issue