fxos/include/fxos/ai/RelConst.h

130 lines
4.7 KiB
C++

//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
// fxos/ai/RelConst: Abstract domain of relative constants
//
// This abstract domain represents values of the form <base + offset> where
// the base is a register, a symbolic function argument, or the initial value
// of a callee-saved register in a function, and the offset is a constant.
//
// I designed this domain for this particular application, although there are
// surely similar takes in decompilation literature.
//
// For readers not familiar with abstract interpretation, the idea is that one
// can run a program by calculating not the exact values being manipulated,
// but instead approximations ("abstractions") of these. The extra freedom
// provided by the approximation makes it possible to defines methods of
// execution that always terminate, thus analyzing any program in finite time.
// This particular domain does little in the way of approximation, but has
// benefits because of its ability to track some symbolic values.
//---
#ifndef FXOS_AI_RELCONST_H
#define FXOS_AI_RELCONST_H
#include <fxos/ai/AbstractDomain.h>
#include <string>
namespace FxOS {
/* The lattice of relative constants (base + offset) */
struct RelConst
{
enum { Bottom = 1, Top = 2 };
/* The following fields concurrently indicate the base. The order of
resolution is as follows (non-trivial types in parentheses):
* If [spe] is equal to Bottom or Top, this is the value.
* If [arg] is non-zero, the value of the arg-th argument is used.
* If [org] is non-zero, the original value of the associated
callee-saved register is used. (CpuRegister)
* If [reg] is non-zero, the base is that register. (CpuRegister)
For efficiency, checking [base==0] will tell apart plain old
constants from values with bases (and specials but these are usually
handled first). */
union
{
struct
{
uint8_t spe;
uint8_t arg;
uint8_t org;
uint8_t reg;
};
uint32_t base;
};
/* The constant value, or offset. The signedness of this value depends
on the context where it is used:
* For special values, the members are unused.
* For [arg] and [org] and [reg] bases with additive offset
semantics, the signedness has no effect. Operations with
non-trivial effect on signs such as multiplication are not
supported with bases.
* For zero bases, the interpretation is instruction-dependent. */
union
{
int32_t ival;
uint32_t uval;
};
//---
// RelConst methods
//---
/* Default constructors gives zero */
RelConst() = default;
/* Evaluates to true if the location is non-trivial, ie. if it is
neither Top nor Bottom. */
operator bool() const noexcept;
/* String representation */
std::string str() const noexcept;
};
class RelConstDomain: public AbstractDomain<RelConst>
{
public:
/* Trivial instances */
RelConstDomain() = default;
/* Implementation of the AbstractDomain specification */
RelConst bottom() const noexcept override;
RelConst top() const noexcept override;
RelConst constant(uint32_t value) const noexcept override;
bool is_constant(RelConst) const noexcept override;
uint32_t constant_value(RelConst) const noexcept override;
RelConst minus(RelConst) const noexcept override;
RelConst add(RelConst, RelConst) const noexcept override;
RelConst sub(RelConst, RelConst) const noexcept override;
RelConst smul(RelConst, RelConst) const noexcept override;
RelConst umul(RelConst, RelConst) const noexcept override;
RelConst extub(RelConst) const noexcept override;
RelConst extsb(RelConst) const noexcept override;
RelConst extuw(RelConst) const noexcept override;
RelConst extsw(RelConst) const noexcept override;
RelConst lnot(RelConst) const noexcept override;
RelConst land(RelConst, RelConst) const noexcept override;
RelConst lor(RelConst, RelConst) const noexcept override;
RelConst lxor(RelConst, RelConst) const noexcept override;
bool cmp(RelConst, RelConst) const noexcept override;
int cmpu(RelConst, RelConst) const noexcept override;
int cmps(RelConst, RelConst) const noexcept override;
};
} /* namespace FxOS */
#endif /* FXOS_AI_RELCONST_H */