1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2014 Intel Corporation
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg#include <string.h>
25b8e80941Smrg
26b8e80941Smrg#include "main/macros.h"
27b8e80941Smrg#include "blob.h"
28b8e80941Smrg
29b8e80941Smrg#ifdef HAVE_VALGRIND
30b8e80941Smrg#include <valgrind.h>
31b8e80941Smrg#include <memcheck.h>
32b8e80941Smrg#define VG(x) x
33b8e80941Smrg#else
34b8e80941Smrg#define VG(x)
35b8e80941Smrg#endif
36b8e80941Smrg
37b8e80941Smrg#define BLOB_INITIAL_SIZE 4096
38b8e80941Smrg
39b8e80941Smrg/* Ensure that \blob will be able to fit an additional object of size
40b8e80941Smrg * \additional.  The growing (if any) will occur by doubling the existing
41b8e80941Smrg * allocation.
42b8e80941Smrg */
43b8e80941Smrgstatic bool
44b8e80941Smrggrow_to_fit(struct blob *blob, size_t additional)
45b8e80941Smrg{
46b8e80941Smrg   size_t to_allocate;
47b8e80941Smrg   uint8_t *new_data;
48b8e80941Smrg
49b8e80941Smrg   if (blob->out_of_memory)
50b8e80941Smrg      return false;
51b8e80941Smrg
52b8e80941Smrg   if (blob->size + additional <= blob->allocated)
53b8e80941Smrg      return true;
54b8e80941Smrg
55b8e80941Smrg   if (blob->fixed_allocation) {
56b8e80941Smrg      blob->out_of_memory = true;
57b8e80941Smrg      return false;
58b8e80941Smrg   }
59b8e80941Smrg
60b8e80941Smrg   if (blob->allocated == 0)
61b8e80941Smrg      to_allocate = BLOB_INITIAL_SIZE;
62b8e80941Smrg   else
63b8e80941Smrg      to_allocate = blob->allocated * 2;
64b8e80941Smrg
65b8e80941Smrg   to_allocate = MAX2(to_allocate, blob->allocated + additional);
66b8e80941Smrg
67b8e80941Smrg   new_data = realloc(blob->data, to_allocate);
68b8e80941Smrg   if (new_data == NULL) {
69b8e80941Smrg      blob->out_of_memory = true;
70b8e80941Smrg      return false;
71b8e80941Smrg   }
72b8e80941Smrg
73b8e80941Smrg   blob->data = new_data;
74b8e80941Smrg   blob->allocated = to_allocate;
75b8e80941Smrg
76b8e80941Smrg   return true;
77b8e80941Smrg}
78b8e80941Smrg
79b8e80941Smrg/* Align the blob->size so that reading or writing a value at (blob->data +
80b8e80941Smrg * blob->size) will result in an access aligned to a granularity of \alignment
81b8e80941Smrg * bytes.
82b8e80941Smrg *
83b8e80941Smrg * \return True unless allocation fails
84b8e80941Smrg */
85b8e80941Smrgstatic bool
86b8e80941Smrgalign_blob(struct blob *blob, size_t alignment)
87b8e80941Smrg{
88b8e80941Smrg   const size_t new_size = ALIGN(blob->size, alignment);
89b8e80941Smrg
90b8e80941Smrg   if (blob->size < new_size) {
91b8e80941Smrg      if (!grow_to_fit(blob, new_size - blob->size))
92b8e80941Smrg         return false;
93b8e80941Smrg
94b8e80941Smrg      if (blob->data)
95b8e80941Smrg         memset(blob->data + blob->size, 0, new_size - blob->size);
96b8e80941Smrg      blob->size = new_size;
97b8e80941Smrg   }
98b8e80941Smrg
99b8e80941Smrg   return true;
100b8e80941Smrg}
101b8e80941Smrg
102b8e80941Smrgstatic void
103b8e80941Smrgalign_blob_reader(struct blob_reader *blob, size_t alignment)
104b8e80941Smrg{
105b8e80941Smrg   blob->current = blob->data + ALIGN(blob->current - blob->data, alignment);
106b8e80941Smrg}
107b8e80941Smrg
108b8e80941Smrgvoid
109b8e80941Smrgblob_init(struct blob *blob)
110b8e80941Smrg{
111b8e80941Smrg   blob->data = NULL;
112b8e80941Smrg   blob->allocated = 0;
113b8e80941Smrg   blob->size = 0;
114b8e80941Smrg   blob->fixed_allocation = false;
115b8e80941Smrg   blob->out_of_memory = false;
116b8e80941Smrg}
117b8e80941Smrg
118b8e80941Smrgvoid
119b8e80941Smrgblob_init_fixed(struct blob *blob, void *data, size_t size)
120b8e80941Smrg{
121b8e80941Smrg   blob->data = data;
122b8e80941Smrg   blob->allocated = size;
123b8e80941Smrg   blob->size = 0;
124b8e80941Smrg   blob->fixed_allocation = true;
125b8e80941Smrg   blob->out_of_memory = false;
126b8e80941Smrg}
127b8e80941Smrg
128b8e80941Smrgbool
129b8e80941Smrgblob_overwrite_bytes(struct blob *blob,
130b8e80941Smrg                     size_t offset,
131b8e80941Smrg                     const void *bytes,
132b8e80941Smrg                     size_t to_write)
133b8e80941Smrg{
134b8e80941Smrg   /* Detect an attempt to overwrite data out of bounds. */
135b8e80941Smrg   if (offset + to_write < offset || blob->size < offset + to_write)
136b8e80941Smrg      return false;
137b8e80941Smrg
138b8e80941Smrg   VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write));
139b8e80941Smrg
140b8e80941Smrg   if (blob->data)
141b8e80941Smrg      memcpy(blob->data + offset, bytes, to_write);
142b8e80941Smrg
143b8e80941Smrg   return true;
144b8e80941Smrg}
145b8e80941Smrg
146b8e80941Smrgbool
147b8e80941Smrgblob_write_bytes(struct blob *blob, const void *bytes, size_t to_write)
148b8e80941Smrg{
149b8e80941Smrg   if (! grow_to_fit(blob, to_write))
150b8e80941Smrg       return false;
151b8e80941Smrg
152b8e80941Smrg   VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write));
153b8e80941Smrg
154b8e80941Smrg   if (blob->data)
155b8e80941Smrg      memcpy(blob->data + blob->size, bytes, to_write);
156b8e80941Smrg   blob->size += to_write;
157b8e80941Smrg
158b8e80941Smrg   return true;
159b8e80941Smrg}
160b8e80941Smrg
161b8e80941Smrgintptr_t
162b8e80941Smrgblob_reserve_bytes(struct blob *blob, size_t to_write)
163b8e80941Smrg{
164b8e80941Smrg   intptr_t ret;
165b8e80941Smrg
166b8e80941Smrg   if (! grow_to_fit (blob, to_write))
167b8e80941Smrg      return -1;
168b8e80941Smrg
169b8e80941Smrg   ret = blob->size;
170b8e80941Smrg   blob->size += to_write;
171b8e80941Smrg
172b8e80941Smrg   return ret;
173b8e80941Smrg}
174b8e80941Smrg
175b8e80941Smrgintptr_t
176b8e80941Smrgblob_reserve_uint32(struct blob *blob)
177b8e80941Smrg{
178b8e80941Smrg   align_blob(blob, sizeof(uint32_t));
179b8e80941Smrg   return blob_reserve_bytes(blob, sizeof(uint32_t));
180b8e80941Smrg}
181b8e80941Smrg
182b8e80941Smrgintptr_t
183b8e80941Smrgblob_reserve_intptr(struct blob *blob)
184b8e80941Smrg{
185b8e80941Smrg   align_blob(blob, sizeof(intptr_t));
186b8e80941Smrg   return blob_reserve_bytes(blob, sizeof(intptr_t));
187b8e80941Smrg}
188b8e80941Smrg
189b8e80941Smrgbool
190b8e80941Smrgblob_write_uint32(struct blob *blob, uint32_t value)
191b8e80941Smrg{
192b8e80941Smrg   align_blob(blob, sizeof(value));
193b8e80941Smrg
194b8e80941Smrg   return blob_write_bytes(blob, &value, sizeof(value));
195b8e80941Smrg}
196b8e80941Smrg
197b8e80941Smrg#define ASSERT_ALIGNED(_offset, _align) \
198b8e80941Smrg   assert(ALIGN((_offset), (_align)) == (_offset))
199b8e80941Smrg
200b8e80941Smrgbool
201b8e80941Smrgblob_overwrite_uint32 (struct blob *blob,
202b8e80941Smrg                       size_t offset,
203b8e80941Smrg                       uint32_t value)
204b8e80941Smrg{
205b8e80941Smrg   ASSERT_ALIGNED(offset, sizeof(value));
206b8e80941Smrg   return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
207b8e80941Smrg}
208b8e80941Smrg
209b8e80941Smrgbool
210b8e80941Smrgblob_write_uint64(struct blob *blob, uint64_t value)
211b8e80941Smrg{
212b8e80941Smrg   align_blob(blob, sizeof(value));
213b8e80941Smrg
214b8e80941Smrg   return blob_write_bytes(blob, &value, sizeof(value));
215b8e80941Smrg}
216b8e80941Smrg
217b8e80941Smrgbool
218b8e80941Smrgblob_write_intptr(struct blob *blob, intptr_t value)
219b8e80941Smrg{
220b8e80941Smrg   align_blob(blob, sizeof(value));
221b8e80941Smrg
222b8e80941Smrg   return blob_write_bytes(blob, &value, sizeof(value));
223b8e80941Smrg}
224b8e80941Smrg
225b8e80941Smrgbool
226b8e80941Smrgblob_overwrite_intptr (struct blob *blob,
227b8e80941Smrg                       size_t offset,
228b8e80941Smrg                       intptr_t value)
229b8e80941Smrg{
230b8e80941Smrg   ASSERT_ALIGNED(offset, sizeof(value));
231b8e80941Smrg   return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
232b8e80941Smrg}
233b8e80941Smrg
234b8e80941Smrgbool
235b8e80941Smrgblob_write_string(struct blob *blob, const char *str)
236b8e80941Smrg{
237b8e80941Smrg   return blob_write_bytes(blob, str, strlen(str) + 1);
238b8e80941Smrg}
239b8e80941Smrg
240b8e80941Smrgvoid
241b8e80941Smrgblob_reader_init(struct blob_reader *blob, const void *data, size_t size)
242b8e80941Smrg{
243b8e80941Smrg   blob->data = data;
244b8e80941Smrg   blob->end = blob->data + size;
245b8e80941Smrg   blob->current = data;
246b8e80941Smrg   blob->overrun = false;
247b8e80941Smrg}
248b8e80941Smrg
249b8e80941Smrg/* Check that an object of size \size can be read from this blob.
250b8e80941Smrg *
251b8e80941Smrg * If not, set blob->overrun to indicate that we attempted to read too far.
252b8e80941Smrg */
253b8e80941Smrgstatic bool
254b8e80941Smrgensure_can_read(struct blob_reader *blob, size_t size)
255b8e80941Smrg{
256b8e80941Smrg   if (blob->overrun)
257b8e80941Smrg      return false;
258b8e80941Smrg
259b8e80941Smrg   if (blob->current <= blob->end && blob->end - blob->current >= size)
260b8e80941Smrg      return true;
261b8e80941Smrg
262b8e80941Smrg   blob->overrun = true;
263b8e80941Smrg
264b8e80941Smrg   return false;
265b8e80941Smrg}
266b8e80941Smrg
267b8e80941Smrgconst void *
268b8e80941Smrgblob_read_bytes(struct blob_reader *blob, size_t size)
269b8e80941Smrg{
270b8e80941Smrg   const void *ret;
271b8e80941Smrg
272b8e80941Smrg   if (! ensure_can_read (blob, size))
273b8e80941Smrg      return NULL;
274b8e80941Smrg
275b8e80941Smrg   ret = blob->current;
276b8e80941Smrg
277b8e80941Smrg   blob->current += size;
278b8e80941Smrg
279b8e80941Smrg   return ret;
280b8e80941Smrg}
281b8e80941Smrg
282b8e80941Smrgvoid
283b8e80941Smrgblob_copy_bytes(struct blob_reader *blob, void *dest, size_t size)
284b8e80941Smrg{
285b8e80941Smrg   const void *bytes;
286b8e80941Smrg
287b8e80941Smrg   bytes = blob_read_bytes(blob, size);
288b8e80941Smrg   if (bytes == NULL)
289b8e80941Smrg      return;
290b8e80941Smrg
291b8e80941Smrg   memcpy(dest, bytes, size);
292b8e80941Smrg}
293b8e80941Smrg
294b8e80941Smrgvoid
295b8e80941Smrgblob_skip_bytes(struct blob_reader *blob, size_t size)
296b8e80941Smrg{
297b8e80941Smrg   if (ensure_can_read (blob, size))
298b8e80941Smrg      blob->current += size;
299b8e80941Smrg}
300b8e80941Smrg
301b8e80941Smrg/* These next three read functions have identical form. If we add any beyond
302b8e80941Smrg * these first three we should probably switch to generating these with a
303b8e80941Smrg * preprocessor macro.
304b8e80941Smrg*/
305b8e80941Smrguint32_t
306b8e80941Smrgblob_read_uint32(struct blob_reader *blob)
307b8e80941Smrg{
308b8e80941Smrg   uint32_t ret;
309b8e80941Smrg   int size = sizeof(ret);
310b8e80941Smrg
311b8e80941Smrg   align_blob_reader(blob, size);
312b8e80941Smrg
313b8e80941Smrg   if (! ensure_can_read(blob, size))
314b8e80941Smrg      return 0;
315b8e80941Smrg
316b8e80941Smrg   ret = *((uint32_t*) blob->current);
317b8e80941Smrg
318b8e80941Smrg   blob->current += size;
319b8e80941Smrg
320b8e80941Smrg   return ret;
321b8e80941Smrg}
322b8e80941Smrg
323b8e80941Smrguint64_t
324b8e80941Smrgblob_read_uint64(struct blob_reader *blob)
325b8e80941Smrg{
326b8e80941Smrg   uint64_t ret;
327b8e80941Smrg   int size = sizeof(ret);
328b8e80941Smrg
329b8e80941Smrg   align_blob_reader(blob, size);
330b8e80941Smrg
331b8e80941Smrg   if (! ensure_can_read(blob, size))
332b8e80941Smrg      return 0;
333b8e80941Smrg
334b8e80941Smrg   ret = *((uint64_t*) blob->current);
335b8e80941Smrg
336b8e80941Smrg   blob->current += size;
337b8e80941Smrg
338b8e80941Smrg   return ret;
339b8e80941Smrg}
340b8e80941Smrg
341b8e80941Smrgintptr_t
342b8e80941Smrgblob_read_intptr(struct blob_reader *blob)
343b8e80941Smrg{
344b8e80941Smrg   intptr_t ret;
345b8e80941Smrg   int size = sizeof(ret);
346b8e80941Smrg
347b8e80941Smrg   align_blob_reader(blob, size);
348b8e80941Smrg
349b8e80941Smrg   if (! ensure_can_read(blob, size))
350b8e80941Smrg      return 0;
351b8e80941Smrg
352b8e80941Smrg   ret = *((intptr_t *) blob->current);
353b8e80941Smrg
354b8e80941Smrg   blob->current += size;
355b8e80941Smrg
356b8e80941Smrg   return ret;
357b8e80941Smrg}
358b8e80941Smrg
359b8e80941Smrgchar *
360b8e80941Smrgblob_read_string(struct blob_reader *blob)
361b8e80941Smrg{
362b8e80941Smrg   int size;
363b8e80941Smrg   char *ret;
364b8e80941Smrg   uint8_t *nul;
365b8e80941Smrg
366b8e80941Smrg   /* If we're already at the end, then this is an overrun. */
367b8e80941Smrg   if (blob->current >= blob->end) {
368b8e80941Smrg      blob->overrun = true;
369b8e80941Smrg      return NULL;
370b8e80941Smrg   }
371b8e80941Smrg
372b8e80941Smrg   /* Similarly, if there is no zero byte in the data remaining in this blob,
373b8e80941Smrg    * we also consider that an overrun.
374b8e80941Smrg    */
375b8e80941Smrg   nul = memchr(blob->current, 0, blob->end - blob->current);
376b8e80941Smrg
377b8e80941Smrg   if (nul == NULL) {
378b8e80941Smrg      blob->overrun = true;
379b8e80941Smrg      return NULL;
380b8e80941Smrg   }
381b8e80941Smrg
382b8e80941Smrg   size = nul - blob->current + 1;
383b8e80941Smrg
384b8e80941Smrg   assert(ensure_can_read(blob, size));
385b8e80941Smrg
386b8e80941Smrg   ret = (char *) blob->current;
387b8e80941Smrg
388b8e80941Smrg   blob->current += size;
389b8e80941Smrg
390b8e80941Smrg   return ret;
391b8e80941Smrg}
392