klee
AssignmentGenerator.cpp
Go to the documentation of this file.
1//===-- AssignmentGenerator.cpp -------------------------------------------===//
2//
3// The KLEE Symbolic Virtual Machine
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
11
15#include "klee/klee.h"
16
17#include <llvm/ADT/APInt.h>
18#include <llvm/Support/raw_ostream.h>
19
20#include <cassert>
21#include <cstdint>
22#include <map>
23#include <set>
24#include <stddef.h>
25#include <string>
26#include <utility>
27
28using namespace klee;
29
30bool AssignmentGenerator::generatePartialAssignment(const ref<Expr> &e,
31 ref<Expr> &val,
32 Assignment *&a) {
33 return helperGenerateAssignment(e, val, a, e->getWidth(), false);
34}
35
37 ref<Expr> &val,
38 Assignment *&a,
39 Expr::Width width,
40 bool sign) {
41 Expr &ep = *e.get();
42 switch (ep.getKind()) {
43
44 // ARITHMETIC
45 case Expr::Add: {
46 // val = val - kid
47 ref<Expr> kid_val;
48 ref<Expr> kid_expr;
49 if (isa<ConstantExpr>(ep.getKid(0))) {
50 kid_val = ep.getKid(0);
51 kid_expr = ep.getKid(1);
52 } else if (isa<ConstantExpr>(ep.getKid(1))) {
53 kid_val = ep.getKid(1);
54 kid_expr = ep.getKid(0);
55 } else {
56 return false;
57 }
58 if (!ExtractExpr::create(kid_val, kid_val.get()->getWidth() - 1,
59 1).get()->isZero()) {
60 // FIXME: really bad hack to support those cases in which KLEE creates
61 // Add expressions with negative values
62 val = createAddExpr(kid_val, val);
63 } else {
64 val = createSubExpr(kid_val, val);
65 }
66 return helperGenerateAssignment(kid_expr, val, a, width, sign);
67 }
68 case Expr::Sub: {
69 // val = val + kid
70 ref<Expr> kid_val;
71 ref<Expr> kid_expr;
72 if (isa<ConstantExpr>(ep.getKid(0))) {
73 kid_val = ep.getKid(0);
74 kid_expr = ep.getKid(1);
75 } else if (isa<ConstantExpr>(ep.getKid(1))) {
76 kid_val = ep.getKid(1);
77 kid_expr = ep.getKid(0);
78 } else {
79 return false;
80 }
81 val = createAddExpr(kid_val, val);
82 return helperGenerateAssignment(kid_expr, val, a, width, sign);
83 }
84 case Expr::Mul: {
85 // val = val / kid (check for sign)
86 ref<Expr> kid_val;
87 ref<Expr> kid_expr;
88 if (isa<ConstantExpr>(ep.getKid(0))) {
89 kid_val = ep.getKid(0);
90 kid_expr = ep.getKid(1);
91 } else if (isa<ConstantExpr>(ep.getKid(1))) {
92 kid_val = ep.getKid(1);
93 kid_expr = ep.getKid(0);
94 } else {
95 return false;
96 }
97
98 if (kid_val.get()->isZero()) {
99 return false;
100 } else if (!createDivRem(kid_val, val, sign)->isZero()) {
101 return false;
102 }
103 val = createDivExpr(kid_val, val, sign);
104 return helperGenerateAssignment(kid_expr, val, a, width, sign);
105 }
106 case Expr::UDiv:
107 // val = val * kid
108 // no break, falling down to case SDiv
109 case Expr::SDiv: {
110 // val = val * kid
111 ref<Expr> kid_val;
112 ref<Expr> kid_expr;
113 if (isa<ConstantExpr>(ep.getKid(0))) {
114 kid_val = ep.getKid(0);
115 kid_expr = ep.getKid(1);
116 } else if (isa<ConstantExpr>(ep.getKid(1))) {
117 kid_val = ep.getKid(1);
118 kid_expr = ep.getKid(0);
119 } else {
120 return false;
121 }
122 val = createMulExpr(kid_val, val);
123 return helperGenerateAssignment(kid_expr, val, a, width, sign);
124 }
125
126 // LOGICAL
127 case Expr::LShr: {
128 if (!isa<ConstantExpr>(ep.getKid(1))) {
129 return false;
130 }
131 ref<Expr> kid_val = ep.getKid(1);
132 val = createShlExpr(val, kid_val);
133 return helperGenerateAssignment(ep.getKid(0), val, a, width, sign);
134 }
135 case Expr::Shl: {
136 if (!isa<ConstantExpr>(ep.getKid(1))) {
137 return false;
138 }
139 ref<Expr> kid_val = ep.getKid(1);
140 val = createLShrExpr(val, kid_val);
141 return helperGenerateAssignment(ep.getKid(0), val, a, width, sign);
142 }
143 case Expr::Not: {
144 return helperGenerateAssignment(ep.getKid(0), val, a, width, sign);
145 }
146 case Expr::And: {
147 // val = val & kid
148 ref<Expr> kid_val;
149 ref<Expr> kid_expr;
150 if (isa<ConstantExpr>(ep.getKid(0))) {
151 kid_val = ep.getKid(0);
152 kid_expr = ep.getKid(1);
153 } else if (isa<ConstantExpr>(ep.getKid(1))) {
154 kid_val = ep.getKid(1);
155 kid_expr = ep.getKid(0);
156 } else {
157 return false;
158 }
159 val = createAndExpr(kid_val, val);
160 return helperGenerateAssignment(kid_expr, val, a, width, sign);
161 }
162
163 // CASTING
164 case Expr::ZExt: {
165 val = createExtractExpr(ep.getKid(0), val);
166 return helperGenerateAssignment(ep.getKid(0), val, a, width, false);
167 }
168 case Expr::SExt: {
169 val = createExtractExpr(ep.getKid(0), val);
170 return helperGenerateAssignment(ep.getKid(0), val, a, width, true);
171 }
172
173 // SPECIAL
174 case Expr::Concat: {
175 ReadExpr *base = hasOrderedReads(&ep);
176 if (base) {
177 return helperGenerateAssignment(ref<Expr>(base), val, a, ep.getWidth(),
178 sign);
179 } else {
180 klee_warning("Not supported");
181 ep.printKind(llvm::errs(), ep.getKind());
182 return false;
183 }
184 }
185 case Expr::Extract: {
186 val = createExtendExpr(ep.getKid(0), val);
187 return helperGenerateAssignment(ep.getKid(0), val, a, width, sign);
188 }
189
190 // READ
191 case Expr::Read: {
192 ReadExpr &re = static_cast<ReadExpr &>(ep);
193 if (isa<ConstantExpr>(re.index)) {
194 if (re.updates.root->isSymbolicArray()) {
195 ConstantExpr &index = static_cast<ConstantExpr &>(*re.index.get());
196 std::vector<unsigned char> c_value =
197 getIndexedValue(getByteValue(val), index, re.updates.root->size);
198 if (c_value.size() == 0) {
199 return false;
200 }
201 if (a->bindings.find(re.updates.root) == a->bindings.end()) {
202 a->bindings.insert(std::make_pair(re.updates.root, c_value));
203 } else {
204 return false;
205 }
206 }
207 } else {
208 return helperGenerateAssignment(re.index, val, a, width, sign);
209 }
210 return true;
211 }
212 default:
213 std::string type_str;
214 llvm::raw_string_ostream rso(type_str);
215 ep.printKind(rso, ep.getKind());
216 klee_warning("%s is not supported", rso.str().c_str());
217 return false;
218 }
219}
220
222 ref<Expr> offset) {
223 const ReadExpr *re = dyn_cast<ReadExpr>(e.get());
224 if (!re || (re->getWidth() != Expr::Int8))
225 return false;
226 return SubExpr::create(re->index, base->index) == offset;
227}
228
230 assert(e->getKind() == Expr::Concat);
231
232 const ReadExpr *base = dyn_cast<ReadExpr>(e->getKid(0));
233
234 // right now, all Reads are byte reads but some
235 // transformations might change this
236 if (!base || base->getWidth() != Expr::Int8)
237 return NULL;
238
239 // Get stride expr in proper index width.
240 Expr::Width idxWidth = base->index->getWidth();
241 ref<Expr> strideExpr = ConstantExpr::alloc(-1, idxWidth);
242 ref<Expr> offset = ConstantExpr::create(0, idxWidth);
243
244 e = e->getKid(1);
245
246 // concat chains are unbalanced to the right
247 while (e->getKind() == Expr::Concat) {
248 offset = AddExpr::create(offset, strideExpr);
249 if (!isReadExprAtOffset(e->getKid(0), base, offset))
250 return NULL;
251 e = e->getKid(1);
252 }
253
254 offset = AddExpr::create(offset, strideExpr);
255 if (!isReadExprAtOffset(e, base, offset))
256 return NULL;
257
258 return cast<ReadExpr>(e.get());
259}
260
262 return SubExpr::create(r, l);
263}
264
266 return AddExpr::create(r, l);
267}
268
270 return MulExpr::create(r, l);
271}
272
274 bool sign) {
275 if (sign)
276 return SRemExpr::create(r, l);
277 else
278 return URemExpr::create(r, l);
279}
280
282 bool sign) {
283 if (sign)
284 return SDivExpr::create(r, l);
285 else
286 return UDivExpr::create(r, l);
287}
288
290 return ShlExpr::create(r, l);
291}
292
294 ref<Expr> &r) {
295 return LShrExpr::create(r, l);
296}
297
299 return AndExpr::create(r, l);
300}
301
303 ref<Expr> &r) {
304 return ExtractExpr::create(r, 0, l.get()->getWidth());
305}
306
308 ref<Expr> &r) {
309 if (l.get()->getKind() == Expr::ZExt) {
310 return ZExtExpr::create(r, l.get()->getWidth());
311 } else {
312 return SExtExpr::create(r, l.get()->getWidth());
313 }
314}
315
316std::vector<unsigned char> AssignmentGenerator::getByteValue(ref<Expr> &val) {
317 std::vector<unsigned char> toReturn;
318 if (ConstantExpr *value = dyn_cast<ConstantExpr>(val)) {
319 for (unsigned w = 0; w < val.get()->getWidth() / 8; ++w) {
320 ref<ConstantExpr> byte = value->Extract(w * 8, Expr::Int8);
321 unsigned char mem_val;
322 byte->toMemory(&mem_val);
323 toReturn.push_back(mem_val);
324 }
325 }
326 return toReturn;
327}
328
329std::vector<unsigned char>
330AssignmentGenerator::getIndexedValue(const std::vector<unsigned char> &c_val,
331 ConstantExpr &index,
332 const unsigned int size) {
333 std::vector<unsigned char> toReturn;
334 const llvm::APInt index_val = index.getAPValue();
335 assert(!index_val.isSignMask() && "Negative index");
336 const uint64_t id = index_val.getZExtValue() / c_val.size();
337 uint64_t arraySize = size / c_val.size();
338 for (uint64_t i = 0; i < arraySize; ++i) {
339 if (i == id) {
340 for (unsigned arr_i = 0; arr_i < c_val.size(); ++arr_i) {
341 toReturn.push_back(c_val[arr_i]);
342 }
343 } else {
344 for (unsigned arr_i = 0; arr_i < c_val.size(); ++arr_i) {
345 toReturn.push_back(0);
346 }
347 }
348 }
349
350 return toReturn;
351}
const unsigned size
Definition: Expr.h:489
bool isSymbolicArray() const
Definition: Expr.h:524
static ref< Expr > createLShrExpr(const ref< Expr > &l, ref< Expr > &r)
static ref< Expr > createDivRem(const ref< Expr > &l, ref< Expr > &r, bool sign)
static bool isReadExprAtOffset(ref< Expr > e, const ReadExpr *base, ref< Expr > offset)
static ref< Expr > createAddExpr(const ref< Expr > &l, ref< Expr > &r)
static ref< Expr > createExtendExpr(const ref< Expr > &l, ref< Expr > &r)
static ref< Expr > createShlExpr(const ref< Expr > &l, ref< Expr > &r)
static ref< Expr > createExtractExpr(const ref< Expr > &l, ref< Expr > &r)
static ref< Expr > createDivExpr(const ref< Expr > &l, ref< Expr > &r, bool sign)
static bool helperGenerateAssignment(const ref< Expr > &e, ref< Expr > &val, Assignment *&a, Expr::Width width, bool sign)
static ref< Expr > createMulExpr(const ref< Expr > &l, ref< Expr > &r)
static std::vector< unsigned char > getIndexedValue(const std::vector< unsigned char > &c_val, ConstantExpr &index, const unsigned int size)
static ref< Expr > createAndExpr(const ref< Expr > &l, ref< Expr > &r)
static std::vector< unsigned char > getByteValue(ref< Expr > &val)
static ref< Expr > createSubExpr(const ref< Expr > &l, ref< Expr > &r)
static ReadExpr * hasOrderedReads(ref< Expr > e)
bindings_ty bindings
Definition: Assignment.h:26
static ref< ConstantExpr > create(uint64_t v, Width w)
Definition: Expr.h:1079
static ref< ConstantExpr > alloc(const llvm::APInt &v)
Definition: Expr.h:1065
const llvm::APInt & getAPValue() const
Definition: Expr.h:1019
Class representing symbolic expressions.
Definition: Expr.h:91
virtual Kind getKind() const =0
virtual Width getWidth() const =0
@ Not
Definition: Expr.h:133
@ LShr
Definition: Expr.h:151
@ Add
Definition: Expr.h:138
@ And
Definition: Expr.h:147
@ ZExt
Definition: Expr.h:129
@ SDiv
Definition: Expr.h:142
@ Mul
Definition: Expr.h:140
@ Extract
Definition: Expr.h:126
@ Read
Definition: Expr.h:123
@ Sub
Definition: Expr.h:139
@ Shl
Definition: Expr.h:150
@ Concat
Definition: Expr.h:125
@ SExt
Definition: Expr.h:130
@ UDiv
Definition: Expr.h:141
unsigned Width
The type of an expression is simply its width, in bits.
Definition: Expr.h:97
bool isZero() const
isZero - Is this a constant zero.
Definition: Expr.h:1150
virtual ref< Expr > getKid(unsigned i) const =0
static void printKind(llvm::raw_ostream &os, Kind k)
Definition: Expr.cpp:135
static const Width Int8
Definition: Expr.h:101
static ref< Expr > create(ref< Expr > e, unsigned bitOff, Width w)
Creates an ExtractExpr with the given bit offset and width.
Definition: Expr.cpp:675
Class representing a one byte read from an array.
Definition: Expr.h:565
ref< Expr > index
Definition: Expr.h:572
Width getWidth() const
Definition: Expr.h:583
UpdateList updates
Definition: Expr.h:571
const Array * root
Definition: Expr.h:543
T * get() const
Definition: Ref.h:129
Definition: main.cpp:291
void void void klee_warning(const char *msg,...) __attribute__((format(printf