From 9c9938e0662fa3b5cb48a79a10bf5e53edddb19b Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Wed, 30 Jul 2025 19:32:34 +0000 Subject: [PATCH] GP-5889 Check for common source in duplicated switch guard detection --- .../src/decompile/cpp/coreaction.cc | 30 ++++++++++++------- .../src/decompile/cpp/coreaction.hh | 5 ++-- .../Decompiler/src/decompile/cpp/jumptable.cc | 23 ++++++++++++-- .../Decompiler/src/decompile/cpp/jumptable.hh | 1 + 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index c76121c410..2d0a90edb8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -2169,8 +2169,19 @@ int4 ActionLikelyTrash::apply(Funcdata &data) return 0; } +/// \param vn is the given Varnode +/// \return \b true if it is a constant or a COPY of a constant +bool ActionRestructureVarnode::isCopyConstant(Varnode *vn) + +{ + if (vn->isConstant()) return true; + if (!vn->isWritten()) return false; + if (vn->getDef()->code() != CPUI_COPY) return false; + return vn->getDef()->getIn(0)->isConstant(); +} + /// Return \b true if either the Varnode is a constant or if it is the not yet simplified -/// INT_ADD of constants. +/// COPY or INT_ADD of constants. /// \param vn is the given Varnode to test /// \return \b true if the Varnode will be a constant bool ActionRestructureVarnode::isDelayedConstant(Varnode *vn) @@ -2179,14 +2190,13 @@ bool ActionRestructureVarnode::isDelayedConstant(Varnode *vn) if (vn->isConstant()) return true; if (!vn->isWritten()) return false; PcodeOp *op = vn->getDef(); - if (op->code() != CPUI_INT_ADD) return false; - if (!op->getIn(1)->isConstant()) return false; - Varnode *cvn = op->getIn(0); - if (cvn->isConstant()) return true; - if (!cvn->isWritten()) return false; - PcodeOp *copy = cvn->getDef(); - if (copy->code() != CPUI_COPY) return false; - return copy->getIn(0)->isConstant(); + OpCode opc = op->code(); + if (opc == CPUI_COPY) + return op->getIn(0)->isConstant(); + if (opc != CPUI_INT_ADD) return false; + if (!isCopyConstant(op->getIn(1))) return false; + if (!isCopyConstant(op->getIn(0))) return false; + return true; } /// Test if the path to the given BRANCHIND originates from a constant but passes through INDIRECT operations. @@ -5349,7 +5359,7 @@ void ActionDatabase::buildDefaultGroups(void) setGroup("decompile",members); const char *jumptab[] = { "base", "noproto", "localrecovery", "deadcode", "stackptrflow", - "stackvars", "analysis", "segment", "subvar", "conditionalexe", "" }; + "stackvars", "analysis", "segment", "subvar", "normalizebranches", "conditionalexe", "" }; setGroup("jumptable",jumptab); const char *normali[] = { "base", "protorecovery", "protorecovery_b", "deindirect", "localrecovery", diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh index 3c6ac0fa4c..19a1be62b5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -831,6 +831,7 @@ public: /// This produces on intermediate view of symbols on the stack. class ActionRestructureVarnode : public Action { int4 numpass; ///< Number of passes performed for this function + static bool isCopyConstant(Varnode *vn); ///< Is the given Varnode a constant or a COPY of a constant static bool isDelayedConstant(Varnode *vn); ///< Determine if given Varnode is or will be a constant static void protectSwitchPathIndirects(PcodeOp *op); ///< Protect path to the given switch from INDIRECT collapse static void protectSwitchPaths(Funcdata &data); ///< Look for switches and protect path of switch variable diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc index 860a07a594..ba71812299 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc @@ -1284,6 +1284,18 @@ bool JumpBasic::flowsOnlyToModel(Varnode *vn,PcodeOp *trailOp) return true; } +/// \param arr is the array of Varnodes +/// \return \b true if all elements are the same +bool JumpBasic::duplicateVarnodes(const vector &arr) + +{ + Varnode *vn = arr[0]; + for(int4 i=1;igetIn(0)->getFlipPath() ? 1-indpath : indpath; PcodeOp *readOp = cbranch; for(int4 j=0;jfindMultiequal(varArray); - if (multiOp != (PcodeOp *)0) { - selectguards.push_back(GuardRecord(cbranch,readOp,indpathstore,rng,multiOp->getOut(),true)); + if (duplicateVarnodes(varArray)) { + selectguards.push_back(GuardRecord(cbranch,readOp,indpathstore,rng,varArray[0],true)); + } + else { + PcodeOp *multiOp = bl->findMultiequal(varArray); + if (multiOp != (PcodeOp *)0) { + selectguards.push_back(GuardRecord(cbranch,readOp,indpathstore,rng,multiOp->getOut(),true)); + } } Varnode *markup; // Throw away markup information Varnode *vn = varArray[0]; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh index eb6e1d7d11..2b1b121258 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh @@ -382,6 +382,7 @@ protected: static int4 getStride(Varnode *vn); ///< Get the step/stride associated with the Varnode static uintb backup2Switch(Funcdata *fd,uintb output,Varnode *outvn,Varnode *invn); static uintb getMaxValue(Varnode *vn); ///< Get maximum value associated with the given Varnode + static bool duplicateVarnodes(const vector &arr); ///< Return \b true if all array elements are the same Varnode void findDeterminingVarnodes(PcodeOp *op,int4 slot); void analyzeGuards(BlockBasic *bl,int4 pathout); void calcRange(Varnode *vn,CircleRange &rng) const;