From 3817686d9559c1fa1fc6bca73873654824f288ea Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sun, 26 Dec 2021 17:24:00 +0800 Subject: [PATCH] Add autocomment for breakpoint --- src/dbg/_exports.cpp | 359 +++++++++++++++++----------- src/gui/Src/Gui/BreakpointsView.cpp | 14 +- 2 files changed, 229 insertions(+), 144 deletions(-) diff --git a/src/dbg/_exports.cpp b/src/dbg/_exports.cpp index e46b0f31..53aef9d0 100644 --- a/src/dbg/_exports.cpp +++ b/src/dbg/_exports.cpp @@ -287,6 +287,225 @@ static bool getLabel(duint addr, char* label, bool noFuncOffset) return retval; } +static bool getAutoComment(duint addr, String & comment) +{ + bool retval; + duint disp; + char fileName[MAX_STRING_SIZE] = {}; + int lineNumber = 0; + if(!bNoSourceLineAutoComments && SymGetSourceLine(addr, fileName, &lineNumber, &disp) && !disp) + { + + char* actualName = fileName; + char* l = strrchr(fileName, '\\'); + if(l) + actualName = l + 1; + + comment = StringUtils::sprintf("%s:%u", actualName, lineNumber); + retval = true; + } + + DISASM_INSTR instr; + String temp_string; + BRIDGE_ADDRINFO newinfo; + char string_text[MAX_STRING_SIZE] = ""; + + Zydis cp; + auto getregs = !bOnlyCipAutoComments || addr == lastContext.cip; + disasmget(cp, addr, &instr, getregs); + // Some nop variants have 'operands' that should be ignored + if(cp.Success() && !cp.IsNop()) + { + //Ignore register values when not on CIP and OnlyCipAutoComments is enabled: https://github.com/x64dbg/x64dbg/issues/1383 + if(!getregs) + { + for(int i = 0; i < instr.argcount; i++) + instr.arg[i].value = instr.arg[i].constant; + } + + if(addr == lastContext.cip && (cp.GetId() == ZYDIS_MNEMONIC_SYSCALL || (cp.GetId() == ZYDIS_MNEMONIC_INT && cp[0].imm.value.u == 0x2e))) + { + auto syscallName = SyscallToName((unsigned int)lastContext.cax); + if(!syscallName.empty()) + { + if(!comment.empty()) + { + comment.push_back(','); + comment.push_back(' '); + } + comment.append(syscallName); + retval = true; + } + } + + for(int i = 0; i < instr.argcount; i++) + { + memset(&newinfo, 0, sizeof(BRIDGE_ADDRINFO)); + newinfo.flags = flaglabel; + + STRING_TYPE strtype = str_none; + + if(instr.arg[i].constant == instr.arg[i].value) //avoid: call ; addr:label + { + auto constant = instr.arg[i].constant; + if(instr.arg[i].type == arg_normal && instr.arg[i].value == addr + instr.instr_size && cp.IsCall()) + temp_string.assign("call $0"); + else if(instr.arg[i].type == arg_normal && instr.arg[i].value == addr + instr.instr_size && cp.IsJump()) + temp_string.assign("jmp $0"); + else if(instr.type == instr_branch) + continue; + else if(instr.arg[i].type == arg_normal && constant < 256 && (isprint(int(constant)) || isspace(int(constant))) && (strstr(instr.instruction, "cmp") || strstr(instr.instruction, "mov"))) + { + temp_string.assign(instr.arg[i].mnemonic); + temp_string.push_back(':'); + temp_string.push_back('\''); + temp_string.append(StringUtils::Escape((unsigned char)constant)); + temp_string.push_back('\''); + } + else if(DbgGetStringAt(instr.arg[i].constant, string_text)) + { + temp_string.assign(instr.arg[i].mnemonic); + temp_string.push_back(':'); + temp_string.append(string_text); + } + } + else if(instr.arg[i].memvalue && (DbgGetStringAt(instr.arg[i].memvalue, string_text) || _dbg_addrinfoget(instr.arg[i].memvalue, instr.arg[i].segment, &newinfo))) + { + if(*string_text) + { + temp_string.assign("["); + temp_string.append(instr.arg[i].mnemonic); + temp_string.push_back(']'); + temp_string.push_back(':'); + temp_string.append(string_text); + } + else if(*newinfo.label) + { + temp_string.assign("["); + temp_string.append(instr.arg[i].mnemonic); + temp_string.push_back(']'); + temp_string.push_back(':'); + temp_string.append(newinfo.label); + } + } + else if(instr.arg[i].value && (DbgGetStringAt(instr.arg[i].value, string_text) || _dbg_addrinfoget(instr.arg[i].value, instr.arg[i].segment, &newinfo))) + { + if(instr.type != instr_normal) //stack/jumps (eg add esp, 4 or jmp 401110) cannot directly point to strings + { + if(*newinfo.label) + { + temp_string = instr.arg[i].mnemonic; + temp_string.push_back(':'); + temp_string.append(newinfo.label); + } + } + else if(*string_text) + { + temp_string = instr.arg[i].mnemonic; + temp_string.push_back(':'); + temp_string.append(string_text); + } + else if(*newinfo.label) + { + temp_string = instr.arg[i].mnemonic; + temp_string.push_back(':'); + temp_string.append(newinfo.label); + } + } + else + continue; + + if(!strstr(comment.c_str(), temp_string.c_str())) //avoid duplicate comments + { + if(!comment.empty()) + { + comment.push_back(','); + comment.push_back(' '); + } + comment.append(temp_string); + retval = true; + } + } + } + BREAKPOINT bp; + // Add autocomment for breakpoints with BreakpointsView format because there's usually something useful + if(BpGet(addr, BPNORMAL, nullptr, &bp) || BpGet(addr, BPHARDWARE, nullptr, &bp)) + { + auto next = [&temp_string]() + { + if(!temp_string.empty()) + temp_string += ", "; + }; + if(*bp.breakCondition) + { + next(); + temp_string += GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "breakif")); + temp_string += "("; + temp_string += bp.breakCondition; + temp_string += ")"; + } + + if(bp.fastResume) + { + next(); + temp_string += GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "fastresume()")); + } + else //fast resume skips all other steps + { + if(*bp.logText) + { + next(); + if(*bp.logCondition) + { + temp_string += GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "logif")); + temp_string += "("; + temp_string += bp.logCondition; + temp_string += ", "; + } + else + { + temp_string += GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "log")); + temp_string += "("; + } + temp_string += bp.logText; + temp_string += ")"; + } + + if(*bp.commandText) + { + next(); + if(*bp.commandCondition) + { + temp_string += GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "cmdif")); + temp_string += "("; + temp_string += bp.commandCondition; + temp_string += ", "; + } + else + { + temp_string += GuiTranslateText(QT_TRANSLATE_NOOP("DBG", "cmd")); + temp_string += "("; + } + temp_string += bp.commandText; + temp_string += ")"; + } + } + if(!temp_string.empty()) + { + if(!comment.empty()) + { + comment.push_back(','); + comment.push_back(' '); + } + comment.append(temp_string); + retval = true; + } + } + StringUtils::ReplaceAll(comment, "{", "{{"); + StringUtils::ReplaceAll(comment, "}", "}}"); + return retval; +} + extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, BRIDGE_ADDRINFO* addrinfo) { if(!DbgIsDebugging()) @@ -331,145 +550,7 @@ extern "C" DLL_EXPORT bool _dbg_addrinfoget(duint addr, SEGMENTREG segment, BRID else { String comment; - duint disp; - char fileName[MAX_STRING_SIZE] = {}; - int lineNumber = 0; - if(!bNoSourceLineAutoComments && SymGetSourceLine(addr, fileName, &lineNumber, &disp) && !disp) - { - - char* actualName = fileName; - char* l = strrchr(fileName, '\\'); - if(l) - actualName = l + 1; - - comment = StringUtils::sprintf("%s:%u", actualName, lineNumber); - retval = true; - } - - DISASM_INSTR instr; - String temp_string; - BRIDGE_ADDRINFO newinfo; - char string_text[MAX_STRING_SIZE] = ""; - - Zydis cp; - auto getregs = !bOnlyCipAutoComments || addr == lastContext.cip; - disasmget(cp, addr, &instr, getregs); - // Some nop variants have 'operands' that should be ignored - if(cp.Success() && !cp.IsNop()) - { - //Ignore register values when not on CIP and OnlyCipAutoComments is enabled: https://github.com/x64dbg/x64dbg/issues/1383 - if(!getregs) - { - for(int i = 0; i < instr.argcount; i++) - instr.arg[i].value = instr.arg[i].constant; - } - - if(addr == lastContext.cip && (cp.GetId() == ZYDIS_MNEMONIC_SYSCALL || (cp.GetId() == ZYDIS_MNEMONIC_INT && cp[0].imm.value.u == 0x2e))) - { - auto syscallName = SyscallToName((unsigned int)lastContext.cax); - if(!syscallName.empty()) - { - if(!comment.empty()) - { - comment.push_back(','); - comment.push_back(' '); - } - comment.append(syscallName); - retval = true; - } - } - - for(int i = 0; i < instr.argcount; i++) - { - memset(&newinfo, 0, sizeof(BRIDGE_ADDRINFO)); - newinfo.flags = flaglabel; - - STRING_TYPE strtype = str_none; - - if(instr.arg[i].constant == instr.arg[i].value) //avoid: call ; addr:label - { - auto constant = instr.arg[i].constant; - if(instr.arg[i].type == arg_normal && instr.arg[i].value == addr + instr.instr_size && cp.IsCall()) - temp_string.assign("call $0"); - else if(instr.arg[i].type == arg_normal && instr.arg[i].value == addr + instr.instr_size && cp.IsJump()) - temp_string.assign("jmp $0"); - else if(instr.type == instr_branch) - continue; - else if(instr.arg[i].type == arg_normal && constant < 256 && (isprint(int(constant)) || isspace(int(constant))) && (strstr(instr.instruction, "cmp") || strstr(instr.instruction, "mov"))) - { - temp_string.assign(instr.arg[i].mnemonic); - temp_string.push_back(':'); - temp_string.push_back('\''); - temp_string.append(StringUtils::Escape((unsigned char)constant)); - temp_string.push_back('\''); - } - else if(DbgGetStringAt(instr.arg[i].constant, string_text)) - { - temp_string.assign(instr.arg[i].mnemonic); - temp_string.push_back(':'); - temp_string.append(string_text); - } - } - else if(instr.arg[i].memvalue && (DbgGetStringAt(instr.arg[i].memvalue, string_text) || _dbg_addrinfoget(instr.arg[i].memvalue, instr.arg[i].segment, &newinfo))) - { - if(*string_text) - { - temp_string.assign("["); - temp_string.append(instr.arg[i].mnemonic); - temp_string.push_back(']'); - temp_string.push_back(':'); - temp_string.append(string_text); - } - else if(*newinfo.label) - { - temp_string.assign("["); - temp_string.append(instr.arg[i].mnemonic); - temp_string.push_back(']'); - temp_string.push_back(':'); - temp_string.append(newinfo.label); - } - } - else if(instr.arg[i].value && (DbgGetStringAt(instr.arg[i].value, string_text) || _dbg_addrinfoget(instr.arg[i].value, instr.arg[i].segment, &newinfo))) - { - if(instr.type != instr_normal) //stack/jumps (eg add esp, 4 or jmp 401110) cannot directly point to strings - { - if(*newinfo.label) - { - temp_string = instr.arg[i].mnemonic; - temp_string.push_back(':'); - temp_string.append(newinfo.label); - } - } - else if(*string_text) - { - temp_string = instr.arg[i].mnemonic; - temp_string.push_back(':'); - temp_string.append(string_text); - } - else if(*newinfo.label) - { - temp_string = instr.arg[i].mnemonic; - temp_string.push_back(':'); - temp_string.append(newinfo.label); - } - } - else - continue; - - if(!strstr(comment.c_str(), temp_string.c_str())) //avoid duplicate comments - { - if(!comment.empty()) - { - comment.push_back(','); - comment.push_back(' '); - } - comment.append(temp_string); - retval = true; - } - } - } - StringUtils::ReplaceAll(comment, "{", "{{"); - StringUtils::ReplaceAll(comment, "}", "}}"); + retval = getAutoComment(addr, comment); strcpy_s(addrinfo->comment, "\1"); strncat_s(addrinfo->comment, comment.c_str(), _TRUNCATE); } diff --git a/src/gui/Src/Gui/BreakpointsView.cpp b/src/gui/Src/Gui/BreakpointsView.cpp index 0f3ab381..610c27ee 100644 --- a/src/gui/Src/Gui/BreakpointsView.cpp +++ b/src/gui/Src/Gui/BreakpointsView.cpp @@ -458,7 +458,7 @@ void BreakpointsView::updateBreakpointsSlot() if(*bp.breakCondition) { next(); - colored("breakif", mSummaryKeywordColor); + colored(tr("breakif"), mSummaryKeywordColor); colored("(", mSummaryParenColor); text(bp.breakCondition); colored(")", mSummaryParenColor); @@ -475,17 +475,19 @@ void BreakpointsView::updateBreakpointsSlot() if(*bp.logText) { next(); - colored(tr("log"), mSummaryKeywordColor); if(*bp.logCondition) { - colored("if", mSummaryKeywordColor); + colored(tr("logif"), mSummaryKeywordColor); colored("(", mSummaryParenColor); text(bp.logCondition); colored(",", mSummaryParenColor); text(" "); } else + { + colored(tr("log"), mSummaryKeywordColor); colored("(", mSummaryParenColor); + } colored(QString("\"%1\"").arg(bp.logText), mSummaryStringColor); colored(")", mSummaryParenColor); } @@ -493,17 +495,19 @@ void BreakpointsView::updateBreakpointsSlot() if(*bp.commandText) { next(); - colored(tr("cmd"), mSummaryKeywordColor); if(*bp.commandCondition) { - colored("if", mSummaryKeywordColor); + colored(tr("cmdif"), mSummaryKeywordColor); colored("(", mSummaryParenColor); text(bp.commandCondition); colored(",", mSummaryParenColor); text(" "); } else + { + colored(tr("cmd"), mSummaryKeywordColor); colored("(", mSummaryParenColor); + } colored(QString("\"%1\"").arg(bp.commandText), mSummaryStringColor); colored(")", mSummaryParenColor); }