From 90e3127bb6662570928d113afb24a261996643a6 Mon Sep 17 00:00:00 2001 From: Evan Teran Date: Thu, 19 Mar 2026 10:17:15 -0400 Subject: [PATCH 1/2] Started to work on fixing issue #863 by making sure that we always test for a valid process object did some formatting --- lib/libELF/include/libELF/elf_syminfo.h | 2 +- plugins/Analyzer/Analyzer.cpp | 12 +- plugins/BinaryInfo/ELFXX.cpp | 10 +- plugins/CheckVersion/CheckVersion.cpp | 2 +- .../unix/openbsd/PlatformState.cpp | 2 +- .../DebuggerCore/unix/osx/DebuggerCore.cpp | 6 +- .../DebuggerCore/unix/osx/PlatformState.cpp | 2 +- plugins/DebuggerCore/win32/PlatformRegion.cpp | 75 +++--- plugins/ODbgRegisterView/DialogEditGPR.h | 4 +- plugins/ODbgRegisterView/Plugin.cpp | 2 +- .../arch/arm-generic/armGroups.cpp | 3 +- .../arch/x86-generic/x86Groups.cpp | 6 +- scripts/clang-format.sh | 24 ++ src/Debugger.cpp | 40 ++-- src/widgets/QDisassemblyView.cpp | 219 +++++++++--------- 15 files changed, 221 insertions(+), 188 deletions(-) create mode 100755 scripts/clang-format.sh diff --git a/lib/libELF/include/libELF/elf_syminfo.h b/lib/libELF/include/libELF/elf_syminfo.h index ebc75084b..a14eafd93 100644 --- a/lib/libELF/include/libELF/elf_syminfo.h +++ b/lib/libELF/include/libELF/elf_syminfo.h @@ -120,7 +120,7 @@ enum { template constexpr T ELF32_ST_VISIBILITY(T o) { - return ((o)&0x03); + return ((o) & 0x03); } /* For ELF64 the definitions are the same. */ diff --git a/plugins/Analyzer/Analyzer.cpp b/plugins/Analyzer/Analyzer.cpp index 7e2361c9b..a2e2821f0 100644 --- a/plugins/Analyzer/Analyzer.cpp +++ b/plugins/Analyzer/Analyzer.cpp @@ -368,11 +368,13 @@ void Analyzer::bonusMain(RegionData *data) const { Q_ASSERT(data); - const QString s = edb::v1::debugger_core->process()->executable(); - if (!s.isEmpty()) { - if (const edb::address_t main = edb::v1::locate_main_function()) { - if (data->region->contains(main)) { - data->knownFunctions.insert(main); + if (IProcess *process = edb::v1::debugger_core->process()) { + const QString s = process->executable(); + if (!s.isEmpty()) { + if (const edb::address_t main = edb::v1::locate_main_function()) { + if (data->region->contains(main)) { + data->knownFunctions.insert(main); + } } } } diff --git a/plugins/BinaryInfo/ELFXX.cpp b/plugins/BinaryInfo/ELFXX.cpp index 24fd6c381..02f1b8344 100644 --- a/plugins/BinaryInfo/ELFXX.cpp +++ b/plugins/BinaryInfo/ELFXX.cpp @@ -109,10 +109,12 @@ ELFXX::ELFXX(const std::shared_ptr ®ion) } } else if (header_.e_type == ET_DYN) { - const QString process_executable = edb::v1::debugger_core->process()->name(); - for (const std::shared_ptr &r : edb::v1::memory_regions().regions()) { - if (r->accessible() && r->name() == region->name()) { - lowest = std::min(lowest, r->start()); + if (IProcess *process = edb::v1::debugger_core->process()) { + const QString process_executable = process->name(); + for (const std::shared_ptr &r : edb::v1::memory_regions().regions()) { + if (r->accessible() && r->name() == region->name()) { + lowest = std::min(lowest, r->start()); + } } } } diff --git a/plugins/CheckVersion/CheckVersion.cpp b/plugins/CheckVersion/CheckVersion.cpp index 4d870da1a..640a58669 100644 --- a/plugins/CheckVersion/CheckVersion.cpp +++ b/plugins/CheckVersion/CheckVersion.cpp @@ -101,7 +101,7 @@ void CheckVersion::setProxy(const QUrl &url) { if (!proxy_str.isEmpty()) { const QUrl proxy_url = QUrl::fromUserInput(proxy_str); const int port = proxy_url.port(80); - const auto qport = static_cast(qBound(0, port, 65535)); + const auto qport = static_cast(qBound(0, port, 65535)); proxy = QNetworkProxy(QNetworkProxy::HttpProxy, proxy_url.host(), qport, proxy_url.userName(), proxy_url.password()); } diff --git a/plugins/DebuggerCore/unix/openbsd/PlatformState.cpp b/plugins/DebuggerCore/unix/openbsd/PlatformState.cpp index 49601189d..a7254017d 100644 --- a/plugins/DebuggerCore/unix/openbsd/PlatformState.cpp +++ b/plugins/DebuggerCore/unix/openbsd/PlatformState.cpp @@ -414,7 +414,7 @@ void PlatformState::set_instruction_pointer(edb::address_t value) { #if defined(EDB_X86) regs_.r_eip = value; #elif defined(EDB_X86_64) - regs_.r_rip = value; + regs_.r_rip = value; #endif } diff --git a/plugins/DebuggerCore/unix/osx/DebuggerCore.cpp b/plugins/DebuggerCore/unix/osx/DebuggerCore.cpp index a676752a4..aba631289 100644 --- a/plugins/DebuggerCore/unix/osx/DebuggerCore.cpp +++ b/plugins/DebuggerCore/unix/osx/DebuggerCore.cpp @@ -398,9 +398,9 @@ void DebuggerCore::set_state(const State &state) { // const thread_state_flavor_t fpu_flavor = x86_FLOAT_STATE32; // const thread_state_flavor_t exception_flavor = x86_EXCEPTION_STATE32; #elif defined(EDB_X86_64) - mach_msg_type_number_t state_count = x86_THREAD_STATE64_COUNT; - const thread_state_flavor_t flavor = x86_THREAD_STATE64; - const thread_state_flavor_t debug_flavor = x86_DEBUG_STATE64; + mach_msg_type_number_t state_count = x86_THREAD_STATE64_COUNT; + const thread_state_flavor_t flavor = x86_THREAD_STATE64; + const thread_state_flavor_t debug_flavor = x86_DEBUG_STATE64; // const thread_state_flavor_t fpu_flavor = x86_FLOAT_STATE64; // const thread_state_flavor_t exception_flavor = x86_EXCEPTION_STATE64; #endif diff --git a/plugins/DebuggerCore/unix/osx/PlatformState.cpp b/plugins/DebuggerCore/unix/osx/PlatformState.cpp index e24f059b5..198f5fcd7 100644 --- a/plugins/DebuggerCore/unix/osx/PlatformState.cpp +++ b/plugins/DebuggerCore/unix/osx/PlatformState.cpp @@ -468,7 +468,7 @@ void PlatformState::set_instruction_pointer(edb::address_t value) { #if defined(EDB_X86) thread_state_.REG(eip) = value; #elif defined(EDB_X86_64) - thread_state_.REG(rip) = value; + thread_state_.REG(rip) = value; #endif } diff --git a/plugins/DebuggerCore/win32/PlatformRegion.cpp b/plugins/DebuggerCore/win32/PlatformRegion.cpp index 273e3b0b2..9537a3447 100644 --- a/plugins/DebuggerCore/win32/PlatformRegion.cpp +++ b/plugins/DebuggerCore/win32/PlatformRegion.cpp @@ -113,44 +113,47 @@ size_t PlatformRegion::size() const { * @param execute */ void PlatformRegion::setPermissions(bool read, bool write, bool execute) { - if (HANDLE ph = OpenProcess(PROCESS_VM_OPERATION, FALSE, edb::v1::debugger_core->process()->pid())) { - DWORD prot = PAGE_NOACCESS; - - switch ((static_cast(read) << 2) | (static_cast(write) << 1) | (static_cast(execute) << 0)) { - case 0x0: - prot = PAGE_NOACCESS; - break; - case 0x1: - prot = PAGE_EXECUTE; - break; - case 0x2: - prot = PAGE_WRITECOPY; - break; - case 0x3: - prot = PAGE_EXECUTE_WRITECOPY; - break; - case 0x4: - prot = PAGE_READONLY; - break; - case 0x5: - prot = PAGE_EXECUTE_READ; - break; - case 0x6: - prot = PAGE_READWRITE; - break; - case 0x7: - prot = PAGE_EXECUTE_READWRITE; - break; - } - - prot |= permissions_ & ~KnownPermissions; // keep modifiers - DWORD prev_prot; - if (VirtualProtectEx(ph, reinterpret_cast(start().toUint()), size(), prot, &prev_prot)) { - permissions_ = prot; + if (IProcess *process = edb::v1::debugger_core->process()) { + if (HANDLE ph = OpenProcess(PROCESS_VM_OPERATION, FALSE, process->pid())) { + DWORD prot = PAGE_NOACCESS; + + switch ((static_cast(read) << 2) | (static_cast(write) << 1) | (static_cast(execute) << 0)) { + case 0x0: + prot = PAGE_NOACCESS; + break; + case 0x1: + prot = PAGE_EXECUTE; + break; + case 0x2: + prot = PAGE_WRITECOPY; + break; + case 0x3: + prot = PAGE_EXECUTE_WRITECOPY; + break; + case 0x4: + prot = PAGE_READONLY; + break; + case 0x5: + prot = PAGE_EXECUTE_READ; + break; + case 0x6: + prot = PAGE_READWRITE; + break; + case 0x7: + prot = PAGE_EXECUTE_READWRITE; + break; + } + + prot |= permissions_ & ~KnownPermissions; // keep modifiers + + DWORD prev_prot; + if (VirtualProtectEx(ph, reinterpret_cast(start().toUint()), size(), prot, &prev_prot)) { + permissions_ = prot; + } + + CloseHandle(ph); } - - CloseHandle(ph); } } diff --git a/plugins/ODbgRegisterView/DialogEditGPR.h b/plugins/ODbgRegisterView/DialogEditGPR.h index c332b35c6..1860647ee 100644 --- a/plugins/ODbgRegisterView/DialogEditGPR.h +++ b/plugins/ODbgRegisterView/DialogEditGPR.h @@ -77,8 +77,8 @@ private Q_SLOTS: void setupFocus(); private: - std::array labels_ = {{nullptr}}; - std::array entries_ = {{nullptr}}; + std::array labels_ = {{nullptr}}; + std::array entries_ = {{nullptr}}; std::uint64_t value_; std::size_t bitSize_ = 0; Register reg_; diff --git a/plugins/ODbgRegisterView/Plugin.cpp b/plugins/ODbgRegisterView/Plugin.cpp index 21c5591b3..9508624aa 100644 --- a/plugins/ODbgRegisterView/Plugin.cpp +++ b/plugins/ODbgRegisterView/Plugin.cpp @@ -54,7 +54,7 @@ void Plugin::setupDocks() { void Plugin::saveSettings() const { QSettings settings; - const auto size = static_cast(registerViews_.size()); + const auto size = static_cast(registerViews_.size()); const auto arrayKey = pluginName + "/" + views; settings.remove(arrayKey); settings.beginWriteArray(arrayKey, size); diff --git a/plugins/ODbgRegisterView/arch/arm-generic/armGroups.cpp b/plugins/ODbgRegisterView/arch/arm-generic/armGroups.cpp index b9017ec4a..b0d48a98b 100644 --- a/plugins/ODbgRegisterView/arch/arm-generic/armGroups.cpp +++ b/plugins/ODbgRegisterView/arch/arm-generic/armGroups.cpp @@ -116,8 +116,7 @@ RegisterGroup *createCPSR(RegisterViewModelBase::Model *model, QWidget *parent) const auto valueWidth = 8; const auto valueIndex = nameIndex.sibling(nameIndex.row(), ModelValueColumn); column += nameWidth + 1; - group->insert(0, column, new ValueField( - valueWidth, valueIndex, [](QString const &v) { return v.right(8); }, group)); + group->insert(0, column, new ValueField(valueWidth, valueIndex, [](QString const &v) { return v.right(8); }, group)); const auto commentIndex = nameIndex.sibling(nameIndex.row(), ModelCommentColumn); column += valueWidth + 1; group->insert(0, column, new FieldWidget(0, commentIndex, group)); diff --git a/plugins/ODbgRegisterView/arch/x86-generic/x86Groups.cpp b/plugins/ODbgRegisterView/arch/x86-generic/x86Groups.cpp index a5803bb9c..d0d049f03 100644 --- a/plugins/ODbgRegisterView/arch/x86-generic/x86Groups.cpp +++ b/plugins/ODbgRegisterView/arch/x86-generic/x86Groups.cpp @@ -203,11 +203,7 @@ RegisterGroup *create_eflags(RegisterViewModelBase::Model *model, QWidget *paren constexpr int ValueWidth = 8; const auto valueIndex = nameIndex.sibling(nameIndex.row(), ModelValueColumn); column += NameWidth + 1; - group->insert(0, column, new ValueField( - ValueWidth, valueIndex, [](const QString &v) { - return v.right(8); - }, - group)); + group->insert(0, column, new ValueField(ValueWidth, valueIndex, [](const QString &v) { return v.right(8); }, group)); const auto commentIndex = nameIndex.sibling(nameIndex.row(), ModelCommentColumn); column += ValueWidth + 1; diff --git a/scripts/clang-format.sh b/scripts/clang-format.sh new file mode 100755 index 000000000..f5f18f447 --- /dev/null +++ b/scripts/clang-format.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." || exit 1 + +EXCLUDED_DIRS="lib/gdtoa-desktop src/qhexview/" + +EXCLUDE_PATH_ARGS=() +for dir in $EXCLUDED_DIRS; do + dir="${dir%/}" + EXCLUDE_PATH_ARGS+=( -path "$dir" -o -path "$dir/*" -o ) +done + +# Remove trailing "-o" so the prune expression is valid. +if [ ${#EXCLUDE_PATH_ARGS[@]} -gt 0 ]; then + unset 'EXCLUDE_PATH_ARGS[${#EXCLUDE_PATH_ARGS[@]}-1]' + FILES=$(find include src plugins lib \ + \( "${EXCLUDE_PATH_ARGS[@]}" \) -prune -o \ + -type f \( -name "*.cpp" -o -name "*.h" \) -print) +else + FILES=$(find include src plugins lib -type f \( -name "*.cpp" -o -name "*.h" \)) +fi + +echo $FILES | xargs clang-format -i diff --git a/src/Debugger.cpp b/src/Debugger.cpp index 46d7d6ebd..daae4770e 100644 --- a/src/Debugger.cpp +++ b/src/Debugger.cpp @@ -738,7 +738,11 @@ std::shared_ptr Debugger::currentDataViewInfo() const { // Desc: sets the caption part to also show the application name and pid //------------------------------------------------------------------------------ void Debugger::setDebuggerCaption(const QString &appname) { - setWindowTitle(tr("edb - %1 [%2]").arg(appname).arg(edb::v1::debugger_core->process()->pid())); + if (IProcess *process = edb::v1::debugger_core->process()) { + setWindowTitle(tr("edb - %1 [%2]").arg(appname).arg(process->pid())); + } else { + setWindowTitle(tr("edb")); + } } //------------------------------------------------------------------------------ @@ -2996,8 +3000,7 @@ void Debugger::setInitialDebuggerState() { dynamicInfoBreakpointSet_ = false; #endif - IProcess *process = edb::v1::debugger_core->process(); - + IProcess *process = edb::v1::debugger_core->process(); const QString executable = process ? process->executable() : QString(); setDebuggerCaption(executable); @@ -3066,7 +3069,9 @@ void Debugger::setInitialBreakpoint(const QString &s) { } if (entryPoint == 0 || edb::v1::config().initial_breakpoint == Configuration::EntryPoint) { - entryPoint = edb::v1::debugger_core->process()->entryPoint(); + if (IProcess *process = edb::v1::debugger_core->process()) { + entryPoint = process->entryPoint(); + } } if (entryPoint != 0) { @@ -3085,13 +3090,13 @@ void Debugger::setInitialBreakpoint(const QString &s) { void Debugger::on_action_Restart_triggered() { Q_ASSERT(edb::v1::debugger_core); - if (edb::v1::debugger_core->process()) { + if (IProcess *process = edb::v1::debugger_core->process()) { - workingDirectory_ = edb::v1::debugger_core->process()->currentWorkingDirectory(); - QList args = edb::v1::debugger_core->process()->arguments(); - const QString exe = edb::v1::debugger_core->process()->executable(); - const QString in = edb::v1::debugger_core->process()->standardInput(); - const QString out = edb::v1::debugger_core->process()->standardOutput(); + workingDirectory_ = process->currentWorkingDirectory(); + QList args = process->arguments(); + const QString exe = process->executable(); + const QString in = process->standardInput(); + const QString out = process->standardOutput(); if (!args.empty()) { args.removeFirst(); @@ -3221,17 +3226,18 @@ void Debugger::attach(edb::pid_t pid) { } if (const auto status = edb::v1::debugger_core->attach(pid)) { + if (IProcess *process = edb::v1::debugger_core->process()) { - workingDirectory_ = edb::v1::debugger_core->process()->currentWorkingDirectory(); + workingDirectory_ = process->currentWorkingDirectory(); + QList args = process->arguments(); - QList args = edb::v1::debugger_core->process()->arguments(); + if (!args.empty()) { + args.removeFirst(); + } - if (!args.empty()) { - args.removeFirst(); + argumentsDialog_->setArguments(args); + attachComplete(); } - - argumentsDialog_->setArguments(args); - attachComplete(); } else { QMessageBox::critical(this, tr("Attach"), tr("Failed to attach to process: %1").arg(status.error())); } diff --git a/src/widgets/QDisassemblyView.cpp b/src/widgets/QDisassemblyView.cpp index 12d2e453f..abd33253c 100644 --- a/src/widgets/QDisassemblyView.cpp +++ b/src/widgets/QDisassemblyView.cpp @@ -1354,140 +1354,141 @@ void QDisassemblyView::drawJumpArrows(QPainter &painter, const DrawingContext *c } // get current process state - State state; - IProcess *process = edb::v1::debugger_core->process(); - process->currentThread()->getState(&state); - painter.save(); - painter.setRenderHint(QPainter::Antialiasing, true); + if (IProcess *process = edb::v1::debugger_core->process()) { + State state; + process->currentThread()->getState(&state); - for (const JumpArrow &jump_arrow : jump_arrow_vec) { + painter.save(); + painter.setRenderHint(QPainter::Antialiasing, true); - bool is_dst_upward = jump_arrow.target < instructions_[jump_arrow.sourceLine].rva(); + for (const JumpArrow &jump_arrow : jump_arrow_vec) { - // horizontal line - int end_x = ctx->l1 - 3; - int start_x = end_x - jump_arrow.horizontalLength; + bool is_dst_upward = jump_arrow.target < instructions_[jump_arrow.sourceLine].rva(); - // vertical line - int src_y = jump_arrow.sourceLine * ctx->lineHeight + (fontHeight_ / 2); - int dst_y; + // horizontal line + int end_x = ctx->l1 - 3; + int start_x = end_x - jump_arrow.horizontalLength; - if (jump_arrow.destInMiddleOfInstruction) { - dst_y = jump_arrow.destLine * ctx->lineHeight; - } else { - dst_y = jump_arrow.destLine * ctx->lineHeight + (fontHeight_ / 2); - } + // vertical line + int src_y = jump_arrow.sourceLine * ctx->lineHeight + (fontHeight_ / 2); + int dst_y; - QColor arrow_color = palette().color(ctx->group, QPalette::Text); - double arrow_width = 1.0; - auto arrow_style = Qt::DashLine; + if (jump_arrow.destInMiddleOfInstruction) { + dst_y = jump_arrow.destLine * ctx->lineHeight; + } else { + dst_y = jump_arrow.destLine * ctx->lineHeight + (fontHeight_ / 2); + } - if (ctx->selectedLines == jump_arrow.sourceLine || ctx->selectedLines == jump_arrow.destLine) { - arrow_width = 2.0; // enlarge arrow width - } + QColor arrow_color = palette().color(ctx->group, QPalette::Text); + double arrow_width = 1.0; + auto arrow_style = Qt::DashLine; - bool conditional_jmp = is_conditional_jump(instructions_[jump_arrow.sourceLine]); - bool unconditional_jmp = is_unconditional_jump(instructions_[jump_arrow.sourceLine]); + if (ctx->selectedLines == jump_arrow.sourceLine || ctx->selectedLines == jump_arrow.destLine) { + arrow_width = 2.0; // enlarge arrow width + } - // if direct jmp, then draw in solid line - if (unconditional_jmp) { - arrow_style = Qt::SolidLine; - } + bool conditional_jmp = is_conditional_jump(instructions_[jump_arrow.sourceLine]); + bool unconditional_jmp = is_unconditional_jump(instructions_[jump_arrow.sourceLine]); - // if direct jmp (src) is selected, then draw arrow in red - if (unconditional_jmp && ctx->selectedLines == jump_arrow.sourceLine) { - arrow_color = takenJumpColor_; - } + // if direct jmp, then draw in solid line + if (unconditional_jmp) { + arrow_style = Qt::SolidLine; + } - // if direct jmp (dst) is selected, then draw arrow in red - if (unconditional_jmp && ctx->selectedLines == jump_arrow.destLine) { - if (showAddresses_[jump_arrow.destLine] != currentAddress_) { // if eip + // if direct jmp (src) is selected, then draw arrow in red + if (unconditional_jmp && ctx->selectedLines == jump_arrow.sourceLine) { arrow_color = takenJumpColor_; } - } - // if current conditional jump is taken, then draw arrow in red - if (showAddresses_[jump_arrow.sourceLine] == currentAddress_) { // if eip - if (conditional_jmp) { - if (edb::v1::arch_processor().isExecuted(instructions_[jump_arrow.sourceLine], state)) { + // if direct jmp (dst) is selected, then draw arrow in red + if (unconditional_jmp && ctx->selectedLines == jump_arrow.destLine) { + if (showAddresses_[jump_arrow.destLine] != currentAddress_) { // if eip arrow_color = takenJumpColor_; } } - } - // Align both 1px and 2px lines to pixel grid. This requires different offset in even-width and odd-width case. - const auto arrow_pixel_offset = std::fmod(arrow_width, 2.) == 1 ? 0.5 : 0; - painter.save(); - painter.translate(arrow_pixel_offset, arrow_pixel_offset); + // if current conditional jump is taken, then draw arrow in red + if (showAddresses_[jump_arrow.sourceLine] == currentAddress_) { // if eip + if (conditional_jmp) { + if (edb::v1::arch_processor().isExecuted(instructions_[jump_arrow.sourceLine], state)) { + arrow_color = takenJumpColor_; + } + } + } - painter.setPen(QPen(arrow_color, arrow_width, arrow_style)); + // Align both 1px and 2px lines to pixel grid. This requires different offset in even-width and odd-width case. + const auto arrow_pixel_offset = std::fmod(arrow_width, 2.) == 1 ? 0.5 : 0; + painter.save(); + painter.translate(arrow_pixel_offset, arrow_pixel_offset); - int src_reg_badge_width = 0; - int dst_reg_badge_width = 0; + painter.setPen(QPen(arrow_color, arrow_width, arrow_style)); - if (ctx->lineBadgeWidth.find(jump_arrow.sourceLine) != ctx->lineBadgeWidth.end()) { - src_reg_badge_width = ctx->lineBadgeWidth.at(jump_arrow.sourceLine); - } else if (ctx->lineBadgeWidth.find(jump_arrow.destLine) != ctx->lineBadgeWidth.end()) { - dst_reg_badge_width = ctx->lineBadgeWidth.at(jump_arrow.destLine); - } + int src_reg_badge_width = 0; + int dst_reg_badge_width = 0; - if (jump_arrow.destInViewport) { - - QPoint points[] = { - QPoint(end_x - src_reg_badge_width, src_y), - QPoint(start_x, src_y), - QPoint(start_x, dst_y), - QPoint(end_x - dst_reg_badge_width - fontWidth_ / 3, dst_y)}; - - painter.drawPolyline(points, 4); - - // draw arrow tips - QPainterPath path; - path.moveTo(end_x - dst_reg_badge_width, dst_y); - path.lineTo(end_x - dst_reg_badge_width - (fontWidth_ / 2.), dst_y - (fontHeight_ / 3.)); - path.lineTo(end_x - dst_reg_badge_width - (fontWidth_ / 2.), dst_y + (fontHeight_ / 3.)); - path.lineTo(end_x - dst_reg_badge_width, dst_y); - painter.fillPath(path, QBrush(arrow_color)); - - } else if (is_dst_upward) { // if dst out of viewport, and arrow facing upward - - QPoint points[] = { - QPoint(end_x - src_reg_badge_width, src_y), - QPoint(start_x, src_y), - QPoint(start_x, fontWidth_ / 3)}; - - painter.drawPolyline(points, 3); - - // draw arrow tips - QPainterPath path; - path.moveTo(start_x, 0); - path.lineTo(start_x - (fontWidth_ / 2.), fontHeight_ / 3.); - path.lineTo(start_x + (fontWidth_ / 2.), fontHeight_ / 3.); - path.lineTo(start_x, 0); - painter.fillPath(path, QBrush(arrow_color)); - - } else { // if dst out of viewport, and arrow facing downward - - QPoint points[] = { - QPoint(end_x - src_reg_badge_width, src_y), - QPoint(start_x, src_y), - QPoint(start_x, viewport()->height() - fontWidth_ / 3)}; - - painter.drawPolyline(points, 3); - - // draw arrow tips - QPainterPath path; - path.moveTo(start_x, viewport()->height() - 1); - path.lineTo(start_x - (fontWidth_ / 2.), viewport()->height() - (fontHeight_ / 3.) - 1); - path.lineTo(start_x + (fontWidth_ / 2.), viewport()->height() - (fontHeight_ / 3.) - 1); - path.lineTo(start_x, viewport()->height() - 1); - painter.fillPath(path, QBrush(arrow_color)); - } + if (ctx->lineBadgeWidth.find(jump_arrow.sourceLine) != ctx->lineBadgeWidth.end()) { + src_reg_badge_width = ctx->lineBadgeWidth.at(jump_arrow.sourceLine); + } else if (ctx->lineBadgeWidth.find(jump_arrow.destLine) != ctx->lineBadgeWidth.end()) { + dst_reg_badge_width = ctx->lineBadgeWidth.at(jump_arrow.destLine); + } - painter.restore(); - } + if (jump_arrow.destInViewport) { + + QPoint points[] = { + QPoint(end_x - src_reg_badge_width, src_y), + QPoint(start_x, src_y), + QPoint(start_x, dst_y), + QPoint(end_x - dst_reg_badge_width - fontWidth_ / 3, dst_y)}; + + painter.drawPolyline(points, 4); + + // draw arrow tips + QPainterPath path; + path.moveTo(end_x - dst_reg_badge_width, dst_y); + path.lineTo(end_x - dst_reg_badge_width - (fontWidth_ / 2.), dst_y - (fontHeight_ / 3.)); + path.lineTo(end_x - dst_reg_badge_width - (fontWidth_ / 2.), dst_y + (fontHeight_ / 3.)); + path.lineTo(end_x - dst_reg_badge_width, dst_y); + painter.fillPath(path, QBrush(arrow_color)); + + } else if (is_dst_upward) { // if dst out of viewport, and arrow facing upward + + QPoint points[] = { + QPoint(end_x - src_reg_badge_width, src_y), + QPoint(start_x, src_y), + QPoint(start_x, fontWidth_ / 3)}; + + painter.drawPolyline(points, 3); + + // draw arrow tips + QPainterPath path; + path.moveTo(start_x, 0); + path.lineTo(start_x - (fontWidth_ / 2.), fontHeight_ / 3.); + path.lineTo(start_x + (fontWidth_ / 2.), fontHeight_ / 3.); + path.lineTo(start_x, 0); + painter.fillPath(path, QBrush(arrow_color)); + + } else { // if dst out of viewport, and arrow facing downward + + QPoint points[] = { + QPoint(end_x - src_reg_badge_width, src_y), + QPoint(start_x, src_y), + QPoint(start_x, viewport()->height() - fontWidth_ / 3)}; + + painter.drawPolyline(points, 3); + + // draw arrow tips + QPainterPath path; + path.moveTo(start_x, viewport()->height() - 1); + path.lineTo(start_x - (fontWidth_ / 2.), viewport()->height() - (fontHeight_ / 3.) - 1); + path.lineTo(start_x + (fontWidth_ / 2.), viewport()->height() - (fontHeight_ / 3.) - 1); + path.lineTo(start_x, viewport()->height() - 1); + painter.fillPath(path, QBrush(arrow_color)); + } + painter.restore(); + } + } painter.restore(); } From 8faf601ff445782a1cb4456fcea1d40227f304e4 Mon Sep 17 00:00:00 2001 From: Evan Teran Date: Thu, 19 Mar 2026 10:31:34 -0400 Subject: [PATCH 2/2] more null pointer protections --- src/Debugger.cpp | 24 +- src/RegisterViewModelBase.cpp | 15 +- src/arch/x86-generic/ArchProcessor.cpp | 137 ++++++----- src/edb.cpp | 60 ++--- src/widgets/QDisassemblyView.cpp | 328 +++++++++++++------------ 5 files changed, 296 insertions(+), 268 deletions(-) diff --git a/src/Debugger.cpp b/src/Debugger.cpp index daae4770e..d66155abe 100644 --- a/src/Debugger.cpp +++ b/src/Debugger.cpp @@ -211,8 +211,13 @@ class RunUntilRet : public IDebugEventHandler { if (IProcess *process = edb::v1::debugger_core->process()) { + std::shared_ptr thread = process->currentThread(); + if (!thread) { + return pass_back_to_debugger(); + } + State state; - process->currentThread()->getState(&state); + thread->getState(&state); edb::address_t address = state.instructionPointer(); IDebugEvent::TRAP_REASON trap_reason = event->trapReason(); @@ -251,7 +256,7 @@ class RunUntilRet : public IDebugEventHandler { // Adjust RIP since 1st byte was replaced with 0xcc and we are now 1 byte after it. state.setInstructionPointer(prev_address); - process->currentThread()->setState(state); + thread->setState(state); address = prev_address; // If it wasn't internal, it was a user breakpoint. Pass back to Debugger. @@ -1344,9 +1349,11 @@ Register Debugger::activeRegister() const { if (IDebugger *core = edb::v1::debugger_core) { if (IProcess *process = core->process()) { - State state; - process->currentThread()->getState(&state); - return state[regName]; + if (std::shared_ptr thread = process->currentThread()) { + State state; + thread->getState(&state); + return state[regName]; + } } } return {}; @@ -2319,8 +2326,11 @@ edb::EventStatus Debugger::handleTrap(const std::shared_ptr &event) IProcess *process = edb::v1::debugger_core->process(); Q_ASSERT(process); + std::shared_ptr thread = process->currentThread(); + Q_ASSERT(thread); + State state; - process->currentThread()->getState(&state); + thread->getState(&state); // look it up in our breakpoint list, make sure it is one of OUR int3s! // if it is, we need to backup EIP and pause ourselves @@ -2336,7 +2346,7 @@ edb::EventStatus Debugger::handleTrap(const std::shared_ptr &event) // back up eip the size of a breakpoint, since we executed a breakpoint // instead of the real code that belongs there state.setInstructionPointer(previous_ip); - process->currentThread()->setState(state); + thread->setState(state); #if defined(Q_OS_LINUX) // test if we have hit our internal LD hook BP. If so, read in the r_debug diff --git a/src/RegisterViewModelBase.cpp b/src/RegisterViewModelBase.cpp index 2a1dc9369..27a8aa852 100644 --- a/src/RegisterViewModelBase.cpp +++ b/src/RegisterViewModelBase.cpp @@ -67,9 +67,12 @@ bool set_debuggee_register(const QString &name, const T &value, T &resultingValu IProcess *process = core->process(); Q_ASSERT(process); + std::shared_ptr thread = process->currentThread(); + Q_ASSERT(thread); + State state; // read - process->currentThread()->getState(&state); + thread->getState(&state); Register reg = state[name]; if (!reg) { @@ -89,10 +92,10 @@ bool set_debuggee_register(const QString &name, const T &value, T &resultingValu // write state.setRegister(reg); - process->currentThread()->setState(state); + thread->setState(state); // check - process->currentThread()->getState(&state); + thread->getState(&state); const Register resultReg = state[name]; if (!resultReg) { @@ -392,7 +395,11 @@ QVariant Model::data(const QModelIndex &index, int role) const { // read if (IProcess *process = core->process()) { - process->currentThread()->getState(&state); + if (std::shared_ptr thread = process->currentThread()) { + thread->getState(&state); + } else { + return {}; + } } return QVariant::fromValue(state[name]); } diff --git a/src/arch/x86-generic/ArchProcessor.cpp b/src/arch/x86-generic/ArchProcessor.cpp index 4274c5fa4..48ab507df 100644 --- a/src/arch/x86-generic/ArchProcessor.cpp +++ b/src/arch/x86-generic/ArchProcessor.cpp @@ -1488,96 +1488,99 @@ QStringList ArchProcessor::updateInstructionInfo(edb::address_t address) { edb::Instruction inst(buffer, buffer + sizeof(buffer), address); if (inst) { - State state; - process->currentThread()->getState(&state); + if (std::shared_ptr thread = process->currentThread()) { - std::int64_t origAX; - if (debuggeeIs64Bit()) { - origAX = state["orig_rax"].valueAsSignedInteger(); - } else { - origAX = state["orig_eax"].valueAsSignedInteger(); - } + State state; + thread->getState(&state); - const std::uint64_t rax = state.gpRegister(rAX).valueAsSignedInteger(); + std::int64_t origAX; + if (debuggeeIs64Bit()) { + origAX = state["orig_rax"].valueAsSignedInteger(); + } else { + origAX = state["orig_eax"].valueAsSignedInteger(); + } - if (origAX != -1 && !falseSyscallReturn(state, origAX)) { + const std::uint64_t rax = state.gpRegister(rAX).valueAsSignedInteger(); - // FIXME: this all doesn't work correctly when we're on the first instruction of a signal handler - // The registers there don't correspond to arguments of the syscall, and it's not correct to say the - // debuggee _returned_ from the syscall, since it's just interrupted the syscall to handle the signal - analyze_syscall(state, inst, ret, origAX); + if (origAX != -1 && !falseSyscallReturn(state, origAX)) { + + // FIXME: this all doesn't work correctly when we're on the first instruction of a signal handler + // The registers there don't correspond to arguments of the syscall, and it's not correct to say the + // debuggee _returned_ from the syscall, since it's just interrupted the syscall to handle the signal + analyze_syscall(state, inst, ret, origAX); #ifdef Q_OS_LINUX - enum { - // restart if no handler or if SA_RESTART is set, can be seen when interrupting e.g. waitpid - ERESTARTSYS = 512, - // restart unconditionally - ERESTARTNOINTR = 513, - // restart if no handler - ERESTARTNOHAND = 514, - // restart by sys_restart_syscall, can be seen when interrupting e.g. nanosleep - ERESTART_RESTARTBLOCK = 516, - }; - const auto err = rax >= -4095UL ? -rax : 0; - const bool interrupted = err == EINTR || - err == ERESTARTSYS || - err == ERESTARTNOINTR || - err == ERESTARTNOHAND || - err == ERESTART_RESTARTBLOCK; - - if (!ret.isEmpty() && ret.back().startsWith("SYSCALL")) { - if (interrupted) { - ret.back() = "Interrupted " + ret.back(); - } else { - ret.back() = "Returned from " + ret.back(); + enum { + // restart if no handler or if SA_RESTART is set, can be seen when interrupting e.g. waitpid + ERESTARTSYS = 512, + // restart unconditionally + ERESTARTNOINTR = 513, + // restart if no handler + ERESTARTNOHAND = 514, + // restart by sys_restart_syscall, can be seen when interrupting e.g. nanosleep + ERESTART_RESTARTBLOCK = 516, + }; + const auto err = rax >= -4095UL ? -rax : 0; + const bool interrupted = err == EINTR || + err == ERESTARTSYS || + err == ERESTARTNOINTR || + err == ERESTARTNOHAND || + err == ERESTART_RESTARTBLOCK; + + if (!ret.isEmpty() && ret.back().startsWith("SYSCALL")) { + if (interrupted) { + ret.back() = "Interrupted " + ret.back(); + } else { + ret.back() = "Returned from " + ret.back(); + } + } + // FIXME: actually only ERESTARTNOINTR guarantees reexecution. But it seems the other ERESTART* signals + // won't go into user space, so whatever the state of signal handlers, the tracee should never appear + // to see these signals. So I guess it's OK to assume that tha syscall _will_ be restarted by the kernel. + if (interrupted && err != EINTR) { + ret << QStringLiteral("Syscall will be restarted on next step/run"); } - } - // FIXME: actually only ERESTARTNOINTR guarantees reexecution. But it seems the other ERESTART* signals - // won't go into user space, so whatever the state of signal handlers, the tracee should never appear - // to see these signals. So I guess it's OK to assume that tha syscall _will_ be restarted by the kernel. - if (interrupted && err != EINTR) { - ret << QStringLiteral("Syscall will be restarted on next step/run"); - } #else - Q_UNUSED(rax) + Q_UNUSED(rax) #endif - } + } - // figure out the instruction type and display some information about it - // TODO: handle SETcc, LOOPcc, REPcc OP - if (is_conditional_move(inst)) { + // figure out the instruction type and display some information about it + // TODO: handle SETcc, LOOPcc, REPcc OP + if (is_conditional_move(inst)) { - analyze_cmov(state, inst, ret); + analyze_cmov(state, inst, ret); - } else if (is_ret(inst)) { + } else if (is_ret(inst)) { - analyze_return(state, inst, ret); + analyze_return(state, inst, ret); - } else if (is_jump(inst) || is_call(inst)) { + } else if (is_jump(inst) || is_call(inst)) { - if (is_conditional_jump(inst)) { - analyze_jump(state, inst, ret); - } - analyze_call(state, inst, ret); - } else if (is_int(inst)) { + if (is_conditional_jump(inst)) { + analyze_jump(state, inst, ret); + } + analyze_call(state, inst, ret); + } else if (is_int(inst)) { #ifdef Q_OS_LINUX - if ((inst[0]->imm & 0xff) == 0x80) { + if ((inst[0]->imm & 0xff) == 0x80) { + + analyze_syscall(state, inst, ret, state.gpRegister(rAX).valueAsInteger()); + } else { + + analyze_operands(state, inst, ret); + } +#endif + } else if (is_syscall(inst) || is_sysenter(inst)) { analyze_syscall(state, inst, ret, state.gpRegister(rAX).valueAsInteger()); + } else { analyze_operands(state, inst, ret); } -#endif - } else if (is_syscall(inst) || is_sysenter(inst)) { - - analyze_syscall(state, inst, ret, state.gpRegister(rAX).valueAsInteger()); - } else { - - analyze_operands(state, inst, ret); + analyze_jump_targets(inst, ret); } - - analyze_jump_targets(inst, ret); } } diff --git a/src/edb.cpp b/src/edb.cpp index 3e1356aca..3fa42dba0 100644 --- a/src/edb.cpp +++ b/src/edb.cpp @@ -741,38 +741,40 @@ address_t get_variable(const QString &s, bool *ok, ExpressionError *err) { Q_ASSERT(err); if (IProcess *process = debugger_core->process()) { + if (std::shared_ptr thread = process->currentThread()) { + + State state; + thread->getState(&state); + const Register reg = state.value(s); + *ok = reg.valid(); + if (!*ok) { + if (const std::shared_ptr sym = edb::v1::symbol_manager().find(s)) { + *ok = true; + return sym->address; + } - State state; - process->currentThread()->getState(&state); - const Register reg = state.value(s); - *ok = reg.valid(); - if (!*ok) { - if (const std::shared_ptr sym = edb::v1::symbol_manager().find(s)) { - *ok = true; - return sym->address; + *err = ExpressionError(ExpressionError::UnknownVariable); + return 0; } - *err = ExpressionError(ExpressionError::UnknownVariable); - return 0; - } + // FIXME: should this really return segment base, not selector? + // FIXME: if it's really meant to return base, then need to check whether + // State::operator[]() returned valid Register + if (reg.name() == "fs") { + return state["fs_base"].valueAsAddress(); + } - // FIXME: should this really return segment base, not selector? - // FIXME: if it's really meant to return base, then need to check whether - // State::operator[]() returned valid Register - if (reg.name() == "fs") { - return state["fs_base"].valueAsAddress(); - } + if (reg.name() == "gs") { + return state["gs_base"].valueAsAddress(); + } - if (reg.name() == "gs") { - return state["gs_base"].valueAsAddress(); - } + if (reg.bitSize() > 8 * sizeof(edb::address_t)) { + *err = ExpressionError(ExpressionError::UnknownVariable); + return 0; + } - if (reg.bitSize() > 8 * sizeof(edb::address_t)) { - *err = ExpressionError(ExpressionError::UnknownVariable); - return 0; + return reg.valueAsAddress(); } - - return reg.valueAsAddress(); } *err = ExpressionError(ExpressionError::UnknownVariable); @@ -1297,9 +1299,11 @@ address_t current_data_view_address() { //------------------------------------------------------------------------------ address_t instruction_pointer_address() { if (IProcess *process = debugger_core->process()) { - State state; - process->currentThread()->getState(&state); - return state.instructionPointer(); + if(std::shared_ptr thread = process->currentThread()) { + State state; + thread->getState(&state); + return state.instructionPointer(); + } } return address_t{}; diff --git a/src/widgets/QDisassemblyView.cpp b/src/widgets/QDisassemblyView.cpp index abd33253c..e251acb26 100644 --- a/src/widgets/QDisassemblyView.cpp +++ b/src/widgets/QDisassemblyView.cpp @@ -819,75 +819,77 @@ void QDisassemblyView::drawRegisterBadges(QPainter &painter, DrawingContext *ctx if (process->isPaused()) { - State state; - process->currentThread()->getState(&state); - - std::vector badge_labels(ctx->linesToRender); - { - unsigned int reg_num = 0; - Register reg; - reg = state.gpRegister(reg_num); + if (std::shared_ptr thread = process->currentThread()) { + State state; + thread->getState(&state); - while (reg.valid()) { - // Does addr appear here? - edb::address_t addr = reg.valueAsAddress(); + std::vector badge_labels(ctx->linesToRender); + { + unsigned int reg_num = 0; + Register reg; + reg = state.gpRegister(reg_num); - if (std::optional line = getLineOfAddress(addr)) { - if (!badge_labels[*line].isEmpty()) { - badge_labels[*line].append(", "); - } - badge_labels[*line].append(reg.name()); - } + while (reg.valid()) { + // Does addr appear here? + edb::address_t addr = reg.valueAsAddress(); - // what about [addr]? - if (process->readBytes(addr, &addr, edb::v1::pointer_size())) { if (std::optional line = getLineOfAddress(addr)) { if (!badge_labels[*line].isEmpty()) { badge_labels[*line].append(", "); } - badge_labels[*line].append("[" + reg.name() + "]"); + badge_labels[*line].append(reg.name()); } - } - - reg = state.gpRegister(++reg_num); - } - } - painter.setPen(badgeForegroundColor_); - - for (int line = 0; line < ctx->linesToRender; line++) { - if (!badge_labels[line].isEmpty()) { - - int width = badge_labels[line].length() * fontWidth_ + fontWidth_ / 2; - int height = ctx->lineHeight; - int triangle_point = line1() - 3; - int x = triangle_point - (height / 2) - width; - int y = line * ctx->lineHeight; + // what about [addr]? + if (process->readBytes(addr, &addr, edb::v1::pointer_size())) { + if (std::optional line = getLineOfAddress(addr)) { + if (!badge_labels[*line].isEmpty()) { + badge_labels[*line].append(", "); + } + badge_labels[*line].append("[" + reg.name() + "]"); + } + } - // if badge is not in viewpoint, then don't draw - if (x < 0) { - continue; + reg = state.gpRegister(++reg_num); } + } - ctx->lineBadgeWidth[line] = line1() - x; + painter.setPen(badgeForegroundColor_); - QRect bounds(x, y, width, height); + for (int line = 0; line < ctx->linesToRender; line++) { + if (!badge_labels[line].isEmpty()) { - // draw a rectangle + box around text - QPainterPath path; - path.addRect(bounds); - path.moveTo(bounds.x() + bounds.width(), bounds.y()); // top right - path.lineTo(triangle_point, bounds.y() + bounds.height() / 2.); // triangle point - path.lineTo(bounds.x() + bounds.width(), bounds.y() + bounds.height()); // bottom right - painter.fillPath(path, badgeBackgroundColor_); + int width = badge_labels[line].length() * fontWidth_ + fontWidth_ / 2; + int height = ctx->lineHeight; + int triangle_point = line1() - 3; + int x = triangle_point - (height / 2) - width; + int y = line * ctx->lineHeight; - painter.drawText( - bounds.x() + fontWidth_ / 4, - line * ctx->lineHeight, - fontWidth_ * badge_labels[line].size(), - ctx->lineHeight, - Qt::AlignVCenter, - (edb::v1::config().uppercase_disassembly ? badge_labels[line].toUpper() : badge_labels[line])); + // if badge is not in viewpoint, then don't draw + if (x < 0) { + continue; + } + + ctx->lineBadgeWidth[line] = line1() - x; + + QRect bounds(x, y, width, height); + + // draw a rectangle + box around text + QPainterPath path; + path.addRect(bounds); + path.moveTo(bounds.x() + bounds.width(), bounds.y()); // top right + path.lineTo(triangle_point, bounds.y() + bounds.height() / 2.); // triangle point + path.lineTo(bounds.x() + bounds.width(), bounds.y() + bounds.height()); // bottom right + painter.fillPath(path, badgeBackgroundColor_); + + painter.drawText( + bounds.x() + fontWidth_ / 4, + line * ctx->lineHeight, + fontWidth_ * badge_labels[line].size(), + ctx->lineHeight, + Qt::AlignVCenter, + (edb::v1::config().uppercase_disassembly ? badge_labels[line].toUpper() : badge_labels[line])); + } } } } @@ -1356,137 +1358,139 @@ void QDisassemblyView::drawJumpArrows(QPainter &painter, const DrawingContext *c // get current process state if (IProcess *process = edb::v1::debugger_core->process()) { - State state; - process->currentThread()->getState(&state); - - painter.save(); - painter.setRenderHint(QPainter::Antialiasing, true); + if (std::shared_ptr thread = process->currentThread()) { + State state; + thread->getState(&state); - for (const JumpArrow &jump_arrow : jump_arrow_vec) { + painter.save(); + painter.setRenderHint(QPainter::Antialiasing, true); - bool is_dst_upward = jump_arrow.target < instructions_[jump_arrow.sourceLine].rva(); + for (const JumpArrow &jump_arrow : jump_arrow_vec) { - // horizontal line - int end_x = ctx->l1 - 3; - int start_x = end_x - jump_arrow.horizontalLength; + bool is_dst_upward = jump_arrow.target < instructions_[jump_arrow.sourceLine].rva(); - // vertical line - int src_y = jump_arrow.sourceLine * ctx->lineHeight + (fontHeight_ / 2); - int dst_y; + // horizontal line + int end_x = ctx->l1 - 3; + int start_x = end_x - jump_arrow.horizontalLength; - if (jump_arrow.destInMiddleOfInstruction) { - dst_y = jump_arrow.destLine * ctx->lineHeight; - } else { - dst_y = jump_arrow.destLine * ctx->lineHeight + (fontHeight_ / 2); - } + // vertical line + int src_y = jump_arrow.sourceLine * ctx->lineHeight + (fontHeight_ / 2); + int dst_y; - QColor arrow_color = palette().color(ctx->group, QPalette::Text); - double arrow_width = 1.0; - auto arrow_style = Qt::DashLine; + if (jump_arrow.destInMiddleOfInstruction) { + dst_y = jump_arrow.destLine * ctx->lineHeight; + } else { + dst_y = jump_arrow.destLine * ctx->lineHeight + (fontHeight_ / 2); + } - if (ctx->selectedLines == jump_arrow.sourceLine || ctx->selectedLines == jump_arrow.destLine) { - arrow_width = 2.0; // enlarge arrow width - } + QColor arrow_color = palette().color(ctx->group, QPalette::Text); + double arrow_width = 1.0; + auto arrow_style = Qt::DashLine; - bool conditional_jmp = is_conditional_jump(instructions_[jump_arrow.sourceLine]); - bool unconditional_jmp = is_unconditional_jump(instructions_[jump_arrow.sourceLine]); + if (ctx->selectedLines == jump_arrow.sourceLine || ctx->selectedLines == jump_arrow.destLine) { + arrow_width = 2.0; // enlarge arrow width + } - // if direct jmp, then draw in solid line - if (unconditional_jmp) { - arrow_style = Qt::SolidLine; - } + bool conditional_jmp = is_conditional_jump(instructions_[jump_arrow.sourceLine]); + bool unconditional_jmp = is_unconditional_jump(instructions_[jump_arrow.sourceLine]); - // if direct jmp (src) is selected, then draw arrow in red - if (unconditional_jmp && ctx->selectedLines == jump_arrow.sourceLine) { - arrow_color = takenJumpColor_; - } + // if direct jmp, then draw in solid line + if (unconditional_jmp) { + arrow_style = Qt::SolidLine; + } - // if direct jmp (dst) is selected, then draw arrow in red - if (unconditional_jmp && ctx->selectedLines == jump_arrow.destLine) { - if (showAddresses_[jump_arrow.destLine] != currentAddress_) { // if eip + // if direct jmp (src) is selected, then draw arrow in red + if (unconditional_jmp && ctx->selectedLines == jump_arrow.sourceLine) { arrow_color = takenJumpColor_; } - } - // if current conditional jump is taken, then draw arrow in red - if (showAddresses_[jump_arrow.sourceLine] == currentAddress_) { // if eip - if (conditional_jmp) { - if (edb::v1::arch_processor().isExecuted(instructions_[jump_arrow.sourceLine], state)) { + // if direct jmp (dst) is selected, then draw arrow in red + if (unconditional_jmp && ctx->selectedLines == jump_arrow.destLine) { + if (showAddresses_[jump_arrow.destLine] != currentAddress_) { // if eip arrow_color = takenJumpColor_; } } - } - // Align both 1px and 2px lines to pixel grid. This requires different offset in even-width and odd-width case. - const auto arrow_pixel_offset = std::fmod(arrow_width, 2.) == 1 ? 0.5 : 0; - painter.save(); - painter.translate(arrow_pixel_offset, arrow_pixel_offset); + // if current conditional jump is taken, then draw arrow in red + if (showAddresses_[jump_arrow.sourceLine] == currentAddress_) { // if eip + if (conditional_jmp) { + if (edb::v1::arch_processor().isExecuted(instructions_[jump_arrow.sourceLine], state)) { + arrow_color = takenJumpColor_; + } + } + } - painter.setPen(QPen(arrow_color, arrow_width, arrow_style)); + // Align both 1px and 2px lines to pixel grid. This requires different offset in even-width and odd-width case. + const auto arrow_pixel_offset = std::fmod(arrow_width, 2.) == 1 ? 0.5 : 0; + painter.save(); + painter.translate(arrow_pixel_offset, arrow_pixel_offset); - int src_reg_badge_width = 0; - int dst_reg_badge_width = 0; + painter.setPen(QPen(arrow_color, arrow_width, arrow_style)); - if (ctx->lineBadgeWidth.find(jump_arrow.sourceLine) != ctx->lineBadgeWidth.end()) { - src_reg_badge_width = ctx->lineBadgeWidth.at(jump_arrow.sourceLine); - } else if (ctx->lineBadgeWidth.find(jump_arrow.destLine) != ctx->lineBadgeWidth.end()) { - dst_reg_badge_width = ctx->lineBadgeWidth.at(jump_arrow.destLine); - } + int src_reg_badge_width = 0; + int dst_reg_badge_width = 0; - if (jump_arrow.destInViewport) { - - QPoint points[] = { - QPoint(end_x - src_reg_badge_width, src_y), - QPoint(start_x, src_y), - QPoint(start_x, dst_y), - QPoint(end_x - dst_reg_badge_width - fontWidth_ / 3, dst_y)}; - - painter.drawPolyline(points, 4); - - // draw arrow tips - QPainterPath path; - path.moveTo(end_x - dst_reg_badge_width, dst_y); - path.lineTo(end_x - dst_reg_badge_width - (fontWidth_ / 2.), dst_y - (fontHeight_ / 3.)); - path.lineTo(end_x - dst_reg_badge_width - (fontWidth_ / 2.), dst_y + (fontHeight_ / 3.)); - path.lineTo(end_x - dst_reg_badge_width, dst_y); - painter.fillPath(path, QBrush(arrow_color)); - - } else if (is_dst_upward) { // if dst out of viewport, and arrow facing upward - - QPoint points[] = { - QPoint(end_x - src_reg_badge_width, src_y), - QPoint(start_x, src_y), - QPoint(start_x, fontWidth_ / 3)}; - - painter.drawPolyline(points, 3); - - // draw arrow tips - QPainterPath path; - path.moveTo(start_x, 0); - path.lineTo(start_x - (fontWidth_ / 2.), fontHeight_ / 3.); - path.lineTo(start_x + (fontWidth_ / 2.), fontHeight_ / 3.); - path.lineTo(start_x, 0); - painter.fillPath(path, QBrush(arrow_color)); - - } else { // if dst out of viewport, and arrow facing downward - - QPoint points[] = { - QPoint(end_x - src_reg_badge_width, src_y), - QPoint(start_x, src_y), - QPoint(start_x, viewport()->height() - fontWidth_ / 3)}; - - painter.drawPolyline(points, 3); - - // draw arrow tips - QPainterPath path; - path.moveTo(start_x, viewport()->height() - 1); - path.lineTo(start_x - (fontWidth_ / 2.), viewport()->height() - (fontHeight_ / 3.) - 1); - path.lineTo(start_x + (fontWidth_ / 2.), viewport()->height() - (fontHeight_ / 3.) - 1); - path.lineTo(start_x, viewport()->height() - 1); - painter.fillPath(path, QBrush(arrow_color)); - } + if (ctx->lineBadgeWidth.find(jump_arrow.sourceLine) != ctx->lineBadgeWidth.end()) { + src_reg_badge_width = ctx->lineBadgeWidth.at(jump_arrow.sourceLine); + } else if (ctx->lineBadgeWidth.find(jump_arrow.destLine) != ctx->lineBadgeWidth.end()) { + dst_reg_badge_width = ctx->lineBadgeWidth.at(jump_arrow.destLine); + } + + if (jump_arrow.destInViewport) { + + QPoint points[] = { + QPoint(end_x - src_reg_badge_width, src_y), + QPoint(start_x, src_y), + QPoint(start_x, dst_y), + QPoint(end_x - dst_reg_badge_width - fontWidth_ / 3, dst_y)}; + + painter.drawPolyline(points, 4); - painter.restore(); + // draw arrow tips + QPainterPath path; + path.moveTo(end_x - dst_reg_badge_width, dst_y); + path.lineTo(end_x - dst_reg_badge_width - (fontWidth_ / 2.), dst_y - (fontHeight_ / 3.)); + path.lineTo(end_x - dst_reg_badge_width - (fontWidth_ / 2.), dst_y + (fontHeight_ / 3.)); + path.lineTo(end_x - dst_reg_badge_width, dst_y); + painter.fillPath(path, QBrush(arrow_color)); + + } else if (is_dst_upward) { // if dst out of viewport, and arrow facing upward + + QPoint points[] = { + QPoint(end_x - src_reg_badge_width, src_y), + QPoint(start_x, src_y), + QPoint(start_x, fontWidth_ / 3)}; + + painter.drawPolyline(points, 3); + + // draw arrow tips + QPainterPath path; + path.moveTo(start_x, 0); + path.lineTo(start_x - (fontWidth_ / 2.), fontHeight_ / 3.); + path.lineTo(start_x + (fontWidth_ / 2.), fontHeight_ / 3.); + path.lineTo(start_x, 0); + painter.fillPath(path, QBrush(arrow_color)); + + } else { // if dst out of viewport, and arrow facing downward + + QPoint points[] = { + QPoint(end_x - src_reg_badge_width, src_y), + QPoint(start_x, src_y), + QPoint(start_x, viewport()->height() - fontWidth_ / 3)}; + + painter.drawPolyline(points, 3); + + // draw arrow tips + QPainterPath path; + path.moveTo(start_x, viewport()->height() - 1); + path.lineTo(start_x - (fontWidth_ / 2.), viewport()->height() - (fontHeight_ / 3.) - 1); + path.lineTo(start_x + (fontWidth_ / 2.), viewport()->height() - (fontHeight_ / 3.) - 1); + path.lineTo(start_x, viewport()->height() - 1); + painter.fillPath(path, QBrush(arrow_color)); + } + + painter.restore(); + } } } painter.restore();