static bool hasLinearPathInternal(std::set<uint32> &visited, const Block &block1, const Block &block2) { /* Checks that a linear path exists between two blocks, by recursively * descending into the children of the earlier block, until we either * reached the later block (which means there is a path), or moved * past the later block (which means there is no path). */ // Remember which blocks we already visited, so we don't process them twice visited.insert(block1.address); // The two blocks are the same => we found a path if (block1.address == block2.address) return true; // We moved past the destination => no path if (block1.address > block2.address) return false; // Continue along the children assert(block1.children.size() == block1.childrenTypes.size()); for (size_t i = 0; i < block1.children.size(); i++) { const Block &child = *block1.children[i]; const BlockEdgeType type = block1.childrenTypes[i]; // Don't follow subroutine calls, don't jump backwards and don't visit blocks twice if (!isSubRoutineCall(type) && (child.address > block1.address)) if (visited.find(child.address) == visited.end()) if (hasLinearPathInternal(visited, child, block2)) return true; } return false; }
std::vector<const Block *> Block::getLaterParents(bool includeSubRoutines) const { std::vector<const Block *> result; for (std::vector<const Block *>::const_iterator p = parents.begin(); p != parents.end(); ++p) if ((*p)->address >= address) if (includeSubRoutines || !isSubRoutineCall(getParentChildEdgeType(**p, *this))) result.push_back(*p); return result; }
std::vector<const Block *> Block::getLaterChildren(bool includeSubRoutines) const { std::vector<const Block *> result; for (std::vector<const Block *>::const_iterator c = children.begin(); c != children.end(); ++c) if ((*c)->address >= address) if (includeSubRoutines || !isSubRoutineCall(getParentChildEdgeType(*this, **c))) result.push_back(*c); return result; }
void Decompiler::writeBlock(Common::WriteStream &out, const Block *block, size_t indent) { for (const auto instruction : block->instructions) { writeInstruction(out, instruction, indent); } for (const auto &childType : block->childrenTypes) { if (isSubRoutineCall(childType)) { writeIndent(out, indent); const Instruction *instruction = block->instructions.back(); out.writeString(formatJumpLabelName(*instruction->branches[0])); out.writeString("("); for (size_t i = 0; i < instruction->variables.size(); ++i) { out.writeString(formatVariableName(instruction->variables[i])); if (i < instruction->variables.size() - 1) out.writeString(", "); } out.writeString(");\n"); writeBlock(out, block->children[1], indent); } } for (const auto &control : block->controls) { if (control.type == kControlTypeReturn) { writeIndent(out, indent); out.writeString("return;\n"); } else if (control.type == kControlTypeIfCond) { writeIfControl(out, control, indent); } // TODO: while // TODO: break // TODO: continue } }
bool Block::isSubRoutineChild(const Block &child) const { return isSubRoutineCall(getParentChildEdgeType(*this, child)); }
bool Block::isSubRoutineChild(size_t i) const { return (i < childrenTypes.size() && isSubRoutineCall(childrenTypes[i])); }