1/*-
2 * Copyright (c) 2007 John Birrell (jb@freebsd.org)
3 * Copyright (c) 2010 Kai Wang
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include "_libdwarf.h"
29
30ELFTC_VCSID("$Id: libdwarf_rw.c 3286 2015-12-31 16:45:46Z emaste $");
31
32uint64_t
33_dwarf_read_lsb(uint8_t *data, uint64_t *offsetp, int bytes_to_read)
34{
35	uint64_t ret;
36	uint8_t *src;
37
38	src = data + *offsetp;
39
40	ret = 0;
41	switch (bytes_to_read) {
42	case 8:
43		ret |= ((uint64_t) src[4]) << 32 | ((uint64_t) src[5]) << 40;
44		ret |= ((uint64_t) src[6]) << 48 | ((uint64_t) src[7]) << 56;
45		/* FALLTHROUGH */
46	case 4:
47		ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24;
48		/* FALLTHROUGH */
49	case 2:
50		ret |= ((uint64_t) src[1]) << 8;
51		/* FALLTHROUGH */
52	case 1:
53		ret |= src[0];
54		break;
55	default:
56		return (0);
57	}
58
59	*offsetp += bytes_to_read;
60
61	return (ret);
62}
63
64uint64_t
65_dwarf_decode_lsb(uint8_t **data, int bytes_to_read)
66{
67	uint64_t ret;
68	uint8_t *src;
69
70	src = *data;
71
72	ret = 0;
73	switch (bytes_to_read) {
74	case 8:
75		ret |= ((uint64_t) src[4]) << 32 | ((uint64_t) src[5]) << 40;
76		ret |= ((uint64_t) src[6]) << 48 | ((uint64_t) src[7]) << 56;
77		/* FALLTHROUGH */
78	case 4:
79		ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24;
80		/* FALLTHROUGH */
81	case 2:
82		ret |= ((uint64_t) src[1]) << 8;
83		/* FALLTHROUGH */
84	case 1:
85		ret |= src[0];
86		break;
87	default:
88		return (0);
89	}
90
91	*data += bytes_to_read;
92
93	return (ret);
94}
95
96uint64_t
97_dwarf_read_msb(uint8_t *data, uint64_t *offsetp, int bytes_to_read)
98{
99	uint64_t ret;
100	uint8_t *src;
101
102	src = data + *offsetp;
103
104	switch (bytes_to_read) {
105	case 1:
106		ret = src[0];
107		break;
108	case 2:
109		ret = src[1] | ((uint64_t) src[0]) << 8;
110		break;
111	case 4:
112		ret = src[3] | ((uint64_t) src[2]) << 8;
113		ret |= ((uint64_t) src[1]) << 16 | ((uint64_t) src[0]) << 24;
114		break;
115	case 8:
116		ret = src[7] | ((uint64_t) src[6]) << 8;
117		ret |= ((uint64_t) src[5]) << 16 | ((uint64_t) src[4]) << 24;
118		ret |= ((uint64_t) src[3]) << 32 | ((uint64_t) src[2]) << 40;
119		ret |= ((uint64_t) src[1]) << 48 | ((uint64_t) src[0]) << 56;
120		break;
121	default:
122		return (0);
123	}
124
125	*offsetp += bytes_to_read;
126
127	return (ret);
128}
129
130uint64_t
131_dwarf_decode_msb(uint8_t **data, int bytes_to_read)
132{
133	uint64_t ret;
134	uint8_t *src;
135
136	src = *data;
137
138	ret = 0;
139	switch (bytes_to_read) {
140	case 1:
141		ret = src[0];
142		break;
143	case 2:
144		ret = src[1] | ((uint64_t) src[0]) << 8;
145		break;
146	case 4:
147		ret = src[3] | ((uint64_t) src[2]) << 8;
148		ret |= ((uint64_t) src[1]) << 16 | ((uint64_t) src[0]) << 24;
149		break;
150	case 8:
151		ret = src[7] | ((uint64_t) src[6]) << 8;
152		ret |= ((uint64_t) src[5]) << 16 | ((uint64_t) src[4]) << 24;
153		ret |= ((uint64_t) src[3]) << 32 | ((uint64_t) src[2]) << 40;
154		ret |= ((uint64_t) src[1]) << 48 | ((uint64_t) src[0]) << 56;
155		break;
156	default:
157		return (0);
158		break;
159	}
160
161	*data += bytes_to_read;
162
163	return (ret);
164}
165
166void
167_dwarf_write_lsb(uint8_t *data, uint64_t *offsetp, uint64_t value,
168    int bytes_to_write)
169{
170	uint8_t *dst;
171
172	dst = data + *offsetp;
173
174	switch (bytes_to_write) {
175	case 8:
176		dst[7] = (value >> 56) & 0xff;
177		dst[6] = (value >> 48) & 0xff;
178		dst[5] = (value >> 40) & 0xff;
179		dst[4] = (value >> 32) & 0xff;
180		/* FALLTHROUGH */
181	case 4:
182		dst[3] = (value >> 24) & 0xff;
183		dst[2] = (value >> 16) & 0xff;
184		/* FALLTHROUGH */
185	case 2:
186		dst[1] = (value >> 8) & 0xff;
187		/* FALLTHROUGH */
188	case 1:
189		dst[0] = value & 0xff;
190		break;
191	default:
192		return;
193	}
194
195	*offsetp += bytes_to_write;
196}
197
198int
199_dwarf_write_lsb_alloc(uint8_t **block, uint64_t *size, uint64_t *offsetp,
200    uint64_t value, int bytes_to_write, Dwarf_Error *error)
201{
202
203	assert(*size > 0);
204
205	while (*offsetp + bytes_to_write > *size) {
206		*size *= 2;
207		*block = realloc(*block, (size_t) *size);
208		if (*block == NULL) {
209			DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
210			return (DW_DLE_MEMORY);
211		}
212	}
213
214	_dwarf_write_lsb(*block, offsetp, value, bytes_to_write);
215
216	return (DW_DLE_NONE);
217}
218
219void
220_dwarf_write_msb(uint8_t *data, uint64_t *offsetp, uint64_t value,
221    int bytes_to_write)
222{
223	uint8_t *dst;
224
225	dst = data + *offsetp;
226
227	switch (bytes_to_write) {
228	case 8:
229		dst[7] = value & 0xff;
230		dst[6] = (value >> 8) & 0xff;
231		dst[5] = (value >> 16) & 0xff;
232		dst[4] = (value >> 24) & 0xff;
233		value >>= 32;
234		/* FALLTHROUGH */
235	case 4:
236		dst[3] = value & 0xff;
237		dst[2] = (value >> 8) & 0xff;
238		value >>= 16;
239		/* FALLTHROUGH */
240	case 2:
241		dst[1] = value & 0xff;
242		value >>= 8;
243		/* FALLTHROUGH */
244	case 1:
245		dst[0] = value & 0xff;
246		break;
247	default:
248		return;
249	}
250
251	*offsetp += bytes_to_write;
252}
253
254int
255_dwarf_write_msb_alloc(uint8_t **block, uint64_t *size, uint64_t *offsetp,
256    uint64_t value, int bytes_to_write, Dwarf_Error *error)
257{
258
259	assert(*size > 0);
260
261	while (*offsetp + bytes_to_write > *size) {
262		*size *= 2;
263		*block = realloc(*block, (size_t) *size);
264		if (*block == NULL) {
265			DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
266			return (DW_DLE_MEMORY);
267		}
268	}
269
270	_dwarf_write_msb(*block, offsetp, value, bytes_to_write);
271
272	return (DW_DLE_NONE);
273}
274
275int64_t
276_dwarf_read_sleb128(uint8_t *data, uint64_t *offsetp)
277{
278	int64_t ret = 0;
279	uint8_t b;
280	int shift = 0;
281	uint8_t *src;
282
283	src = data + *offsetp;
284
285	do {
286		b = *src++;
287		ret |= ((b & 0x7f) << shift);
288		(*offsetp)++;
289		shift += 7;
290	} while ((b & 0x80) != 0);
291
292	if (shift < 64 && (b & 0x40) != 0)
293		ret |= (-1 << shift);
294
295	return (ret);
296}
297
298int
299_dwarf_write_sleb128(uint8_t *data, uint8_t *end, int64_t val)
300{
301	uint8_t *p;
302
303	p = data;
304
305	for (;;) {
306		if (p >= end)
307			return (-1);
308		*p = val & 0x7f;
309		val >>= 7;
310		if ((val == 0 && (*p & 0x40) == 0) ||
311		    (val == -1 && (*p & 0x40) != 0)) {
312			p++;
313			break;
314		}
315		*p++ |= 0x80;
316	}
317
318	return (p - data);
319}
320
321int
322_dwarf_write_sleb128_alloc(uint8_t **block, uint64_t *size, uint64_t *offsetp,
323    int64_t val, Dwarf_Error *error)
324{
325	int len;
326
327	assert(*size > 0);
328
329	while ((len = _dwarf_write_sleb128(*block + *offsetp, *block + *size,
330	    val)) < 0) {
331		*size *= 2;
332		*block = realloc(*block, (size_t) *size);
333		if (*block == NULL) {
334			DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
335			return (DW_DLE_MEMORY);
336		}
337	}
338
339	*offsetp += len;
340
341	return (DW_DLE_NONE);
342}
343
344uint64_t
345_dwarf_read_uleb128(uint8_t *data, uint64_t *offsetp)
346{
347	uint64_t ret = 0;
348	uint8_t b;
349	int shift = 0;
350	uint8_t *src;
351
352	src = data + *offsetp;
353
354	do {
355		b = *src++;
356		ret |= ((b & 0x7f) << shift);
357		(*offsetp)++;
358		shift += 7;
359	} while ((b & 0x80) != 0);
360
361	return (ret);
362}
363
364int
365_dwarf_write_uleb128(uint8_t *data, uint8_t *end, uint64_t val)
366{
367	uint8_t *p;
368
369	p = data;
370
371	do {
372		if (p >= end)
373			return (-1);
374		*p = val & 0x7f;
375		val >>= 7;
376		if (val > 0)
377			*p |= 0x80;
378		p++;
379	} while (val > 0);
380
381	return (p - data);
382}
383
384int
385_dwarf_write_uleb128_alloc(uint8_t **block, uint64_t *size, uint64_t *offsetp,
386    uint64_t val, Dwarf_Error *error)
387{
388	int len;
389
390	assert(*size > 0);
391
392	while ((len = _dwarf_write_uleb128(*block + *offsetp, *block + *size,
393	    val)) < 0) {
394		*size *= 2;
395		*block = realloc(*block, (size_t) *size);
396		if (*block == NULL) {
397			DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
398			return (DW_DLE_MEMORY);
399		}
400	}
401
402	*offsetp += len;
403
404	return (DW_DLE_NONE);
405}
406
407int64_t
408_dwarf_decode_sleb128(uint8_t **dp)
409{
410	int64_t ret = 0;
411	uint8_t b;
412	int shift = 0;
413
414	uint8_t *src = *dp;
415
416	do {
417		b = *src++;
418		ret |= ((b & 0x7f) << shift);
419		shift += 7;
420	} while ((b & 0x80) != 0);
421
422	if (shift < 64 && (b & 0x40) != 0)
423		ret |= (-1 << shift);
424
425	*dp = src;
426
427	return (ret);
428}
429
430uint64_t
431_dwarf_decode_uleb128(uint8_t **dp)
432{
433	uint64_t ret = 0;
434	uint8_t b;
435	int shift = 0;
436
437	uint8_t *src = *dp;
438
439	do {
440		b = *src++;
441		ret |= ((b & 0x7f) << shift);
442		shift += 7;
443	} while ((b & 0x80) != 0);
444
445	*dp = src;
446
447	return (ret);
448}
449
450char *
451_dwarf_read_string(void *data, Dwarf_Unsigned size, uint64_t *offsetp)
452{
453	char *ret, *src;
454
455	ret = src = (char *) data + *offsetp;
456
457	while (*src != '\0' && *offsetp < size) {
458		src++;
459		(*offsetp)++;
460	}
461
462	if (*src == '\0' && *offsetp < size)
463		(*offsetp)++;
464
465	return (ret);
466}
467
468void
469_dwarf_write_string(void *data, uint64_t *offsetp, char *string)
470{
471	char *dst;
472
473	dst = (char *) data + *offsetp;
474	strcpy(dst, string);
475	(*offsetp) += strlen(string) + 1;
476}
477
478int
479_dwarf_write_string_alloc(uint8_t **block, uint64_t *size, uint64_t *offsetp,
480    char *string, Dwarf_Error *error)
481{
482	size_t len;
483
484	assert(*size > 0);
485
486	len = strlen(string) + 1;
487	while (*offsetp + len > *size) {
488		*size *= 2;
489		*block = realloc(*block, (size_t) *size);
490		if (*block == NULL) {
491			DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
492			return (DW_DLE_MEMORY);
493		}
494	}
495
496	_dwarf_write_string(*block, offsetp, string);
497
498	return (DW_DLE_NONE);
499}
500
501uint8_t *
502_dwarf_read_block(void *data, uint64_t *offsetp, uint64_t length)
503{
504	uint8_t *ret, *src;
505
506	ret = src = (uint8_t *) data + *offsetp;
507
508	(*offsetp) += length;
509
510	return (ret);
511}
512
513void
514_dwarf_write_block(void *data, uint64_t *offsetp, uint8_t *blk,
515    uint64_t length)
516{
517	uint8_t *dst;
518
519	dst = (uint8_t *) data + *offsetp;
520	memcpy(dst, blk, length);
521	(*offsetp) += length;
522}
523
524int
525_dwarf_write_block_alloc(uint8_t **block, uint64_t *size, uint64_t *offsetp,
526    uint8_t *blk, uint64_t length, Dwarf_Error *error)
527{
528
529	assert(*size > 0);
530
531	while (*offsetp + length > *size) {
532		*size *= 2;
533		*block = realloc(*block, (size_t) *size);
534		if (*block == NULL) {
535			DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
536			return (DW_DLE_MEMORY);
537		}
538	}
539
540	_dwarf_write_block(*block, offsetp, blk, length);
541
542	return (DW_DLE_NONE);
543}
544
545void
546_dwarf_write_padding(void *data, uint64_t *offsetp, uint8_t byte,
547    uint64_t length)
548{
549	uint8_t *dst;
550
551	dst = (uint8_t *) data + *offsetp;
552	memset(dst, byte, length);
553	(*offsetp) += length;
554}
555
556int
557_dwarf_write_padding_alloc(uint8_t **block, uint64_t *size, uint64_t *offsetp,
558    uint8_t byte, uint64_t cnt, Dwarf_Error *error)
559{
560	assert(*size > 0);
561
562	while (*offsetp + cnt > *size) {
563		*size *= 2;
564		*block = realloc(*block, (size_t) *size);
565		if (*block == NULL) {
566			DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
567			return (DW_DLE_MEMORY);
568		}
569	}
570
571	_dwarf_write_padding(*block, offsetp, byte, cnt);
572
573	return (DW_DLE_NONE);
574}
575