diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc index a53c48e11c..70ff12994a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc @@ -1030,6 +1030,21 @@ PcodeOp *PathMeld::getEarliestOp(int4 pos) const return (PcodeOp *)0; } +/// Search for a Varnode in the common path, prior to the given point, defined by a LOAD operation. +/// \param i is the given point in the path +/// \return \b true if a LOAD is present +bool PathMeld::isLoadInPath(int4 i) const + +{ + while(i > 0) { + i -= 1; + Varnode *vn = commonVn[i]; + if (!vn->isWritten()) continue; + if (vn->getDef()->code() == CPUI_LOAD) return true; + } + return false; +} + /// \brief Analyze CBRANCHs leading up to the given basic-block as a potential switch \e guard. /// /// In general there is only one path to the switch, and the given basic-block will @@ -1180,8 +1195,10 @@ void JumpBasic::findSmallestNormal(uint4 matchsize) calcRange(pathMeld.getVarnode(i),rng); sz = rng.getSize(); if (sz < maxsize) { - // Don't let a 1-byte switch variable get thru without a guard - if ((sz != 256)||(pathMeld.getVarnode(i)->getSize()!=1)) { + // Don't accept a 1-byte switch variable unless there is an explicit guard + // or a table lookup between the byte and the indirect jump. + // "goto *(#const + byteVar)" should not be interpreted as 256 case switch + if (sz != 256 || pathMeld.getVarnode(i)->getSize()!=1 || pathMeld.isLoadInPath(i)) { varnodeIndex = i; maxsize = sz; jrange->setRange(rng); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh index c6486103f7..a0206545b0 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh @@ -98,6 +98,7 @@ public: Varnode *getOpParent(int4 i) const { return commonVn[ opMeld[i].rootVn ]; } ///< Get the split-point for the i-th PcodeOp PcodeOp *getOp(int4 i) const { return opMeld[i].op; } ///< Get the i-th PcodeOp PcodeOp *getEarliestOp(int4 pos) const; ///< Find \e earliest PcodeOp that has a specific common Varnode as input + bool isLoadInPath(int4 i) const; ///< Return \b true if a LOAD exists in the common path bool empty(void) const { return commonVn.empty(); } ///< Return \b true if \b this container holds no paths }; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index 962c525b7f..6dc548520b 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -4630,6 +4630,9 @@ void TypeFactory::decodeAlignmentMap(Decoder &decoder) alignMap[sz] = val; decoder.closeElement(mapId); } + if (alignMap.empty()) + throw LowlevelError("Alignment map empty"); + alignMap[0] = 1; int4 curAlign = 1; for(int4 sz=1;sz < alignMap.size();++sz) { int4 tmpAlign = alignMap[sz]; @@ -4644,7 +4647,7 @@ void TypeFactory::decodeAlignmentMap(Decoder &decoder) void TypeFactory::setDefaultAlignmentMap(void) { - alignMap.resize(9,0); + alignMap.resize(9,1); alignMap[1] = 1; alignMap[2] = 2; alignMap[3] = 2;