Skip to content

Commit

Permalink
added the ability for the analysis to split basic blocks on call inst…
Browse files Browse the repository at this point in the history
…ructions

this has the effect that any block that has a call, has exactly one call
and that call is the last instruction. This may seem useless at first, but it allows
for simpler implementations of other analyses.

For example, to determine if a function is a no-return function, with this change
we can simply look at all terminating blocks and if ALL of them end with either
call to a no-return function, then it is also a no-return function.

(There are of course other cases that will need to be handled, but you get the gist)
  • Loading branch information
eteran committed Mar 23, 2024
1 parent fd5ac05 commit 1485125
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 2 deletions.
3 changes: 3 additions & 0 deletions include/BasicBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ class EDB_EXPORT BasicBlock {
[[nodiscard]] edb::address_t firstAddress() const;
[[nodiscard]] edb::address_t lastAddress() const;

public:
std::pair<BasicBlock, BasicBlock> splitBlock(const instruction_pointer &inst);

private:
std::vector<instruction_pointer> instructions_;
std::vector<std::pair<edb::address_t, edb::address_t>> references_;
Expand Down
2 changes: 2 additions & 0 deletions include/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class EDB_EXPORT Function {
[[nodiscard]] Type type() const;
void setType(Type t);

void erase(const_iterator it);

public:
[[nodiscard]] const_reference back() const;
[[nodiscard]] const_reference front() const;
Expand Down
64 changes: 62 additions & 2 deletions plugins/Analyzer/Analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,21 @@ void set_function_types(IAnalyzer::FunctionMap *results) {
Q_ASSERT(results);

// give bonus if we have a symbol for the address
std::for_each(results->begin(), results->end(), [](Function &function) {
for (auto it = results->begin(); it != results->end(); ++it) {

Function &function = it.value();

if (function.empty()) {
qDebug() << "HERE:" << it.key().toString();
}

Q_ASSERT(!function.empty());
if (is_thunk(function.entryAddress())) {
function.setType(Function::Thunk);
} else {
function.setType(Function::Standard);
}
});
}
}

/**
Expand Down Expand Up @@ -431,6 +439,56 @@ void Analyzer::identHeader(Analyzer::RegionData *data) {
Q_UNUSED(data)
}

bool split_function(Function &func) {

for (auto bb_it = func.begin(); bb_it != func.end(); ++bb_it) {
BasicBlock &bb = bb_it->second;

if (bb.size() <= 1) {
continue;
}

for (auto it = bb.begin(); it != bb.end(); ++it) {
const std::shared_ptr<edb::Instruction> &insn = *it;

// if it's a call and not the last instruction of the BB
// then split!
if (is_call(*insn) && insn != bb.back()) {

auto newBlocks = bb.splitBlock(insn);
func.erase(bb_it);

Q_ASSERT(!newBlocks.first.empty());
Q_ASSERT(!newBlocks.second.empty());

func.insert(newBlocks.first);
func.insert(newBlocks.second);

return true;
}
}
}

return false;
}

void Analyzer::splitBlocks(RegionData *data) {
Q_ASSERT(data);

for (auto it = data->functions.begin(); it != data->functions.end(); ++it) {
const edb::address_t function = it.key();
Function &func = it.value();

while (split_function(func)) {
continue;
}
}
}

void Analyzer::computeNonReturning(Analyzer::RegionData *data) {
Q_UNUSED(data);
}

/**
* @brief Analyzer::collectFunctions
* @param data
Expand Down Expand Up @@ -693,6 +751,8 @@ void Analyzer::analyze(const std::shared_ptr<IRegion> &region) {
{"attempting to add marked functions to the list...", [this, &region_data]() { bonusMarkedFunctions(&region_data); }},
{"attempting to collect functions with fuzzy analysis...", [this, &region_data]() { collectFuzzyFunctions(&region_data); }},
{"collecting basic blocks...", [this, &region_data]() { collectFunctions(&region_data); }},
{"splitting basic blocks...", [this, &region_data]() { splitBlocks(&region_data); }},
{"computing non-returning functions...", [this, &region_data]() { computeNonReturning(&region_data); }},
};

const int total_steps = sizeof(analysis_steps) / sizeof(analysis_steps[0]);
Expand Down
2 changes: 2 additions & 0 deletions plugins/Analyzer/Analyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class Analyzer final : public QObject, public IAnalyzer, public IPlugin {
void bonusMarkedFunctions(RegionData *data);
void bonusSymbols(RegionData *data);
void collectFunctions(RegionData *data);
void computeNonReturning(RegionData *data);
void splitBlocks(RegionData *data);
void collectFuzzyFunctions(RegionData *data);
void doAnalysis(const std::shared_ptr<IRegion> &region);
void identHeader(Analyzer::RegionData *data);
Expand Down
11 changes: 11 additions & 0 deletions plugins/FunctionFinder/DialogResults.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ DialogResults::DialogResults(QWidget *parent, Qt::WindowFlags f)
}
}
} else if (is_terminator(inst)) {
} else {
// if the bb's last address is another blocks first address
// connect them because they run into each other

auto to = nodes.find(bb.lastAddress());
if (to != nodes.end()) {
auto from = nodes.find(bb.firstAddress());
if (to != nodes.end() && from != nodes.end()) {
new GraphEdge(from.value(), to.value(), Qt::blue);
}
}
}
}
}
Expand Down
33 changes: 33 additions & 0 deletions src/BasicBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,36 @@ void BasicBlock::addReference(edb::address_t refsite, edb::address_t target) {
std::vector<std::pair<edb::address_t, edb::address_t>> BasicBlock::references() const {
return references_;
}

/**
* @brief BasicBlock::references
* @return
*/
std::pair<BasicBlock, BasicBlock> BasicBlock::splitBlock(const instruction_pointer &inst) {
BasicBlock block1;
BasicBlock block2;

auto it = begin();
for (; it != end(); ++it) {

block1.push_back(*it);
if (*it == inst) {
++it;
break;
}
}

for (; it != end(); ++it) {
block2.push_back(*it);
}

for (auto it = references_.begin(); it != references_.end(); ++it) {
if (it->first >= block1.firstAddress() && it->first < block1.lastAddress()) {
block1.addReference(it->first, it->second);
} else {
block2.addReference(it->first, it->second);
}
}

return std::make_pair(block1, block2);
}
7 changes: 7 additions & 0 deletions src/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ void Function::insert(BasicBlock &&bb) {
* @return
*/
edb::address_t Function::entryAddress() const {
Q_ASSERT(!empty());
return front().firstAddress();
}

Expand All @@ -58,6 +59,7 @@ edb::address_t Function::entryAddress() const {
* @return
*/
edb::address_t Function::endAddress() const {
Q_ASSERT(!empty());
return back().lastAddress() - 1;
}

Expand All @@ -66,6 +68,7 @@ edb::address_t Function::endAddress() const {
* @return
*/
edb::address_t Function::lastInstruction() const {
Q_ASSERT(!empty());
return back().back()->rva();
}

Expand Down Expand Up @@ -214,3 +217,7 @@ Function::Type Function::type() const {
void Function::setType(Type t) {
type_ = t;
}

void Function::erase(const_iterator it) {
blocks_.erase(it);
}

0 comments on commit 1485125

Please sign in to comment.