/** * Test the renaming of variables. */ void CfgTest::testRenameVars() { auto prog = Prog::open(FRONTIER_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); df->dominators(cfg); df->placePhiFunctions(pProc); pProc->numberStatements(); // After placing phi functions! df->renameBlockVars(pProc, 0, 1); // Block 0, mem depth 1 // MIKE: something missing here? delete prog; }
void printProcsRecursive(Function *function, int indent, OStream &f, std::set<Function *> &seen) { const bool firsttime = (seen.find(function) == seen.end()); if (firsttime) { seen.insert(function); } for (int i = 0; i < indent; i++) { f << " "; } if (!function->isLib() && firsttime) { // seen lib proc f << function->getEntryAddress(); f << " __nodecode __incomplete void " << function->getName() << "();\n"; UserProc *proc = static_cast<UserProc *>(function); for (Function *callee : proc->getCallees()) { printProcsRecursive(callee, indent + 1, f, seen); } for (int i = 0; i < indent; i++) { f << " "; } f << "// End of " << function->getName() << "\n"; } else { f << "// " << function->getName() << "();\n"; } }
/** * Test the placing of phi functions. */ void CfgTest::testPlacePhi() { auto prog = Prog::open(FRONTIER_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); DataFlow *df = pProc->getDataFlow(); df->dominators(cfg); df->placePhiFunctions(pProc); // m[r29 - 8] (x for this program) Exp *e = Location::memOf( new Binary(opMinus, Location::regOf(29), new Const(4))); // A_phi[x] should be the set {7 8 10 15 20 21} (all the join points) std::ostringstream ost; std::set<int> &A_phi = df->getA_phi(e); for (const auto &ii : A_phi) ost << ii << " "; std::string expected("7 8 10 15 20 21 "); CPPUNIT_ASSERT_EQUAL(expected, ost.str()); delete prog; }
/*============================================================================== * FUNCTION: CfgTest::testRenameVars * OVERVIEW: Test the renaming of variables *============================================================================*/ void CfgTest::testRenameVars () { BinaryFileFactory bff; BinaryFile* pBF = bff.Load(FRONTIER_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd* pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); DataFlow* df = pProc->getDataFlow(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); df->dominators(cfg); df->placePhiFunctions(pProc); pProc->numberStatements(); // After placing phi functions! df->renameBlockVars(pProc, 0, 1); // Block 0, mem depth 1 // MIKE: something missing here? delete pFE; }
// a should be the address of a UserProc void FrontEnd::decodeOnly(Prog *prog, ADDRESS a) { UserProc* p = (UserProc*)prog->setNewProc(a); assert(!p->isLib()); std::ofstream os; if (processProc(p->getNativeAddress(), p, os)) p->setDecoded(); prog->wellForm(); }
/*============================================================================== * FUNCTION: CfgTest::testPlacePhi2 * OVERVIEW: Test a case where a phi function is not needed *============================================================================*/ void CfgTest::testPlacePhi2 () { BinaryFileFactory bff; BinaryFile* pBF = bff.Load(IFTHEN_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd* pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); DataFlow* df = pProc->getDataFlow(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); df->dominators(cfg); df->placePhiFunctions(pProc); // In this program, x is allocated at [ebp-4], a at [ebp-8], and // b at [ebp-12] // We check that A_phi[ m[ebp-8] ] is 4, and that // A_phi A_phi[ m[ebp-8] ] is null // (block 4 comes out with n=4) std::string expected = "4 "; std::ostringstream actual; // m[r29 - 8] Exp* e = new Unary(opMemOf, new Binary(opMinus, Location::regOf(29), new Const(8))); std::set<int>& s = df->getA_phi(e); std::set<int>::iterator pp; for (pp = s.begin(); pp != s.end(); pp++) actual << *pp << " "; CPPUNIT_ASSERT_EQUAL(expected, actual.str()); delete e; expected = ""; std::ostringstream actual2; // m[r29 - 12] e = new Unary(opMemOf, new Binary(opMinus, Location::regOf(29), new Const(12))); std::set<int>& s2 = df->getA_phi(e); for (pp = s2.begin(); pp != s2.end(); pp++) actual2 << *pp << " "; CPPUNIT_ASSERT_EQUAL(expected, actual2.str()); delete e; delete pFE; }
/** * Test the dominator frontier code. */ void CfgTest::testDominators() { #define FRONTIER_FOUR 0x08048347 #define FRONTIER_FIVE 0x08048351 #define FRONTIER_TWELVE 0x080483b2 #define FRONTIER_THIRTEEN 0x080483b9 auto prog = Prog::open(FRONTIER_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); bool gotMain; ADDRESS addr = fe->getMainEntryPoint(gotMain); CPPUNIT_ASSERT(addr != NO_ADDRESS); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "5" (as per Appel, Figure 19.5). BasicBlock *bb = nullptr; for (const auto &b : *cfg) { if (b->getLowAddr() == FRONTIER_FIVE) { bb = b; break; } } CPPUNIT_ASSERT(bb); std::ostringstream expected, actual; #if 0 expected << std::hex << FRONTIER_FIVE << " " << FRONTIER_THIRTEEN << " " << FRONTIER_TWELVE << " " << FRONTIER_FOUR << " " << std::dec; #endif expected << std::hex << FRONTIER_THIRTEEN << " " << FRONTIER_FOUR << " " << FRONTIER_TWELVE << " " << FRONTIER_FIVE << " " << std::dec; int n5 = df->pbbToNode(bb); std::set<int> &DFset = df->getDF(n5); for (const auto &ii : DFset) actual << std::hex << (unsigned)df->nodeToBB(ii)->getLowAddr() << std::dec << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); delete prog; }
/** * Test a case where semi dominators are different to dominators. */ void CfgTest::testSemiDominators() { #define SEMI_L 0x80483b0 #define SEMI_M 0x80483e2 #define SEMI_B 0x8048345 #define SEMI_D 0x8048354 #define SEMI_M 0x80483e2 auto prog = Prog::open(SEMI_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); bool gotMain; ADDRESS addr = fe->getMainEntryPoint(gotMain); CPPUNIT_ASSERT(addr != NO_ADDRESS); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "L (6)" (as per Appel, Figure 19.8). BasicBlock *bb = nullptr; for (const auto &b : *cfg) { if (b->getLowAddr() == SEMI_L) { bb = b; break; } } CPPUNIT_ASSERT(bb); int nL = df->pbbToNode(bb); // The dominator for L should be B, where the semi dominator is D // (book says F) unsigned actual_dom = (unsigned)df->nodeToBB(df->getIdom(nL))->getLowAddr(); unsigned actual_semi = (unsigned)df->nodeToBB(df->getSemi(nL))->getLowAddr(); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_B, actual_dom); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_D, actual_semi); // Check the final dominator frontier as well; should be M and B std::ostringstream expected, actual; #if 0 expected << std::hex << SEMI_M << " " << SEMI_B << " " << std::dec; #endif expected << std::hex << SEMI_B << " " << SEMI_M << " " << std::dec; std::set<int> &DFset = df->getDF(nL); for (const auto &ii : DFset) actual << std::hex << (unsigned)df->nodeToBB(ii)->getLowAddr() << std::dec << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); delete prog; }
/** * Test a case where a phi function is not needed. */ void CfgTest::testPlacePhi2() { auto prog = Prog::open(IFTHEN_PENTIUM); CPPUNIT_ASSERT(prog); auto fe = prog->getFrontEnd(); Type::clearNamedTypes(); fe->decode(); UserProc *pProc = (UserProc *)prog->getProc(0); Cfg *cfg = pProc->getCFG(); DataFlow *df = pProc->getDataFlow(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); df->dominators(cfg); df->placePhiFunctions(pProc); // In this program, x is allocated at [ebp-4], a at [ebp-8], and // b at [ebp-12] // We check that A_phi[ m[ebp-8] ] is 4, and that // A_phi A_phi[ m[ebp-8] ] is null // (block 4 comes out with n=4) std::string expected = "4 "; std::ostringstream actual; // m[r29 - 8] Exp *e = Location::memOf( new Binary(opMinus, Location::regOf(29), new Const(8))); std::set<int> &s = df->getA_phi(e); for (const auto &pp : s) actual << pp << " "; CPPUNIT_ASSERT_EQUAL(expected, actual.str()); delete e; expected = ""; std::ostringstream actual2; // m[r29 - 12] e = Location::memOf( new Binary(opMinus, Location::regOf(29), new Const(12))); std::set<int> &s2 = df->getA_phi(e); for (const auto &pp : s2) actual2 << pp << " "; CPPUNIT_ASSERT_EQUAL(expected, actual2.str()); delete e; delete prog; }
void CfgTest::testSemiDominators () { BinaryFileFactory bff; BinaryFile* pBF = bff.Load(SEMI_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd* pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); bool gotMain; ADDRESS addr = pFE->getMainEntryPoint(gotMain); CPPUNIT_ASSERT (addr != NO_ADDRESS); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); DataFlow* df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "L (6)" (as per Appel, Figure 19.8). BB_IT it; PBB bb = cfg->getFirstBB(it); while (bb && bb->getLowAddr() != SEMI_L) { bb = cfg->getNextBB(it); } CPPUNIT_ASSERT(bb); int nL = df->pbbToNode(bb); // The dominator for L should be B, where the semi dominator is D // (book says F) unsigned actual_dom = (unsigned)df->nodeToBB(df->getIdom(nL))->getLowAddr(); unsigned actual_semi = (unsigned)df->nodeToBB(df->getSemi(nL))->getLowAddr(); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_B, actual_dom); CPPUNIT_ASSERT_EQUAL((unsigned)SEMI_D, actual_semi); // Check the final dominator frontier as well; should be M and B std::ostringstream expected, actual; //expected << std::hex << SEMI_M << " " << SEMI_B << " "; expected << std::hex << SEMI_B << " " << SEMI_M << " "; std::set<int>::iterator ii; std::set<int>& DFset = df->getDF(nL); for (ii=DFset.begin(); ii != DFset.end(); ii++) actual << std::hex << (unsigned)df->nodeToBB(*ii)->getLowAddr() << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); delete pFE; }
void CfgTest::testDominators () { BinaryFileFactory bff; BinaryFile *pBF = bff.Load(FRONTIER_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd *pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); bool gotMain; ADDRESS addr = pFE->getMainEntryPoint(gotMain); CPPUNIT_ASSERT (addr != NO_ADDRESS); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); DataFlow* df = pProc->getDataFlow(); df->dominators(cfg); // Find BB "5" (as per Appel, Figure 19.5). BB_IT it; PBB bb = cfg->getFirstBB(it); while (bb && bb->getLowAddr() != FRONTIER_FIVE) { bb = cfg->getNextBB(it); } CPPUNIT_ASSERT(bb); std::ostringstream expected, actual; //expected << std::hex << FRONTIER_FIVE << " " << FRONTIER_THIRTEEN << " " << FRONTIER_TWELVE << " " << // FRONTIER_FOUR << " "; expected << std::hex << FRONTIER_THIRTEEN << " " << FRONTIER_FOUR << " " << FRONTIER_TWELVE << " " << FRONTIER_FIVE << " "; int n5 = df->pbbToNode(bb); std::set<int>::iterator ii; std::set<int>& DFset = df->getDF(n5); for (ii=DFset.begin(); ii != DFset.end(); ii++) actual << std::hex << (unsigned)df->nodeToBB(*ii)->getLowAddr() << " "; CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str()); pBF->UnLoad(); delete pFE; }
/*============================================================================== * FUNCTION: CfgTest::testPlacePhi * OVERVIEW: Test the placing of phi functions *============================================================================*/ void CfgTest::testPlacePhi () { BinaryFileFactory bff; BinaryFile* pBF = bff.Load(FRONTIER_PENTIUM); CPPUNIT_ASSERT(pBF != 0); Prog* prog = new Prog; FrontEnd* pFE = new PentiumFrontEnd(pBF, prog, &bff); Type::clearNamedTypes(); prog->setFrontEnd(pFE); pFE->decode(prog); UserProc* pProc = (UserProc*) prog->getProc(0); Cfg* cfg = pProc->getCFG(); // Simplify expressions (e.g. m[ebp + -8] -> m[ebp - 8] prog->finishDecode(); DataFlow* df = pProc->getDataFlow(); df->dominators(cfg); df->placePhiFunctions(pProc); // m[r29 - 8] (x for this program) Exp* e = new Unary(opMemOf, new Binary(opMinus, Location::regOf(29), new Const(4))); // A_phi[x] should be the set {7 8 10 15 20 21} (all the join points) std::ostringstream ost; std::set<int>::iterator ii; std::set<int>& A_phi = df->getA_phi(e); for (ii = A_phi.begin(); ii != A_phi.end(); ++ii) ost << *ii << " "; std::string expected("7 8 10 15 20 21 "); CPPUNIT_ASSERT_EQUAL(expected, ost.str()); delete pFE; }
/** * Parse and execute a command supplied in interactive mode. * * \param argc The number of arguments. * \param argv Pointers to the arguments. * * \return A value indicating what happened. * * \retval 0 Success * \retval 1 Faillure * \retval 2 The user exited with \a quit or \a exit */ int Boomerang::parseCmd(int argc, const char **argv) { static Prog *prog = NULL; if (!strcmp(argv[0], "decode")) { if (argc <= 1) { std::cerr << "not enough arguments for cmd\n"; return 1; } const char *fname = argv[1]; Prog *p = loadAndDecode(fname); if (p == NULL) { std::cerr << "failed to load " << fname << "\n"; return 1; } prog = p; #if USE_XML } else if (!strcmp(argv[0], "load")) { if (argc <= 1) { std::cerr << "not enough arguments for cmd\n"; return 1; } const char *fname = argv[1]; XMLProgParser *p = new XMLProgParser(); Prog *pr = p->parse(fname); if (pr == NULL) { // try guessing pr = p->parse((outputPath + fname + "/" + fname + ".xml").c_str()); if (pr == NULL) { std::cerr << "failed to read xml " << fname << "\n"; return 1; } } prog = pr; } else if (!strcmp(argv[0], "save")) { if (prog == NULL) { std::cerr << "need to load or decode before save!\n"; return 1; } XMLProgParser *p = new XMLProgParser(); p->persistToXML(prog); #endif } else if (!strcmp(argv[0], "decompile")) { if (argc > 1) { Proc *proc = prog->findProc(argv[1]); if (proc == NULL) { std::cerr << "cannot find proc " << argv[1] << "\n"; return 1; } if (proc->isLib()) { std::cerr << "cannot decompile a lib proc\n"; return 1; } int indent = 0; ((UserProc*)proc)->decompile(new ProcList, indent); } else { prog->decompile(); } } else if (!strcmp(argv[0], "codegen")) { if (argc > 1 ) { Cluster *cluster = prog->findCluster(argv[1]); if (cluster == NULL) { std::cerr << "cannot find cluster " << argv[1] << "\n"; return 1; } prog->generateCode(cluster); } else { prog->generateCode(); } } else if (!strcmp(argv[0], "move")) { if (argc <= 1) { std::cerr << "not enough arguments for cmd\n"; return 1; } if (!strcmp(argv[1], "proc")) { if (argc <= 3) { std::cerr << "not enough arguments for cmd\n"; return 1; } Proc *proc = prog->findProc(argv[2]); if (proc == NULL) { std::cerr << "cannot find proc " << argv[2] << "\n"; return 1; } Cluster *cluster = prog->findCluster(argv[3]); if (cluster == NULL) { std::cerr << "cannot find cluster " << argv[3] << "\n"; return 1; } proc->setCluster(cluster); } else if (!strcmp(argv[1], "cluster")) { if (argc <= 3) { std::cerr << "not enough arguments for cmd\n"; return 1; } Cluster *cluster = prog->findCluster(argv[2]); if (cluster == NULL) { std::cerr << "cannot find cluster " << argv[2] << "\n"; return 1; } Cluster *parent = prog->findCluster(argv[3]); if (parent == NULL) { std::cerr << "cannot find cluster " << argv[3] << "\n"; return 1; } parent->addChild(cluster); } else { std::cerr << "don't know how to move a " << argv[1] << "\n"; return 1; } } else if (!strcmp(argv[0], "add")) { if (argc <= 1) { std::cerr << "not enough arguments for cmd\n"; return 1; } if (!strcmp(argv[1], "cluster")) { if (argc <= 2) { std::cerr << "not enough arguments for cmd\n"; return 1; } Cluster *cluster = new Cluster(argv[2]); if (cluster == NULL) { std::cerr << "cannot create cluster " << argv[2] << "\n"; return 1; } Cluster *parent = prog->getRootCluster(); if (argc > 3) { parent = prog->findCluster(argv[3]); if (cluster == NULL) { std::cerr << "cannot find cluster " << argv[3] << "\n"; return 1; } } parent->addChild(cluster); } else { std::cerr << "don't know how to add a " << argv[1] << "\n"; return 1; } } else if (!strcmp(argv[0], "delete")) { if (argc <= 1) { std::cerr << "not enough arguments for cmd\n"; return 1; } if (!strcmp(argv[1], "cluster")) { if (argc <= 2) { std::cerr << "not enough arguments for cmd\n"; return 1; } Cluster *cluster = prog->findCluster(argv[2]); if (cluster == NULL) { std::cerr << "cannot find cluster " << argv[2] << "\n"; return 1; } if (cluster->hasChildren() || cluster == prog->getRootCluster()) { std::cerr << "cluster " << argv[2] << " is not empty\n"; return 1; } if (prog->clusterUsed(cluster)) { std::cerr << "cluster " << argv[2] << " is not empty\n"; return 1; } unlink(cluster->getOutPath("xml")); unlink(cluster->getOutPath("c")); assert(cluster->getParent()); cluster->getParent()->removeChild(cluster); } else { std::cerr << "don't know how to delete a " << argv[1] << "\n"; return 1; } } else if (!strcmp(argv[0], "rename")) { if (argc <= 1) { std::cerr << "not enough arguments for cmd\n"; return 1; } if (!strcmp(argv[1], "proc")) { if (argc <= 3) { std::cerr << "not enough arguments for cmd\n"; return 1; } Proc *proc = prog->findProc(argv[2]); if (proc == NULL) { std::cerr << "cannot find proc " << argv[2] << "\n"; return 1; } Proc *nproc = prog->findProc(argv[3]); if (nproc != NULL) { std::cerr << "proc " << argv[3] << " already exists\n"; return 1; } proc->setName(argv[3]); } else if (!strcmp(argv[1], "cluster")) { if (argc <= 3) { std::cerr << "not enough arguments for cmd\n"; return 1; } Cluster *cluster = prog->findCluster(argv[2]); if (cluster == NULL) { std::cerr << "cannot find cluster " << argv[2] << "\n"; return 1; } Cluster *ncluster = prog->findCluster(argv[3]); if (ncluster == NULL) { std::cerr << "cluster " << argv[3] << " already exists\n"; return 1; } cluster->setName(argv[3]); } else { std::cerr << "don't know how to rename a " << argv[1] << "\n"; return 1; } } else if (!strcmp(argv[0], "info")) { if (argc <= 1) { std::cerr << "not enough arguments for cmd\n"; return 1; } if (!strcmp(argv[1], "prog")) { std::cout << "prog " << prog->getName() << ":\n"; std::cout << "\tclusters:\n"; prog->getRootCluster()->printTree(std::cout); std::cout << "\n\tlibprocs:\n"; PROGMAP::const_iterator it; for (Proc *p = prog->getFirstProc(it); p; p = prog->getNextProc(it)) if (p->isLib()) std::cout << "\t\t" << p->getName() << "\n"; std::cout << "\n\tuserprocs:\n"; for (Proc *p = prog->getFirstProc(it); p; p = prog->getNextProc(it)) if (!p->isLib()) std::cout << "\t\t" << p->getName() << "\n"; std::cout << "\n"; return 0; } else if (!strcmp(argv[1], "cluster")) { if (argc <= 2) { std::cerr << "not enough arguments for cmd\n"; return 1; } Cluster *cluster = prog->findCluster(argv[2]); if (cluster == NULL) { std::cerr << "cannot find cluster " << argv[2] << "\n"; return 1; } std::cout << "cluster " << cluster->getName() << ":\n"; if (cluster->getParent()) std::cout << "\tparent = " << cluster->getParent()->getName() << "\n"; else std::cout << "\troot cluster.\n"; std::cout << "\tprocs:\n"; PROGMAP::const_iterator it; for (Proc *p = prog->getFirstProc(it); p; p = prog->getNextProc(it)) if (p->getCluster() == cluster) std::cout << "\t\t" << p->getName() << "\n"; std::cout << "\n"; return 0; } else if (!strcmp(argv[1], "proc")) { if (argc <= 2) { std::cerr << "not enough arguments for cmd\n"; return 1; } Proc *proc = prog->findProc(argv[2]); if (proc == NULL) { std::cerr << "cannot find proc " << argv[2] << "\n"; return 1; } std::cout << "proc " << proc->getName() << ":\n"; std::cout << "\tbelongs to cluster " << proc->getCluster()->getName() << "\n"; std::cout << "\tnative address " << std::hex << proc->getNativeAddress() << std::dec << "\n"; if (proc->isLib()) std::cout << "\tis a library proc.\n"; else { std::cout << "\tis a user proc.\n"; UserProc *p = (UserProc*)proc; if (p->isDecoded()) std::cout << "\thas been decoded.\n"; //if (p->isAnalysed()) // std::cout << "\thas been analysed.\n"; } std::cout << "\n"; return 0; } else { std::cerr << "don't know how to print info about a " << argv[1] << "\n"; return 1; } } else if (!strcmp(argv[0], "print")) { if (argc <= 1) { std::cerr << "not enough arguments for cmd\n"; return 1; } Proc *proc = prog->findProc(argv[1]); if (proc == NULL) { std::cerr << "cannot find proc " << argv[1] << "\n"; return 1; } if (proc->isLib()) { std::cerr << "cannot print a libproc.\n"; return 1; } ((UserProc*)proc)->print(std::cout); std::cout << "\n"; return 0; } else if (!strcmp(argv[0], "exit")) { return 2; } else if (!strcmp(argv[0], "quit")) { return 2; } else if (!strcmp(argv[0], "help")) { helpcmd(); return 0; } else { std::cerr << "unknown cmd " << argv[0] << ".\n"; return 1; } return 0; }
/*============================================================================== * FUNCTION: TypeTest::testDataIntervalOverlaps * OVERVIEW: Test the DataIntervalMap class with overlapping addItems *============================================================================*/ void TypeTest::testDataIntervalOverlaps() { DataIntervalMap dim; Prog* prog = new Prog; UserProc* proc = (UserProc*) prog->newProc("test", 0x123); std::string name("test"); proc->setSignature(Signature::instantiate(PLAT_PENTIUM, CONV_C, name.c_str())); dim.setProc(proc); dim.addItem(0x1000, "firstInt", new IntegerType(32, 1)); dim.addItem(0x1004, "firstFloat", new FloatType(32)); dim.addItem(0x1008, "secondInt", new IntegerType(32, 1)); dim.addItem(0x100C, "secondFloat", new FloatType(32)); CompoundType ct; ct.addType(new IntegerType(32, 1), "int3"); ct.addType(new FloatType(32), "float3"); dim.addItem(0x1010, "existingStruct", &ct); // First insert a new struct over the top of the existing middle pair CompoundType ctu; ctu.addType(new IntegerType(32, 0), "newInt"); // This int has UNKNOWN sign ctu.addType(new FloatType(32), "newFloat"); dim.addItem(0x1008, "replacementStruct", &ctu); DataIntervalEntry* pdie = dim.find(0x1008); std::string expected = "struct { int newInt; float newFloat; }"; std::string actual = pdie->second.type->getCtype(); CPPUNIT_ASSERT_EQUAL(expected, actual); // Attempt a weave; should fail CompoundType ct3; ct3.addType(new FloatType(32), "newFloat3"); ct3.addType(new IntegerType(32, 0), "newInt3"); dim.addItem(0x1004, "weaveStruct1", &ct3); pdie = dim.find(0x1004); expected = "firstFloat"; actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); // Totally unaligned dim.addItem(0x1001, "weaveStruct2", &ct3); pdie = dim.find(0x1001); expected = "firstInt"; actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); dim.addItem(0x1004, "firstInt", new IntegerType(32, 1)); // Should fail pdie = dim.find(0x1004); expected = "firstFloat"; actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); // Set up three ints dim.deleteItem(0x1004); dim.addItem(0x1004, "firstInt", new IntegerType(32, 1)); // Definately signed dim.deleteItem(0x1008); dim.addItem(0x1008, "firstInt", new IntegerType(32, 0)); // Unknown signedess // then, add an array over the three integers ArrayType at(new IntegerType(32, 0), 3); dim.addItem(0x1000, "newArray", &at); pdie = dim.find(0x1005); // Check middle element expected = "newArray"; actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); pdie = dim.find(0x1000); // Check first actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); pdie = dim.find(0x100B); // Check last actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); // Already have an array of 3 ints at 0x1000. Put a new array completely before, then with only one word overlap dim.addItem(0xF00, "newArray2", &at); pdie = dim.find(0x1000); // Shouyld still be newArray at 0x1000 actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); pdie = dim.find(0xF00); expected = "newArray2"; actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); dim.addItem(0xFF8, "newArray3", &at); // Should fail pdie = dim.find(0xFF8); unsigned ue = 0; // Expect NULL unsigned ua = (unsigned)pdie; CPPUNIT_ASSERT_EQUAL(ue, ua); }
/*============================================================================== * FUNCTION: TypeTest::testDataInterval * OVERVIEW: Test the DataIntervalMap class *============================================================================*/ void TypeTest::testDataInterval() { DataIntervalMap dim; Prog* prog = new Prog; UserProc* proc = (UserProc*) prog->newProc("test", 0x123); std::string name("test"); proc->setSignature(Signature::instantiate(PLAT_PENTIUM, CONV_C, name.c_str())); dim.setProc(proc); dim.addItem(0x1000, "first", new IntegerType(32, 1)); dim.addItem(0x1004, "second", new FloatType(64)); std::string actual(dim.prints()); std::string expected("0x1000 first int\n" "0x1004 second double\n"); CPPUNIT_ASSERT_EQUAL(expected, actual); DataIntervalEntry* pdie = dim.find(0x1000); expected = "first"; CPPUNIT_ASSERT(pdie); actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); pdie = dim.find(0x1003); CPPUNIT_ASSERT(pdie); actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); pdie = dim.find(0x1004); CPPUNIT_ASSERT(pdie); expected = "second"; actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); pdie = dim.find(0x1007); CPPUNIT_ASSERT(pdie); actual = pdie->second.name; CPPUNIT_ASSERT_EQUAL(expected, actual); CompoundType ct; ct.addType(new IntegerType(16, 1), "short1"); ct.addType(new IntegerType(16, 1), "short2"); ct.addType(new IntegerType(32, 1), "int1"); ct.addType(new FloatType(32), "float1"); dim.addItem(0x1010, "struct1", &ct); ComplexTypeCompList& ctcl = ct.compForAddress(0x1012, dim); unsigned ua = ctcl.size(); unsigned ue = 1; CPPUNIT_ASSERT_EQUAL(ue, ua); ComplexTypeComp& ctc = ctcl.front(); ue = 0; ua = ctc.isArray; CPPUNIT_ASSERT_EQUAL(ue, ua); expected = "short2"; actual = ctc.u.memberName; CPPUNIT_ASSERT_EQUAL(expected, actual); // An array of 10 struct1's ArrayType at(&ct, 10); dim.addItem(0x1020, "array1", &at); ComplexTypeCompList& ctcl2 = at.compForAddress(0x1020+0x3C+8, dim); // Should be 2 components: [5] and .float1 ue = 2; ua = ctcl2.size(); CPPUNIT_ASSERT_EQUAL(ue, ua); ComplexTypeComp& ctc0 = ctcl2.front(); ComplexTypeComp& ctc1 = ctcl2.back(); ue = 1; ua = ctc0.isArray; CPPUNIT_ASSERT_EQUAL(ue, ua); ue = 5; ua = ctc0.u.index; CPPUNIT_ASSERT_EQUAL(ue, ua); ue = 0; ua = ctc1.isArray; CPPUNIT_ASSERT_EQUAL(ue, ua); expected = "float1"; actual = ctc1.u.memberName; CPPUNIT_ASSERT_EQUAL(expected, actual); }
void FrontSparcTest::testDelaySlot() { BinaryFileFactory bff; BinaryFile *pBF = bff.Load(BRANCH_SPARC); if (pBF == NULL) pBF = new BinaryFileStub(); // fallback on stub CPPUNIT_ASSERT(pBF != 0); CPPUNIT_ASSERT(pBF->GetMachine() == MACHINE_SPARC); Prog* prog = new Prog; FrontEnd *pFE = new SparcFrontEnd(pBF, prog, &bff); prog->setFrontEnd(pFE); // decode calls readLibraryCatalog(), which needs to have definitions for non-sparc architectures cleared Type::clearNamedTypes(); pFE->decode(prog); bool gotMain; ADDRESS addr = pFE->getMainEntryPoint(gotMain); CPPUNIT_ASSERT (addr != NO_ADDRESS); std::string name("testDelaySlot"); UserProc* pProc = new UserProc(prog, name, addr); std::ofstream dummy; bool res = pFE->processProc(addr, pProc, dummy, false); CPPUNIT_ASSERT(res == 1); Cfg* cfg = pProc->getCFG(); BB_IT it; PBB bb = cfg->getFirstBB(it); std::ostringstream o1; bb->print(o1); std::string expected("Call BB:\n" "in edges: \n" "out edges: 10a98 \n" "00010a80 0 *32* tmp := r14 - 120\n" " 0 *32* m[r14] := r16\n" " 0 *32* m[r14 + 4] := r17\n" " 0 *32* m[r14 + 8] := r18\n" " 0 *32* m[r14 + 12] := r19\n" " 0 *32* m[r14 + 16] := r20\n" " 0 *32* m[r14 + 20] := r21\n" " 0 *32* m[r14 + 24] := r22\n" " 0 *32* m[r14 + 28] := r23\n" " 0 *32* m[r14 + 32] := r24\n" " 0 *32* m[r14 + 36] := r25\n" " 0 *32* m[r14 + 40] := r26\n" " 0 *32* m[r14 + 44] := r27\n" " 0 *32* m[r14 + 48] := r28\n" " 0 *32* m[r14 + 52] := r29\n" " 0 *32* m[r14 + 56] := r30\n" " 0 *32* m[r14 + 60] := r31\n" " 0 *32* r24 := r8\n" " 0 *32* r25 := r9\n" " 0 *32* r26 := r10\n" " 0 *32* r27 := r11\n" " 0 *32* r28 := r12\n" " 0 *32* r29 := r13\n" " 0 *32* r30 := r14\n" " 0 *32* r31 := r15\n" " 0 *32* r14 := tmp\n" "00010a84 0 *32* r16 := 0x11400\n" "00010a88 0 *32* r16 := r16 | 808\n" "00010a8c 0 *32* r8 := r16\n" "00010a90 0 *32* tmp := r30\n" " 0 *32* r9 := r30 - 20\n" "00010a90 0 CALL scanf(\n" " )\n" " Reaching definitions: \n" " Live variables: \n"); std::string actual(o1.str()); CPPUNIT_ASSERT_EQUAL(expected, actual); bb = cfg->getNextBB(it); CPPUNIT_ASSERT(bb); std::ostringstream o2; bb->print(o2); expected = std::string("Call BB:\n" "in edges: 10a90 \n" "out edges: 10aa4 \n" "00010a98 0 *32* r8 := r16\n" "00010a9c 0 *32* tmp := r30\n" " 0 *32* r9 := r30 - 24\n" "00010a9c 0 CALL scanf(\n" " )\n" " Reaching definitions: \n" " Live variables: \n"); actual = std::string(o2.str()); CPPUNIT_ASSERT_EQUAL(expected, actual); bb = cfg->getNextBB(it); CPPUNIT_ASSERT(bb); std::ostringstream o3; bb->print(o3); expected = std::string("Twoway BB:\n" "in edges: 10a9c \n" "out edges: 10ac8 10ab8 \n" "00010aa4 0 *32* r8 := m[r30 - 20]\n" "00010aa8 0 *32* r16 := 5\n" "00010aac 0 *32* tmp := r16\n" " 0 *32* r0 := r16 - r8\n" " 0 *v* %flags := SUBFLAGS( tmp, r8, r0 )\n" "00010ab0 0 *32* r8 := 0x11400\n" "00010ab0 0 BRANCH 0x10ac8, condition not equals\n" "High level: %flags\n"); actual = std::string(o3.str()); CPPUNIT_ASSERT_EQUAL(expected, actual); bb = cfg->getNextBB(it); CPPUNIT_ASSERT(bb); std::ostringstream o4; bb->print(o4); expected = std::string("L1: Twoway BB:\n" "in edges: 10ab0 10ac4 \n" "out edges: 10ad8 10ad0 \n" "00010ac8 0 *32* r8 := 0x11400\n" "00010ac8 0 BRANCH 0x10ad8, condition equals\n" "High level: %flags\n"); actual = std::string(o4.str()); CPPUNIT_ASSERT_EQUAL(expected, actual); bb = cfg->getNextBB(it); CPPUNIT_ASSERT(bb); std::ostringstream o5; bb->print(o5); expected = std::string("Call BB:\n" "in edges: 10ab0 \n" "out edges: 10ac0 \n" "00010ab8 0 *32* r8 := r8 | 816\n" "00010ab8 0 CALL printf(\n" " )\n" " Reaching definitions: \n" " Live variables: \n"); actual = std::string(o5.str()); CPPUNIT_ASSERT_EQUAL(expected, actual); delete prog; }
// Somehow, a == NO_ADDRESS has come to mean decode anything not already decoded void FrontEnd::decode(Prog *prog, ADDRESS a) { if (a != NO_ADDRESS) { std::cout<<"decode main at a!= NOADDRESS\n"; prog->setNewProc(a); if (VERBOSE) LOG << "starting decode at address " << a << "\n"; UserProc* p = (UserProc*)prog->findProc(a); if (p == NULL) { if (VERBOSE) LOG << "no proc found at address " << a << "\n"; return; } if (p->isLib()) { LOG << "NOT decoding library proc at address 0x" << a << "\n"; return; } std::ofstream os; PROGMAP::const_iterator it; for (Proc *pProc = prog->getFirstProc(it); pProc != NULL; pProc = prog->getNextProc(it)) { std::cout<<"Proc name Before main "<<pProc->getName()<<"\n"; } processProc(a, p, os); for (Proc *pProc = prog->getFirstProc(it); pProc != NULL; pProc = prog->getNextProc(it)) { std::cout<<"Proc name After decode main "<<pProc->getName()<<"\n"; } p->setDecoded(); } else { // a == NO_ADDRESS std::cout<<"decode child proc\n"; bool change = true; while (change) { change = false; PROGMAP::const_iterator it; for (Proc *pProc = prog->getFirstProc(it); pProc != NULL; pProc = prog->getNextProc(it)) { if (pProc->isLib()) continue; UserProc *p = (UserProc*)pProc; if (p->isDecoded()) continue; // undecoded userproc.. decode it change = true; std::ofstream os; std::cout<<"Signature Before :"<<p->getSignature()->prints()<<"\n"; int res = processProc(p->getNativeAddress(), p, os); std::cout<<"Signature After :"<<p->getSignature()->prints()<<"\n"; //std::cout<<"Sig type:"<<p->getSignature()->prints()<<"\n"; std::cout<<"process Proc finish< res:"<<res<<"\n"; if (res == 1) p->setDecoded(); else break; // Break out of the loops if not decoding children if (Boomerang::get()->noDecodeChildren) break; } if (Boomerang::get()->noDecodeChildren) break; } } prog->wellForm(); }
std::vector<ADDRESS> FrontEnd::getEntryPoints() { std::vector<ADDRESS> entrypoints; bool gotMain = false; ADDRESS a = getMainEntryPoint(gotMain); if (a != NO_ADDRESS) entrypoints.push_back(a); else { // try some other tricks const char *fname = pBF->getFilename(); // X11 Module if (!strcmp(fname + strlen(fname) - 6, "_drv.o")) { const char *p = fname + strlen(fname) - 6; while (*p != '/' && *p != '\\' && p != fname) p--; if (p != fname) { p++; char *name = (char*)malloc(strlen(p) + 30); strcpy(name, p); name[strlen(name)-6] = 0; strcat(name, "ModuleData"); ADDRESS a = pBF->GetAddressByName(name, true); if (a != NO_ADDRESS) { ADDRESS vers, setup, teardown; vers = pBF->readNative4(a); setup = pBF->readNative4(a+4); teardown = pBF->readNative4(a+8); if (setup) { Type *ty = NamedType::getNamedType("ModuleSetupProc"); assert(ty->isFunc()); UserProc *proc = (UserProc*)prog->setNewProc(setup); assert(proc); Signature *sig = ty->asFunc()->getSignature()->clone(); const char *sym = pBF->SymbolByAddress(setup); if (sym) sig->setName(sym); sig->setForced(true); proc->setSignature(sig); entrypoints.push_back(setup); } if (teardown) { Type *ty = NamedType::getNamedType("ModuleTearDownProc"); assert(ty->isFunc()); UserProc *proc = (UserProc*)prog->setNewProc(teardown); assert(proc); Signature *sig = ty->asFunc()->getSignature()->clone(); const char *sym = pBF->SymbolByAddress(teardown); if (sym) sig->setName(sym); sig->setForced(true); proc->setSignature(sig); entrypoints.push_back(teardown); } } } } // Linux kernel module if (!strcmp(fname + strlen(fname) - 3, ".ko")) { a = pBF->GetAddressByName("init_module"); if (a != NO_ADDRESS) entrypoints.push_back(a); a = pBF->GetAddressByName("cleanup_module"); if (a != NO_ADDRESS) entrypoints.push_back(a); } } return entrypoints; }
ProcStatus ProcDecompiler::tryDecompileRecursive(UserProc *proc) { /* Cycle detection logic: * ********************* * cycleGrp is an initially null pointer to a set of procedures, representing the procedures * involved in the current recursion group, if any. These procedures have to be analysed * together as a group, after individual pre-group analysis. child is a set of procedures, * cleared at the top of decompile(), representing the cycles associated with the current * procedure and all of its children. If this is empty, the current procedure is not involved in * recursion, and can be decompiled up to and including removing unused statements. callStack is * an initially empty list of procedures, representing the call stack from the current entry * point to the current procedure, inclusive. If (after all children have been processed: * important!) the first element in callStack and also cycleGrp is the current procedure, we * have the maximal set of distinct cycles, so we can do the recursion group analysis and return * an empty set. At the end of the recursion group analysis, the whole group is complete, ready * for the global analyses. * * cycleSet decompile(ProcList callStack) // call stack initially empty * child = new ProcSet * push this proc to the call stack * for each child c called by this proc * if c has already been visited but not finished * // have new cycle * if c is in callStack * // this is a completely new cycle * insert every proc from c to the end of callStack into child * else * // this is a new branch of an existing cycle * child = c->cycleGrp * find first element f of callStack that is in cycleGrp * insert every proc after f to the end of callStack into child * for each element e of child * insert e->cycleGrp into child * e->cycleGrp = child * else * // no new cycle * tmp = c->decompile(callStack) * child = union(child, tmp) * set return statement in call to that of c * * if (child empty) * earlyDecompile() * child = middleDecompile() * removeUnusedStatments() // Not involved in recursion * else * // Is involved in recursion * find first element f in callStack that is also in cycleGrp * if (f == this) // The big test: have we got the complete strongly connected component? * recursionGroupAnalysis() // Yes, we have * child = new ProcSet // Don't add these processed cycles to the parent * remove last element (= this) from callStack * return child */ Project *project = proc->getProg()->getProject(); LOG_MSG("%1 procedure '%2'", (proc->getStatus() >= PROC_VISITED) ? "Re-visiting" : "Visiting", proc->getName()); project->alertDiscovered(proc); // Prevent infinite loops when there are cycles in the call graph (should never happen now) if (proc->getStatus() >= PROC_FINAL) { LOG_WARN("Proc %1 already has status PROC_FINAL", proc->getName()); return PROC_FINAL; // Already decompiled } if (proc->getStatus() < PROC_DECODED) { // Can happen e.g. if a callee is visible only after analysing a switch statement // Actually decoding for the first time, not REdecoding if (!proc->getProg()->reDecode(proc)) { return PROC_UNDECODED; } } if (proc->getStatus() < PROC_VISITED) { proc->setStatus(PROC_VISITED); // We have at least visited this proc "on the way down" } m_callStack.push_back(proc); if (project->getSettings()->verboseOutput) { printCallStack(); } if (project->getSettings()->decodeChildren) { // Recurse to callees first, to perform a depth first search for (BasicBlock *bb : *proc->getCFG()) { if (bb->getType() != BBType::Call) { continue; } // The call Statement will be in the last RTL in this BB CallStatement *call = static_cast<CallStatement *>(bb->getRTLs()->back()->getHlStmt()); if (!call->isCall()) { LOG_WARN("BB at address %1 is a CALL but last stmt is not a call: %2", bb->getLowAddr(), call); continue; } assert(call->isCall()); UserProc *callee = dynamic_cast<UserProc *>(call->getDestProc()); if (callee == nullptr) { // not an user proc, or missing dest continue; } if (callee->getStatus() == PROC_FINAL) { // Already decompiled, but the return statement still needs to be set for this call call->setCalleeReturn(callee->getRetStmt()); continue; } // check if the callee has already been visited but not done (apart from global // analyses). This means that we have found a new cycle or a part of an existing cycle if ((callee->getStatus() >= PROC_VISITED) && (callee->getStatus() <= PROC_EARLYDONE)) { // if callee is in callStack ProcList::iterator calleeIt = std::find(m_callStack.begin(), m_callStack.end(), callee); if (calleeIt != m_callStack.end()) { // This is a completely new cycle std::shared_ptr<ProcSet> newRecursionGroup(new ProcSet()); newRecursionGroup->insert(calleeIt, m_callStack.end()); createRecursionGoup(newRecursionGroup); } else if (callee->getRecursionGroup()) { // This is a new branch of an existing cycle that was visited previously std::shared_ptr<ProcSet> recursionGroup = callee->getRecursionGroup(); // Find first element func of callStack that is in callee->recursionGroup ProcList::iterator _pi = std::find_if( m_callStack.begin(), m_callStack.end(), [callee](UserProc *func) { return callee->getRecursionGroup()->find(func) != callee->getRecursionGroup()->end(); }); // Insert every proc after func to the end of path into child assert(_pi != m_callStack.end()); for (auto it = std::next(_pi); it != m_callStack.end(); ++it) { addToRecursionGroup(*it, recursionGroup); } } proc->setStatus(PROC_INCYCLE); } else { // No new cycle LOG_VERBOSE("Preparing to decompile callee '%1' of '%2'", callee->getName(), proc->getName()); callee->promoteSignature(); tryDecompileRecursive(callee); // Child has at least done middleDecompile(), possibly more call->setCalleeReturn(callee->getRetStmt()); if (proc->getStatus() != PROC_INCYCLE && m_recursionGroups.find(proc) != m_recursionGroups.end()) { proc->setStatus(PROC_INCYCLE); proc->setRecursionGroup(m_recursionGroups.find(proc)->second); } } } } // if no child involved in recursion if (proc->getStatus() != PROC_INCYCLE) { project->alertDecompiling(proc); LOG_MSG("Decompiling procedure '%1'", proc->getName()); earlyDecompile(proc); middleDecompile(proc); if (project->getSettings()->verboseOutput) { printCallStack(); } } if (proc->getStatus() != PROC_INCYCLE) { lateDecompile(proc); // Do the whole works proc->setStatus(PROC_FINAL); project->alertEndDecompile(proc); } else if (m_recursionGroups.find(proc) != m_recursionGroups.end()) { // This proc's callees, and hence this proc, is/are involved in recursion. // Find first element f in path that is also in our recursion group ProcList::iterator f = std::find_if( m_callStack.begin(), m_callStack.end(), [proc](UserProc *func) { return proc->getRecursionGroup()->find(func) != proc->getRecursionGroup()->end(); }); // The big test: have we found the whole strongly connected component (in the call graph)? if (*f == proc) { // Yes, process these procs as a group recursionGroupAnalysis(proc->getRecursionGroup()); proc->setStatus(PROC_FINAL); project->alertEndDecompile(proc); } } // Remove last element (= this) from path assert(!m_callStack.empty()); assert(m_callStack.back() == proc); m_callStack.pop_back(); LOG_MSG("Finished decompile of '%1'", proc->getName()); if (project->getSettings()->verboseOutput) { printCallStack(); } return proc->getStatus(); }