From ea397351c3e6b1f11a3e3077a6742b894eeab6a1 Mon Sep 17 00:00:00 2001 From: Kingcom Date: Sun, 22 Sep 2013 11:00:44 +0200 Subject: [PATCH] Better branch lines --- Windows/Debugger/CtrlDisAsmView.cpp | 282 +++++++++++++++++++++++---- Windows/Debugger/CtrlDisAsmView.h | 24 +++ Windows/Debugger/Debugger_Disasm.cpp | 1 + 3 files changed, 272 insertions(+), 35 deletions(-) diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index 3a882911f6..e98ba88f66 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -19,6 +19,7 @@ #include "Common/CommonWindows.h" #include "util/text/utf8.h" +#include "ext/xxhash.h" #include #include @@ -53,6 +54,157 @@ void CtrlDisAsmView::deinit() } +typedef struct +{ + bool used; + u32 end; +} LaneInfo; +#define NUM_LANES 16 + +void CtrlDisAsmView::scanFunctions() +{ + u32 pos = windowStart; + u32 windowEnd = windowStart+visibleRows*instructionSize; + + visibleFunctionAddresses.clear(); + strayLines.clear(); + + while (pos < windowEnd) + { + SymbolInfo info; + if (symbolMap.GetSymbolInfo(&info,pos)) + { + u32 hash = XXH32(Memory::GetPointer(info.address),info.size,0xBACD7814); + u32 funcEnd = info.address+info.size; + + visibleFunctionAddresses.push_back(info.address); + + auto it = functions.find(info.address); + if (it != functions.end() && it->second.hash == hash) + { + // function is unchaged + pos = funcEnd; + continue; + } + + DisassemblyFunction func; + func.hash = hash; + + LaneInfo lanes[NUM_LANES]; + for (int i = 0; i < NUM_LANES; i++) + lanes[i].used = false; + + + for (int funcPos = info.address; funcPos < funcEnd; funcPos += instructionSize) + { + MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(debugger,funcPos); + if (opInfo.isBranch && !opInfo.isBranchToRegister && !opInfo.isLinkedBranch) + { + BranchLine line; + if (opInfo.branchTarget < funcPos) + { + line.first = opInfo.branchTarget; + line.second = funcPos; + line.type = LINE_UP; + } else { + line.first = funcPos; + line.second = opInfo.branchTarget; + line.type = LINE_DOWN; + } + + func.lines.push_back(line); + } + } + + for (int i = 0; i < func.lines.size(); i++) + { + for (int l = 0; l < NUM_LANES; l++) + { + if (func.lines[i].first > lanes[l].end) + lanes[l].used = false; + } + + int lane = -1; + for (int i = 0; i < NUM_LANES; i++) + { + if (lanes[i].used == false) + { + lane = i; + break; + } + } + + if (lane == -1) + { + // error + continue; + } + + lanes[lane].end = func.lines[i].second; + lanes[lane].used = true; + func.lines[i].laneIndex = lane; + } + + functions[info.address] = func; + pos = funcEnd; + } else { + MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(debugger,pos); + if (opInfo.isBranch && !opInfo.isBranchToRegister && !opInfo.isLinkedBranch) + { + BranchLine line; + if (opInfo.branchTarget < pos) + { + line.first = opInfo.branchTarget; + line.second = pos; + line.type = LINE_UP; + } else { + line.first = pos; + line.second = opInfo.branchTarget; + line.type = LINE_DOWN; + } + + strayLines.push_back(line); + } + + pos += instructionSize; + } + } + + // calculate lanes for strayBranches + LaneInfo lanes[NUM_LANES]; + for (int i = 0; i < NUM_LANES; i++) + lanes[i].used = false; + + for (int i = 0; i < strayLines.size(); i++) + { + for (int l = 0; l < NUM_LANES; l++) + { + if (strayLines[i].first > lanes[l].end) + lanes[l].used = false; + } + + int lane = -1; + for (int i = 0; i < NUM_LANES; i++) + { + if (lanes[i].used == false) + { + lane = i; + break; + } + } + + if (lane == -1) + { + // error + continue; + } + + lanes[lane].end = strayLines[i].second; + lanes[lane].used = true; + strayLines[i].laneIndex = lane; + } + +} LRESULT CALLBACK CtrlDisAsmView::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -319,17 +471,93 @@ void CtrlDisAsmView::assembleOpcode(u32 address, std::string defaultText) } } + +void CtrlDisAsmView::drawBranchLine(HDC hdc, BranchLine& line) +{ + u32 windowEnd = windowStart+(visibleRows+2)*instructionSize; + + int topY; + int bottomY; + if (line.first < windowStart) + { + topY = -1; + } else if (line.first >= windowEnd) + { + topY = rect.bottom+1; + } else { + int row = (line.first-windowStart)/instructionSize; + topY = row*rowHeight + rowHeight/2; + } + + if (line.second < windowStart) + { + bottomY = -1; + } else if (line.second >= windowEnd) + { + bottomY = rect.bottom+1; + } else { + int row = (line.second-windowStart)/instructionSize; + bottomY = row*rowHeight + rowHeight/2; + } + + if ((topY < 0 && bottomY < 0) || (topY > rect.bottom && bottomY > rect.bottom)) + { + return; + } + + int x = pixelPositions.arrowsStart+line.laneIndex*8; + if (topY < 0) // first is not visible, but second is + { + MoveToEx(hdc,x-2,bottomY,0); + LineTo(hdc,x+2,bottomY); + LineTo(hdc,x+2,0); + + if (line.type == LINE_DOWN) + { + MoveToEx(hdc,x,bottomY-4,0); + LineTo(hdc,x-4,bottomY); + LineTo(hdc,x+1,bottomY+5); + } + } else if (bottomY > rect.bottom) // second is not visible, but first is + { + MoveToEx(hdc,x-2,topY,0); + LineTo(hdc,x+2,topY); + LineTo(hdc,x+2,rect.bottom); + + if (line.type == LINE_UP) + { + MoveToEx(hdc,x,topY-4,0); + LineTo(hdc,x-4,topY); + LineTo(hdc,x+1,topY+5); + } + } else { // both are visible + if (line.type == LINE_UP) + { + MoveToEx(hdc,x-2,bottomY,0); + LineTo(hdc,x+2,bottomY); + LineTo(hdc,x+2,topY); + LineTo(hdc,x-4,topY); + + MoveToEx(hdc,x,topY-4,0); + LineTo(hdc,x-4,topY); + LineTo(hdc,x+1,topY+5); + } else { + MoveToEx(hdc,x-2,topY,0); + LineTo(hdc,x+2,topY); + LineTo(hdc,x+2,bottomY); + LineTo(hdc,x-4,bottomY); + + MoveToEx(hdc,x,bottomY-4,0); + LineTo(hdc,x-4,bottomY); + LineTo(hdc,x+1,bottomY+5); + } + } +} + void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam) { if (!debugger->isAlive()) return; - struct branch - { - int src,dst,srcAddr; - }; - branch branches[256]; - int numBranches=0; - PAINTSTRUCT ps; HDC actualHdc = BeginPaint(wnd, &ps); HDC hdc = CreateCompatibleDC(actualHdc); @@ -425,39 +653,23 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam) SelectObject(hdc,boldfont); TextOutA(hdc,pixelPositions.opcodeStart,rowY1+2,opcode,(int)strlen(opcode)); SelectObject(hdc,font); - - if (info.isBranch && info.isConditional) + } + + SelectObject(hdc,condPen); + for (int i = 0; i < visibleFunctionAddresses.size(); i++) + { + auto it = functions.find(visibleFunctionAddresses[i]); + DisassemblyFunction& func = it->second; + + for (int l = 0; l < func.lines.size(); l++) { - branches[numBranches].src=rowY1 + rowHeight/2; - branches[numBranches].srcAddr=address/instructionSize; - branches[numBranches].dst=(int)(rowY1+((__int64)branchTarget-(__int64)address)*rowHeight/instructionSize + rowHeight/2); - numBranches++; + drawBranchLine(hdc,func.lines[l]); } } - for (int i=0; i < numBranches; i++) + for (int i = 0; i < strayLines.size(); i++) { - SelectObject(hdc,condPen); - int x=pixelPositions.arrowsStart+i*8; - MoveToEx(hdc,x-2,branches[i].src,0); - - if (branches[i].dst < 0) - { - LineTo(hdc,x+2,branches[i].src); - LineTo(hdc,x+2,0); - } else if (branches[i].dst > rect.bottom) - { - LineTo(hdc,x+2,branches[i].src); - LineTo(hdc,x+2,rect.bottom); - } else { - LineTo(hdc,x+2,branches[i].src); - LineTo(hdc,x+2,branches[i].dst); - LineTo(hdc,x-4,branches[i].dst); - - MoveToEx(hdc,x,branches[i].dst-4,0); - LineTo(hdc,x-4,branches[i].dst); - LineTo(hdc,x+1,branches[i].dst+5); - } + drawBranchLine(hdc,strayLines[i]); } SelectObject(hdc,oldFont); diff --git a/Windows/Debugger/CtrlDisAsmView.h b/Windows/Debugger/CtrlDisAsmView.h index c9437c8f08..3fce21cf3d 100644 --- a/Windows/Debugger/CtrlDisAsmView.h +++ b/Windows/Debugger/CtrlDisAsmView.h @@ -28,6 +28,22 @@ using std::min; using std::max; +typedef enum { LINE_UP, LINE_DOWN, LINE_RIGHT } LineType; + +typedef struct +{ + u32 first; + u32 second; + LineType type; + int laneIndex; +} BranchLine; + +typedef struct +{ + u32 hash; + std::vector lines; +} DisassemblyFunction; + class CtrlDisAsmView { HWND wnd; @@ -35,6 +51,10 @@ class CtrlDisAsmView HFONT boldfont; RECT rect; + std::map functions; + std::vector visibleFunctionAddresses; + std::vector strayLines; + u32 curAddress; u32 selectRangeStart; u32 selectRangeEnd; @@ -78,6 +98,7 @@ class CtrlDisAsmView bool getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels); void parseDisasm(const char* disasm, char* opcode, char* arguments); void updateStatusBarText(); + void drawBranchLine(HDC hdc, BranchLine& line); public: CtrlDisAsmView(HWND _wnd); ~CtrlDisAsmView(); @@ -97,6 +118,7 @@ public: void scrollAddressIntoView(); bool curAddressIsVisible(); void redraw(); + void scanFunctions(); void getOpcodeText(u32 address, char* dest); u32 yToAddress(int y); @@ -144,6 +166,7 @@ public: void scrollWindow(int lines) { windowStart += lines*instructionSize; + scanFunctions(); redraw(); } @@ -154,5 +177,6 @@ public: selectRangeStart = extend ? std::min(selectRangeStart, newAddress) : newAddress; selectRangeEnd = extend ? std::max(selectRangeEnd, after) : after; updateStatusBarText(); + scanFunctions(); } }; \ No newline at end of file diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp index 5d38052de8..ab7874e465 100644 --- a/Windows/Debugger/Debugger_Disasm.cpp +++ b/Windows/Debugger/Debugger_Disasm.cpp @@ -810,6 +810,7 @@ void CDisasm::SetDebugMode(bool _bDebug, bool switchPC) if (switchPC) ptr->gotoPC(); + ptr->scanFunctions(); CtrlMemView *mem = CtrlMemView::getFrom(GetDlgItem(m_hDlg,IDC_DEBUGMEMVIEW)); mem->redraw();