1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
//! This module defines the intermediate representation used to represent a binary
//! and all its contained executable code.
//!
//! The main data structure is the `Project` struct,
//! which contains all information recovered about a binary during the disassembly step.
//! To learn how individual instructions are encoded,
//! you should first take a look at the `Expression` type and then at the `Def` and `Jmp` data types,
//! which form the basis of the basic block `Blk` struct.
use crate::prelude::*;
use derive_more::*;
mod bitvector;
pub use bitvector::*;
mod variable;
pub use variable::*;
mod expression;
pub use expression::*;
mod term;
pub use term::*;
mod def;
pub use def::*;
mod jmp;
pub use jmp::*;
mod blk;
pub use blk::*;
mod sub;
pub use sub::*;
mod program;
pub use program::*;
mod project;
pub use project::*;
mod runtime_memory_image;
pub use runtime_memory_image::*;
#[cfg(test)]
#[macro_use]
mod macros;
#[cfg(test)]
pub use macros::*;
/// An unsigned number of bytes.
///
/// Used to represent sizes of values in registers or in memory.
/// Can also be used for other byte-valued numbers, like offsets,
/// as long as the number is guaranteed to be non-negative.
#[derive(
Serialize,
Deserialize,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Clone,
Copy,
Display,
Binary,
Octal,
LowerHex,
UpperHex,
From,
Into,
Not,
Add,
Sub,
Mul,
Div,
Rem,
Shr,
Shl,
AddAssign,
SubAssign,
MulAssign,
DivAssign,
RemAssign,
ShrAssign,
ShlAssign,
Sum,
)]
#[serde(transparent)]
pub struct ByteSize(u64);
impl From<ByteSize> for apint::BitWidth {
fn from(bytesize: ByteSize) -> apint::BitWidth {
apint::BitWidth::from((u64::from(bytesize) * 8) as usize)
}
}
impl From<apint::BitWidth> for ByteSize {
/// Convert to `ByteSize`, while always rounding up to the nearest full byte.
fn from(bitwidth: apint::BitWidth) -> ByteSize {
ByteSize::new((bitwidth.to_usize() + 7) as u64 / 8)
}
}
impl ByteSize {
/// Create a new `ByteSize` object
pub fn new(value: u64) -> ByteSize {
ByteSize(value)
}
/// Convert to the equivalent size in bits (by multiplying with 8).
pub fn as_bit_length(self) -> usize {
(u64::from(self) * 8) as usize
}
}
/// Properties of C/C++ data types such as size.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct DatatypeProperties {
/// Holds the size of the char type
pub char_size: ByteSize,
/// Holds the size of the double type
pub double_size: ByteSize,
/// Holds the size of the float type
pub float_size: ByteSize,
/// Holds the size of the integer type
pub integer_size: ByteSize,
/// Holds the size of the long double type
pub long_double_size: ByteSize,
/// Holds the size of the long long type
pub long_long_size: ByteSize,
/// Holds the size of the long type
pub long_size: ByteSize,
/// Holds the size of the pointer type
pub pointer_size: ByteSize,
/// Holds the size of the short type
pub short_size: ByteSize,
}
impl DatatypeProperties {
/// Matches a given data type with its size from the properties struct.
pub fn get_size_from_data_type(&self, data_type: Datatype) -> ByteSize {
match data_type {
Datatype::Char => self.char_size,
Datatype::Double => self.double_size,
Datatype::Float => self.float_size,
Datatype::Integer => self.integer_size,
Datatype::LongDouble => self.long_double_size,
Datatype::LongLong => self.long_long_size,
Datatype::Long => self.long_size,
Datatype::Pointer => self.pointer_size,
Datatype::Short => self.short_size,
}
}
}
/// C/C++ data types.
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum Datatype {
/// C char data type
Char,
/// C double data type
Double,
/// C float data type
Float,
/// C integer data type
Integer,
/// C long double data type
LongDouble,
/// C long long data type
LongLong,
/// C long data type
Long,
/// C pointer data type
Pointer,
/// C short data type
Short,
}
impl From<String> for Datatype {
/// The purpose of this conversion is to locate parameters to variadic functions.
/// Therefore, char types have to be mapped to the integer size since they undergo the default
/// argument promotion. (e.g. 1 byte char -> 4 byte integer)
/// The same holds for all float types that are promoted to doubles. (e.g. 8 byte float -> 16 byte double)
fn from(specifier: String) -> Self {
match specifier.as_str() {
"c" | "C" => Datatype::Char,
"d" | "i" | "u" | "o" | "p" | "x" | "X" | "hi" | "hd" | "hu" => Datatype::Integer,
"s" | "S" | "n" => Datatype::Pointer,
"lf" | "lg" | "le" | "la" | "lF" | "lG" | "lE" | "lA" | "f" | "F" | "e" | "E" | "a"
| "A" | "g" | "G" => Datatype::Double,
"li" | "ld" | "lu" => Datatype::Long,
"lli" | "lld" | "llu" => Datatype::LongLong,
"Lf" | "Lg" | "Le" | "La" | "LF" | "LG" | "LE" | "LA" => Datatype::LongDouble,
_ => panic!("Invalid data type specifier from format string."),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use apint::BitWidth;
#[test]
fn check_bit_to_byte_conversion() {
let bits: BitWidth = BitWidth::new(8).unwrap();
let bytes: ByteSize = bits.into();
assert_eq!(u64::from(bytes), 1);
let bits: BitWidth = bytes.into();
assert_eq!(bits.to_usize(), 8);
assert_eq!(ByteSize::new(2).as_bit_length(), 16);
}
}