fxos/include/fxos/analysis.h

130 lines
3.5 KiB
C++

//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
// fxos/analysis: Static analysis for assembler programs
//
// TODO: Designed to be an abstract interpreter, still WIP
//---
#ifndef FXOS_ANALYSIS_H
#define FXOS_ANALYSIS_H
#include <fxos/util/types.h>
#include <fxos/ai/RelConst.h>
#include <fxos/function.h>
#include <memory>
#include <vector>
namespace FxOS {
struct ProgramStateDiff;
/* Full description of a program state for the analyzer, at a known PC. */
struct ProgramState
{
ProgramState()
{
setBottom();
}
RelConst getRegister(int n) const
{
return ((unsigned)n >= 16) ? RelConstDomain().bottom() : m_regs[n];
}
// TODO: More value in program state
/* Set to initial program state at entry of function. */
void setFunctionInit();
/* Set to initial non-entry-block state at entry of function (all bot). */
void setBottom();
/* Apply a diff. */
void applyDiff(ProgramStateDiff const &diff);
/* Join with another program state. */
void joinWith(ProgramState const &other);
/* Lattice order. */
bool le(ProgramState const &other) const;
private:
/* Values for registers r0..r15 */
RelConst m_regs[16];
};
/* Change in program state over a single (contextually known) instruction. */
struct ProgramStateDiff
{
enum class Target : int { None = -1, Unknown = -2, CallStandard = -3 };
/* Number of the register that changes, or Target::*. */
int target() const
{
return m_target;
}
/* New value for that register. */
RelConst value() const
{
return m_value;
}
// TODO: Needs way more flexibility
/* Set the diff to changing register rn to new value v. */
void setRegisterUpdate(int n, RelConst v)
{
m_target = n;
m_value = v;
}
/* Set the diff to changing register rn to an unknown value. */
void setRegisterTouched(int n)
{
setRegisterUpdate(n, RelConstDomain().top());
}
/* Set the diff to changing no register state. */
void setNoop()
{
m_target = static_cast<int>(Target::None);
}
/* Set the diff to modifyin register states as allowed by the standard
function calling convention. */
void setCallStandard()
{
m_target = static_cast<int>(Target::CallStandard);
}
/* Set the diff to unknown effect on registers. */
void setUnknown()
{
m_target = static_cast<int>(Target::Unknown);
}
std::string str() const;
private:
int m_target;
RelConst m_value;
};
/* Function's storage of program states at every control point. */
struct StaticFunctionAnalysis
{
/* Information stored for each block */
struct Block
{
ProgramState entry;
std::vector<ProgramStateDiff> diffs;
};
std::vector<Block> blocks;
};
/* Analyze a function; returns analysis results if successful, a null pointer
on error. Does not store the results in f itself. */
std::unique_ptr<StaticFunctionAnalysis> analyzeFunction(Function const &f);
} // namespace FxOS
#endif /* FXOS_ANALYSIS_H */