findConstants.h

Go to the documentation of this file.
00001 /* The primary purpose of this header file is to define a "policy" for instruction semantics such as for the
00002  * X86InstructionSemantics class. This particular policy is for tracking the flow of constant values. */
00003 
00004 #ifndef findConstants_H
00005 #define findConstants_H
00006 
00007 #include "x86InstructionSemantics.h"
00008 #include "integerOps.h"
00009 #include "flowEquations.h"
00010 
00011 #include <cassert>
00012 #include <cstdio>
00013 #include <boost/lexical_cast.hpp>
00014 
00024 template <size_t Len>                         // Sums are modulo 2^Len
00025 struct LatticeElement {
00026     bool isTop;
00027     uint64_t name;                            // 0 for constants, a nonzero ID number for everything else
00028     SgAsmx86Instruction* definingInstruction; // Functionally dependent on name (mostly for debugging)
00029     bool negate;                              // Switch between name+offset and -name+offset; should be false for constants
00030     uint64_t offset;                          // Offset from name
00031 
00032     /* Constructs a "top" lattice element */
00033     LatticeElement()
00034         : isTop(true), name(0), definingInstruction(NULL), negate(false), offset(0)
00035         {}
00036 
00037     /* Construct a named lattice element (no offset) */
00038     static LatticeElement nonconstant(uint64_t name, SgAsmx86Instruction* definingInstruction) {
00039         return LatticeElement(name, definingInstruction, false, 0);
00040     }
00041 
00042     /* Construct a non-top, named lattice element with optional offset. */
00043     LatticeElement(uint64_t name, SgAsmx86Instruction* definingInstruction, bool negate, uint64_t offset)
00044         : isTop(false), name(name), definingInstruction(definingInstruction), negate(negate),
00045           offset(offset & (IntegerOps::GenMask<uint64_t, Len>::value))
00046         {}
00047 
00048     /* Construct a named lattice element with optional offset. */
00049     LatticeElement(bool isTop, uint64_t name, SgAsmx86Instruction* definingInstruction, bool negate, uint64_t offset)
00050         : isTop(isTop), name(name), definingInstruction(definingInstruction), negate(negate),
00051           offset(offset & (IntegerOps::GenMask<uint64_t, Len>::value))
00052         {}
00053 
00054     /* Construct a constant lattice element */
00055     static LatticeElement constant(uint64_t c, SgAsmx86Instruction* definingInstruction) {
00056         return LatticeElement(0, definingInstruction, false, c);
00057     }
00058 
00059     friend bool operator==(const LatticeElement& a, const LatticeElement& b) {
00060         if (a.isTop != b.isTop) return false;
00061         if (a.isTop) return true;
00062         return a.name == b.name && (a.name == 0 || a.negate == b.negate) && a.offset == b.offset;
00063     }
00064     friend bool operator<(const LatticeElement& a, const LatticeElement& b) { // Arbitrary order
00065         if (a.isTop < b.isTop) return true;
00066         if (b.isTop < a.isTop) return false;
00067         if (a.name < b.name) return true;
00068         if (b.name < a.name) return false;
00069         if (a.name != 0 && a.negate < b.negate) return true;
00070         if (a.name != 0 && b.negate < a.negate) return false;
00071         return a.offset < b.offset;
00072     }
00073     void merge(const LatticeElement& elt, uint64_t newName, SgAsmx86Instruction* def) {
00074         if (elt.isTop) return;
00075         if (this->isTop) {
00076             *this = elt;
00077             return;
00078         }
00079         if (*this == elt)
00080             return;
00081         this->isTop = false;
00082         this->name = newName;
00083         this->definingInstruction = def;
00084         this->negate = false;
00085         this->offset = 0;
00086         return;
00087     }
00088 };
00089 
00096 template <size_t Len>
00097 std::ostream& operator<<(std::ostream& o, const LatticeElement<Len>& e)
00098 {
00099     if (e.isTop) {
00100         o << "<top>";
00101     } else {
00102         uint64_t sign_bit = (uint64_t)1 << (Len-1);  /* e.g., 80000000 */
00103         uint64_t val_mask = sign_bit - 1;            /* e.g., 7fffffff */
00104         uint64_t negative = (e.offset & sign_bit) ? (~e.offset & val_mask) + 1 : 0; /*magnitude of negative value*/
00105 
00106         if (e.name!=0) {
00107             /* This is a named value rather than a constant. */
00108             const char *sign = e.negate ? "-" : "";
00109             o <<sign <<"v" <<std::dec <<e.name;
00110             if (negative) {
00111                 o <<"-0x" <<std::hex <<negative;
00112             } else if (e.offset) {
00113                 o <<"+0x" <<std::hex <<e.offset;
00114             }
00115         } else {
00116             /* This is a constant */
00117             ROSE_ASSERT(!e.negate);
00118             o  <<"0x" <<std::hex <<e.offset;
00119             if (negative)
00120                 o <<" (-0x" <<std::hex <<negative <<")";
00121         }
00122         if (e.definingInstruction!=NULL)
00123             o << " [from " << unparseInstructionWithAddress(e.definingInstruction) << "]";
00124     }
00125     return o;
00126 }
00127 
00129 extern uint64_t xvarNameCounter;
00130 
00133 extern SgAsmx86Instruction* currentInstruction;
00134 
00135 template <size_t Len>
00136 struct XVariable: public Variable { /*Variable defined in flowEquations.h*/
00137     LatticeElement<Len> value;
00138     uint64_t myName;
00139     SgAsmx86Instruction* def;
00140     XVariable()
00141         : value(), myName(++xvarNameCounter), def(currentInstruction)
00142         {}
00143 
00145     void set(const LatticeElement<Len>& le) {
00146         LatticeElement<Len> newValue = value;
00147         newValue.merge(le, myName, def);
00148         if (value == newValue)
00149             return;
00150         value = newValue;
00151         this->pushChanges();
00152     }
00153 
00155     LatticeElement<Len> get() const {
00156         return value;
00157     }
00158 };
00159 
00161 template <size_t Len>
00162 struct XVariablePtr {
00163     XVariable<Len>* var;
00164     XVariablePtr()
00165         : var(NULL)
00166         {}
00167     XVariablePtr(XVariable<Len>* var)
00168         : var(var)
00169         {}
00170     operator XVariable<Len>*() const {
00171         return var;
00172     }
00173     XVariable<Len>* operator->() const {
00174         return var;
00175     }
00176     static XVariablePtr bottom() {
00177         struct BottomConstraint: public Constraint {
00178             XVariablePtr<Len> var;
00179             BottomConstraint(XVariablePtr<Len> var)
00180                 : var(var)
00181                 {}
00182             virtual void run() const {
00183                 var->set(LatticeElement<Len>::nonconstant(var->myName, var->def));
00184             }
00185             virtual void markDependencies() {}
00186         };
00187         XVariablePtr<Len> var = new XVariable<Len>();
00188         (new BottomConstraint(var))->activate();
00189         return var;
00190     }
00191 };
00192 
00193 template <size_t Len>
00194 std::ostream& operator<<(std::ostream& o, XVariablePtr<Len> v) {
00195     o << v->value;
00196     return o;
00197 }
00198 
00201 struct MemoryWrite {
00202     LatticeElement<32> address;
00203     LatticeElement<32> data;
00204     unsigned int len;
00205     friend bool operator==(const MemoryWrite& a, const MemoryWrite& b) {
00206         return a.address == b.address && a.data == b.data && a.len == b.len;
00207     }
00208     friend bool operator<(const MemoryWrite& a, const MemoryWrite& b) {
00209         return a.address < b.address;
00210     }
00211 };
00212 
00213 bool mayAlias(const MemoryWrite&, const MemoryWrite&);
00214 bool mustAlias(const MemoryWrite&, const MemoryWrite&);
00215 
00216 template <size_t From, size_t To>
00217 XVariablePtr<To> unsignedExtend(XVariablePtr<From>);
00218 
00219 template <size_t From, size_t To, size_t Len>
00220 XVariablePtr<To - From> extract(XVariablePtr<Len>);
00221 
00223 /* FIXME: Why are addresses and data always 32 bits? Will this work for a 64-bit architecture? [RPM 2009-02-03] */
00224 struct MemoryWriteSet {
00225     bool isTop;
00226     std::vector<MemoryWrite> writes;         /* Always sorted by address */
00227 
00228     MemoryWriteSet()
00229         : isTop(true), writes()
00230         {}
00231 
00233     void addWrite(LatticeElement<32> address, LatticeElement<32> data, unsigned int len) {
00234         isTop = false;
00235         MemoryWrite mw;
00236         mw.address = address;
00237         mw.data = data;
00238         mw.len = len;
00239         std::vector<MemoryWrite> newWrites;
00240         for (size_t i = 0; i < writes.size(); ++i) {
00241             if (!mayAlias(writes[i], mw))
00242                 newWrites.push_back(writes[i]);
00243         }
00244         newWrites.push_back(mw);
00245         writes = newWrites;
00246         std::sort(writes.begin(), writes.end());
00247     }
00248 
00250     template <size_t Len> // In bits
00251     bool getValueAtAddress(LatticeElement<32> address, LatticeElement<Len>& result, uint32_t resultName,
00252                            SgAsmx86Instruction* resultDef) const {
00253         /* Construct the MemoryWrite object for the address in question since it's needed by mustAlias() */
00254         MemoryWrite mw;
00255         mw.address = address;
00256         mw.data = LatticeElement<32>::constant(0, resultDef);
00257         mw.len = Len / 8;
00258 
00259         /* Scan vector until we find a match and then return that value. */
00260         for (size_t i = 0; i < writes.size(); ++i) {
00261             if (mustAlias(writes[i], mw)) {
00262                 //std::cout << "Found data " << writes[i].data << " for address " << address << std::endl;
00263                 const LatticeElement<32>& data = writes[i].data;
00264                 result = LatticeElement<Len>(data.isTop, data.name, data.definingInstruction, data.negate, data.offset);
00265                 return true;
00266             }
00267         }
00268 
00269         /* No match found */
00270         result = isTop ? LatticeElement<Len>() : LatticeElement<Len>::nonconstant(resultName, resultDef);
00271         return false;
00272     }
00273 
00274     static MemoryWriteSet bottom() {
00275         MemoryWriteSet mws;
00276         mws.isTop = false;
00277         mws.writes.clear();
00278         return mws;
00279     }
00280 
00281     bool mergeIn(const MemoryWriteSet& o) { // Returns to determine whether changes were made
00282         if (o.isTop)
00283             return false;
00284         if (this->isTop) {
00285             *this = o;
00286             return !o.isTop;
00287         }
00288         bool result = !writes.empty();
00289         *this = bottom(); // FIXME [JJW]
00290         return result;
00291     }
00292 
00293     friend bool operator==(const MemoryWriteSet& a, const MemoryWriteSet& b) {
00294         return a.isTop == b.isTop && (a.isTop || a.writes == b.writes);
00295     }
00296 };
00297 
00298 struct MemoryVariable: public Variable {
00299     MemoryWriteSet mws;
00300     MemoryVariable()
00301         : mws()
00302         {}
00303     void set(const MemoryWriteSet& s) {
00304         if (mws.mergeIn(s)) this->pushChanges();
00305     }
00306     const MemoryWriteSet& get() const {
00307         return mws;
00308     }
00309 };
00310 
00311 template <size_t OutputLen>
00312 struct NullaryConstraint: public Constraint {
00313     XVariablePtr<OutputLen> result;
00314     NullaryConstraint(XVariablePtr<OutputLen> result): result(result) {}
00315     virtual void run() const {
00316         uint64_t newVal = this->compute();
00317         result->set(LatticeElement<OutputLen>::constant(newVal, result->def));
00318     }
00319     virtual void markDependencies() {}
00320     virtual uint64_t compute() const = 0;
00321 };
00322 
00323 template <size_t InputLen, size_t OutputLen>
00324 struct UnaryConstraint: public Constraint {
00325     XVariablePtr<OutputLen> result;
00326     XVariablePtr<InputLen> var;
00327     UnaryConstraint(XVariablePtr<OutputLen> result, XVariablePtr<InputLen> var)
00328         : result(result), var(var)
00329         {}
00330     virtual void run() const {
00331         LatticeElement<InputLen> le = var->get();
00332         if (le.isTop) {result->set(LatticeElement<OutputLen>()); return;}
00333         if (le.name != 0) {result->set(LatticeElement<OutputLen>::nonconstant(result->myName, result->def)); return;}
00334         uint64_t newVal = this->compute(le.offset);
00335         result->set(LatticeElement<OutputLen>::constant(newVal, result->def));
00336     }
00337     virtual void markDependencies() {
00338         addDependency(var);
00339     }
00340     virtual uint64_t compute(uint64_t a) const = 0;
00341 };
00342 
00343 #define UNARY_COMPUTATION(name, InLen, OutLen, Formula)                                                                        \
00344     XVariablePtr<(OutLen)> name(XVariablePtr<(InLen)> a) {                                                                     \
00345         XVariablePtr<(OutLen)> result = new XVariable<(OutLen)>();                                                             \
00346         struct IC: public UnaryConstraint<(InLen), (OutLen)> {                                                                 \
00347             IC(XVariablePtr<(OutLen)> result, XVariablePtr<(InLen)> var1)                                                      \
00348                 : UnaryConstraint<(InLen), (OutLen)>(result, var1)                                                             \
00349                 {}                                                                                                             \
00350             virtual uint64_t compute(uint64_t a) const {                                                                       \
00351                 Formula                                                                                                        \
00352             }                                                                                                                  \
00353         };                                                                                                                     \
00354         (new IC(result, a))->activate();                                                                                       \
00355         return result;                                                                                                         \
00356     }
00357 
00358 #define UNARY_COMPUTATION_SPECIAL(name, InLen1, OutLen, Formula)                                                               \
00359     XVariablePtr<(OutLen)> name(XVariablePtr<(InLen1)> a) {                                                                    \
00360         XVariablePtr<(OutLen)> result = new XVariable<(OutLen)>();                                                             \
00361         struct IC: public UnaryConstraint<(InLen1), (OutLen)> {                                                                \
00362             IC(XVariablePtr<(OutLen)> result, XVariablePtr<(InLen1)> var1)                                                     \
00363                 : UnaryConstraint<(InLen1), (OutLen)>(result, var1)                                                            \
00364                 {}                                                                                                             \
00365             virtual void run() const {                                                                                         \
00366                 LatticeElement<(InLen1)> le1 = UnaryConstraint<(InLen1), (OutLen)>::var->get();                                \
00367                 XVariablePtr<(OutLen)> result = UnaryConstraint<(InLen1), (OutLen)>::result;                                   \
00368                 if (le1.isTop) {result->set(LatticeElement<(OutLen)>()); return;}                                              \
00369                 Formula                                                                                                        \
00370             }                                                                                                                  \
00371             virtual uint64_t compute(uint64_t) const {abort();}                                                                \
00372         };                                                                                                                     \
00373         (new IC(result, a))->activate();                                                                                       \
00374         return result;                                                                                                         \
00375     }
00376 
00377 template <size_t InputLen1, size_t InputLen2, size_t OutputLen>
00378 struct BinaryConstraint: public Constraint {
00379     XVariablePtr<OutputLen> result;
00380     XVariablePtr<InputLen1> var1;
00381     XVariablePtr<InputLen2> var2;
00382 
00383     BinaryConstraint(XVariablePtr<OutputLen> result, XVariablePtr<InputLen1> var1, XVariablePtr<InputLen2> var2)
00384         : result(result), var1(var1), var2(var2)
00385         {}
00386 
00387     virtual void run() const {
00388         LatticeElement<InputLen1> le1 = var1->get();
00389         LatticeElement<InputLen2> le2 = var2->get();
00390         if (le1.isTop || le2.isTop) {
00391             result->set(LatticeElement<OutputLen>());
00392             return;
00393         }
00394         if (le1.name != 0 || le2.name != 0) {
00395             result->set(LatticeElement<OutputLen>::nonconstant(result->myName, result->def));
00396             return;
00397         }
00398         uint64_t newVal = this->compute(le1.offset, le2.offset);
00399         result->set(LatticeElement<OutputLen>::constant(newVal, result->def));
00400     }
00401 
00402     virtual void markDependencies() {
00403         addDependency(var1);
00404         addDependency(var2);
00405     }
00406     virtual uint64_t compute(uint64_t a, uint64_t b) const = 0;
00407 };
00408 
00409 #define BINARY_COMPUTATION(name, InLen1, InLen2, OutLen, Formula)                                                              \
00410     XVariablePtr<(OutLen)> name(XVariablePtr<(InLen1)> a, XVariablePtr<(InLen2)> b) {                                          \
00411         XVariablePtr<(OutLen)> result = new XVariable<(OutLen)>();                                                             \
00412         struct IC: public BinaryConstraint<(InLen1), (InLen2), (OutLen)> {                                                     \
00413             IC(XVariablePtr<(OutLen)> result, XVariablePtr<(InLen1)> var1, XVariablePtr<(InLen2)> var2)                        \
00414                 : BinaryConstraint<(InLen1), (InLen2), (OutLen)>(result, var1, var2)                                           \
00415                 {}                                                                                                             \
00416             virtual uint64_t compute(uint64_t a, uint64_t b) const {                                                           \
00417                 Formula                                                                                                        \
00418             }                                                                                                                  \
00419         };                                                                                                                     \
00420         (new IC(result, a, b))->activate();                                                                                    \
00421         return result;                                                                                                         \
00422     }
00423 
00424 #define BINARY_COMPUTATION_SPECIAL(name, InLen1, InLen2, OutLen, Formula)                                                      \
00425     XVariablePtr<(OutLen)> name(XVariablePtr<(InLen1)> a, XVariablePtr<(InLen2)> b) {                                          \
00426         XVariablePtr<(OutLen)> result = new XVariable<(OutLen)>();                                                             \
00427         struct IC: public BinaryConstraint<(InLen1), (InLen2), (OutLen)> {                                                     \
00428             IC(XVariablePtr<(OutLen)> result, XVariablePtr<(InLen1)> var1, XVariablePtr<(InLen2)> var2)                        \
00429                 : BinaryConstraint<(InLen1), (InLen2), (OutLen)>(result, var1, var2)                                           \
00430                 {}                                                                                                             \
00431             virtual void run() const {                                                                                         \
00432                 LatticeElement<(InLen1)> le1 = BinaryConstraint<(InLen1), (InLen2), (OutLen)>::var1->get();                    \
00433                 LatticeElement<(InLen2)> le2 = BinaryConstraint<(InLen1), (InLen2), (OutLen)>::var2->get();                    \
00434                 XVariablePtr<(OutLen)> result = BinaryConstraint<(InLen1), (InLen2), (OutLen)>::result;                        \
00435                 if (le1.isTop || le2.isTop) {                                                                                  \
00436                     result->set(LatticeElement<(OutLen)>());                                                                   \
00437                     return;                                                                                                    \
00438                 }                                                                                                              \
00439                 Formula                                                                                                        \
00440             }                                                                                                                  \
00441             virtual uint64_t compute(uint64_t, uint64_t) const {                                                               \
00442                 abort();                                                                                                       \
00443             }                                                                                                                  \
00444         };                                                                                                                     \
00445         (new IC(result, a, b))->activate();                                                                                    \
00446         return result;                                                                                                         \
00447     }
00448 
00449 template <size_t InputLen1, size_t InputLen2, size_t InputLen3, size_t OutputLen>
00450 struct TernaryConstraint: public Constraint {
00451     XVariablePtr<OutputLen> result;
00452     XVariablePtr<InputLen1> var1;
00453     XVariablePtr<InputLen2> var2;
00454     XVariablePtr<InputLen3> var3;
00455 
00456     TernaryConstraint(XVariablePtr<OutputLen> result,
00457                       XVariablePtr<InputLen1> var1, XVariablePtr<InputLen2> var2, XVariablePtr<InputLen3> var3)
00458         : result(result), var1(var1), var2(var2), var3(var3)
00459         {}
00460 
00461     virtual void run() const {
00462         LatticeElement<InputLen1> le1 = var1->get();
00463         LatticeElement<InputLen2> le2 = var2->get();
00464         LatticeElement<InputLen3> le3 = var3->get();
00465         if (le1.isTop || le2.isTop || le3.isTop) {
00466             result->set(LatticeElement<OutputLen>());
00467             return;
00468         }
00469         if (le1.name != 0 || le2.name != 0 || le3.name != 0) {
00470             result->set(LatticeElement<OutputLen>::nonconstant(result->myName, result->def));
00471             return;
00472         }
00473         uint64_t newVal = this->compute(le1.offset, le2.offset, le3.offset);
00474         result->set(LatticeElement<OutputLen>::constant(newVal, result->def));
00475     }
00476 
00477     virtual void markDependencies() {
00478         addDependency(var1);
00479         addDependency(var2);
00480         addDependency(var3);
00481     }
00482 
00483     virtual uint64_t compute(uint64_t a, uint64_t b, uint64_t c) const = 0;
00484 };
00485 
00486 #define TERNARY_COMPUTATION(name, InLen1, InLen2, InLen3, OutLen, Formula)                                                     \
00487     XVariablePtr<(OutLen)> name(XVariablePtr<(InLen1)> a, XVariablePtr<(InLen2)> b, XVariablePtr<(InLen3)> c) {                \
00488         XVariable<(OutLen)>* result = new XVariable<(OutLen)>();                                                               \
00489         struct IC: public TernaryConstraint<(InLen1), (InLen2), (InLen3), (OutLen)> {                                          \
00490             IC(XVariablePtr<(OutLen)> result,                                                                                  \
00491                XVariablePtr<(InLen1)> var1, XVariablePtr<(InLen2)> var2, XVariablePtr<(InLen3)> var3)                          \
00492                 : TernaryConstraint<(InLen1), (InLen2), (InLen3), (OutLen)>(result, var1, var2, var3)                          \
00493                 {}                                                                                                             \
00494             virtual uint64_t compute(uint64_t a, uint64_t b, uint64_t c) const {                                               \
00495                 Formula                                                                                                        \
00496             }                                                                                                                  \
00497         };                                                                                                                     \
00498         (new IC(result, a, b, c))->activate();                                                                                 \
00499         return result;                                                                                                         \
00500     }
00501 
00502 #define TERNARY_COMPUTATION_SPECIAL(name, InLen1, InLen2, InLen3, OutLen, Formula)                                             \
00503     XVariablePtr<(OutLen)> name(XVariablePtr<(InLen1)> a, XVariablePtr<(InLen2)> b, XVariablePtr<(InLen3)> c) {                \
00504         XVariablePtr<(OutLen)> result = new XVariable<(OutLen)>();                                                             \
00505         struct IC: public TernaryConstraint<(InLen1), (InLen2), (InLen3), (OutLen)> {                                          \
00506             IC(XVariablePtr<(OutLen)> result,                                                                                  \
00507                XVariablePtr<(InLen1)> var1, XVariablePtr<(InLen2)> var2, XVariablePtr<(InLen3)> var3)                          \
00508                 : TernaryConstraint<(InLen1), (InLen2), (InLen3), (OutLen)>(result, var1, var2, var3)                          \
00509                 {}                                                                                                             \
00510             virtual void run() const {                                                                                         \
00511                 LatticeElement<(InLen1)> le1 = TernaryConstraint<(InLen1), (InLen2), (InLen3), (OutLen)>::var1->get();         \
00512                 LatticeElement<(InLen2)> le2 = TernaryConstraint<(InLen1), (InLen2), (InLen3), (OutLen)>::var2->get();         \
00513                 LatticeElement<(InLen3)> le3 = TernaryConstraint<(InLen1), (InLen2), (InLen3), (OutLen)>::var3->get();         \
00514                 XVariablePtr<(OutLen)> result = TernaryConstraint<(InLen1), (InLen2), (InLen3), (OutLen)>::result;             \
00515                 if (le1.isTop || le2.isTop || le3.isTop) {                                                                     \
00516                     result->set(LatticeElement<(OutLen)>());                                                                   \
00517                     return;                                                                                                    \
00518                 }                                                                                                              \
00519                 Formula                                                                                                        \
00520             }                                                                                                                  \
00521             virtual uint64_t compute(uint64_t, uint64_t, uint64_t) const {                                                     \
00522                 abort();                                                                                                       \
00523             }                                                                                                                  \
00524         };                                                                                                                     \
00525         (new IC(result, a, b, c))->activate();                                                                                 \
00526         return result;                                                                                                         \
00527     }
00528 
00529 
00530 template <size_t Len>
00531 struct MergeConstraint: public Constraint {
00532     XVariablePtr<Len> result;
00533     XVariablePtr<Len> var1;
00534     MergeConstraint(XVariablePtr<Len> result, XVariablePtr<Len> var1)
00535         : result(result), var1(var1)
00536         {}
00537     virtual void run() const {
00538         result->set(var1->get());
00539     }
00540     virtual void markDependencies() {
00541         addDependency(var1);
00542     }
00543 };
00544 
00545 struct MemoryMergeConstraint: public Constraint {
00546     MemoryVariable* result;
00547     MemoryVariable* var1;
00548     MemoryMergeConstraint(MemoryVariable* result, MemoryVariable* var1)
00549         : result(result), var1(var1)
00550         {}
00551     virtual void run() const {
00552         result->set(var1->get());
00553     }
00554     virtual void markDependencies() {
00555         addDependency(var1);
00556     }
00557 };
00558 
00559 struct RegisterSet {
00560     static const size_t n_gprs = 8;             
00561     static const size_t n_segregs = 6;          
00562     static const size_t n_flags = 32;           
00564     XVariablePtr<32> gpr[n_gprs];
00565     XVariablePtr<16> segreg[n_segregs];
00566     XVariablePtr<1> flag[n_flags];
00567     MemoryVariable* memoryWrites; // Undefined elements are bottom, no two elements can satisfy mayAlias
00568     
00569     RegisterSet() {
00570         for (size_t i = 0; i < n_gprs; ++i)
00571             gpr[i] = new XVariable<32>();
00572         for (size_t i = 0; i < n_segregs; ++i)
00573             segreg[i] = new XVariable<16>();
00574         for (size_t i = 0; i < 16; ++i)
00575             flag[i] = new XVariable<1>();
00576         memoryWrites = new MemoryVariable();
00577     }
00578 
00579     void setToBottom() {
00580         for (size_t i = 0; i < n_gprs; ++i)
00581             gpr[i] = XVariablePtr<32>::bottom();
00582         for (size_t i = 0; i < n_segregs; ++i)
00583             segreg[i] = XVariablePtr<16>::bottom();
00584         for (size_t i = 0; i < 16; ++i)
00585             flag[i] = XVariablePtr<1>::bottom();
00586         memoryWrites->set(MemoryWriteSet::bottom());
00587     }
00588 
00589     void mergeIn(const RegisterSet& rs) {
00590         for (size_t i = 0; i < n_gprs; ++i)
00591             (new MergeConstraint<32>(gpr[i], rs.gpr[i]))->activate();
00592         for (size_t i = 0; i < n_segregs; ++i)
00593             (new MergeConstraint<16>(segreg[i], rs.segreg[i]))->activate();
00594         for (size_t i = 0; i < 16; ++i)
00595             (new MergeConstraint<1>(flag[i], rs.flag[i]))->activate();
00596         (new MemoryMergeConstraint(memoryWrites, rs.memoryWrites))->activate();
00597     }
00598 
00600     std::string diff(const RegisterSet &orig, std::string prefix="") {
00601         std::ostringstream s;
00602         for (size_t i=0; i<n_gprs; i++) {
00603             if (!(orig.gpr[i]->get()==gpr[i]->get())) {
00604                 s <<prefix <<gprToString((X86GeneralPurposeRegister)i) <<" = " <<gpr[i] <<"\n";
00605             }
00606         }
00607         for (size_t i=0; i<n_segregs; i++) {
00608             if (!(orig.segreg[i]->get()==segreg[i]->get())) {
00609                 s <<prefix <<segregToString((X86SegmentRegister)i) <<" = " <<segreg[i] <<"\n";
00610             }
00611         }
00612         for (size_t i=0; i<16; i++) {
00613             if (!(orig.flag[i]->get()==flag[i]->get())) {
00614                 s <<prefix <<flagToString((X86Flag)i) << " = " <<flag[i] <<"\n";
00615             }
00616         }
00617         /* Show memory in this register set that is different than the original */
00618         if (!memoryWrites->get().isTop) {
00619             for (size_t i=0; i<memoryWrites->get().writes.size(); i++) {
00620                 LatticeElement<32> addr = memoryWrites->get().writes[i].address;
00621                 LatticeElement<32> orig_data;
00622                 if (!orig.memoryWrites->get().getValueAtAddress(addr, orig_data/*out*/, 0, NULL) ||
00623                     !(orig_data==memoryWrites->get().writes[i].data)) {
00624                     s <<prefix <<"mem @ " <<addr <<" = " <<memoryWrites->get().writes[i].data <<"\n";
00625                 }
00626             }
00627         }
00628         
00629 
00630         return s.str();
00631     }
00632     
00633 };
00634 
00635 std::ostream&
00636 operator<<(std::ostream& o, const RegisterSet& rs);
00637 
00638 struct FindConstantsPolicy {
00639     std::map<uint64_t, RegisterSet> rsets;
00640     RegisterSet cur_state, *orig_state;
00641     uint32_t addr;
00642     XVariablePtr<32> newIp; // To determine if it is a constant
00643     const RegisterDictionary *regdict;
00644     
00645     struct Exception {
00646         Exception(const std::string &mesg): mesg(mesg) {}
00647         friend std::ostream& operator<<(std::ostream &o, const Exception &e) {
00648             o <<"VirtualMachineSemantics exception: " <<e.mesg;
00649             return o;
00650         }
00651         std::string mesg;
00652     };
00653 
00654     FindConstantsPolicy()
00655         : orig_state(NULL), addr(0), regdict(NULL)
00656         {
00657             newIp = number<32>(0);
00658         }
00659 
00660     /* Use this constructor when performing constant propagation analysis on a function where you want the entry point of the
00661      * function to use the specified initial values. See FindConstantsPolicy::startInstruction() for how this is used. */
00662     FindConstantsPolicy(RegisterSet *initial_rs)
00663         : orig_state(initial_rs), addr(0), regdict(NULL) {}
00664 
00666     const RegisterDictionary *get_register_dictionary() const {
00667         return regdict ? regdict : RegisterDictionary::dictionary_pentium4();
00668     }
00669 
00671     void set_register_dictionary(const RegisterDictionary *regdict) {
00672         this->regdict = regdict;
00673     }
00674 
00675     /* Only used by number<>(uint64_t) below, but gcc-4.0.1 on OSX (Apple Inc. build 5484) does not like this struct to be
00676      * defined inside that function.  It results in strange warnings about an unrelated function in
00677      * x86InstructionSemantics.C having no return value. [RPM 2010-05-27] */
00678     template <size_t Len>
00679     struct NumberConstraint: public NullaryConstraint<Len> {
00680         uint64_t val;
00681         NumberConstraint(XVariablePtr<Len> var, uint64_t val)
00682             : NullaryConstraint<Len>(var), val(val)
00683             {}
00684         virtual uint64_t compute() const {
00685             return val;
00686         }
00687     };
00688         
00689     template <size_t Len>
00690     XVariablePtr<Len> number(uint64_t n) {
00691         XVariablePtr<Len> var = new XVariable<Len>();
00692         (new NumberConstraint<Len>(var, n))->activate();
00693         return var;
00694     }
00695 
00696     // Only safe when MSBs don't matter (i.e., you can't extract bits from something and then use this to put in zeros -- the
00697     // original bits will probably appear again)
00698     template <size_t Len, size_t Len2>
00699     static UNARY_COMPUTATION_SPECIAL(unsignedExtend, Len, Len2, {
00700             result->set(LatticeElement<Len2>(le1.name, le1.definingInstruction, le1.negate, le1.offset));
00701         })
00702 
00703     template <size_t From, size_t To, size_t Len>
00704     static UNARY_COMPUTATION_SPECIAL(extract, Len, To - From, {
00705             if (From == 0) {
00706                 result->set(LatticeElement<To - From>(le1.name, le1.definingInstruction, le1.negate, le1.offset));
00707                 return;
00708             }
00709             if (le1.name != 0) {
00710                 result->set(LatticeElement<To - From>::nonconstant(result->myName, result->def));
00711                 return;
00712             }
00713             result->set(LatticeElement<To - From>::constant((le1.offset >> From) & (IntegerOps::SHL1<uint64_t, To - From>::value - 1),
00714                                                             result->def));
00715         })
00716 
00717 
00718     template <size_t Len1, size_t Len2>
00719     BINARY_COMPUTATION(concat, Len1, Len2, Len1 + Len2, {
00720             return a | (b << Len1);
00721         })
00722 
00723     XVariablePtr<1> false_() {
00724         return number<1>(0);
00725     }
00726     XVariablePtr<1> true_() {
00727         return number<1>(1);
00728     }
00729     XVariablePtr<1> undefined_() {
00730         return new XVariable<1>();
00731     }
00732 
00733     template <size_t Len>
00734     UNARY_COMPUTATION_SPECIAL(invert, Len, Len, {
00735             if (le1.name == 0)
00736                 result->set(LatticeElement<Len>::constant(~le1.offset, result->def));
00737             else
00738                 result->set(LatticeElement<Len>(le1.name, le1.definingInstruction, !le1.negate, ~le1.offset));
00739         })
00740 
00741     template <size_t Len>
00742     UNARY_COMPUTATION_SPECIAL(negate, Len, Len, {
00743             if (le1.name == 0)
00744                 result->set(LatticeElement<Len>::constant(-le1.offset, result->def));
00745             else
00746                 result->set(LatticeElement<Len>(le1.name, le1.definingInstruction, !le1.negate, -le1.offset));
00747         })
00748 
00749     template <size_t Len>
00750     BINARY_COMPUTATION(and_, Len, Len, Len, {return (a & b);})
00751 
00752     template <size_t Len>
00753     BINARY_COMPUTATION(or_, Len, Len, Len, {return (a | b);})
00754 
00755     template <size_t Len>
00756     BINARY_COMPUTATION_SPECIAL(xor_, Len, Len, Len, {
00757             if (le1 == le2) {
00758                 result->set(LatticeElement<Len>::constant(0, result->def));
00759                 return;
00760             }
00761             if (le1.name == 0 && le2.name == 0) {
00762                 result->set(LatticeElement<Len>::constant(le1.offset ^ le2.offset, result->def));
00763                 return;
00764             }
00765             result->set(LatticeElement<Len>::nonconstant(result->myName, result->def));
00766         })
00767 
00768     template <size_t From, size_t To>
00769     UNARY_COMPUTATION(signExtend, From, To, {return (From==To ? (a) : IntegerOps::signExtend<From, To>(a));})
00770 
00771     template <size_t Len>
00772     XVariablePtr<Len> ite(XVariablePtr<1> sel, XVariablePtr<Len> ifTrue, XVariablePtr<Len> ifFalse) {
00773         XVariablePtr<Len> result = new XVariable<Len>();
00774         struct IteConstraint: public Constraint {
00775             XVariablePtr<Len> result;
00776             XVariablePtr<Len> ifTrue;
00777             XVariablePtr<Len> ifFalse;
00778             XVariablePtr<1> sel;
00779             IteConstraint(XVariablePtr<Len> result, XVariablePtr<1> sel, XVariablePtr<Len> ifTrue, XVariablePtr<Len> ifFalse)
00780                 : result(result), ifTrue(ifTrue), ifFalse(ifFalse), sel(sel)
00781                 {}
00782             virtual void run() const {
00783                 LatticeElement<Len> res;
00784                 if (sel->get().name != 0 || (sel->get().name == 0 && sel->get().offset == 1)) {
00785                     res.merge(ifTrue->get(), result->myName, result->def);
00786                 }
00787                 if (sel->get().name != 0 || (sel->get().name == 0 && sel->get().offset == 0)) {
00788                     res.merge(ifFalse->get(), result->myName, result->def);
00789                 }
00790                 result->set(res);
00791             }
00792             virtual void markDependencies() {
00793                 addDependency(sel);
00794                 addDependency(ifTrue);
00795                 addDependency(ifFalse);
00796             }
00797         };
00798         (new IteConstraint(result, sel, ifTrue, ifFalse))->activate();
00799         return result;
00800     }
00801 
00802     template <size_t Len>
00803     UNARY_COMPUTATION(equalToZero, Len, 1, {return (a == 0);})
00804 
00805     template <size_t Len, size_t SCLen>
00806     UNARY_COMPUTATION(generateMask, SCLen, Len, {return IntegerOps::genMask<uint64_t>(a);})
00807 
00808 #if 1
00809     template <size_t Len>
00810     BINARY_COMPUTATION_SPECIAL(add, Len, Len, Len, {
00811             if (le1.name == 0 || le2.name == 0) {
00812                 result->set(LatticeElement<Len>(le1.name + le2.name, result->def,
00813                                                 le1.negate || le2.negate, le1.offset + le2.offset));
00814                 return;
00815             }
00816             if (le1.name == le2.name && le1.negate == !le2.negate) {
00817                 result->set(LatticeElement<Len>::constant(le1.offset + le2.offset, result->def));
00818                 return;
00819             }
00820             result->set(LatticeElement<Len>::nonconstant(result->myName, result->def));
00821         })
00822 #else
00823     template <size_t Len>
00824     BINARY_COMPUTATION(add, Len, Len, Len, {return (a & b);})
00825 
00826 #endif
00827 
00828 
00829     template <size_t Len>
00830     TERNARY_COMPUTATION_SPECIAL(add3, Len, Len, 1, Len, {
00831             if ((le1.name == 0) + (le2.name == 0) + (le3.name == 0)) {
00832                 result->set(LatticeElement<Len>(le1.name + le2.name + le3.name, result->def,
00833                                                 le1.negate || le2.negate || le3.negate,
00834                                                 le1.offset + le2.offset + le3.offset));
00835                 return;
00836             }
00837             if (le1.name == le2.name && le3.name == 0 && le1.negate == !le2.negate) {
00838                 result->set(LatticeElement<Len>::constant(le1.offset + le2.offset + le3.offset, result->def));
00839                 return;
00840             }
00841             result->set(LatticeElement<Len>::nonconstant(result->myName, result->def));
00842         })
00843 
00844     template <size_t Len>
00845     TERNARY_COMPUTATION(xor3, Len, Len, Len, Len, {return (a ^ b ^ c);})
00846 
00847     template <size_t Len>
00848     XVariablePtr<Len> addWithCarries(XVariablePtr<Len> a, XVariablePtr<Len> b, XVariablePtr<1> carryIn,
00849                                      XVariablePtr<Len>& carries) { // Full case
00850         XVariablePtr<Len + 1> aa = unsignedExtend<Len, Len + 1>(a);
00851         XVariablePtr<Len + 1> bb = unsignedExtend<Len, Len + 1>(b);
00852         XVariablePtr<Len + 1> result = add3(aa, bb, carryIn);
00853         carries = extract<1, Len + 1>(xor3(aa, bb, result));
00854         return extract<0, Len>(result);
00855     }
00856 
00857     template <size_t Len, size_t SALen>
00858     BINARY_COMPUTATION(rotateLeft, Len, SALen, Len, {
00859             return IntegerOps::rotateLeft<Len>(a, b);
00860         })
00861 
00862     template <size_t Len, size_t SALen>
00863     BINARY_COMPUTATION(rotateRight, Len, SALen, Len, {
00864             return IntegerOps::rotateRight<Len>(a, b);
00865         })
00866 
00867     template <size_t Len, size_t SALen>
00868     BINARY_COMPUTATION(shiftLeft, Len, SALen, Len, {
00869             return IntegerOps::shiftLeft<Len>(a, b);
00870         })
00871 
00872     template <size_t Len, size_t SALen>
00873     BINARY_COMPUTATION(shiftRight, Len, SALen, Len, {
00874             return IntegerOps::shiftRightLogical<Len>(a, b);
00875         })
00876 
00877     template <size_t Len, size_t SALen>
00878     BINARY_COMPUTATION(shiftRightArithmetic, Len, SALen, Len, {
00879             return IntegerOps::shiftRightArithmetic<Len>(a, b);
00880         })
00881 
00882     template <size_t Len1, size_t Len2>
00883     BINARY_COMPUTATION(signedMultiply, Len1, Len2, Len1 + Len2, {
00884             return (IntegerOps::signExtend<Len1, 64>(a) * IntegerOps::signExtend<Len2, 64>(b));
00885         })
00886 
00887     template <size_t Len1, size_t Len2>
00888     BINARY_COMPUTATION(unsignedMultiply, Len1, Len2, Len1 + Len2, {
00889             return (a * b);
00890         })
00891 
00892     template <size_t Len1, size_t Len2>
00893     BINARY_COMPUTATION(signedDivide, Len1, Len2, Len1, {
00894             return (IntegerOps::signExtend<Len1, 64>(a) / IntegerOps::signExtend<Len2, 64>(b));
00895         })
00896 
00897     template <size_t Len1, size_t Len2>
00898     BINARY_COMPUTATION(signedModulo, Len1, Len2, Len2, {
00899             return (IntegerOps::signExtend<Len1, 64>(a) % IntegerOps::signExtend<Len2, 64>(b))
00900                 ;})
00901 
00902     template <size_t Len1, size_t Len2>
00903     BINARY_COMPUTATION(unsignedDivide, Len1, Len2, Len1, {
00904             if (0==b) throw std::string("division by zero");
00905             return (a / b);
00906         })
00907 
00908     template <size_t Len1, size_t Len2>
00909     BINARY_COMPUTATION(unsignedModulo, Len1, Len2, Len2, {
00910             return (a % b);
00911         })
00912 
00913     template <size_t Len>
00914     UNARY_COMPUTATION(leastSignificantSetBit, Len, Len, {
00915             for (int i = 0; i < (int)Len; ++i) {
00916                 if (a & IntegerOps::shl1<uint64_t>(i))
00917                     return i;
00918             }
00919             return 0;
00920         })
00921 
00922     template <size_t Len>
00923     UNARY_COMPUTATION(mostSignificantSetBit, Len, Len, {
00924             for (int i = (int)Len - 1; i >= 0; --i) {
00925                 if (a & IntegerOps::shl1<uint64_t>(i))
00926                     return i;
00927             }
00928             return 0;
00929         })
00930 
00931     XVariablePtr<32> filterIndirectJumpTarget(XVariablePtr<32> x) {
00932         return x;
00933     }
00934     XVariablePtr<32> filterCallTarget(XVariablePtr<32> x) {
00935         return x;
00936     }
00937     XVariablePtr<32> filterReturnTarget(XVariablePtr<32> x) {
00938         return x;
00939     }
00940 
00941     template <size_t Len> // In bits
00942     XVariablePtr<Len> readMemory(X86SegmentRegister segreg, XVariablePtr<32> addr, XVariablePtr<1> cond) {
00943         struct ReadMemoryConstraint: public Constraint {
00944             XVariablePtr<Len> result;
00945             MemoryVariable* memory;
00946             XVariablePtr<32> addr;
00947             virtual void run() const {
00948                 LatticeElement<Len> resultRaw;
00949                 const MemoryWriteSet &mws = memory->get();
00950                 mws.getValueAtAddress<Len>(addr->get(), resultRaw, result->myName, result->def);
00951                 result->set(resultRaw);
00952             }
00953             virtual void markDependencies() {
00954                 addDependency(memory);
00955                 addDependency(addr);
00956             }
00957         };
00958         ReadMemoryConstraint* c = new ReadMemoryConstraint();
00959         c->result = new XVariable<Len>();
00960         c->memory = cur_state.memoryWrites;
00961         c->addr = addr;
00962         c->activate();
00963         return c->result;
00964     }
00965 
00966     template <size_t Len>
00967     static MemoryVariable* memoryWriteHelper(MemoryVariable* memory, XVariablePtr<32> address, XVariablePtr<Len> data) {
00968         struct C: public Constraint {
00969             MemoryVariable* memory;
00970             XVariablePtr<32> address;
00971             XVariablePtr<Len> data;
00972             MemoryVariable* memoryOut;
00973             virtual void run() const {
00974                 MemoryWriteSet mws = memory->get();
00975                 mws.addWrite(address->get(), unsignedExtend<Len, 32>(data)->get(), Len / 8);
00976                 memoryOut->set(mws);
00977             }
00978             virtual void markDependencies() {addDependency(memory); addDependency(address); addDependency(data);}
00979         };
00980         C* c = new C();
00981         c->memory = memory;
00982         c->address = address;
00983         c->data = data;
00984         c->memoryOut = new MemoryVariable();
00985         c->activate();
00986         return c->memoryOut;
00987     }
00988 
00990     template <size_t Len>
00991     void writeMemory(X86SegmentRegister segreg, XVariablePtr<32> addr, XVariablePtr<Len> data, XVariablePtr<1> cond) {
00992         cur_state.memoryWrites = memoryWriteHelper(cur_state.memoryWrites, addr, data);
00993     }
00994 
00996     template <size_t nbits>
00997     void writeMemory(X86SegmentRegister segreg, XVariablePtr<32> addr, XVariablePtr<nbits> data, XVariablePtr<32> repeat,
00998                      XVariablePtr<1> cond) {
00999         /* If repeat is a constant then perform the write that number of times. */
01000         if (0==repeat->get().name) {
01001             for (size_t i=0; i<repeat->get().offset; i++) {
01002                 XVariablePtr<32> tmp_addr = add(addr, number<32>(i*nbits/8));
01003                 cur_state.memoryWrites = memoryWriteHelper(cur_state.memoryWrites, tmp_addr, data);
01004             }
01005         } else {
01006             cur_state.memoryWrites = memoryWriteHelper(cur_state.memoryWrites, addr, data);
01007         }
01008     }
01009 
01010     void hlt() {} // FIXME
01011 
01012     void cpuid() {} // FIXME
01013 
01014     void interrupt(uint8_t num) {
01015         cur_state.setToBottom();
01016     }
01017 
01018     void sysenter() {
01019         cur_state.setToBottom();
01020     }
01021 
01022     XVariablePtr<64> rdtsc() { // FIXME
01023         return number<64>(0);
01024     }
01025     void startBlock(uint64_t addr) {}
01026 
01027     void finishBlock(uint64_t addr) {}
01028 
01033     bool isInstructionExternallyVisible(SgAsmInstruction* insn) const {
01034         return isFunctionEntry(insn);
01035     }
01036 
01038     bool isFunctionEntry(SgAsmInstruction *insn) const {
01039         SgAsmFunction *fdefn = containingFunction(insn);
01040         ROSE_ASSERT(fdefn);
01041         SgAsmBlock *first_bb = isSgAsmBlock(fdefn->get_statementList()[0]);
01042         return first_bb->get_id()==insn->get_address();
01043     }
01044     
01046     SgAsmFunction *
01047     containingFunction(SgAsmInstruction *insn) const {
01048         SgAsmBlock *bb = isSgAsmBlock(insn->get_parent());
01049         ROSE_ASSERT(bb!=NULL);
01050         SgAsmFunction *fdefn = isSgAsmFunction(bb->get_parent());
01051         ROSE_ASSERT(fdefn!=NULL);
01052         return fdefn;
01053     }
01054 
01056     void startInstruction(SgAsmInstruction* insn) {
01057         addr = insn->get_address();
01058         newIp = number<32>(addr);
01059         if (isInstructionExternallyVisible(insn)) {
01060             if (orig_state) {
01061                 rsets[addr] = *orig_state;
01062                 orig_state = NULL;
01063             } else {
01064                 rsets[addr].setToBottom();
01065             }
01066         }
01067         cur_state = rsets[addr];
01068         currentInstruction = isSgAsmx86Instruction(insn);
01069     }
01070 
01073     void finishInstruction(SgAsmInstruction* insn) {
01074         currentInstruction = NULL;
01075         SgAsmx86Instruction* insnx = isSgAsmx86Instruction(insn);
01076         ROSE_ASSERT (insnx);
01077         std::vector<uint64_t> succs;
01078         if (newIp->get().name == 0) {
01079             /* We know the address of the next instruction. */
01080             succs.push_back(newIp->get().offset);
01081         } else {
01082             /* We don't know the address of the next instruction, so compute it from successors */
01083             uint64_t nextAddr = insnx->get_address() + insnx->get_raw_bytes().size();
01084             if (!x86InstructionIsUnconditionalBranch(insnx)) {
01085                 succs.push_back(nextAddr);
01086             }
01087             if (isAsmBranch(insnx)) {
01088                 uint64_t addr = 0;
01089                 bool knownTarget = getAsmKnownBranchTarget(insnx, addr);
01090                 if (knownTarget) {
01091                     succs.push_back(addr);
01092                 }
01093             }
01094         }
01095 
01096         /* Merge result of processing instruction into register sets for successors */
01097         for (size_t i = 0; i < succs.size(); ++i) {
01098             uint64_t s = succs[i];
01099             rsets[s].mergeIn(cur_state);
01100         }
01101     }
01102 
01103 #define ValueType XVariablePtr
01104 #define EIP_LOCATION newIp
01105 #include "ReadWriteRegisterFragment.h"
01106 #undef ValueType
01107     
01108 };
01109 
01111 class CdeclFunctionPolicy : public FindConstantsPolicy {
01112     VirtualBinCFG::AuxiliaryInformation *info;
01113 public:
01114     CdeclFunctionPolicy(VirtualBinCFG::AuxiliaryInformation *info, RegisterSet *rs)
01115         : FindConstantsPolicy(rs), info(info) {}
01116 
01118     void startInstruction(SgAsmInstruction* insn) {
01119         /* Any instruction that is a branch target should set the registerset to bottom rather than top. This isn't actually
01120          * the accurate thing to do, but it turns out that it works better this way for finding the signal handlers. */
01121         VirtualBinCFG::InstructionToAddressesMap::iterator found = info->incomingEdges.find(insn);
01122         if (found!=info->incomingEdges.end() && found->second.size()>1) {
01123             RegisterSet &rs = rsets[insn->get_address()];
01124             MemoryWriteSet saved = rs.memoryWrites->get();
01125             rs.setToBottom();
01126             rs.memoryWrites->set(saved);
01127         }
01128 
01129         FindConstantsPolicy::startInstruction(insn);
01130 
01131         /* GCC assumes that the direction flag (df) is zero on function entry. See gcc man page for -mcld switch. */
01132         LatticeElement<1> df = rsets[insn->get_address()].flag[x86_flag_df]->get();
01133         if (df.name!=0)
01134             writeRegister("df", false_());
01135 
01136 #if 0   /*DEBUGGING: Show register set at start of instruction */
01137         std::cout <<"Initial RSET for [" <<unparseInstructionWithAddress(insn) <<"]\n" <<cur_state;
01138 #endif
01139     }
01140 
01141     /* It is common for a function to align local variables on a particular boundary and this happens near the beginning of a
01142      * function by masking off the low-order bits of the stack pointer. For example:
01143      *     push ebp                   -- save stack frame
01144      *     mov  ebp, esp              -- create new stack frame
01145      *     sub  esp, 0xa8             -- allocate stack space for locals
01146      *     and  esp, 0xfffffff0       -- align stack on 16-byte boundary
01147      * The FindConstantsPolicy, when it encounters such an AND instruction with a named value (non-constant) in %esp, simply
01148      * gives %esp a new named value.  What we want to do instead is subtract 16 from the stack pointer, thus introducing some
01149      * padding between the top local variable and the bottom of the call frame. The stack after the AND looks like this:
01150      *     argN
01151      *     ...
01152      *     arg0
01153      *     return address
01154      *     old stack frame from [push ebp]
01155      *     padding we inserted from [and esp, 0xfffffff0]
01156      *     top local variable
01157      *     ...
01158      *     bottom local variable          <--- stack pointer points here
01159      *     
01160      * Note: The policy "and_" method is called for other instructions besides AND, some of which don't have two operands.
01161      */
01162     template<size_t Len>
01163     XVariablePtr<Len> and_(XVariablePtr<Len> a, XVariablePtr<Len> b) {
01164         XVariablePtr<Len> result = new XVariable<Len>();
01165         struct IC: public BinaryConstraint<Len, Len, Len> {
01166             IC(XVariablePtr<Len> result, XVariablePtr<Len> var1, XVariablePtr<Len> var2)
01167                 : BinaryConstraint<Len, Len, Len>(result, var1, var2)
01168                 {}
01169             virtual void run() const {
01170                 /* "var1", "var2", and "result" here are initialized from "a", "b", and "result" above */
01171                 LatticeElement<Len> le1 = BinaryConstraint<Len, Len, Len>::var1->get();
01172                 LatticeElement<Len> le2 = BinaryConstraint<Len, Len, Len>::var2->get();
01173                 XVariablePtr<Len> result = BinaryConstraint<Len, Len, Len>::result;
01174 
01175                 /* The instruction for which this policy method is being invoked. */
01176                 SgAsmx86Instruction *insn = isSgAsmx86Instruction(result->def);
01177                 ROSE_ASSERT(insn);
01178                 SgAsmExpressionPtrList &opands = insn->get_operandList()->get_operands();
01179 
01180                 if (!le1.name && !le2.name) {
01181                     /* Operands are known constants, so the result will be a known constant. */
01182                     result->set(LatticeElement<Len>::constant(le1.offset & le2.offset, result->def));
01183                 } else {
01184                     /* Is this instruction aligning the stack pointer? */
01185                     SgAsmx86RegisterReferenceExpression *op1 = (opands.size()==2 ?
01186                                                                 isSgAsmx86RegisterReferenceExpression(opands[0]) : NULL);
01187                     if (op1 && insn->get_kind()==x86_and &&
01188                         op1->get_descriptor().get_major()==x86_regclass_gpr && op1->get_descriptor().get_minor()==x86_gpr_sp &&
01189                         !le2.isTop) {
01190                         /* Yes, we're aligning the stack pointer. */
01191                         LatticeElement<Len> newval = le1; /* stack pointer */
01192                         uint32_t alignment = ~(uint32_t)le2.offset + 1; /*two's complement*/
01193                         //std::cout <<"ROBB: aligning stack on "<<std::dec <<alignment <<"-byte boundary"
01194                         //          <<" [" <<unparseInstructionWithAddress(insn) <<"]\n";
01195                         newval.offset -= alignment;
01196                         newval.definingInstruction = insn;
01197                         result->set(newval);
01198                     } else {
01199                         /* No, it is some other use of AND and one or both of the operands are unknown values */
01200                         result->set(LatticeElement<Len>());
01201                     }
01202                 }
01203             }
01204             virtual uint64_t compute(uint64_t, uint64_t) const {
01205                 abort(); /* handled by run() above */
01206             }
01207         };
01208         (new IC(result, a, b))->activate(); /*invokes the run() method above*/
01209         return result;
01210     }
01211 };
01212 
01217 class FindConstantsABIPolicy: public FindConstantsPolicy {
01218 public:
01219     /* Returns the function containing the instruction. */
01220     SgAsmFunction* find_function(SgAsmInstruction* insn) {
01221         SgNode* n=insn;
01222         while (n && !isSgAsmFunction(n))
01223             n = n->get_parent();
01224         return isSgAsmFunction(n);
01225     }
01226 
01227     /* Determines if the function contains an instruction at the specified address. */
01228     bool function_contains_address(SgAsmFunction* f, rose_addr_t va) {
01229         for (size_t i=0; i<f->get_statementList().size(); ++i) {
01230             SgAsmBlock* block = isSgAsmBlock(f->get_statementList()[i]);
01231             ROSE_ASSERT(block!=NULL);
01232             for (size_t j=0; j<block->get_statementList().size(); ++j) {
01233                 SgAsmInstruction* insn = isSgAsmInstruction(block->get_statementList()[j]);
01234                 if (insn && insn->get_address()==va)
01235                     return true;
01236             }
01237         }
01238         return false;
01239     }
01240 
01241     /* Returns true if the function at the specified address complies with the ABI */
01242     bool is_abi_compliant(rose_addr_t) {
01243         return true; /* left as an exercise for later ;-) */
01244     }
01245 
01246     /* Determines if a CALL instruction in fact calls a function. Malware sometimes uses CALL instructions for unconditional
01247      * jumps, in which case the instruction partitioner (Partitioner class) would have placed the call target in the same
01248      * function as the CALL instruction (note that recursive calls are to the entry address of the function). */
01249     bool is_abi_function_call(SgAsmInstruction* insn_) {
01250         SgAsmx86Instruction* insn = isSgAsmx86Instruction(insn_);
01251         ROSE_ASSERT(insn!=NULL);
01252         if (insn->get_kind()!=x86_call && insn->get_kind()!=x86_farcall)
01253             return false;
01254         if (newIp->get().name!=0)
01255             return true; /*if we don't know the call target then assume it's a function call*/
01256         SgAsmFunction *caller = find_function(insn);
01257         rose_addr_t callee = newIp->get().offset;
01258         if (function_contains_address(caller, callee) && caller->get_entry_va()!=callee)
01259             return false; /*intra-function branch*/
01260         return is_abi_compliant(callee);
01261     }
01262 
01263     /* Augments superclass method so that the instruction following a CALL (provided this is really a function call and not
01264      * just an intra-function branch) has a register set whose callee-preserved registers are actually reserved across the
01265      * CALL instruction. We also preserve the stack pointer, frame pointer, and all memory. */
01266     void finishInstruction(SgAsmInstruction* insn_) {
01267         SgAsmx86Instruction* insn = isSgAsmx86Instruction(insn_);
01268         ROSE_ASSERT(insn!=NULL);
01269         if (is_abi_function_call(insn)) {
01270             rose_addr_t call_va = insn->get_address();
01271             rose_addr_t next_va = insn->get_address() + insn->get_raw_bytes().size();
01272             RegisterSet rset;
01273             rset.setToBottom();
01274             rset.memoryWrites = rsets[call_va].memoryWrites;
01275             rset.gpr[x86_gpr_bx] = rsets[call_va].gpr[x86_gpr_bx];
01276             rset.gpr[x86_gpr_di] = rsets[call_va].gpr[x86_gpr_di];
01277             rset.gpr[x86_gpr_si] = rsets[call_va].gpr[x86_gpr_si];
01278             rset.gpr[x86_gpr_sp] = rsets[call_va].gpr[x86_gpr_sp];
01279             rset.gpr[x86_gpr_bp] = rsets[call_va].gpr[x86_gpr_bp];
01280             rsets[next_va].mergeIn(rset);
01281         }
01282         FindConstantsPolicy::finishInstruction(insn);
01283     }
01284 };
01285 
01286 #endif /* !findConstants_H */

Generated on Sat May 19 00:53:06 2012 for ROSE by  doxygen 1.4.7