@@ -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,
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
@@ -66,6 +71,17 @@ static array_exprt unpack_array_vector(
6671 // round up to nearest multiple of el_bytes
6772 max_elements = (*max_bytes_int + el_bytes - 1 ) / el_bytes;
6873 }
74+
75+ if (auto offset_bytes_int = numeric_cast<mp_integer>(offset_bytes))
76+ {
77+ // compute offset as number of elements
78+ first_element = *offset_bytes_int / el_bytes;
79+ // insert offset_bytes-many nil bytes into the output array
80+ *offset_bytes_int -= *offset_bytes_int % el_bytes;
81+ byte_operands.resize (
82+ numeric_cast_v<std::size_t >(*offset_bytes_int),
83+ from_integer (0 , unsignedbv_typet (8 )));
84+ }
6985 }
7086
7187 // the maximum number of bytes is an upper bound in case the size of the
@@ -76,7 +92,6 @@ static array_exprt unpack_array_vector(
7692
7793 const exprt src_simp = simplify_expr (src, ns);
7894
79- exprt::operandst byte_operands;
8095 for (mp_integer i = first_element; i < *num_elements; ++i)
8196 {
8297 exprt element;
@@ -95,7 +110,8 @@ static array_exprt unpack_array_vector(
95110
96111 // recursively unpack each element until so that we eventually just have an
97112 // array of bytes left
98- exprt sub = unpack_rec (element, little_endian, max_bytes, ns, true );
113+ exprt sub =
114+ unpack_rec (element, little_endian, nil_exprt (), max_bytes, ns, true );
99115 byte_operands.insert (
100116 byte_operands.end (), sub.operands ().begin (), sub.operands ().end ());
101117 }
@@ -109,6 +125,8 @@ static array_exprt unpack_array_vector(
109125// / Rewrite an object into its individual bytes.
110126// / \param src: object to unpack
111127// / \param little_endian: true, iff assumed endianness is little-endian
128+ // / \param offset_bytes: if not nil, bytes prior to this offset will be filled
129+ // / with nil values
112130// / \param max_bytes: if not nil, use as upper bound of the number of bytes to
113131// / unpack
114132// / \param ns: namespace for type lookups
@@ -121,6 +139,7 @@ static array_exprt unpack_array_vector(
121139static exprt unpack_rec (
122140 const exprt &src,
123141 bool little_endian,
142+ const exprt &offset_bytes,
124143 const exprt &max_bytes,
125144 const namespacet &ns,
126145 bool unpack_byte_array)
@@ -137,7 +156,13 @@ static exprt unpack_rec(
137156 return src;
138157
139158 return unpack_array_vector (
140- src, array_type.size (), *element_width, little_endian, max_bytes, ns);
159+ src,
160+ array_type.size (),
161+ *element_width,
162+ little_endian,
163+ offset_bytes,
164+ max_bytes,
165+ ns);
141166 }
142167 else if (src.type ().id () == ID_vector)
143168 {
@@ -151,13 +176,21 @@ static exprt unpack_rec(
151176 return src;
152177
153178 return unpack_array_vector (
154- src, vector_type.size (), *element_width, little_endian, max_bytes, ns);
179+ src,
180+ vector_type.size (),
181+ *element_width,
182+ little_endian,
183+ offset_bytes,
184+ max_bytes,
185+ ns);
155186 }
156187 else if (ns.follow (src.type ()).id ()==ID_struct)
157188 {
158189 const struct_typet &struct_type=to_struct_type (ns.follow (src.type ()));
159190 const struct_typet::componentst &components=struct_type.components ();
160191
192+ mp_integer member_offset_bits = 0 ;
193+
161194 exprt::operandst byte_operands;
162195 for (const auto &comp : components)
163196 {
@@ -171,11 +204,43 @@ static exprt unpack_rec(
171204 throw non_byte_alignedt (struct_type, comp, *element_width);
172205 }
173206
207+ exprt offset_in_member = nil_exprt ();
208+ auto offset_in_member_int = numeric_cast<mp_integer>(offset_bytes);
209+ exprt max_bytes_left = nil_exprt ();
210+ auto max_bytes_left_int = numeric_cast<mp_integer>(max_bytes);
211+
212+ if (offset_in_member_int.has_value ())
213+ {
214+ *offset_in_member_int -= member_offset_bits / 8 ;
215+ // if the offset is negative, offset_in_member remains nil, which has
216+ // the same effect as setting it to zero
217+ if (*offset_in_member_int >= 0 )
218+ {
219+ offset_in_member =
220+ from_integer (*offset_in_member_int, offset_bytes.type ());
221+ }
222+ }
223+
224+ if (max_bytes_left_int.has_value ())
225+ {
226+ *max_bytes_left_int -= member_offset_bits / 8 ;
227+ if (*max_bytes_left_int >= 0 )
228+ max_bytes_left = from_integer (*max_bytes_left_int, max_bytes.type ());
229+ else
230+ break ;
231+ }
232+
174233 member_exprt member (src, comp.get_name (), comp.type ());
175- exprt sub=unpack_rec (member, little_endian, max_bytes, ns, true );
234+ if (src.id () == ID_struct)
235+ simplify (member, ns);
236+
237+ exprt sub = unpack_rec (
238+ member, little_endian, offset_in_member, max_bytes_left, ns, true );
176239
177240 byte_operands.insert (
178241 byte_operands.end (), sub.operands ().begin (), sub.operands ().end ());
242+
243+ member_offset_bits += *element_width;
179244 }
180245
181246 const std::size_t size = byte_operands.size ();
@@ -295,9 +360,12 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
295360 typecast_exprt (src.offset (), upper_bound.type ())),
296361 ns);
297362
363+ exprt lb = src.offset ();
364+ if (!lb.is_constant ())
365+ lb.make_nil ();
366+
298367 byte_extract_exprt unpacked (src);
299- unpacked.op ()=
300- unpack_rec (src.op (), little_endian, upper_bound, ns);
368+ unpacked.op () = unpack_rec (src.op (), little_endian, lb, upper_bound, ns);
301369
302370 if (src.type ().id ()==ID_array)
303371 {
0 commit comments