Ejemplo n.º 1
0
/**
 * 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;
}
Ejemplo n.º 2
0
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";
    }
}
Ejemplo n.º 3
0
/**
 * 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;
}
Ejemplo n.º 4
0
/*==============================================================================
 * 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;
}
Ejemplo n.º 5
0
// 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();
}
Ejemplo n.º 6
0
/*==============================================================================
 * 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;
}
Ejemplo n.º 7
0
/**
 * 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;
}
Ejemplo n.º 8
0
/**
 * 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;
}
Ejemplo n.º 9
0
/**
 * 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;
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
/*==============================================================================
 * 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;
}
Ejemplo n.º 13
0
/**
 * 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;
}
Ejemplo n.º 14
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);
}
Ejemplo n.º 15
0
/*==============================================================================
 * 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);
}
Ejemplo n.º 16
0
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;
}
Ejemplo n.º 17
0
// 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();
}
Ejemplo n.º 18
0
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;
}
Ejemplo n.º 19
0
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();
}