isla_lib/init.rs
1// BSD 2-Clause License
2//
3// Copyright (c) 2019, 2020 Alasdair Armstrong
4//
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
10//
11// 1. Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// 2. Redistributions in binary form must reproduce the above copyright
15// notice, this list of conditions and the following disclaimer in the
16// documentation and/or other materials provided with the distribution.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30//! This module defines a function to initialize a Sail architecture
31//! specification. The function [initialize_architecture] takes a
32//! mutable reference to some parsed IR with it's symbols interned
33//! into a [Symtab], and produces a [SharedState] struct, along with
34//! [Bindings] environments for both the registers and the global let
35//! bindings.
36//!
37//! The general flow to load and initialize a Sail specification is as
38//! follows:
39//!
40//! * Load the architecture `.ir` file, containing the compiled _Jib_
41//! IR produced by Sail.
42//!
43//! * Then create a symbol table and intern the IR symbols producing
44//! new IR with identifiers of type [Name].
45//!
46//! * Next load the ISA configuration file to generate an
47//! [ISAConfig]. This configuration can refer to symbols in the
48//! architecture which is why we need to produce the symbol table
49//! before loading this.
50//!
51//! * Finally use the [initialize_architecture] function in this
52//! module to set up everything ready for symbolic execution.
53
54use std::collections::HashMap;
55use std::sync::Mutex;
56
57use crate::bitvector::BV;
58use crate::config::ISAConfig;
59use crate::executor::{start_single, LocalFrame, TaskState};
60use crate::ir::*;
61use crate::log;
62use crate::zencode;
63
64fn initialize_letbindings<'ir, B: BV>(
65 arch: &'ir [Def<Name, B>],
66 shared_state: &SharedState<'ir, B>,
67 regs: &Bindings<'ir, B>,
68 letbindings: &Mutex<Bindings<'ir, B>>,
69) {
70 for def in arch.iter() {
71 if let Def::Let(bindings, setup) = def {
72 let vars: Vec<_> = bindings.iter().map(|(id, ty)| (*id, ty)).collect();
73 let task_state = TaskState::new();
74 let task = {
75 let lets = letbindings.lock().unwrap();
76 LocalFrame::new(TOP_LEVEL_LET, &vars, None, setup).add_regs(®s).add_lets(&lets).task(0, &task_state)
77 };
78
79 start_single(
80 task,
81 &shared_state,
82 &letbindings,
83 &move |_tid, _task_id, result, shared_state, _solver, letbindings| match result {
84 Ok((_, frame)) => {
85 for (id, _) in bindings.iter() {
86 let symbol = zencode::decode(shared_state.symtab.to_str(*id));
87 match frame.vars().get(id) {
88 Some(value) => {
89 let mut state = letbindings.lock().unwrap();
90 state.insert(*id, value.clone());
91 let symbol = zencode::decode(shared_state.symtab.to_str(*id));
92 log!(log::VERBOSE, &format!("{} = {:?}", symbol, value));
93 }
94 None => log!(log::VERBOSE, &format!("No value for symbol {}", symbol)),
95 }
96 }
97 }
98 Err(err) => log!(log::VERBOSE, &format!("Failed to evaluate letbinding: {:?}", err)),
99 },
100 );
101 }
102 }
103}
104
105fn initialize_register_state<'ir, B: BV>(
106 defs: &'ir [Def<Name, B>],
107 initial_registers: &HashMap<Name, Val<B>>,
108 symtab: &Symtab,
109) -> Bindings<'ir, B> {
110 let mut registers = HashMap::new();
111 for def in defs.iter() {
112 if let Def::Register(id, ty) = def {
113 if let Some(value) = initial_registers.get(id) {
114 value.plausible(ty, symtab).unwrap_or_else(|_| panic!("Bad initial value for {}", symtab.to_str(*id)));
115 registers.insert(*id, UVal::Init(value.clone()));
116 } else {
117 registers.insert(*id, UVal::Uninit(ty));
118 }
119 }
120 }
121 registers
122}
123
124pub struct Initialized<'ir, B> {
125 pub regs: Bindings<'ir, B>,
126 pub lets: Bindings<'ir, B>,
127 pub shared_state: SharedState<'ir, B>,
128}
129
130pub fn initialize_architecture<'ir, B: BV>(
131 arch: &'ir mut [Def<Name, B>],
132 symtab: Symtab<'ir>,
133 isa_config: &ISAConfig<B>,
134 mode: AssertionMode,
135) -> Initialized<'ir, B> {
136 insert_monomorphize(arch);
137 insert_primops(arch, mode);
138
139 let regs = initialize_register_state(arch, &isa_config.default_registers, &symtab);
140 let lets = Mutex::new(HashMap::new());
141 let shared_state = SharedState::new(symtab, arch, isa_config.probes.clone(), isa_config.reset_registers.clone());
142
143 initialize_letbindings(arch, &shared_state, ®s, &lets);
144
145 Initialized { regs, lets: lets.into_inner().unwrap(), shared_state }
146}