diff --git a/SMPProgram.cpp b/SMPProgram.cpp index b69e729901e075376238f40e2670a883215a167e..c99aff62dde2aa2db3f482892cbd0488cc7f7981 100644 --- a/SMPProgram.cpp +++ b/SMPProgram.cpp @@ -34,10 +34,48 @@ // Set to 1 for debugging output #define SMP_DEBUG 1 -#define SMP_DEBUG_GLOBAL_GRANULARITY 0 +#define SMP_DEBUG_GLOBAL_GRANULARITY 1 // Compute fine-grained global static data boundaries? #define SMP_COMPUTE_GLOBAL_GRANULARITY 1 +// Distinguish between indexed and direct accesses in global granularity? +#define SMP_DETECT_INDEXED_ACCESSES 0 + +// Does the instruction at InstAddr access the global data offset in GlobalAddr +// using an index register? +bool MDIsIndexedAccess(ea_t InstAddr, ea_t GlobalAddr) { + int InstLen = ua_ana0(InstAddr); + bool DebugFlag = (InstAddr == 0x80502d3); +#if SMP_DETECT_INDEXED_ACCESSES + if (0 >= InstLen) +#endif + return false; + for (int i = 0; i < UA_MAXOP; ++i) { + op_t CurrOp = cmd.Operands[i]; + if ((CurrOp.type == o_mem) || (CurrOp.type == o_displ)) { + if (GlobalAddr == CurrOp.addr) { + if (CurrOp.hasSIB) { + // GlobalAddr is referenced, and SIB byte is present, so we might have + // an indexed access to GlobalAddr. + regnum_t IndexReg = sib_index(CurrOp); + if (R_sp != IndexReg) { + // R_sp is a SIB index dummy value; means no index register + return true; + } + } + else if (o_displ == CurrOp.type) { // index reg in reg field, not in SIB byte + return true; + } + else if (DebugFlag) { + msg("Failed to find index in operand: "); + PrintOneOperand(CurrOp, 0, -1); + msg("\n"); + } + } + } + } // end for all operands + return false; +} // end MDIsIndexedAccess() // ***************************************************************** // Class SMPProgram @@ -143,11 +181,21 @@ void SMPProgram::InitStaticDataTable(void) { return; } // end of SMPProgram::InitStaticDataTable() +// Find the direct and indexed accesses to offsets within each static data table entry. +// Record the offset and kind of access (indexed or not) and conservatively mark the +// field boundaries based on the unindexed accesses. void SMPProgram::ComputeGlobalFieldOffsets(struct GlobalVar &CurrGlobal) { xrefblk_t xb; ea_t addr; size_t offset; + bool DebugFlag = false; + DebugFlag |= (0 == strcmp("spec_fd", CurrGlobal.name)); for (addr = CurrGlobal.addr; addr < CurrGlobal.addr + CurrGlobal.size; ++addr) { + bool Referenced = false; + offset = addr - CurrGlobal.addr; + pair<size_t, bool> TempOffset; + TempOffset.first = offset; + TempOffset.second = false; // No indexed accesses seen yet for (bool ok = xb.first_to(addr, XREF_ALL); ok; ok = xb.next_to()) { uchar XrefType = xb.type & XREF_MASK; if (xb.iscode) { @@ -159,12 +207,13 @@ void SMPProgram::ComputeGlobalFieldOffsets(struct GlobalVar &CurrGlobal) { else { if ((XrefType == dr_O) || (XrefType == dr_W) || (XrefType == dr_R)) { #if SMP_DEBUG_GLOBAL_GRANULARITY - msg("Data xref to global data at %x from code at %x\n", addr, - xb.from); + SMPInstr TempInstr(xb.from); + TempInstr.Analyze(); + msg("Data xref to global data %s at %x from code at %x %s\n", + CurrGlobal.name, addr, xb.from, TempInstr.GetDisasm()); #endif - offset = addr - CurrGlobal.addr; - CurrGlobal.FieldOffsets.insert(offset); - continue; // only need one xref per offset addr to identify offset + Referenced = true; + TempOffset.second |= MDIsIndexedAccess(xb.from, addr); } else { #if SMP_DEBUG_GLOBAL_GRANULARITY @@ -173,8 +222,11 @@ void SMPProgram::ComputeGlobalFieldOffsets(struct GlobalVar &CurrGlobal) { ; } } + } // end for (bool ok = iterate through xrefs ...) + if (Referenced) { + CurrGlobal.FieldOffsets.insert(TempOffset); } - } + } // end for all addrs in current global return; } // end of SMPProgram::ComputeGlobalFieldOffsets() @@ -239,15 +291,27 @@ void SMPProgram::EmitAnnotations(FILE *AnnotFile) { // Output the name, address, size, and type info. struct GlobalVar TempGlobal = GlobalIter->second; // If we have an offset other than 0 but not 0, add 0 to offsets. - if (0 != *(TempGlobal.FieldOffsets.begin())) { - TempGlobal.FieldOffsets.insert(0); + pair<size_t,bool> FirstOffset = (*(TempGlobal.FieldOffsets.begin())); + if (0 != FirstOffset.first) { + pair<size_t,bool> TempOffset; + TempOffset.first = 0; + TempOffset.second = false; + TempGlobal.FieldOffsets.insert(TempOffset); #if SMP_DEBUG_GLOBAL_GRANULARITY msg("Inserted offset 0 for global var %s\n", TempGlobal.name); #endif } unsigned long ParentReferentID = DataReferentID++; - // If 0 is the only offset, the data is not structured. - if (2 > TempGlobal.FieldOffsets.size()) { // No fields within object + bool DirectAccesses = false; // Any direct field accesses in this global? + set<pair<size_t, bool>, LessOff>::iterator CurrOffset; + for (CurrOffset = TempGlobal.FieldOffsets.begin(); CurrOffset != TempGlobal.FieldOffsets.end(); ++CurrOffset) { + pair<size_t, bool> TempOffset = *CurrOffset; + if (!TempOffset.second) + DirectAccesses = true; + } + // If 0 is the only direct offset, the data is not structured. + if (!DirectAccesses || (2 > TempGlobal.FieldOffsets.size())) { + // No fields within object, or all fields were accessed through indices if (TempGlobal.ReadOnly) { qfprintf(AnnotFile, "%10x %6d DATAREF GLOBAL %d %x PARENT %s %s RO\n", @@ -276,22 +340,30 @@ void SMPProgram::EmitAnnotations(FILE *AnnotFile) { TempGlobal.name, DataTypes[get_optype_flags0(TempGlobal.flags) >> 20]); } // Now, emit an annotation for each field offset. - set<size_t>::iterator FieldIter, TempIter; + set<pair<size_t,bool>, LessOff>::iterator FieldIter, TempIter; size_t counter = 1; size_t FieldSize; for (FieldIter = TempGlobal.FieldOffsets.begin(); FieldIter != TempGlobal.FieldOffsets.end(); ++FieldIter, ++counter) { + pair<size_t,bool> CurrOffset = (*FieldIter); if (counter < TempGlobal.FieldOffsets.size()) { - TempIter = ++FieldIter; - --FieldIter; - FieldSize = (*TempIter) - (*FieldIter); + TempIter = FieldIter; + ++TempIter; + pair<size_t,bool> TempOffset = (*TempIter); + FieldSize = TempOffset.first - CurrOffset.first; } else { - FieldSize = TempGlobal.size - (*FieldIter); + FieldSize = TempGlobal.size - CurrOffset.first; } qfprintf(AnnotFile, - "%10x %6d DATAREF GLOBAL %d %x CHILDOF %d OFFSET %d %s + %d FIELD\n", + "%10x %6d DATAREF GLOBAL %d %x CHILDOF %d OFFSET %d %s + %d FIELD", 0, FieldSize, DataReferentID, TempGlobal.addr, ParentReferentID, - (*FieldIter), TempGlobal.name, *FieldIter); + CurrOffset.first, TempGlobal.name, CurrOffset.first); + if (CurrOffset.second) { // indexed accesses to this field + qfprintf(AnnotFile, " INDEXED\n"); + } + else { // only direct accesses to this field + qfprintf(AnnotFile, " DIRECT\n"); + } ++DataReferentID; } } // end if unstructured data ... else ... diff --git a/SMPProgram.h b/SMPProgram.h index f77283da73bcdaf3396f6a4e6233d982700ef65e..9afc9f1e914c3db5cc27f2921d3bd2fe9954cdf1 100644 --- a/SMPProgram.h +++ b/SMPProgram.h @@ -24,13 +24,21 @@ using namespace std; +class LessOff { +public: + bool operator()(const pair<size_t, bool> &Off1, const pair<size_t, bool> &Off2) const { + return (Off1.first < Off2.first); + } // end operator +}; // end class LessOff + struct GlobalVar { ea_t addr; size_t size; char name[MAXSTR]; bool ReadOnly; // came from read-only data segment type + bool IndexedAccess; flags_t flags; - set<size_t> FieldOffsets; + set<pair<size_t, bool>, LessOff> FieldOffsets; // bool = accessed through index register by any instruction? }; // Class encapsulating all that the SMP static analyzer cares to know