diff --git a/parseAPI/src/BoundFactCalculator.C b/parseAPI/src/BoundFactCalculator.C index abd00cbf19..6dc8655bf0 100644 --- a/parseAPI/src/BoundFactCalculator.C +++ b/parseAPI/src/BoundFactCalculator.C @@ -392,7 +392,7 @@ BoundFact* BoundFactsCalculator::Meet(Node::Ptr curNode) { first = false; if (newCopy) newFact = prevFact; else newFact = new BoundFact(*prevFact); } else { - newFact->Meet(*prevFact); + newFact->Meet(*prevFact, func->entry()); if (newCopy) delete prevFact; } } diff --git a/parseAPI/src/BoundFactData.C b/parseAPI/src/BoundFactData.C index 622b0bb7dc..95dacd8bf4 100644 --- a/parseAPI/src/BoundFactData.C +++ b/parseAPI/src/BoundFactData.C @@ -360,6 +360,7 @@ BoundValue::BoundValue(int64_t val): targetBase(0), tableReadSize(0), multiply(1), + values(NULL), isInverted(false), isSubReadContent(false), isZeroExtend(false) {} @@ -369,6 +370,7 @@ BoundValue::BoundValue(const StridedInterval &si): targetBase(0), tableReadSize(0), multiply(1), + values(NULL), isInverted(false), isSubReadContent(false), isZeroExtend(false){} @@ -378,6 +380,7 @@ BoundValue::BoundValue(): targetBase(0), tableReadSize(0), multiply(1), + values(NULL), isInverted(false), isSubReadContent(false), isZeroExtend(false) {} @@ -387,21 +390,37 @@ BoundValue::BoundValue(const BoundValue & bv): targetBase(bv.targetBase), tableReadSize(bv.tableReadSize), multiply(bv.multiply), + values(NULL), isInverted(bv.isInverted), isSubReadContent(bv.isSubReadContent), isZeroExtend(bv.isZeroExtend) { + if (bv.values != NULL) { + values = new set(*(bv.values)); + } } +BoundValue::~BoundValue() { + if (values != NULL) { + delete values; + values = NULL; + } +} bool BoundValue::operator == (const BoundValue &bv) const { - return (interval == bv.interval) && - (targetBase == bv.targetBase) && - (tableReadSize == bv.tableReadSize) && - (multiply == bv.multiply) && - (isInverted == bv.isInverted) && - (isSubReadContent == bv.isSubReadContent) && - (isZeroExtend == bv.isZeroExtend); + if (values == NULL && bv.values == NULL) { + return (interval == bv.interval) && + (targetBase == bv.targetBase) && + (tableReadSize == bv.tableReadSize) && + (multiply == bv.multiply) && + (isInverted == bv.isInverted) && + (isSubReadContent == bv.isSubReadContent) && + (isZeroExtend == bv.isZeroExtend); + } else if (values != NULL && bv.values != NULL) { + return *values == *bv.values; + } else { + return false; + } } bool BoundValue::operator != (const BoundValue &bv) const { @@ -417,18 +436,32 @@ BoundValue & BoundValue::operator = (const BoundValue &bv) { isInverted = bv.isInverted; isSubReadContent = bv.isSubReadContent; isZeroExtend = bv.isZeroExtend; + if (values != NULL) { + delete values; + values = NULL; + } + if (bv.values != NULL) { + values = new set(*bv.values); + } return *this; } void BoundValue::Print() { - parsing_printf("Interval %s, ", interval.format().c_str() ); - parsing_printf("targetBase %lx, ",targetBase); - parsing_printf("tableReadSize %d, ", tableReadSize); - parsing_printf("multiply %d, ", multiply); - parsing_printf("isInverted %d, ", isInverted); - parsing_printf("isSubReadContent %d, ", isSubReadContent); - parsing_printf("isZeroExtend %d\n", isZeroExtend); + if (values == NULL) { + parsing_printf("Interval %s, ", interval.format().c_str() ); + parsing_printf("targetBase %lx, ",targetBase); + parsing_printf("tableReadSize %d, ", tableReadSize); + parsing_printf("multiply %d, ", multiply); + parsing_printf("isInverted %d, ", isInverted); + parsing_printf("isSubReadContent %d, ", isSubReadContent); + parsing_printf("isZeroExtend %d\n", isZeroExtend); + } else { + parsing_printf("Values:"); + for (auto vit = values->begin(); vit != values->end(); ++vit) + parsing_printf(" %x", *vit); + parsing_printf("\n"); + } } @@ -471,7 +504,7 @@ void BoundValue::DeleteElementFromInterval(int64_t val) { interval.DeleteElement(val); } -void BoundValue::Join(BoundValue &bv) { +void BoundValue::Join(BoundValue &bv, Block *b) { // If one is a table read and the other is a constant, // assume that the constant appears in the table read. if (tableReadSize > 0 && bv.interval.stride == 0) { @@ -481,6 +514,21 @@ void BoundValue::Join(BoundValue &bv) { *this = bv; return; } + if (tableReadSize > 0 && bv.tableReadSize > 0) { + // If both paths represent a table read, + // it could be a case where multiple jump tables share + // an indirect jump. + // Example: 0x47947 at libc-2.17.so + set left, right; + bool leftRet, rightRet; + leftRet = PerformTableRead(*this, left, b->obj()->cs()); + rightRet = PerformTableRead(bv, right, b->obj()->cs()); + if (leftRet && rightRet) { + left.insert(right.begin(), right.end()); + values = new set (left); + return; + } + } if (tableReadSize != bv.tableReadSize) { // Unless boths are table reads, we stop trakcing // how the read is used. @@ -694,7 +742,7 @@ void BoundValue::MemoryRead(Block* b, int readSize) { } } -void BoundFact::Meet(BoundFact &bf) { +void BoundFact::Meet(BoundFact &bf, Block* b) { for (auto fit = fact.begin(); fit != fact.end();) { BoundValue *val2 = bf.GetBound(fit->first); // if ast fit->first cannot be found in bf, @@ -702,7 +750,7 @@ void BoundFact::Meet(BoundFact &bf) { // Anything joins top becomes top if (val2 != NULL) { BoundValue *val1 = fit->second; - val1->Join(*val2); + val1->Join(*val2, b); ++fit; } else { auto toErase = fit; @@ -1538,17 +1586,6 @@ AST::Ptr BoundFact::GetAlias(const AST::Ptr ast) { } void BoundFact::TrackAlias(AST::Ptr expr, AST::Ptr outAST, bool findBound) { - // This definition should kill all existing aliases - // involving outAST, as outAST is assigned to a new value - parsing_printf("\tTracking alias for %s = %s\n", outAST->format().c_str(), expr->format().c_str()); - for (auto ait = aliasMap.begin(); ait != aliasMap.end(); ) { - if (ContainAnAST(ait->second , outAST)) { - auto e = ait; - ++ait; - aliasMap.erase(e); - } else ++ait; - } - expr = SubstituteAnAST(expr, aliasMap); bool find = false; for (auto ait = aliasMap.begin(); ait != aliasMap.end(); ++ait) { diff --git a/parseAPI/src/BoundFactData.h b/parseAPI/src/BoundFactData.h index 7e8a33c1a3..a4aa286b67 100644 --- a/parseAPI/src/BoundFactData.h +++ b/parseAPI/src/BoundFactData.h @@ -81,6 +81,7 @@ struct BoundValue { // Otherwise, tableReadSize reprenents the number bytes of the access int tableReadSize; int multiply; + std::set * values; bool isInverted; bool isSubReadContent; bool isZeroExtend; @@ -89,6 +90,7 @@ struct BoundValue { BoundValue(); BoundValue(const BoundValue & bv); BoundValue& operator = (const BoundValue &bv); + ~BoundValue(); bool operator< (const BoundValue &bv) const { return interval < bv.interval; } bool operator== (const BoundValue &bv) const; bool operator!= (const BoundValue &bv) const; @@ -97,7 +99,7 @@ struct BoundValue { void SetToBottom(); void IntersectInterval(StridedInterval &si); void DeleteElementFromInterval(int64_t val); - void Join(BoundValue &bv); + void Join(BoundValue &bv, ParseAPI::Block* b); void ClearTableCheck(); void Add(const BoundValue &rhs); void And(const BoundValue &rhs); @@ -152,6 +154,13 @@ struct BoundFact { vector relation; + // We need to track aliases of each register and memory locations. + // The left hand side represents an abstract location at the current address + // and the right hand side represents an AST of input absloc locations. + // eax at the current location can be different from eax at the input absloc location + // + // Register abstract location with address 0 represents an absloc at the current address + // Register abstract location with address 1 represents an input absloc typedef std::map AliasMap; AliasMap aliasMap; @@ -210,7 +219,7 @@ struct BoundFact { BoundValue* GetBound(const AST::Ptr ast); BoundValue* GetBound(const AST* ast); AST::Ptr GetAlias(const AST::Ptr ast); - void Meet(BoundFact &bf); + void Meet(BoundFact &bf, ParseAPI::Block* b); bool ConditionalJumpBound(InstructionAPI::Instruction::Ptr insn, EdgeTypeEnum type); diff --git a/parseAPI/src/IndirectASTVisitor.C b/parseAPI/src/IndirectASTVisitor.C index e2486e343f..eafbf7a33f 100644 --- a/parseAPI/src/IndirectASTVisitor.C +++ b/parseAPI/src/IndirectASTVisitor.C @@ -5,6 +5,11 @@ #include using namespace Dyninst::ParseAPI; +#define SIGNEX_64_32 0xffffffff00000000LL +#define SIGNEX_64_16 0xffffffffffff0000LL +#define SIGNEX_64_8 0xffffffffffffff00LL +#define SIGNEX_32_16 0xffff0000 +#define SIGNEX_32_8 0xffffff00 Address PCValue(Address cur, size_t insnSize, Architecture a) { switch (a) { @@ -288,7 +293,7 @@ AST::Ptr BoundCalcVisitor::visit(DataflowAPI::RoseAST *ast) { case ROSEOperation::ifOp: if (IsResultBounded(ast->child(1)) && IsResultBounded(ast->child(2))) { BoundValue *val = new BoundValue(*GetResultBound(ast->child(1))); - val->Join(*GetResultBound(ast->child(2))); + val->Join(*GetResultBound(ast->child(2)), block); if (*val != BoundValue::top) bound.insert(make_pair(ast, val)); } @@ -404,6 +409,12 @@ AST::Ptr SubstituteAnAST(AST::Ptr ast, const BoundFact::AliasMap &aliasMap) { for (unsigned i = 0 ; i < totalChildren; ++i) { ast->setChild(i, SubstituteAnAST(ast->child(i), aliasMap)); } + if (ast->getID() == AST::V_VariableAST) { + // If this variable is not in the aliasMap yet, + // this variable is from the input. + VariableAST::Ptr varAST = boost::static_pointer_cast(ast); + return VariableAST::create(Variable(varAST->val().reg, 1)); + } return ast; } @@ -497,3 +508,99 @@ AST::Ptr JumpTableFormatVisitor::visit(DataflowAPI::RoseAST *ast) { } return AST::Ptr(); } + +bool PerformTableRead(BoundValue &target, set & jumpTargets, CodeSource *cs) { + + Address tableBase = (Address)target.interval.low; + Address tableLastEntry = (Address)target.interval.high; + int addressWidth = cs->getAddressWidth(); + if (addressWidth == 4) { + tableBase &= 0xffffffff; + tableLastEntry &= 0xffffffff; + } + +#if defined(os_windows) + tableBase -= cs->loadAddress(); + tableLastEntry -= cs->loadAddress(); +#endif + + if (!cs->isCode(tableBase) && !cs->isData(tableBase)) { + parsing_printf("\ttableBase 0x%lx invalid, returning false\n", tableBase); + parsing_printf("Not jump table format!\n"); + return false; + } + if (!cs->isReadOnly(tableBase)) { + parsing_printf("\ttableBase 0x%lx not read only, returning false\n", tableBase); + parsing_printf("Not jump table format!\n"); + return false; + } + + + for (Address tableEntry = tableBase; tableEntry <= tableLastEntry; tableEntry += target.interval.stride) { + if (!cs->isCode(tableEntry) && !cs->isData(tableEntry)) continue; + if (!cs->isReadOnly(tableEntry)) continue; + int targetAddress = 0; + if (target.tableReadSize > 0) { + switch (target.tableReadSize) { + case 8: + targetAddress = *(const uint64_t *) cs->getPtrToInstruction(tableEntry); + break; + case 4: + targetAddress = *(const uint32_t *) cs->getPtrToInstruction(tableEntry); + if (target.isZeroExtend) break; + if ((addressWidth == 8) && (targetAddress & 0x80000000)) { + targetAddress |= SIGNEX_64_32; + } + break; + case 2: + targetAddress = *(const uint16_t *) cs->getPtrToInstruction(tableEntry); + if (target.isZeroExtend) break; + if ((addressWidth == 8) && (targetAddress & 0x8000)) { + targetAddress |= SIGNEX_64_16; + } + if ((addressWidth == 4) && (targetAddress & 0x8000)) { + targetAddress |= SIGNEX_32_16; + } + + break; + case 1: + targetAddress = *(const uint8_t *) cs->getPtrToInstruction(tableEntry); + if (target.isZeroExtend) break; + if ((addressWidth == 8) && (targetAddress & 0x80)) { + targetAddress |= SIGNEX_64_8; + } + if ((addressWidth == 4) && (targetAddress & 0x80)) { + targetAddress |= SIGNEX_32_8; + } + + break; + + default: + parsing_printf("Invalid memory read size %d\n", target.tableReadSize); + return false; + } + targetAddress *= target.multiply; + if (target.targetBase != 0) { + if (target.isSubReadContent) + targetAddress = target.targetBase - targetAddress; + else + targetAddress += target.targetBase; + + } +#if defined(os_windows) + targetAddress -= cs->loadAddress(); +#endif + } else targetAddress = tableEntry; + + if (addressWidth == 4) targetAddress &= 0xffffffff; + parsing_printf("Jumping to target %lx,", targetAddress); + if (cs->isCode(targetAddress)) { + // Jump tables may contain may repetitious entries. + // We only want to create one edge for disctinct each jump target. + jumpTargets.insert(targetAddress); + } + // If the jump target is resolved to be a constant, + if (target.interval.stride == 0) break; + } + return true; +} diff --git a/parseAPI/src/IndirectASTVisitor.h b/parseAPI/src/IndirectASTVisitor.h index e5393be8e5..02268f4975 100644 --- a/parseAPI/src/IndirectASTVisitor.h +++ b/parseAPI/src/IndirectASTVisitor.h @@ -5,7 +5,7 @@ #include "DynAST.h" #include "SymEval.h" - +#include "CodeSource.h" #include "BoundFactData.h" using namespace std; @@ -17,6 +17,8 @@ AST::Ptr SimplifyAnAST(AST::Ptr ast, Address addr); AST::Ptr SubstituteAnAST(AST::Ptr ast, const BoundFact::AliasMap &aliasMap); AST::Ptr DeepCopyAnAST(AST::Ptr ast); bool ContainAnAST(AST::Ptr root, AST::Ptr check); +bool PerformTableRead(BoundValue &target, set & jumpTargets, CodeSource*); + // On x86 and x86-64, the value of PC is post-instruction, // which is the current address plus the length of the instruction. diff --git a/parseAPI/src/JumpTablePred.C b/parseAPI/src/JumpTablePred.C index 90413bc577..44cfd6845c 100644 --- a/parseAPI/src/JumpTablePred.C +++ b/parseAPI/src/JumpTablePred.C @@ -17,14 +17,10 @@ using namespace Dyninst; using namespace Dyninst::DataflowAPI; using namespace Dyninst::ParseAPI; using namespace Dyninst::InstructionAPI; -#define SIGNEX_64_32 0xffffffff00000000LL -#define SIGNEX_64_16 0xffffffffffff0000LL -#define SIGNEX_64_8 0xffffffffffffff00LL -#define SIGNEX_32_16 0xffff0000 -#define SIGNEX_32_8 0xffffff00 - // Assume the table contain less than this many entries. #define MAX_TABLE_ENTRY 1000000 + + static void BuildEdgesAux(SliceNode::Ptr srcNode, ParseAPI::Block* curBlock, map > &targetMap, @@ -260,106 +256,19 @@ bool JumpTablePred::addNodeCallback(AssignmentPtr ap, set &visi } bool JumpTablePred::FillInOutEdges(BoundValue &target, vector >& outEdges) { - set
jumpTargets; - outEdges.clear(); - Address tableBase = (Address)target.interval.low; - Address tableLastEntry = (Address)target.interval.high; - int addressWidth = block->obj()->cs()->getAddressWidth(); - if (addressWidth == 4) { - tableBase &= 0xffffffff; - tableLastEntry &= 0xffffffff; + if (target.values != NULL) { + outEdges.clear(); + for (auto tit = target.values->begin(); tit != target.values->end(); ++tit) { + outEdges.push_back(make_pair(*tit, INDIRECT)); + } + return true; } - -#if defined(os_windows) - tableBase -= block->obj()->cs()->loadAddress(); - tableLastEntry -= block->obj()->cs()->loadAddress(); -#endif - - parsing_printf("The final target bound fact:\n"); - target.Print(); - if (!block->obj()->cs()->isCode(tableBase) && !block->obj()->cs()->isData(tableBase)) { - parsing_printf("\ttableBase 0x%lx invalid, returning false\n", tableBase); - jumpTableFormat = false; - parsing_printf("Not jump table format!\n"); + set jumpTargets; + if (!PerformTableRead(target, jumpTargets, block->obj()->cs())) { + jumpTableFormat = false; return false; } - if (!block->obj()->cs()->isReadOnly(tableBase)) { - parsing_printf("\ttableBase 0x%lx not read only, returning false\n", tableBase); - jumpTableFormat = false; - parsing_printf("Not jump table format!\n"); - return false; - } - - - for (Address tableEntry = tableBase; tableEntry <= tableLastEntry; tableEntry += target.interval.stride) { - if (!block->obj()->cs()->isCode(tableEntry) && !block->obj()->cs()->isData(tableEntry)) continue; - if (!block->obj()->cs()->isReadOnly(tableEntry)) continue; - int targetAddress = 0; - if (target.tableReadSize > 0) { - switch (target.tableReadSize) { - case 8: - targetAddress = *(const uint64_t *) block->obj()->cs()->getPtrToInstruction(tableEntry); - break; - case 4: - targetAddress = *(const uint32_t *) block->obj()->cs()->getPtrToInstruction(tableEntry); - if (target.isZeroExtend) break; - if ((addressWidth == 8) && (targetAddress & 0x80000000)) { - targetAddress |= SIGNEX_64_32; - } - break; - case 2: - targetAddress = *(const uint16_t *) block->obj()->cs()->getPtrToInstruction(tableEntry); - if (target.isZeroExtend) break; - if ((addressWidth == 8) && (targetAddress & 0x8000)) { - targetAddress |= SIGNEX_64_16; - } - if ((addressWidth == 4) && (targetAddress & 0x8000)) { - targetAddress |= SIGNEX_32_16; - } - - break; - case 1: - targetAddress = *(const uint8_t *) block->obj()->cs()->getPtrToInstruction(tableEntry); - if (target.isZeroExtend) break; - if ((addressWidth == 8) && (targetAddress & 0x80)) { - targetAddress |= SIGNEX_64_8; - } - if ((addressWidth == 4) && (targetAddress & 0x80)) { - targetAddress |= SIGNEX_32_8; - } - - break; - - default: - parsing_printf("Invalid memory read size %d\n", target.tableReadSize); - return false; - } - targetAddress *= target.multiply; - if (target.targetBase != 0) { - if (target.isSubReadContent) - targetAddress = target.targetBase - targetAddress; - else - targetAddress += target.targetBase; - - } -#if defined(os_windows) - targetAddress -= block->obj()->cs()->loadAddress(); -#endif - } else targetAddress = tableEntry; - - if (addressWidth == 4) targetAddress &= 0xffffffff; - parsing_printf("Jumping to target %lx,", targetAddress); - if (block->obj()->cs()->isCode(targetAddress)) { - // Jump tables may contain may repetitious entries. - // We only want to create one edge for disctinct each jump target. - jumpTargets.insert(targetAddress); - parsing_printf(" is code.\n" ); - } else { - parsing_printf(" not code.\n"); - } - // If the jump target is resolved to be a constant, - if (target.interval.stride == 0) break; - } + outEdges.clear(); for (auto tit = jumpTargets.begin(); tit != jumpTargets.end(); ++tit) { outEdges.push_back(make_pair(*tit, INDIRECT)); } @@ -381,7 +290,11 @@ bool JumpTablePred::IsJumpTable(GraphPtr slice, BoundValue *tarBoundValue = bf->GetBound(ip); if (tarBoundValue != NULL) { target = *(tarBoundValue); - uint64_t s = target.interval.size(); + uint64_t s; + if (target.values == NULL) + s = target.interval.size(); + else + s = target.values->size(); if (s > 0 && s <= MAX_TABLE_ENTRY) return true; } AST::Ptr ipExp = bf->GetAlias(ip);