@@ -21,6 +21,7 @@ Author: Daniel Kroening, kroening@kroening.com
2121static exprt unpack_rec (
2222 const exprt &src,
2323 bool little_endian,
24+ const exprt &offset_bytes,
2425 const exprt &max_bytes,
2526 const namespacet &ns,
2627 bool unpack_byte_array = false );
@@ -31,6 +32,8 @@ static exprt unpack_rec(
3132// / a constant value, otherwise we fail with an exception
3233// / \param element_width: bit width of array/vector elements
3334// / \param little_endian: true, iff assumed endianness is little-endian
35+ // / \param offset_bytes: if not nil, bytes prior to this offset will be filled
36+ // / with nil values
3437// / \param max_bytes: if not nil, use as upper bound of the number of bytes to
3538// / unpack
3639// / \param ns: namespace for type lookups
@@ -40,6 +43,7 @@ static array_exprt unpack_array_vector(
4043 const exprt &src_size,
4144 const mp_integer &element_width,
4245 bool little_endian,
46+ const exprt &offset_bytes,
4347 const exprt &max_bytes,
4448 const namespacet &ns)
4549{
@@ -51,6 +55,7 @@ static array_exprt unpack_array_vector(
5155 throw non_const_array_sizet (src.type (), max_bytes);
5256 }
5357
58+ exprt::operandst byte_operands;
5459 mp_integer first_element = 0 ;
5560
5661 // refine the number of elements to extract in case the element width is known
@@ -65,6 +70,17 @@ static array_exprt unpack_array_vector(
6570 // turn bytes into elements, rounding up
6671 max_elements = (*max_bytes_int + el_bytes - 1 ) / el_bytes;
6772 }
73+
74+ if (auto offset_bytes_int = numeric_cast<mp_integer>(offset_bytes))
75+ {
76+ // compute offset as number of elements
77+ first_element = *offset_bytes_int / el_bytes;
78+ // insert offset_bytes-many nil bytes into the output array
79+ *offset_bytes_int -= *offset_bytes_int % el_bytes;
80+ byte_operands.resize (
81+ numeric_cast_v<std::size_t >(*offset_bytes_int),
82+ from_integer (0 , unsignedbv_typet (8 )));
83+ }
6884 }
6985
7086 // the maximum number of bytes is an upper bound in case the size of the
@@ -75,7 +91,6 @@ static array_exprt unpack_array_vector(
7591
7692 const exprt src_simp = simplify_expr (src, ns);
7793
78- exprt::operandst byte_operands;
7994 for (mp_integer i = first_element; i < *num_elements; ++i)
8095 {
8196 exprt element;
@@ -94,7 +109,8 @@ static array_exprt unpack_array_vector(
94109
95110 // recursively unpack each element until so that we eventually just have an
96111 // array of bytes left
97- exprt sub = unpack_rec (element, little_endian, max_bytes, ns, true );
112+ exprt sub =
113+ unpack_rec (element, little_endian, nil_exprt (), max_bytes, ns, true );
98114 byte_operands.insert (
99115 byte_operands.end (), sub.operands ().begin (), sub.operands ().end ());
100116 }
@@ -108,6 +124,8 @@ static array_exprt unpack_array_vector(
108124// / Rewrite an object into its individual bytes.
109125// / \param src: object to unpack
110126// / \param little_endian: true, iff assumed endianness is little-endian
127+ // / \param offset_bytes: if not nil, bytes prior to this offset will be filled
128+ // / with nil values
111129// / \param max_bytes: if not nil, use as upper bound of the number of bytes to
112130// / unpack
113131// / \param ns: namespace for type lookups
@@ -120,6 +138,7 @@ static array_exprt unpack_array_vector(
120138static exprt unpack_rec (
121139 const exprt &src,
122140 bool little_endian,
141+ const exprt &offset_bytes,
123142 const exprt &max_bytes,
124143 const namespacet &ns,
125144 bool unpack_byte_array)
@@ -136,7 +155,13 @@ static exprt unpack_rec(
136155 return src;
137156
138157 return unpack_array_vector (
139- src, array_type.size (), *element_width, little_endian, max_bytes, ns);
158+ src,
159+ array_type.size (),
160+ *element_width,
161+ little_endian,
162+ offset_bytes,
163+ max_bytes,
164+ ns);
140165 }
141166 else if (src.type ().id () == ID_vector)
142167 {
@@ -150,13 +175,21 @@ static exprt unpack_rec(
150175 return src;
151176
152177 return unpack_array_vector (
153- src, vector_type.size (), *element_width, little_endian, max_bytes, ns);
178+ src,
179+ vector_type.size (),
180+ *element_width,
181+ little_endian,
182+ offset_bytes,
183+ max_bytes,
184+ ns);
154185 }
155186 else if (ns.follow (src.type ()).id ()==ID_struct)
156187 {
157188 const struct_typet &struct_type=to_struct_type (ns.follow (src.type ()));
158189 const struct_typet::componentst &components=struct_type.components ();
159190
191+ mp_integer member_offset_bits = 0 ;
192+
160193 exprt::operandst byte_operands;
161194 for (const auto &comp : components)
162195 {
@@ -170,11 +203,43 @@ static exprt unpack_rec(
170203 throw non_byte_alignedt (struct_type, comp, *element_width);
171204 }
172205
206+ exprt offset_in_member = nil_exprt ();
207+ auto offset_in_member_int = numeric_cast<mp_integer>(offset_bytes);
208+ exprt max_bytes_left = nil_exprt ();
209+ auto max_bytes_left_int = numeric_cast<mp_integer>(max_bytes);
210+
211+ if (offset_in_member_int.has_value ())
212+ {
213+ *offset_in_member_int -= member_offset_bits / 8 ;
214+ // if the offset is negative, offset_in_member remains nil, which has
215+ // the same effect as setting it to zero
216+ if (*offset_in_member_int >= 0 )
217+ {
218+ offset_in_member =
219+ from_integer (*offset_in_member_int, offset_bytes.type ());
220+ }
221+ }
222+
223+ if (max_bytes_left_int.has_value ())
224+ {
225+ *max_bytes_left_int -= member_offset_bits / 8 ;
226+ if (*max_bytes_left_int >= 0 )
227+ max_bytes_left = from_integer (*max_bytes_left_int, max_bytes.type ());
228+ else
229+ break ;
230+ }
231+
173232 member_exprt member (src, comp.get_name (), comp.type ());
174- exprt sub=unpack_rec (member, little_endian, max_bytes, ns, true );
233+ if (src.id () == ID_struct)
234+ simplify (member, ns);
235+
236+ exprt sub = unpack_rec (
237+ member, little_endian, offset_in_member, max_bytes_left, ns, true );
175238
176239 byte_operands.insert (
177240 byte_operands.end (), sub.operands ().begin (), sub.operands ().end ());
241+
242+ member_offset_bits += *element_width;
178243 }
179244
180245 const std::size_t size = byte_operands.size ();
@@ -294,9 +359,12 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
294359 typecast_exprt (src.offset (), upper_bound.type ())),
295360 ns);
296361
362+ exprt lb = src.offset ();
363+ if (!lb.is_constant ())
364+ lb.make_nil ();
365+
297366 byte_extract_exprt unpacked (src);
298- unpacked.op ()=
299- unpack_rec (src.op (), little_endian, upper_bound, ns);
367+ unpacked.op () = unpack_rec (src.op (), little_endian, lb, upper_bound, ns);
300368
301369 if (src.type ().id ()==ID_array)
302370 {
0 commit comments