1
0
Fork 0

DBG+BRIDGE+GUI+LAUNCER: manually merged pull request #705 (thanks to @wynick27)

This commit is contained in:
mrexodia 2016-06-03 14:47:57 +02:00
parent a89c93c425
commit ee3e030886
No known key found for this signature in database
GPG Key ID: D72F9A4FAA0073B4
30 changed files with 1051 additions and 255 deletions

View File

@ -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()
{

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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("");

View File

@ -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)

View File

@ -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[]);

View File

@ -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:

View File

@ -56,6 +56,7 @@ enum SectionLock
LockSehCache,
LockMnemonicHelp,
LockTraceRecord,
LockCrossReferences,
LockDebugStartStop,
LockArguments,

View File

@ -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)

View File

@ -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" />

View File

@ -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>

183
src/dbg/xrefs.cpp Normal file
View File

@ -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();
}

18
src/dbg/xrefs.h Normal file
View File

@ -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

46
src/dbg/xrefsanalysis.cpp Normal file
View File

@ -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);
}

24
src/dbg/xrefsanalysis.h Normal file
View File

@ -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;
};

View File

@ -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;

View File

@ -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

View File

@ -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());

View File

@ -58,6 +58,7 @@ public slots:
void followActionSlot();
void gotoPreviousSlot();
void gotoNextSlot();
void gotoXrefSlot();
void findReferencesSlot();
void findConstantSlot();
void findStringsSlot();

View File

@ -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;
}

View File

@ -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

View File

@ -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());
}

View File

@ -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

View File

@ -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>

View File

@ -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"));

BIN
src/gui/images/xrefs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

View File

@ -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>

View File

@ -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

View File

@ -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>