Files
TheRock/rocm-systems/projects/rocprofiler-systems/external/dyninst/parseAPI/src/Function.C
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

872 lines
27 KiB
C++

/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Parser.h"
#include <algorithm>
#include "dyntypes.h"
#include "CodeObject.h"
#include "CFG.h"
#include "debug_parse.h"
#include "util.h"
#include "LoopAnalyzer.h"
#include "dominator.h"
#include "dataflowAPI/h/slicing.h"
#include "dataflowAPI/h/AbslocInterface.h"
#include "instructionAPI/h/InstructionDecoder.h"
#include "common/h/Graph.h"
#include "StackTamperVisitor.h"
#include "common/src/dthread.h"
#include <dyncompat/thread/lock_guard.hpp>
using namespace std;
using namespace Dyninst;
using namespace Dyninst::ParseAPI;
Function::Function() :
_start(0),
_obj(NULL),
_region(NULL),
_isrc(NULL),
_cache_valid(false),
_src(RT),
_rs(UNSET),
_entry(NULL),
_is_leaf_function(true),
_ret_addr(0),
_parsed(false),
_no_stack_frame(true),
_saves_fp(false),
_cleans_stack(false),
_tamper(TAMPER_UNSET),
_tamper_addr(0),
_loop_analyzed(false),
_loop_root(NULL),
isDominatorInfoReady(false),
isPostDominatorInfoReady(false)
{
fprintf(stderr,"PROBABLE ERROR, default ParseAPI::Function constructor\n");
}
Function::Function(Address addr, string name, CodeObject * obj,
CodeRegion * region, InstructionSource * isrc) :
_start(addr),
_obj(obj),
_region(region),
_isrc(isrc),
_cache_valid(false),
_src(RT),
_rs(UNSET),
_name(name),
_entry(NULL),
_is_leaf_function(true),
_ret_addr(0),
_parsed(false),
_no_stack_frame(true),
_saves_fp(false),
_cleans_stack(false),
_tamper(TAMPER_UNSET),
_tamper_addr(0),
_loop_analyzed(false),
_loop_root(NULL),
isDominatorInfoReady(false),
isPostDominatorInfoReady(false)
{
if (obj->defensiveMode()) {
mal_printf("new funct at %lx\n",addr);
}
if (obj && obj->cs()) {
obj->cs()->incrementCounter(PARSE_FUNCTION_COUNT);
}
if (obj && obj->cs() && obj->cs()->nonReturning(name)) {
set_retstatus(NORETURN);
}
}
ParseAPI::Edge::~Edge() {
}
Function::~Function()
{
if (_obj && _obj->cs()) {
_obj->cs()->decrementCounter(PARSE_FUNCTION_COUNT);
}
vector<FuncExtent *>::iterator eit = _extents.begin();
for( ; eit != _extents.end(); ++eit) {
delete *eit;
}
for (auto lit = _loops.begin(); lit != _loops.end(); ++lit)
delete *lit;
}
Function::blocklist
Function::blocks()
{
dyncompat::lock_guard<Function> g(*this);
if(!_cache_valid)
finalize();
return blocklist(blocks_begin(), blocks_end());
}
// Get the current set of blocks,
// as a const operation
Function::const_blocklist
Function::blocks() const
{
dyncompat::lock_guard<const Function> g(*this);
assert(_cache_valid);
return const_blocklist(blocks_begin(), blocks_end());
}
const Function::edgelist &
Function::callEdges() {
dyncompat::lock_guard<Function> g(*this);
if(!_cache_valid)
finalize();
return _call_edge_list;
}
Function::const_blocklist
Function::returnBlocks() {
dyncompat::lock_guard<Function> g(*this);
if (!_cache_valid)
finalize();
return const_blocklist(ret_begin(), ret_end());
}
Function::const_blocklist
Function::exitBlocks() {
dyncompat::lock_guard<Function> g(*this);
if (!_cache_valid)
finalize();
return const_blocklist(exit_begin(), exit_end());
}
Function::const_blocklist
Function::exitBlocks() const {
dyncompat::lock_guard<const Function> g(*this);
assert(_cache_valid);
return const_blocklist(exit_begin(), exit_end());
}
vector<FuncExtent *> const&
Function::extents()
{
dyncompat::lock_guard<Function> g(*this);
if(!_cache_valid)
finalize();
return _extents;
}
void
Function::finalize()
{
dyncompat::lock_guard<Function> g(*this);
bool done;
do {
_extents.clear();
_exitBL.clear();
// for each block, decrement its refcount
for (auto blk = blocks_begin(); blk != blocks_end(); blk++) {
(*blk)->_func_cnt.fetch_add(-1);
}
_bmap.clear();
_retBL.clear();
_call_edge_list.clear();
_cache_valid = false;
// The Parser knows how to finalize
// a Function's parse data
done = _obj->parser->finalize(this);
} while (!done);
}
Function::blocklist
Function::blocks_int()
{
dyncompat::lock_guard<Function> g(*this);
if(_cache_valid || !_entry)
return blocklist(blocks_begin(), blocks_end());
// overloaded map warning:
// visited[addr] == 1 means visited
// visited[addr] == 2 means already on the return list
dyn_hash_map<Address,short> visited;
vector<Block *> worklist;
bool need_entry = true;
for(auto bit=blocks_begin();
bit!=blocks_end();++bit)
{
Block * b = *bit;
visited[b->start()] = 1;
need_entry = need_entry && (b != _entry);
}
worklist.insert(worklist.begin(),blocks_begin(), blocks_end());
if(need_entry) {
worklist.push_back(_entry);
visited[_entry->start()] = 1;
add_block(_entry);
}
// We need to revalidate that the exit blocks we found before are still exit blocks
blockmap::iterator nextIt, curIt;
for (curIt = _exitBL.begin(); curIt != _exitBL.end(); ) {
Block *cur = curIt->second;
bool exit_func = false;
bool found_call = false;
bool found_call_ft = false;
dyncompat::lock_guard<Block> blockGuard(*cur);
Block::edgelist targets;
cur->copy_targets(targets);
if (targets.empty()) exit_func = true;
for (auto e : targets) {
Block *t = e->trg();
if(e->type() == CALL || e->interproc()) {
found_call = true;
}
if (e->type() == CALL_FT) {
found_call_ft = true;
}
if (e->type() == RET || !t || t->obj() != cur->obj()) {
exit_func = true;
break;
}
}
if (found_call && !found_call_ft && !obj()->defensiveMode()) exit_func = true;
if (!exit_func) {
nextIt = curIt;
++nextIt;
_exitBL.erase(curIt);
curIt = nextIt;
} else ++curIt;
}
// avoid adding duplicate return blocks
for(auto bit=exit_begin();
bit!=exit_end();++bit)
{
Block * b = *bit;
visited[b->start()] = 2;
}
while(!worklist.empty()) {
Block * cur = worklist.back();
worklist.pop_back();
bool link_return = false;
bool exits_func = false;
bool found_call = false;
bool found_call_ft = false;
Block::edgelist trgs;
cur->copy_targets(trgs);
if (trgs.empty()) {
// Woo hlt!
parsing_printf("No targets, exits func\n");
exits_func = true;
}
for(auto e : trgs) {
Block * t = e->trg();
if(t) {
parsing_printf("\t Considering target block [0x%lx,0x%lx) from edge %p\n",
t->start(), t->end(), (void*)e);
}
if (e->type() == CALL_FT) {
found_call_ft = true;
}
if(e->type() == CALL) {
parsing_printf("\t Call typed\n");
_call_edge_list.insert(e);
found_call = true;
continue;
}
if(e->type() == RET) {
link_return = true;
exits_func = true;
parsing_printf("Block has return edge\n");
if (obj()->defensiveMode()) {
if (_tamper != TAMPER_UNSET && _tamper != TAMPER_NONE)
continue;
}
continue;
}
/* Handle tailcall edges */
if(e->interproc()) {
parsing_printf("\t Interprocedural\n");
_call_edge_list.insert(e);
found_call = true;
continue;
}
// If we are heading to a different CodeObject, call it a return
// and don't add target blocks.
if (t && (t->obj() != cur->obj())) {
// This is a jump to a different CodeObject; call it an exit
parsing_printf("Block exits object\n");
exits_func = true;
continue;
}
/* sink edges receive no further processing */
if(e->sinkEdge()) {
parsing_printf("\t Sink edge, skipping\n");
continue;
}
if(!HASHDEF(visited,e->trg_addr())) {
if(t) {
parsing_printf("\t Adding target block [%lx,%lx) to worklist according to edge from %lx, type %d\n", t->start(), t->end(), e->src()->last(), e->type());
worklist.push_back(t);
visited[e->trg_addr()] = 1;
add_block(t);
}
}
}
if (found_call && !found_call_ft && !obj()->defensiveMode()) {
parsing_printf("\t exits func\n");
exits_func = true;
}
if (link_return) assert(exits_func);
if(exits_func) {
if (link_return)
delayed_link_return(_obj,cur);
if(visited[cur->start()] <= 1) {
_exitBL[cur->start()] = cur;
parsing_printf("Adding block 0x%lx as exit\n", cur->start());
if (link_return) {
_retBL[cur->start()] = cur;
}
}
}
}
return blocklist(blocks_begin(), blocks_end());
}
/* Adds return edges to the CFG for a particular retblk, based
* on callers to this function. Handles case of return block
* that targets the entry block of a new function separately
* (ret to entry happens if the function tampers with its stack
* and maybe if this function is a signal handler?)
*/
void
Function::delayed_link_return(CodeObject * o, Block * retblk)
{
dyncompat::lock_guard<Function> g(*this);
bool link_entry = false;
Block::edgelist::const_iterator eit;
dyn_hash_map<Address,bool> linked;
{
dyncompat::lock_guard<Block> blockGuard(*retblk);
eit = retblk->targets().begin();
for( ; eit != retblk->targets().end(); ++eit) {
Edge * e = *eit;
linked[e->trg_addr()] = true;
}
}
dyncompat::lock_guard<Block> g2(*_entry);
eit = _entry->sources().begin();
for( ; eit != _entry->sources().end(); ++eit) {
Edge * e = *eit;
if(e->type() == CALL) {
parsing_printf("[%s:%d] linking return edge %lx -> %lx\n",
FILE__,__LINE__,retblk->lastInsnAddr(),e->src()->end());
// XXX opportunity here to be more conservative about delayed
// determination of return status
Block * call_ft = _obj->findBlockByEntry(region(),e->src()->end());
if(!call_ft) {
parsing_printf("[%s:%d] no block found, error!\n",
FILE__,__LINE__);
}
else if(!HASHDEF(linked,call_ft->start())) {
if(call_ft == _entry)
link_entry = true;
else
o->add_edge(retblk,call_ft,RET);
linked[call_ft->start()] = true;
}
}
}
// can't do this during iteration
if(link_entry)
o->add_edge(retblk,_entry,RET);
}
void
Function::add_block(Block *b)
{
dyncompat::lock_guard<Function> g(*this);
b->_func_cnt.fetch_add(1); // block counts references
_bmap[b->start()] = b;
}
const string &
Function::name() const
{
return _name;
}
bool
Function::contains(Block *b)
{
dyncompat::lock_guard<Function> g(*this);
if (b == NULL) return false;
if(!_cache_valid)
finalize();
return HASHDEF(_bmap,b->start());
}
bool
Function::contains(Block *b) const
{
// dyncompat::lock_guard<const Function> g(*this);
if (b == NULL) return false;
return HASHDEF(_bmap,b->start());
}
void Function::setEntryBlock(Block *new_entry)
{
dyncompat::lock_guard<Function> g(*this);
obj()->parser->move_func(this, new_entry->start(), new_entry->region());
_region = new_entry->region();
_start = new_entry->start();
_entry = new_entry;
}
void Function::set_retstatus(FuncReturnStatus rs)
{
dyncompat::lock_guard<Function> g(*this);
// If this function is a known non-returning function,
// we should ignore this result.
// A exmaple is .Unwind_Resume, which is non-returning.
// But on powerpc, the function contains a BLR instruction,
// looking like a return instruction, but actually is not.
if (obj()->cs()->nonReturning(_name) && rs != NORETURN) return;
parsing_printf("Set function %s at %lx ret status from %d to %d\n", _name.c_str(), addr(), _rs.load(), rs);
if (_rs == RETURN && rs == NORETURN) {
parsing_printf("\tERROR: ret status is already set to RETURN, now setting to NORETURN\n");
}
if (_rs == NORETURN && rs == RETURN) {
parsing_printf("\tERROR: ret status is already set to NORETURN, now setting to RETURN\n");
}
// If we are changing the return status, update prev counter
if (_rs != UNSET) {
if (_rs == NORETURN) {
_obj->cs()->decrementCounter(PARSE_NORETURN_COUNT);
} else if (_rs == RETURN) {
_obj->cs()->decrementCounter(PARSE_RETURN_COUNT);
} else if (_rs == UNKNOWN) {
_obj->cs()->decrementCounter(PARSE_UNKNOWN_COUNT);
}
}
// Update counter information
if (rs == NORETURN) {
_obj->cs()->incrementCounter(PARSE_NORETURN_COUNT);
} else if (rs == RETURN) {
_obj->cs()->incrementCounter(PARSE_RETURN_COUNT);
} else if (rs == UNKNOWN) {
_obj->cs()->incrementCounter(PARSE_UNKNOWN_COUNT);
}
// Write access is handled by the lock, so this should always work.
// Helgrind gets confused, so the cmp&swap hides the actual write.
FuncReturnStatus e = _rs;
assert(_rs.compare_exchange_strong(e, rs));
}
void
Function::removeBlock(Block* dead)
{
dyncompat::lock_guard<Function> g(*this);
_cache_valid = false;
// specify replacement entry prior to deleting entry block, unless
// deleting all blocks
if (dead == _entry) {
mal_printf("Warning: removing entry block [%lx %lx) for function at "
"%lx\n", dead->start(), dead->end(), addr());
_entry = NULL;
assert(0);
}
// remove dead block from _retBL and _call_edge_list
dyncompat::lock_guard<Block> g2(*dead);
const Block::edgelist & outs = dead->targets();
for (Block::edgelist::const_iterator oit = outs.begin();
outs.end() != oit;
oit++ )
{
switch((*oit)->type()) {
case CALL: {
bool foundEdge = false;
for (set<Edge*>::iterator cit = _call_edge_list.begin();
_call_edge_list.end() != cit;
cit++)
{
if (*oit == *cit) {
foundEdge = true;
_call_edge_list.erase(cit);
break;
}
}
assert(foundEdge || (*oit)->sinkEdge());
break;
}
case RET:
_retBL.erase(dead->start());
break;
default:
break;
}
}
// remove dead block from block map
_bmap.erase(dead->start());
_exitBL.erase(dead->start());
}
class ST_Predicates : public Slicer::Predicates {};
StackTamper
Function::tampersStack(bool recalculate)
{
dyncompat::lock_guard<Function> g(*this);
using namespace SymbolicEvaluation;
using namespace InstructionAPI;
if ( ! obj()->defensiveMode() ) {
assert(0);
_tamper = TAMPER_NONE;
return _tamper;
}
// this is above the cond'n below b/c it finalizes the function,
// which could in turn call this function
Function::const_blocklist retblks(returnBlocks());
if ( retblks.begin() == retblks.end() ) {
_tamper = TAMPER_NONE;
return _tamper;
}
// The following line leads to dangling pointers, but leaving
// in until we understand why it was originally there.
//_cache_valid = false;
// if we want to re-calculate the tamper address
if (!recalculate && TAMPER_UNSET != _tamper) {
return _tamper;
}
assert(_cache_valid);
AssignmentConverter converter(true, true);
vector<Assignment::Ptr> assgns;
ST_Predicates preds;
_tamper = TAMPER_UNSET;
for (auto bit = retblks.begin(); retblks.end() != bit; ++bit) {
assert(_cache_valid);
Address retnAddr = (*bit)->lastInsnAddr();
InstructionDecoder retdec(this->isrc()->getPtrToInstruction(retnAddr),
InstructionDecoder::maxInstructionLength,
this->region()->getArch() );
Instruction retn = retdec.decode();
converter.convert(retn, retnAddr, this, *bit, assgns);
vector<Assignment::Ptr>::iterator ait;
AST::Ptr sliceAtRet;
for (ait = assgns.begin(); assgns.end() != ait; ait++) {
AbsRegion & outReg = (*ait)->out();
if ( outReg.absloc().isPC() ) {
// First check to see if an input is an unresolved stack slot
// (or worse, the heap) - since if that's the case there's no use
// in spending a lot of time slicing.
std::vector<AbsRegion>::const_iterator in_iter;
for (in_iter = (*ait)->inputs().begin();
in_iter != (*ait)->inputs().end(); ++in_iter) {
if (in_iter->type() != Absloc::Unknown) {
_tamper = TAMPER_NONZERO;
_tamper_addr = 0;
set_retstatus(NORETURN);
mal_printf("Stack tamper analysis for ret block at "
"%lx found unresolved stack slot or heap "
"addr, marking as TAMPER_NONZERO\n", retnAddr);
return _tamper;
}
}
Slicer slicer(*ait,*bit,this);
Graph::Ptr slGraph = slicer.backwardSlice(preds);
DataflowAPI::Result_t slRes;
DataflowAPI::SymEval::expand(slGraph,slRes);
sliceAtRet = slRes[*ait];
if (dyn_debug_malware && sliceAtRet != NULL) {
cerr << "assignment " << (*ait)->format() << " is "
<< sliceAtRet->format() << "\n";
}
break;
}
}
if (sliceAtRet == NULL) {
mal_printf("Failed to produce a slice for retn at %lx %s[%d]\n",
retnAddr, FILE__,__LINE__);
continue;
}
StackTamperVisitor vis(Absloc(-static_cast<int>(isrc()->getAddressWidth()), 0, this));
Address curTamperAddr=0;
StackTamper curtamper = vis.tampersStack(sliceAtRet, curTamperAddr);
mal_printf("StackTamperVisitor for func at 0x%lx block[%lx %lx) w/ "
"lastInsn at 0x%lx returns tamper=%d tamperAddr=0x%lx\n",
_start, (*bit)->start(), (*bit)->end(), retnAddr,
curtamper, curTamperAddr);
if (TAMPER_UNSET == _tamper || TAMPER_NONE == _tamper ||
(TAMPER_NONZERO == _tamper &&
TAMPER_NONE != curtamper))
{
_tamper = curtamper;
_tamper_addr = curTamperAddr;
}
else if ((TAMPER_REL == _tamper || TAMPER_ABS == _tamper) &&
(TAMPER_REL == curtamper || TAMPER_ABS == curtamper))
{
if (_tamper != curtamper || _tamper_addr != curTamperAddr) {
fprintf(stderr, "WARNING! Unhandled case in stackTamper "
"analysis, func at %lx has distinct tamperAddrs "
"%d:%lx %d:%lx at different return instructions, "
"setting to TAMPER_NONZERO %s[%d]\n",
this->addr(), _tamper,_tamper_addr, curtamper,
curTamperAddr, FILE__, __LINE__);
_tamper = TAMPER_NONZERO; // let instrumentation take care of it
}
}
assgns.clear();
}
if ( TAMPER_UNSET == _tamper ) {
mal_printf("WARNING: we found no valid slices for function at %lx "
"%s[%d]\n", _start, FILE__,__LINE__);
_tamper = TAMPER_NONZERO;
}
if ( TAMPER_NONE != _tamper && TAMPER_REL != _tamper && RETURN == _rs ) {
set_retstatus(NORETURN);
}
return _tamper;
}
void Function::destroy(Function *f) {
f->obj()->destroy(f);
}
LoopTreeNode* Function::getLoopTree() const{
dyncompat::lock_guard<const Function> g(*this);
if (_loop_root == NULL) {
LoopAnalyzer la(this);
la.createLoopHierarchy();
}
return _loop_root;
}
// this methods returns the loop objects that exist in the control flow
// grap. It returns a set. And if there are no loops, then it returns the empty
// set. not NULL.
void Function::getLoopsByNestingLevel(vector<Loop*>& lbb,
bool outerMostOnly) const
{
dyncompat::lock_guard<const Function> g(*this);
if (_loop_analyzed == false) {
LoopAnalyzer la(this);
la.analyzeLoops();
_loop_analyzed = true;
}
for (std::set<Loop *>::iterator iter = _loops.begin();
iter != _loops.end(); ++iter) {
// if we are only getting the outermost loops
if (outerMostOnly &&
(*iter)->parentLoop() != NULL) continue;
lbb.push_back(*iter);
}
return;
}
// get all the loops in this flow graph
bool
Function::getLoops(vector<Loop*>& lbb) const
{
dyncompat::lock_guard<const Function> g(*this);
getLoopsByNestingLevel(lbb, false);
return true;
}
// get the outermost loops in this flow graph
bool
Function::getOuterLoops(vector<Loop*>& lbb) const
{
dyncompat::lock_guard<const Function> g(*this);
getLoopsByNestingLevel(lbb, true);
return true;
}
Loop *Function::findLoop(const char *name) const
{
dyncompat::lock_guard<const Function> g(*this);
return getLoopTree()->findLoop(name);
}
//this method fill the dominator information of each basic block
//looking at the control flow edges. It uses a fixed point calculation
//to find the immediate dominator of the basic blocks and the set of
//basic blocks that are immediately dominated by this one.
//Before calling this method all the dominator information
//is going to give incorrect results. So first this function must
//be called to process dominator related fields and methods.
void Function::fillDominatorInfo() const
{
dyncompat::lock_guard<const Function> g(*this);
if (!isDominatorInfoReady) {
dominatorCFG domcfg(this);
domcfg.calcDominators();
isDominatorInfoReady = true;
}
}
void Function::fillPostDominatorInfo() const
{
dyncompat::lock_guard<const Function> g(*this);
if (!isPostDominatorInfoReady) {
dominatorCFG domcfg(this);
domcfg.calcPostDominators();
isPostDominatorInfoReady = true;
}
}
bool Function::dominates(Block* A, Block *B) const {
dyncompat::lock_guard<const Function> g(*this);
if (A == NULL || B == NULL) return false;
if (A == B) return true;
fillDominatorInfo();
if (!immediateDominates[A]) return false;
for (auto bit = immediateDominates[A]->begin(); bit != immediateDominates[A]->end(); ++bit)
if (dominates(*bit, B)) return true;
return false;
}
Block* Function::getImmediateDominator(Block *A) const {
dyncompat::lock_guard<const Function> g(*this);
fillDominatorInfo();
return immediateDominator[A];
}
void Function::getImmediateDominates(Block *A, set<Block*> &imd) const {
dyncompat::lock_guard<const Function> g(*this);
fillDominatorInfo();
if (immediateDominates[A] != NULL)
imd.insert(immediateDominates[A]->begin(), immediateDominates[A]->end());
}
void Function::getAllDominates(Block *A, set<Block*> &d) const {
dyncompat::lock_guard<const Function> g(*this);
fillDominatorInfo();
d.insert(A);
if (immediateDominates[A] == NULL) return;
for (auto bit = immediateDominates[A]->begin(); bit != immediateDominates[A]->end(); ++bit)
getAllDominates(*bit, d);
}
bool Function::postDominates(Block* A, Block *B) const {
dyncompat::lock_guard<const Function> g(*this);
if (A == NULL || B == NULL) return false;
if (A == B) return true;
fillPostDominatorInfo();
if (!immediatePostDominates[A]) return false;
for (auto bit = immediatePostDominates[A]->begin(); bit != immediatePostDominates[A]->end(); ++bit)
if (postDominates(*bit, B)) return true;
return false;
}
Block* Function::getImmediatePostDominator(Block *A) const {
dyncompat::lock_guard<const Function> g(*this);
fillPostDominatorInfo();
return immediatePostDominator[A];
}
void Function::getImmediatePostDominates(Block *A, set<Block*> &imd) const {
dyncompat::lock_guard<const Function> g(*this);
fillPostDominatorInfo();
if (immediatePostDominates[A] != NULL)
imd.insert(immediatePostDominates[A]->begin(), immediatePostDominates[A]->end());
}
void Function::getAllPostDominates(Block *A, set<Block*> &d) const {
dyncompat::lock_guard<const Function> g(*this);
fillPostDominatorInfo();
d.insert(A);
if (immediatePostDominates[A] == NULL) return;
for (auto bit = immediatePostDominates[A]->begin(); bit != immediatePostDominates[A]->end(); ++bit)
getAllPostDominates(*bit, d);
}