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
//! A `Function` holds a `ControlFlowGraph`.
//!
//! We can think of a `Function` as providing _location_ to a `ControlFlowGraph`.

use il::*;


/// A function for Falcon IL. Provides location and context in a `Program` to a
/// `ControlFlowGraph`.
#[derive(Clone, Debug, Deserialize, Hash, Eq, PartialEq, Serialize)]
pub struct Function {
    // The address where this function was found
    address: u64,
    // The `ControlFlowGraph` capturing semantics of the function
    control_flow_graph: ControlFlowGraph,
    // The name of the function
    name: Option<String>,
    // Functions which belong to Programs have indices
    index: Option<usize>
}


impl Function {
    /// Create a new `Function`
    ///
    /// # Parameters
    /// * `address` - The address where we recovered this function.
    /// * `control_flow_graph` - A `ControlFlowGraph` capturing the semantics of this function.
    pub fn new(address: u64, control_flow_graph: ControlFlowGraph) -> Function {
        Function {
            address: address,
            control_flow_graph: control_flow_graph,
            name: None,
            index: None
        }
    }

    /// Create a Vec of every RefFunctionLocation for this function.
    ///
    /// Convenient for analyses where we need to check every location in a
    /// function
    pub fn locations(&self) -> Vec<RefFunctionLocation> {
        let mut locations = Vec::new();

        for block in self.blocks() {
            let instructions = block.instructions();
            if instructions.is_empty() {
                locations.push(RefFunctionLocation::EmptyBlock(block));
            }
            else {
                for instruction in instructions {
                    locations.push(RefFunctionLocation::Instruction(block, instruction));
                }
            }
        }

        for edge in self.edges() {
            locations.push(RefFunctionLocation::Edge(edge))
        }

        locations
    }

    /// Get the address of this `Function`.
    ///
    /// The address returned will be the address set when this `Function` was created,
    /// which should be the virtual address where this `Function` was found.
    pub fn address(&self) -> u64 {
        self.address
    }

    /// Return a `Block` from this `Function`'s `ControlFlowGraph` by index.
    pub fn block(&self, index: usize) -> Result<&Block> {
        self.control_flow_graph.block(index)
    }

    /// Return a mutable reference to a `Block` in this `Function`
    pub fn block_mut(&mut self, index: usize) -> Result<&mut Block> {
        self.control_flow_graph.block_mut(index)
    }

    /// Return a Vec of all `Block` in this `Function`
    pub fn blocks(&self) -> Vec<&Block> {
        self.control_flow_graph.blocks()
    }

    /// Return a Vec of mutable references to all `Block` in this `Function`
    pub fn blocks_mut(&mut self) -> Vec<&mut Block> {
        self.control_flow_graph.blocks_mut()
    }

    /// Return an `Edge` from this `Function`'s `ControlFlowGraph` by index.
    pub fn edge(&self, head: usize, tail: usize) -> Result<&Edge> {
        self.control_flow_graph.edge(head, tail)
    }

    /// Return a vec of all `Edge` in this `Function`
    pub fn edges(&self) -> Vec<&Edge> {
        self.control_flow_graph.edges()
    }

    /// Return the `ControlFlowGraph` for this `Function`.
    pub fn control_flow_graph(&self) -> &ControlFlowGraph {
        &self.control_flow_graph
    }

    /// Return a mutable reference to the `ControlFlowGraph` for this `Function`.
    pub fn control_flow_graph_mut(&mut self) -> &mut ControlFlowGraph {
        &mut self.control_flow_graph
    }

    /// Return the name of this `Function`.
    pub fn name(&self) -> String {
        match self.name {
            Some(ref name) => name.to_string(),
            None => format!("unknown@{:08X}", self.address)
        }
    }

    /// Set this `Function`'s name.
    pub fn set_name(&mut self, name: Option<String>) {
        self.name = name;
    }

    /// Return the index of this `Function`. A `Function` will have an index if
    /// it is added to a `Program`.
    pub fn index(&self) -> Option<usize> {
        self.index
    }


    pub fn set_index(&mut self, index: Option<usize>) {
        self.index = index;
    }
}