From 886511fdcdb4b53e913400c6b21d09323077ce1d Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Mon, 25 Jul 2016 18:36:06 +0800 Subject: [PATCH] misc improvments --- src/dbg/value.cpp | 27 +++++++++++++-- src/gui/Src/BasicView/StdTable.cpp | 31 +++++++++++++++++ src/gui/Src/BasicView/StdTable.h | 1 + src/gui/Src/Gui/CPUDisassembly.cpp | 2 +- src/gui/Src/Gui/CPUSideBar.cpp | 55 ++++++++++++++++++++++++++---- src/gui/Src/Gui/CPUSideBar.h | 14 ++++++-- src/gui/Src/Gui/CPUStack.cpp | 13 +++---- src/gui/Src/Gui/CallStackView.cpp | 49 +++++++++++--------------- src/gui/Src/Gui/CallStackView.h | 5 +-- src/gui/Src/Gui/MainWindow.cpp | 3 +- src/gui/Src/Utils/MenuBuilder.h | 8 ++++- 11 files changed, 153 insertions(+), 55 deletions(-) diff --git a/src/dbg/value.cpp b/src/dbg/value.cpp index c054ab47..71916c5e 100644 --- a/src/dbg/value.cpp +++ b/src/dbg/value.cpp @@ -1403,7 +1403,7 @@ bool valapifromstring(const char* name, duint* value, int* value_size, bool prin if(szBaseName) { szBaseName++; - HMODULE hModule = LoadLibraryExW(szModuleName, 0, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); + HMODULE hModule = LoadLibraryExW(szModuleName, 0, DONT_RESOLVE_DLL_REFERENCES); if(hModule) { ULONG_PTR funcAddress = (ULONG_PTR)GetProcAddress(hModule, name); @@ -1448,6 +1448,21 @@ bool valapifromstring(const char* name, duint* value, int* value_size, bool prin return true; } +bool valenvfromstring(const char* string, duint* Address) +{ + if(scmp(string, "peb")) + { + *Address = (duint)GetPEBLocation(fdProcessInfo->hProcess); + return true; + } + else if(scmp(string, "teb")) + { + *Address = (duint)GetTEBLocation(hActiveThread); + return true; + } + return false; +} + /** \brief Check if a string is a valid decimal number. This function also accepts "-" or "." as prefix. \param string The string to check. @@ -1515,6 +1530,11 @@ bool convertLongLongNumber(const char* str, unsigned long long & result, int rad return true; } +/** +\brief Check if a character is a valid hexadecimal digit that is smaller than the size of a pointer. +\param digit The character to check. +\return true if the character is a valid hexadecimal digit. +*/ static bool isdigitduint(char digit) { #ifdef _WIN64 @@ -1609,7 +1629,8 @@ bool valfromstring_noexpr(const char* string, duint* value, bool silent, bool ba if(!valfromstring(ptrstring.c_str(), value, silent, baseonly)) { - dprintf("noexpr failed on %s\n", ptrstring.c_str()); + if(!silent) + dprintf("noexpr failed on %s\n", ptrstring.c_str()); return false; } duint addr = *value; @@ -1702,6 +1723,8 @@ bool valfromstring_noexpr(const char* string, duint* value, bool silent, bool ba *isvar = true; return true; } + else if(valenvfromstring(string, value)) //environment block + return true; else if(strstr(string, "sub_") == string) //then come sub_ functions { auto result = sscanf(string, "sub_%" fext "X", value) == 1; diff --git a/src/gui/Src/BasicView/StdTable.cpp b/src/gui/Src/BasicView/StdTable.cpp index e3238d3e..b2be868a 100644 --- a/src/gui/Src/BasicView/StdTable.cpp +++ b/src/gui/Src/BasicView/StdTable.cpp @@ -444,6 +444,37 @@ void StdTable::setupCopyMenu(QMenu* copyMenu) } } +void StdTable::setupCopyMenu(MenuBuilder *copyMenu) +{ + if(!getColumnCount()) + return; + //Copy->Whole Line + copyMenu->addAction(makeAction(tr("&Line"), SLOT(copyLineSlot()))); + //Copy->Cropped Table + copyMenu->addAction(makeAction(tr("Cropped &Table"), SLOT(copyTableSlot()))); + //Copy->Full Table + copyMenu->addAction(makeAction(tr("&Full Table"), SLOT(copyTableResizeSlot()))); + //Copy->Separator + copyMenu->addSeparator(); + //Copy->ColName + copyMenu->addBuilder(new MenuBuilder(this, [this](QMenu* menu) + { + for(int i = 0; i < getColumnCount(); i++) + { + if(!getCellContent(getInitialSelection(), i).length()) //skip empty cells + continue; + QString title = mCopyTitles.at(i); + if(!title.length()) //skip empty copy titles + continue; + QAction* action = new QAction(title, menu); + action->setObjectName(QString::number(i)); + connect(action, SIGNAL(triggered()), this, SLOT(copyEntrySlot())); + menu->addAction(action); + } + return true; + })); +} + void StdTable::setCopyMenuOnly(bool bSet, bool bDebugOnly) { mCopyMenuOnly = bSet; diff --git a/src/gui/Src/BasicView/StdTable.h b/src/gui/Src/BasicView/StdTable.h index 8cbbb3d4..83b313e7 100644 --- a/src/gui/Src/BasicView/StdTable.h +++ b/src/gui/Src/BasicView/StdTable.h @@ -39,6 +39,7 @@ public: //context menu helpers void setupCopyMenu(QMenu* copyMenu); + void setupCopyMenu(MenuBuilder* copyMenu); void setCopyMenuOnly(bool bSet, bool bDebugOnly = true); signals: diff --git a/src/gui/Src/Gui/CPUDisassembly.cpp b/src/gui/Src/Gui/CPUDisassembly.cpp index 4c2fe7ee..843afaec 100644 --- a/src/gui/Src/Gui/CPUDisassembly.cpp +++ b/src/gui/Src/Gui/CPUDisassembly.cpp @@ -1311,7 +1311,7 @@ void CPUDisassembly::yaraSlot() YaraRuleSelectionDialog yaraDialog(this); if(yaraDialog.exec() == QDialog::Accepted) { - QString addrText = QString("%1").arg(rvaToVa(getInitialSelection()), sizeof(dsint) * 2, 16, QChar('0')).toUpper(); + QString addrText = ToPtrString(rvaToVa(getInitialSelection())); DbgCmdExec(QString("yara \"%0\",%1").arg(yaraDialog.getSelectedFile()).arg(addrText).toUtf8().constData()); emit displayReferencesWidget(); } diff --git a/src/gui/Src/Gui/CPUSideBar.cpp b/src/gui/Src/Gui/CPUSideBar.cpp index ca74a0a1..67283685 100644 --- a/src/gui/Src/Gui/CPUSideBar.cpp +++ b/src/gui/Src/Gui/CPUSideBar.cpp @@ -193,6 +193,7 @@ void CPUSideBar::paintEvent(QPaintEvent* event) #endif //_WIN64 std::vector jumpLines; + std::vector labelArrows; for(int line = 0; line < viewableRows; line++) { @@ -270,7 +271,7 @@ void CPUSideBar::paintEvent(QPaintEvent* event) if(regLabelText.size()) { regLabelText.chop(1); - drawLabel(&painter, line, regLabelText); + labelArrows.push_back(drawLabel(&painter, line, regLabelText)); } //debug @@ -291,10 +292,16 @@ void CPUSideBar::paintEvent(QPaintEvent* event) } if(jumpLines.size()) { - AllocateJumpOffsets(jumpLines); + AllocateJumpOffsets(jumpLines, labelArrows); for(auto i : jumpLines) drawJump(&painter, i.line, i.destLine, i.jumpOffset, i.isConditional, i.isJumpGoingToExecute, i.isSelected); } + else + { + for(auto i = labelArrows.begin(); i != labelArrows.end(); i++) + i->endX = viewport()->width() - 1 - 11 - (isFoldingGraphicsPresent(i->line) != 0 ? mBulletRadius + fontHeight : 0); + } + drawLabelArrows(&painter, labelArrows); } void CPUSideBar::mouseReleaseEvent(QMouseEvent* e) @@ -599,7 +606,7 @@ void CPUSideBar::drawBullets(QPainter* painter, int line, bool isbp, bool isbpdi painter->restore(); } -void CPUSideBar::drawLabel(QPainter* painter, int Line, const QString & Text) +CPUSideBar::LabelArrow CPUSideBar::drawLabel(QPainter* painter, int Line, const QString & Text) { painter->save(); const int LineCoordinate = fontHeight * (1 + Line); @@ -630,7 +637,29 @@ void CPUSideBar::drawLabel(QPainter* painter, int Line, const QString & Text) painter->setBrush(QBrush(IPLabelBG)); drawStraightArrow(painter, rect.right() + 2, y, this->viewport()->width() - x - 11 - (isFoldingGraphicsPresent(Line) != 0 ? mBulletRadius + fontHeight : 0), y);*/ + LabelArrow labelArrow; + labelArrow.line = Line; + labelArrow.startX = rect.right() + 2; + labelArrow.endX = 0; + painter->restore(); + + return labelArrow; +} + +void CPUSideBar::drawLabelArrows(QPainter* painter, const std::vector & labelArrows) +{ + if(!labelArrows.empty()) + { + painter->save(); + painter->setPen(QPen(mCipLabelBackgroundColor, 2.0)); + for(auto i : labelArrows) + { + int y = fontHeight * (1 + i.line) - 0.5 * fontHeight; + drawStraightArrow(painter, i.startX, y, i.endX, y); + } + painter->restore(); + } } void CPUSideBar::drawFoldingCheckbox(QPainter* painter, int y, bool state) @@ -660,10 +689,10 @@ void CPUSideBar::drawStraightArrow(QPainter* painter, int x1, int y1, int x2, in painter->drawLine(x2 - 1, y2, x2 - ArrowSizeX, y2 + ArrowSizeY - 1);// Arrow bottom } -void CPUSideBar::AllocateJumpOffsets(std::vector & jumpLines) +void CPUSideBar::AllocateJumpOffsets(std::vector & jumpLines, std::vector & labelArrows) { - unsigned int* numLines = new unsigned int[viewableRows]; - memset(numLines, 0, sizeof(unsigned int) * viewableRows); + unsigned int* numLines = new unsigned int[viewableRows * 2]; // Low:jump offsets of the vertical jumping line, High:jump offsets of the horizontal jumping line. + memset(numLines, 0, sizeof(unsigned int) * viewableRows * 2); // preprocessing for(size_t i = 0; i < jumpLines.size(); i++) { @@ -707,6 +736,20 @@ void CPUSideBar::AllocateJumpOffsets(std::vector & jumpLines) for(int j = jmp.line; j >= jmp.destLine && j >= 0; j--) numLines[j] = jmp.jumpOffset; } + if(jmp.line >= 0 && jmp.line < viewableRows) + numLines[jmp.line + viewableRows] = jmp.jumpOffset; + if(jmp.destLine >= 0 && jmp.destLine < viewableRows) + numLines[jmp.destLine + viewableRows] = jmp.jumpOffset; + } + // set label arrows according to jump offsets + auto viewportWidth = viewport()->width(); + const int JumpPadding = 11; + for(auto i = labelArrows.begin(); i != labelArrows.end(); i++) + { + if(numLines[i->line + viewableRows] != 0) + i->endX = viewportWidth - numLines[i->line + viewableRows] * JumpPadding - 15 - fontHeight; // This expression should be consistent with drawJump + else + i->endX = viewportWidth - 1- 11 - (isFoldingGraphicsPresent(i->line) != 0 ? mBulletRadius + fontHeight : 0); } delete[] numLines; } diff --git a/src/gui/Src/Gui/CPUSideBar.h b/src/gui/Src/Gui/CPUSideBar.h index c99a7d73..9bebfbff 100644 --- a/src/gui/Src/Gui/CPUSideBar.h +++ b/src/gui/Src/Gui/CPUSideBar.h @@ -43,7 +43,6 @@ protected: void mouseReleaseEvent(QMouseEvent* e); void mouseMoveEvent(QMouseEvent* event); - void drawLabel(QPainter* painter, int Line, const QString & Text); void drawBullets(QPainter* painter, int line, bool ispb, bool isbpdisabled, bool isbookmark); bool isJump(int i) const; void drawJump(QPainter* painter, int startLine, int endLine, int jumpoffset, bool conditional, bool isexecute, bool isactive); @@ -68,12 +67,21 @@ private: { int line; int destLine; - int jumpOffset; + unsigned int jumpOffset; bool isSelected; bool isConditional; bool isJumpGoingToExecute; }; - void AllocateJumpOffsets(std::vector & jumpLines); + struct LabelArrow + { + int line; + int startX; + int endX; + }; + + void AllocateJumpOffsets(std::vector & jumpLines, std::vector & labelArrows); + LabelArrow drawLabel(QPainter* painter, int Line, const QString & Text); + void drawLabelArrows(QPainter* painter, const std::vector & labelArrows); // Configuration QColor mBackgroundColor; diff --git a/src/gui/Src/Gui/CPUStack.cpp b/src/gui/Src/Gui/CPUStack.cpp index 40785a32..a805cd14 100644 --- a/src/gui/Src/Gui/CPUStack.cpp +++ b/src/gui/Src/Gui/CPUStack.cpp @@ -310,13 +310,10 @@ void CPUStack::refreshShortcutsSlot() void CPUStack::getColumnRichText(int col, dsint rva, RichTextPainter::List & richText) { - // Compute RVA - dsint wRva = rva; - duint wVa = rvaToVa(wRva); + // Compute VA + duint wVa = rvaToVa(rva); - bool wActiveStack = true; - if(wVa < mCsp) //inactive stack - wActiveStack = false; + bool wActiveStack = (wVa >= mCsp); //inactive stack STACK_COMMENT comment; RichTextPainter::CustomRichText_t curData; @@ -337,7 +334,7 @@ void CPUStack::getColumnRichText(int col, dsint rva, RichTextPainter::List & ric } } } - else if(col && DbgStackCommentGet(rvaToVa(wRva), &comment)) //paint stack comments + else if(col && DbgStackCommentGet(wVa, &comment)) //paint stack comments { if(wActiveStack) { @@ -407,7 +404,7 @@ QString CPUStack::paintContent(QPainter* painter, dsint rowBase, int rowOffset, if(background.alpha()) painter->fillRect(QRect(x, y, w, h), QBrush(background)); //fill background when defined painter->drawText(QRect(x + 4, y , w - 4 , h), Qt::AlignVCenter | Qt::AlignLeft, makeAddrText(wVa)); - return ""; + return QString(); } return HexDump::paintContent(painter, rowBase, rowOffset, col, x, y, w, h);; } diff --git a/src/gui/Src/Gui/CallStackView.cpp b/src/gui/Src/Gui/CallStackView.cpp index 515fec67..378afe26 100644 --- a/src/gui/Src/Gui/CallStackView.cpp +++ b/src/gui/Src/Gui/CallStackView.cpp @@ -13,22 +13,31 @@ CallStackView::CallStackView(StdTable* parent) : StdTable(parent) connect(Bridge::getBridge(), SIGNAL(updateCallStack()), this, SLOT(updateCallStack())); connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint))); - connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(doubleClickedSlot())); + connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(followTo())); setupContextMenu(); } void CallStackView::setupContextMenu() { - mFollowAddress = new QAction(tr("Follow &Address"), this); - connect(mFollowAddress, SIGNAL(triggered()), this, SLOT(followAddress())); - mFollowTo = new QAction(tr("Follow &To"), this); + mMenuBuilder = new MenuBuilder(this, [](QMenu*) + { + return DbgIsDebugging(); + }); + mMenuBuilder->addAction(makeAction(tr("Follow &Address"), SLOT(followAddress()))); + QAction* mFollowTo = mMenuBuilder->addAction(makeAction(tr("Follow &To"), SLOT(followTo()))); mFollowTo->setShortcutContext(Qt::WidgetShortcut); mFollowTo->setShortcut(QKeySequence("enter")); - connect(mFollowTo, SIGNAL(triggered()), this, SLOT(followTo())); connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followTo())); - mFollowFrom = new QAction(tr("Follow &From"), this); - connect(mFollowFrom, SIGNAL(triggered()), this, SLOT(followFrom())); + mMenuBuilder->addAction(makeAction(tr("Follow &From"), SLOT(followFrom())), [this](QMenu*) + { + return !getCellContent(getInitialSelection(), 2).isEmpty(); + }); + MenuBuilder* mCopyMenu = new MenuBuilder(this); + setupCopyMenu(mCopyMenu); + // Column count cannot be zero + mMenuBuilder->addSeparator(); + mMenuBuilder->addMenu(makeMenu(DIcon("copy.png"), tr("&Copy")), mCopyMenu); } void CallStackView::updateCallStack() @@ -41,13 +50,13 @@ void CallStackView::updateCallStack() setRowCount(callstack.total); for(int i = 0; i < callstack.total; i++) { - QString addrText = QString("%1").arg((duint)callstack.entries[i].addr, sizeof(duint) * 2, 16, QChar('0')).toUpper(); + QString addrText = ToPtrString(callstack.entries[i].addr); setCellContent(i, 0, addrText); - addrText = QString("%1").arg((duint)callstack.entries[i].to, sizeof(duint) * 2, 16, QChar('0')).toUpper(); + addrText = ToPtrString(callstack.entries[i].to); setCellContent(i, 1, addrText); if(callstack.entries[i].from) { - addrText = QString("%1").arg((duint)callstack.entries[i].from, sizeof(duint) * 2, 16, QChar('0')).toUpper(); + addrText = ToPtrString(callstack.entries[i].from); setCellContent(i, 2, addrText); } setCellContent(i, 3, callstack.entries[i].comment); @@ -59,29 +68,11 @@ void CallStackView::updateCallStack() void CallStackView::contextMenuSlot(const QPoint pos) { - if(!DbgIsDebugging()) - return; QMenu wMenu(this); //create context menu - wMenu.addAction(mFollowAddress); - wMenu.addAction(mFollowTo); - QString wStr = getCellContent(getInitialSelection(), 2); - if(wStr.length()) - wMenu.addAction(mFollowFrom); - QMenu wCopyMenu(tr("&Copy"), this); - setupCopyMenu(&wCopyMenu); - if(wCopyMenu.actions().length()) - { - wMenu.addSeparator(); - wMenu.addMenu(&wCopyMenu); - } + mMenuBuilder->build(&wMenu); wMenu.exec(mapToGlobal(pos)); //execute context menu } -void CallStackView::doubleClickedSlot() -{ - followTo(); -} - void CallStackView::followAddress() { QString addrText = getCellContent(getInitialSelection(), 0); diff --git a/src/gui/Src/Gui/CallStackView.h b/src/gui/Src/Gui/CallStackView.h index 8fe070ba..2945bfb6 100644 --- a/src/gui/Src/Gui/CallStackView.h +++ b/src/gui/Src/Gui/CallStackView.h @@ -16,15 +16,12 @@ signals: protected slots: void updateCallStack(); void contextMenuSlot(const QPoint pos); - void doubleClickedSlot(); void followAddress(); void followTo(); void followFrom(); private: - QAction* mFollowAddress; - QAction* mFollowTo; - QAction* mFollowFrom; + MenuBuilder* mMenuBuilder; }; #endif // CALLSTACKVIEW_H diff --git a/src/gui/Src/Gui/MainWindow.cpp b/src/gui/Src/Gui/MainWindow.cpp index 0d5dd28c..da74d9be 100644 --- a/src/gui/Src/Gui/MainWindow.cpp +++ b/src/gui/Src/Gui/MainWindow.cpp @@ -1407,7 +1407,8 @@ void MainWindow::changeCommandLine() void MainWindow::displayManual() { // Open the Windows CHM in the upper directory - QDesktopServices::openUrl(QUrl(QUrl::fromLocalFile(QString("%1/../x64dbg.chm").arg(QCoreApplication::applicationDirPath())))); + if(!QDesktopServices::openUrl(QUrl(QUrl::fromLocalFile(QString("%1/../x64dbg.chm").arg(QCoreApplication::applicationDirPath()))))) + SimpleErrorBox(this, tr("Error"), tr("Manual cannot be opened. Please check if x64dbg.chm exists and ensure there is no other problems with your system.")); } void MainWindow::decompileAt(dsint start, dsint end) diff --git a/src/gui/Src/Utils/MenuBuilder.h b/src/gui/Src/Utils/MenuBuilder.h index c9d6b10d..c22ad0d8 100644 --- a/src/gui/Src/Utils/MenuBuilder.h +++ b/src/gui/Src/Utils/MenuBuilder.h @@ -97,6 +97,11 @@ public: return true; } + inline bool empty() const + { + return _containers.empty(); + } + private: struct Container { @@ -109,7 +114,8 @@ private: }; inline Container() - : type(Separator) + : type(Separator), + action(nullptr) { }