xref: /netbsd-src/external/bsd/elftoolchain/dist/libdwarf/libdwarf_frame.c (revision 5ac3bc719ce6e70593039505b491894133237d12)
1 /*	$NetBSD: libdwarf_frame.c,v 1.5 2024/03/03 17:37:32 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009-2011,2014 Kai Wang
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include "_libdwarf.h"
30 
31 __RCSID("$NetBSD: libdwarf_frame.c,v 1.5 2024/03/03 17:37:32 christos Exp $");
32 ELFTC_VCSID("Id: libdwarf_frame.c 3804 2020-02-07 02:13:34Z emaste");
33 
34 static int
_dwarf_frame_find_cie(Dwarf_FrameSec fs,Dwarf_Unsigned offset,Dwarf_Cie * ret_cie)35 _dwarf_frame_find_cie(Dwarf_FrameSec fs, Dwarf_Unsigned offset,
36     Dwarf_Cie *ret_cie)
37 {
38 	Dwarf_Cie cie;
39 
40 	STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
41 		if (cie->cie_offset == offset)
42 			break;
43 	}
44 
45 	if (cie == NULL)
46 		return (DW_DLE_NO_ENTRY);
47 
48 	if (ret_cie != NULL)
49 		*ret_cie = cie;
50 
51 	return (DW_DLE_NONE);
52 }
53 
54 static int
_dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg,Dwarf_Cie cie,uint64_t * val,uint8_t * data,uint64_t * offsetp,uint8_t encode,Dwarf_Addr pc,Dwarf_Error * error)55 _dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg, Dwarf_Cie cie, uint64_t *val,
56     uint8_t *data, uint64_t *offsetp, uint8_t encode, Dwarf_Addr pc,
57     Dwarf_Error *error)
58 {
59 	uint8_t application;
60 
61 	if (encode == DW_EH_PE_omit)
62 		return (DW_DLE_NONE);
63 
64 	application = encode & 0xf0;
65 	encode &= 0x0f;
66 
67 	switch (encode) {
68 	case DW_EH_PE_absptr:
69 		*val = dbg->read(data, offsetp, cie->cie_addrsize);
70 		break;
71 	case DW_EH_PE_uleb128:
72 		*val = _dwarf_read_uleb128(data, offsetp);
73 		break;
74 	case DW_EH_PE_udata2:
75 		*val = dbg->read(data, offsetp, 2);
76 		break;
77 	case DW_EH_PE_udata4:
78 		*val = dbg->read(data, offsetp, 4);
79 		break;
80 	case DW_EH_PE_udata8:
81 		*val = dbg->read(data, offsetp, 8);
82 		break;
83 	case DW_EH_PE_sleb128:
84 		*val = _dwarf_read_sleb128(data, offsetp);
85 		break;
86 	case DW_EH_PE_sdata2:
87 		*val = (int16_t) dbg->read(data, offsetp, 2);
88 		break;
89 	case DW_EH_PE_sdata4:
90 		*val = (int32_t) dbg->read(data, offsetp, 4);
91 		break;
92 	case DW_EH_PE_sdata8:
93 		*val = dbg->read(data, offsetp, 8);
94 		break;
95 	default:
96 		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
97 		return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
98 	}
99 
100 	if (application == DW_EH_PE_pcrel) {
101 		/*
102 		 * Value is relative to .eh_frame section virtual addr.
103 		 */
104 		switch (encode) {
105 		case DW_EH_PE_uleb128:
106 		case DW_EH_PE_udata2:
107 		case DW_EH_PE_udata4:
108 		case DW_EH_PE_udata8:
109 			*val += pc;
110 			break;
111 		case DW_EH_PE_sleb128:
112 		case DW_EH_PE_sdata2:
113 		case DW_EH_PE_sdata4:
114 		case DW_EH_PE_sdata8:
115 			*val = pc + (int64_t) *val;
116 			break;
117 		default:
118 			/* DW_EH_PE_absptr is absolute value. */
119 			break;
120 		}
121 	}
122 
123 	/* XXX Applications other than DW_EH_PE_pcrel are not handled. */
124 
125 	return (DW_DLE_NONE);
126 }
127 
128 static int
_dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg,Dwarf_Cie cie,Dwarf_Error * error)129 _dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg, Dwarf_Cie cie,
130     Dwarf_Error *error)
131 {
132 	uint8_t *aug_p, *augdata_p;
133 	uint64_t val, offset;
134 	uint8_t encode;
135 	int ret;
136 
137 	assert(cie->cie_augment != NULL && *cie->cie_augment == 'z');
138 
139 	/*
140 	 * Here we're only interested in the presence of augment 'R'
141 	 * and associated CIE augment data, which describes the
142 	 * encoding scheme of FDE PC begin and range.
143 	 */
144 	aug_p = &cie->cie_augment[1];
145 	augdata_p = cie->cie_augdata;
146 	while (*aug_p != '\0') {
147 		switch (*aug_p) {
148 		case 'S':
149 			break;
150 		case 'L':
151 			/* Skip one augment in augment data. */
152 			augdata_p++;
153 			break;
154 		case 'P':
155 			/* Skip two augments in augment data. */
156 			encode = *augdata_p++;
157 			offset = 0;
158 			ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
159 			    augdata_p, &offset, encode, 0, error);
160 			if (ret != DW_DLE_NONE)
161 				return (ret);
162 			augdata_p += offset;
163 			break;
164 		case 'R':
165 			cie->cie_fde_encode = *augdata_p++;
166 			break;
167 		default:
168 			DWARF_SET_ERROR(dbg, error,
169 			    DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
170 			return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
171 		}
172 		aug_p++;
173 	}
174 
175 	return (DW_DLE_NONE);
176 }
177 
178 static int
_dwarf_frame_add_cie(Dwarf_Debug dbg,Dwarf_FrameSec fs,Dwarf_Section * ds,Dwarf_Unsigned * off,Dwarf_Cie * ret_cie,Dwarf_Error * error)179 _dwarf_frame_add_cie(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
180     Dwarf_Unsigned *off, Dwarf_Cie *ret_cie, Dwarf_Error *error)
181 {
182 	Dwarf_Cie cie;
183 	uint64_t length;
184 	int dwarf_size, ret;
185 	char *p;
186 
187 	/* Check if we already added this CIE. */
188 	if (_dwarf_frame_find_cie(fs, *off, &cie) != DW_DLE_NO_ENTRY) {
189 		*off += cie->cie_length + 4;
190 		return (DW_DLE_NONE);
191 	}
192 
193 	if ((cie = calloc(1, sizeof(struct _Dwarf_Cie))) == NULL) {
194 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
195 		return (DW_DLE_MEMORY);
196 	}
197 	STAILQ_INSERT_TAIL(&fs->fs_cielist, cie, cie_next);
198 
199 	cie->cie_dbg = dbg;
200 	cie->cie_index = fs->fs_cielen;
201 	cie->cie_offset = *off;
202 
203 	length = dbg->read(ds->ds_data, off, 4);
204 	if (length == 0xffffffff) {
205 		dwarf_size = 8;
206 		length = dbg->read(ds->ds_data, off, 8);
207 	} else
208 		dwarf_size = 4;
209 
210 	if (length > ds->ds_size - *off) {
211 		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
212 		return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
213 	}
214 
215 	(void) dbg->read(ds->ds_data, off, dwarf_size); /* Skip CIE id. */
216 	cie->cie_length = length;
217 
218 	cie->cie_version = dbg->read(ds->ds_data, off, 1);
219 	if (cie->cie_version != 1 && cie->cie_version != 3 &&
220 	    cie->cie_version != 4) {
221 		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_VERSION_BAD);
222 		return (DW_DLE_FRAME_VERSION_BAD);
223 	}
224 
225 	cie->cie_augment = ds->ds_data + *off;
226 	p = (char *) ds->ds_data;
227 	while (p[(*off)++] != '\0')
228 		;
229 
230 	/* We only recognize normal .dwarf_frame and GNU .eh_frame sections. */
231 	if (*cie->cie_augment != 0 && *cie->cie_augment != 'z') {
232 		*off = cie->cie_offset + ((dwarf_size == 4) ? 4 : 12) +
233 		    cie->cie_length;
234 		return (DW_DLE_NONE);
235 	}
236 
237 	/* Optional EH Data field for .eh_frame section. */
238 	if (strstr((char *)cie->cie_augment, "eh") != NULL)
239 		cie->cie_ehdata = dbg->read(ds->ds_data, off,
240 		    dbg->dbg_pointer_size);
241 
242 	/* DWARF4 added "address_size" and "segment_size". */
243 	if (cie->cie_version == 4) {
244 		cie->cie_addrsize = dbg->read(ds->ds_data, off, 1);
245 		cie->cie_segmentsize = dbg->read(ds->ds_data, off, 1);
246 	} else {
247 		/*
248 		 * Otherwise (DWARF[23]) we just set CIE addrsize to the
249 		 * debug context pointer size.
250 		 */
251 		cie->cie_addrsize = dbg->dbg_pointer_size;
252 	}
253 
254 	cie->cie_caf = _dwarf_read_uleb128(ds->ds_data, off);
255 	cie->cie_daf = _dwarf_read_sleb128(ds->ds_data, off);
256 
257 	/* Return address register. */
258 	if (cie->cie_version == 1)
259 		cie->cie_ra = dbg->read(ds->ds_data, off, 1);
260 	else
261 		cie->cie_ra = _dwarf_read_uleb128(ds->ds_data, off);
262 
263 	/* Optional CIE augmentation data for .eh_frame section. */
264 	if (*cie->cie_augment == 'z') {
265 		cie->cie_auglen = _dwarf_read_uleb128(ds->ds_data, off);
266 		cie->cie_augdata = ds->ds_data + *off;
267 		*off += cie->cie_auglen;
268 		/*
269 		 * XXX Use DW_EH_PE_absptr for default FDE PC start/range,
270 		 * in case _dwarf_frame_parse_lsb_cie_augment fails to
271 		 * find out the real encode.
272 		 */
273 		cie->cie_fde_encode = DW_EH_PE_absptr;
274 		ret = _dwarf_frame_parse_lsb_cie_augment(dbg, cie, error);
275 		if (ret != DW_DLE_NONE)
276 			return (ret);
277 	}
278 
279 	/* CIE Initial instructions. */
280 	cie->cie_initinst = ds->ds_data + *off;
281 	if (dwarf_size == 4)
282 		cie->cie_instlen = cie->cie_offset + 4 + length - *off;
283 	else
284 		cie->cie_instlen = cie->cie_offset + 12 + length - *off;
285 
286 	*off += cie->cie_instlen;
287 
288 #ifdef FRAME_DEBUG
289 	printf("cie:\n");
290 	printf("\tcie_version=%u cie_offset=%ju cie_length=%ju cie_augment=%s"
291 	    " cie_instlen=%ju cie->cie_caf=%ju cie->cie_daf=%jd off=%ju\n",
292 	    cie->cie_version, cie->cie_offset, cie->cie_length,
293 	    (char *)cie->cie_augment, cie->cie_instlen, cie->cie_caf,
294 	    cie->cie_daf, *off);
295 #endif
296 
297 	if (ret_cie != NULL)
298 		*ret_cie = cie;
299 
300 	fs->fs_cielen++;
301 
302 	return (DW_DLE_NONE);
303 }
304 
305 static int
_dwarf_frame_add_fde(Dwarf_Debug dbg,Dwarf_FrameSec fs,Dwarf_Section * ds,Dwarf_Unsigned * off,int eh_frame,Dwarf_Error * error)306 _dwarf_frame_add_fde(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
307     Dwarf_Unsigned *off, int eh_frame, Dwarf_Error *error)
308 {
309 	Dwarf_Cie cie;
310 	Dwarf_Fde fde;
311 	Dwarf_Unsigned cieoff;
312 	uint64_t length, val;
313 	int dwarf_size, ret;
314 
315 	if ((fde = calloc(1, sizeof(struct _Dwarf_Fde))) == NULL) {
316 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
317 		return (DW_DLE_MEMORY);
318 	}
319 	STAILQ_INSERT_TAIL(&fs->fs_fdelist, fde, fde_next);
320 
321 	fde->fde_dbg = dbg;
322 	fde->fde_fs = fs;
323 	fde->fde_addr = ds->ds_data + *off;
324 	fde->fde_offset = *off;
325 
326 	length = dbg->read(ds->ds_data, off, 4);
327 	if (length == 0xffffffff) {
328 		dwarf_size = 8;
329 		length = dbg->read(ds->ds_data, off, 8);
330 	} else
331 		dwarf_size = 4;
332 
333 	if (length > ds->ds_size - *off) {
334 		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
335 		return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
336 	}
337 
338 	fde->fde_length = length;
339 
340 	if (eh_frame) {
341 		fde->fde_cieoff = dbg->read(ds->ds_data, off, 4);
342 		cieoff = *off - (4 + fde->fde_cieoff);
343 		/* This delta should never be 0. */
344 		if (cieoff == fde->fde_offset) {
345 			DWARF_SET_ERROR(dbg, error, DW_DLE_NO_CIE_FOR_FDE);
346 			return (DW_DLE_NO_CIE_FOR_FDE);
347 		}
348 	} else {
349 		fde->fde_cieoff = dbg->read(ds->ds_data, off, dwarf_size);
350 		cieoff = fde->fde_cieoff;
351 	}
352 
353 	if (_dwarf_frame_find_cie(fs, cieoff, &cie) ==
354 	    DW_DLE_NO_ENTRY) {
355 		ret = _dwarf_frame_add_cie(dbg, fs, ds, &cieoff, &cie,
356 		    error);
357 		if (ret != DW_DLE_NONE)
358 			return (ret);
359 	}
360 	fde->fde_cie = cie;
361 	if (eh_frame) {
362 		/*
363 		 * The FDE PC start/range for .eh_frame is encoded according
364 		 * to the LSB spec's extension to DWARF2.
365 		 */
366 		ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
367 		    ds->ds_data, off, cie->cie_fde_encode, ds->ds_addr + *off,
368 		    error);
369 		if (ret != DW_DLE_NONE)
370 			return (ret);
371 		fde->fde_initloc = val;
372 		/*
373 		 * FDE PC range should not be relative value to anything.
374 		 * So pass 0 for pc value.
375 		 */
376 		ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
377 		    ds->ds_data, off, cie->cie_fde_encode, 0, error);
378 		if (ret != DW_DLE_NONE)
379 			return (ret);
380 		fde->fde_adrange = val;
381 	} else {
382 		fde->fde_initloc = dbg->read(ds->ds_data, off,
383 		    cie->cie_addrsize);
384 		fde->fde_adrange = dbg->read(ds->ds_data, off,
385 		    cie->cie_addrsize);
386 	}
387 
388 	/* Optional FDE augmentation data for .eh_frame section. (ignored) */
389 	if (eh_frame && *cie->cie_augment == 'z') {
390 		fde->fde_auglen = _dwarf_read_uleb128(ds->ds_data, off);
391 		fde->fde_augdata = ds->ds_data + *off;
392 		*off += fde->fde_auglen;
393 	}
394 
395 	fde->fde_inst = ds->ds_data + *off;
396 	if (dwarf_size == 4)
397 		fde->fde_instlen = fde->fde_offset + 4 + length - *off;
398 	else
399 		fde->fde_instlen = fde->fde_offset + 12 + length - *off;
400 
401 	*off += fde->fde_instlen;
402 
403 #ifdef FRAME_DEBUG
404 	printf("fde:");
405 	if (eh_frame)
406 		printf("(eh_frame)");
407 	putchar('\n');
408 	printf("\tfde_offset=%ju fde_length=%ju fde_cieoff=%ju"
409 	    " fde_instlen=%ju off=%ju\n", fde->fde_offset, fde->fde_length,
410 	    fde->fde_cieoff, fde->fde_instlen, *off);
411 #endif
412 
413 	fs->fs_fdelen++;
414 
415 	return (DW_DLE_NONE);
416 }
417 
418 static void
_dwarf_frame_section_cleanup(Dwarf_FrameSec fs)419 _dwarf_frame_section_cleanup(Dwarf_FrameSec fs)
420 {
421 	Dwarf_Cie cie, tcie;
422 	Dwarf_Fde fde, tfde;
423 
424 	STAILQ_FOREACH_SAFE(cie, &fs->fs_cielist, cie_next, tcie) {
425 		STAILQ_REMOVE(&fs->fs_cielist, cie, _Dwarf_Cie, cie_next);
426 		free(cie);
427 	}
428 
429 	STAILQ_FOREACH_SAFE(fde, &fs->fs_fdelist, fde_next, tfde) {
430 		STAILQ_REMOVE(&fs->fs_fdelist, fde, _Dwarf_Fde, fde_next);
431 		free(fde);
432 	}
433 
434 	if (fs->fs_ciearray != NULL)
435 		free(fs->fs_ciearray);
436 	if (fs->fs_fdearray != NULL)
437 		free(fs->fs_fdearray);
438 
439 	free(fs);
440 }
441 
442 static int
_dwarf_frame_section_init(Dwarf_Debug dbg,Dwarf_FrameSec * frame_sec,Dwarf_Section * ds,int eh_frame,Dwarf_Error * error)443 _dwarf_frame_section_init(Dwarf_Debug dbg, Dwarf_FrameSec *frame_sec,
444     Dwarf_Section *ds, int eh_frame, Dwarf_Error *error)
445 {
446 	Dwarf_FrameSec fs;
447 	Dwarf_Cie cie;
448 	Dwarf_Fde fde;
449 	uint64_t length, offset, cie_id, entry_off;
450 	int dwarf_size, i, ret;
451 
452 	assert(frame_sec != NULL);
453 	assert(*frame_sec == NULL);
454 
455 	if ((fs = calloc(1, sizeof(struct _Dwarf_FrameSec))) == NULL) {
456 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
457 		return (DW_DLE_MEMORY);
458 	}
459 	STAILQ_INIT(&fs->fs_cielist);
460 	STAILQ_INIT(&fs->fs_fdelist);
461 
462 	offset = 0;
463 	while (offset < ds->ds_size) {
464 		entry_off = offset;
465 		length = dbg->read(ds->ds_data, &offset, 4);
466 		if (length == 0xffffffff) {
467 			dwarf_size = 8;
468 			length = dbg->read(ds->ds_data, &offset, 8);
469 		} else
470 			dwarf_size = 4;
471 
472 		if (length > ds->ds_size - offset ||
473 		    (length == 0 && !eh_frame)) {
474 			ret = DW_DLE_DEBUG_FRAME_LENGTH_BAD;
475 			DWARF_SET_ERROR(dbg, error, ret);
476 			goto fail_cleanup;
477 		}
478 
479 		/* Check terminator for .eh_frame */
480 		if (eh_frame && length == 0)
481 			break;
482 
483 		cie_id = dbg->read(ds->ds_data, &offset, dwarf_size);
484 
485 		if (eh_frame) {
486 			/* GNU .eh_frame use CIE id 0. */
487 			if (cie_id == 0)
488 				ret = _dwarf_frame_add_cie(dbg, fs, ds,
489 				    &entry_off, NULL, error);
490 			else
491 				ret = _dwarf_frame_add_fde(dbg, fs, ds,
492 				    &entry_off, 1, error);
493 		} else {
494 			/* .dwarf_frame use CIE id ~0 */
495 			if ((dwarf_size == 4 && cie_id == ~0U) ||
496 			    (dwarf_size == 8 && cie_id == ~0ULL))
497 				ret = _dwarf_frame_add_cie(dbg, fs, ds,
498 				    &entry_off, NULL, error);
499 			else
500 				ret = _dwarf_frame_add_fde(dbg, fs, ds,
501 				    &entry_off, 0, error);
502 		}
503 
504 		if (ret != DW_DLE_NONE)
505 			goto fail_cleanup;
506 
507 		offset = entry_off;
508 	}
509 
510 	/* Create CIE array. */
511 	if (fs->fs_cielen > 0) {
512 		if ((fs->fs_ciearray = malloc(sizeof(Dwarf_Cie) *
513 		    fs->fs_cielen)) == NULL) {
514 			ret = DW_DLE_MEMORY;
515 			DWARF_SET_ERROR(dbg, error, ret);
516 			goto fail_cleanup;
517 		}
518 		i = 0;
519 		STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
520 			fs->fs_ciearray[i++] = cie;
521 		}
522 		assert((Dwarf_Unsigned)i == fs->fs_cielen);
523 	}
524 
525 	/* Create FDE array. */
526 	if (fs->fs_fdelen > 0) {
527 		if ((fs->fs_fdearray = malloc(sizeof(Dwarf_Fde) *
528 		    fs->fs_fdelen)) == NULL) {
529 			ret = DW_DLE_MEMORY;
530 			DWARF_SET_ERROR(dbg, error, ret);
531 			goto fail_cleanup;
532 		}
533 		i = 0;
534 		STAILQ_FOREACH(fde, &fs->fs_fdelist, fde_next) {
535 			fs->fs_fdearray[i++] = fde;
536 		}
537 		assert((Dwarf_Unsigned)i == fs->fs_fdelen);
538 	}
539 
540 	*frame_sec = fs;
541 
542 	return (DW_DLE_NONE);
543 
544 fail_cleanup:
545 
546 	_dwarf_frame_section_cleanup(fs);
547 
548 	return (ret);
549 }
550 
551 static int
_dwarf_frame_run_inst(Dwarf_Debug dbg,Dwarf_Regtable3 * rt,uint8_t addr_size,uint8_t * insts,Dwarf_Unsigned len,Dwarf_Unsigned caf,Dwarf_Signed daf,Dwarf_Addr pc,Dwarf_Addr pc_req,Dwarf_Addr * row_pc,Dwarf_Error * error)552 _dwarf_frame_run_inst(Dwarf_Debug dbg, Dwarf_Regtable3 *rt, uint8_t addr_size,
553     uint8_t *insts, Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf,
554     Dwarf_Addr pc, Dwarf_Addr pc_req, Dwarf_Addr *row_pc, Dwarf_Error *error)
555 {
556 	Dwarf_Regtable3 *init_rt, *saved_rt;
557 	uint8_t *p, *pe;
558 	uint8_t high2, low6;
559 	uint64_t reg, reg2, uoff, soff;
560 	int ret;
561 
562 #define	CFA	rt->rt3_cfa_rule
563 #define	INITCFA	init_rt->rt3_cfa_rule
564 #define	RL	rt->rt3_rules
565 #define	INITRL	init_rt->rt3_rules
566 
567 #define CHECK_TABLE_SIZE(x)						\
568 	do {								\
569 		if ((x) >= rt->rt3_reg_table_size) {			\
570 			DWARF_SET_ERROR(dbg, error,			\
571 			    DW_DLE_DF_REG_NUM_TOO_HIGH);		\
572 			ret = DW_DLE_DF_REG_NUM_TOO_HIGH;		\
573 			goto program_done;				\
574 		}							\
575 	} while(0)
576 
577 #ifdef FRAME_DEBUG
578 	printf("frame_run_inst: (caf=%ju, daf=%jd)\n", caf, daf);
579 #endif
580 
581 	ret = DW_DLE_NONE;
582 	init_rt = saved_rt = NULL;
583 	*row_pc = pc;
584 
585 	/* Save a copy of the table as initial state. */
586 	_dwarf_frame_regtable_copy(dbg, &init_rt, rt, error);
587 
588 	p = insts;
589 	pe = p + len;
590 
591 	while (p < pe) {
592 
593 #ifdef FRAME_DEBUG
594 		printf("p=%p pe=%p pc=%#jx pc_req=%#jx\n", p, pe, pc, pc_req);
595 #endif
596 
597 		if (*p == DW_CFA_nop) {
598 #ifdef FRAME_DEBUG
599 			printf("DW_CFA_nop\n");
600 #endif
601 			p++;
602 			continue;
603 		}
604 
605 		high2 = *p & 0xc0;
606 		low6 = *p & 0x3f;
607 		p++;
608 
609 		if (high2 > 0) {
610 			switch (high2) {
611 			case DW_CFA_advance_loc:
612 				pc += low6 * caf;
613 #ifdef FRAME_DEBUG
614 				printf("DW_CFA_advance_loc(%#jx(%u))\n", pc,
615 				    low6);
616 #endif
617 				if (pc_req < pc)
618 					goto program_done;
619 				break;
620 			case DW_CFA_offset:
621 				*row_pc = pc;
622 				CHECK_TABLE_SIZE(low6);
623 				RL[low6].dw_offset_relevant = 1;
624 				RL[low6].dw_value_type = DW_EXPR_OFFSET;
625 				RL[low6].dw_regnum = dbg->dbg_frame_cfa_value;
626 				RL[low6].dw_offset_or_block_len =
627 				    _dwarf_decode_uleb128(&p) * daf;
628 #ifdef FRAME_DEBUG
629 				printf("DW_CFA_offset(%jd)\n",
630 				    RL[low6].dw_offset_or_block_len);
631 #endif
632 				break;
633 			case DW_CFA_restore:
634 				*row_pc = pc;
635 				CHECK_TABLE_SIZE(low6);
636 				memcpy(&RL[low6], &INITRL[low6],
637 				    sizeof(Dwarf_Regtable_Entry3));
638 #ifdef FRAME_DEBUG
639 				printf("DW_CFA_restore(%u)\n", low6);
640 #endif
641 				break;
642 			default:
643 				DWARF_SET_ERROR(dbg, error,
644 				    DW_DLE_FRAME_INSTR_EXEC_ERROR);
645 				ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
646 				goto program_done;
647 			}
648 
649 			continue;
650 		}
651 
652 		switch (low6) {
653 		case DW_CFA_set_loc:
654 			pc = dbg->decode(&p, addr_size);
655 #ifdef FRAME_DEBUG
656 			printf("DW_CFA_set_loc(pc=%#jx)\n", pc);
657 #endif
658 			if (pc_req < pc)
659 				goto program_done;
660 			break;
661 		case DW_CFA_advance_loc1:
662 			pc += dbg->decode(&p, 1) * caf;
663 #ifdef FRAME_DEBUG
664 			printf("DW_CFA_set_loc1(pc=%#jx)\n", pc);
665 #endif
666 			if (pc_req < pc)
667 				goto program_done;
668 			break;
669 		case DW_CFA_advance_loc2:
670 			pc += dbg->decode(&p, 2) * caf;
671 #ifdef FRAME_DEBUG
672 			printf("DW_CFA_set_loc2(pc=%#jx)\n", pc);
673 #endif
674 			if (pc_req < pc)
675 				goto program_done;
676 			break;
677 		case DW_CFA_advance_loc4:
678 			pc += dbg->decode(&p, 4) * caf;
679 #ifdef FRAME_DEBUG
680 			printf("DW_CFA_set_loc4(pc=%#jx)\n", pc);
681 #endif
682 			if (pc_req < pc)
683 				goto program_done;
684 			break;
685 		case DW_CFA_offset_extended:
686 			*row_pc = pc;
687 			reg = _dwarf_decode_uleb128(&p);
688 			uoff = _dwarf_decode_uleb128(&p);
689 			CHECK_TABLE_SIZE(reg);
690 			RL[reg].dw_offset_relevant = 1;
691 			RL[reg].dw_value_type = DW_EXPR_OFFSET;
692 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
693 			RL[reg].dw_offset_or_block_len = uoff * daf;
694 #ifdef FRAME_DEBUG
695 			printf("DW_CFA_offset_extended(reg=%ju,uoff=%ju)\n",
696 			    reg, uoff);
697 #endif
698 			break;
699 		case DW_CFA_restore_extended:
700 			*row_pc = pc;
701 			reg = _dwarf_decode_uleb128(&p);
702 			CHECK_TABLE_SIZE(reg);
703 			memcpy(&RL[reg], &INITRL[reg],
704 			    sizeof(Dwarf_Regtable_Entry3));
705 #ifdef FRAME_DEBUG
706 			printf("DW_CFA_restore_extended(%ju)\n", reg);
707 #endif
708 			break;
709 		case DW_CFA_undefined:
710 			*row_pc = pc;
711 			reg = _dwarf_decode_uleb128(&p);
712 			CHECK_TABLE_SIZE(reg);
713 			RL[reg].dw_offset_relevant = 0;
714 			RL[reg].dw_regnum = dbg->dbg_frame_undefined_value;
715 #ifdef FRAME_DEBUG
716 			printf("DW_CFA_undefined(%ju)\n", reg);
717 #endif
718 			break;
719 		case DW_CFA_same_value:
720 			reg = _dwarf_decode_uleb128(&p);
721 			CHECK_TABLE_SIZE(reg);
722 			RL[reg].dw_offset_relevant = 0;
723 			RL[reg].dw_regnum = dbg->dbg_frame_same_value;
724 #ifdef FRAME_DEBUG
725 			printf("DW_CFA_same_value(%ju)\n", reg);
726 #endif
727 			break;
728 		case DW_CFA_register:
729 			*row_pc = pc;
730 			reg = _dwarf_decode_uleb128(&p);
731 			reg2 = _dwarf_decode_uleb128(&p);
732 			CHECK_TABLE_SIZE(reg);
733 			RL[reg].dw_offset_relevant = 0;
734 			RL[reg].dw_regnum = reg2;
735 #ifdef FRAME_DEBUG
736 			printf("DW_CFA_register(reg=%ju,reg2=%ju)\n", reg,
737 			    reg2);
738 #endif
739 			break;
740 		case DW_CFA_remember_state:
741 			_dwarf_frame_regtable_copy(dbg, &saved_rt, rt, error);
742 #ifdef FRAME_DEBUG
743 			printf("DW_CFA_remember_state\n");
744 #endif
745 			break;
746 		case DW_CFA_restore_state:
747 			*row_pc = pc;
748 			_dwarf_frame_regtable_copy(dbg, &rt, saved_rt, error);
749 #ifdef FRAME_DEBUG
750 			printf("DW_CFA_restore_state\n");
751 #endif
752 			break;
753 		case DW_CFA_def_cfa:
754 			*row_pc = pc;
755 			reg = _dwarf_decode_uleb128(&p);
756 			uoff = _dwarf_decode_uleb128(&p);
757 			CFA.dw_offset_relevant = 1;
758 			CFA.dw_value_type = DW_EXPR_OFFSET;
759 			CFA.dw_regnum = reg;
760 			CFA.dw_offset_or_block_len = uoff;
761 #ifdef FRAME_DEBUG
762 			printf("DW_CFA_def_cfa(reg=%ju,uoff=%ju)\n", reg, uoff);
763 #endif
764 			break;
765 		case DW_CFA_def_cfa_register:
766 			*row_pc = pc;
767 			reg = _dwarf_decode_uleb128(&p);
768 			CFA.dw_regnum = reg;
769 			/*
770 			 * Note that DW_CFA_def_cfa_register change the CFA
771 			 * rule register while keep the old offset. So we
772 			 * should not touch the CFA.dw_offset_relevant flag
773 			 * here.
774 			 */
775 #ifdef FRAME_DEBUG
776 			printf("DW_CFA_def_cfa_register(%ju)\n", reg);
777 #endif
778 			break;
779 		case DW_CFA_def_cfa_offset:
780 			*row_pc = pc;
781 			uoff = _dwarf_decode_uleb128(&p);
782 			CFA.dw_offset_relevant = 1;
783 			CFA.dw_value_type = DW_EXPR_OFFSET;
784 			CFA.dw_offset_or_block_len = uoff;
785 #ifdef FRAME_DEBUG
786 			printf("DW_CFA_def_cfa_offset(%ju)\n", uoff);
787 #endif
788 			break;
789 		case DW_CFA_def_cfa_expression:
790 			*row_pc = pc;
791 			CFA.dw_offset_relevant = 0;
792 			CFA.dw_value_type = DW_EXPR_EXPRESSION;
793 			CFA.dw_offset_or_block_len = _dwarf_decode_uleb128(&p);
794 			CFA.dw_block_ptr = p;
795 			p += CFA.dw_offset_or_block_len;
796 #ifdef FRAME_DEBUG
797 			printf("DW_CFA_def_cfa_expression\n");
798 #endif
799 			break;
800 		case DW_CFA_expression:
801 			*row_pc = pc;
802 			reg = _dwarf_decode_uleb128(&p);
803 			CHECK_TABLE_SIZE(reg);
804 			RL[reg].dw_offset_relevant = 0;
805 			RL[reg].dw_value_type = DW_EXPR_EXPRESSION;
806 			RL[reg].dw_offset_or_block_len =
807 			    _dwarf_decode_uleb128(&p);
808 			RL[reg].dw_block_ptr = p;
809 			p += RL[reg].dw_offset_or_block_len;
810 #ifdef FRAME_DEBUG
811 			printf("DW_CFA_expression\n");
812 #endif
813 			break;
814 		case DW_CFA_offset_extended_sf:
815 			*row_pc = pc;
816 			reg = _dwarf_decode_uleb128(&p);
817 			soff = _dwarf_decode_sleb128(&p);
818 			CHECK_TABLE_SIZE(reg);
819 			RL[reg].dw_offset_relevant = 1;
820 			RL[reg].dw_value_type = DW_EXPR_OFFSET;
821 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
822 			RL[reg].dw_offset_or_block_len = soff * daf;
823 #ifdef FRAME_DEBUG
824 			printf("DW_CFA_offset_extended_sf(reg=%ju,soff=%jd)\n",
825 			    reg, soff);
826 #endif
827 			break;
828 		case DW_CFA_def_cfa_sf:
829 			*row_pc = pc;
830 			reg = _dwarf_decode_uleb128(&p);
831 			soff = _dwarf_decode_sleb128(&p);
832 			CFA.dw_offset_relevant = 1;
833 			CFA.dw_value_type = DW_EXPR_OFFSET;
834 			CFA.dw_regnum = reg;
835 			CFA.dw_offset_or_block_len = soff * daf;
836 #ifdef FRAME_DEBUG
837 			printf("DW_CFA_def_cfa_sf(reg=%ju,soff=%jd)\n", reg,
838 			    soff);
839 #endif
840 			break;
841 		case DW_CFA_def_cfa_offset_sf:
842 			*row_pc = pc;
843 			soff = _dwarf_decode_sleb128(&p);
844 			CFA.dw_offset_relevant = 1;
845 			CFA.dw_value_type = DW_EXPR_OFFSET;
846 			CFA.dw_offset_or_block_len = soff * daf;
847 #ifdef FRAME_DEBUG
848 			printf("DW_CFA_def_cfa_offset_sf(soff=%jd)\n", soff);
849 #endif
850 			break;
851 		case DW_CFA_val_offset:
852 			*row_pc = pc;
853 			reg = _dwarf_decode_uleb128(&p);
854 			uoff = _dwarf_decode_uleb128(&p);
855 			CHECK_TABLE_SIZE(reg);
856 			RL[reg].dw_offset_relevant = 1;
857 			RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
858 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
859 			RL[reg].dw_offset_or_block_len = uoff * daf;
860 #ifdef FRAME_DEBUG
861 			printf("DW_CFA_val_offset(reg=%ju,uoff=%ju)\n", reg,
862 			    uoff);
863 #endif
864 			break;
865 		case DW_CFA_val_offset_sf:
866 			*row_pc = pc;
867 			reg = _dwarf_decode_uleb128(&p);
868 			soff = _dwarf_decode_sleb128(&p);
869 			CHECK_TABLE_SIZE(reg);
870 			RL[reg].dw_offset_relevant = 1;
871 			RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
872 			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
873 			RL[reg].dw_offset_or_block_len = soff * daf;
874 #ifdef FRAME_DEBUG
875 			printf("DW_CFA_val_offset_sf(reg=%ju,soff=%jd)\n", reg,
876 			    soff);
877 #endif
878 			break;
879 		case DW_CFA_val_expression:
880 			*row_pc = pc;
881 			reg = _dwarf_decode_uleb128(&p);
882 			CHECK_TABLE_SIZE(reg);
883 			RL[reg].dw_offset_relevant = 0;
884 			RL[reg].dw_value_type = DW_EXPR_VAL_EXPRESSION;
885 			RL[reg].dw_offset_or_block_len =
886 			    _dwarf_decode_uleb128(&p);
887 			RL[reg].dw_block_ptr = p;
888 			p += RL[reg].dw_offset_or_block_len;
889 #ifdef FRAME_DEBUG
890 			printf("DW_CFA_val_expression\n");
891 #endif
892 			break;
893 		default:
894 			DWARF_SET_ERROR(dbg, error,
895 			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
896 			ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
897 			goto program_done;
898 		}
899 	}
900 
901 program_done:
902 
903 	free(init_rt->rt3_rules);
904 	free(init_rt);
905 	if (saved_rt) {
906 		free(saved_rt->rt3_rules);
907 		free(saved_rt);
908 	}
909 
910 	return (ret);
911 
912 #undef	CFA
913 #undef	INITCFA
914 #undef	RL
915 #undef	INITRL
916 #undef	CHECK_TABLE_SIZE
917 }
918 
919 static int
_dwarf_frame_convert_inst(Dwarf_Debug dbg,uint8_t addr_size,uint8_t * insts,Dwarf_Unsigned len,Dwarf_Unsigned * count,Dwarf_Frame_Op * fop,Dwarf_Frame_Op3 * fop3,Dwarf_Error * error)920 _dwarf_frame_convert_inst(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts,
921     Dwarf_Unsigned len, Dwarf_Unsigned *count, Dwarf_Frame_Op *fop,
922     Dwarf_Frame_Op3 *fop3, Dwarf_Error *error)
923 {
924 	uint8_t *p, *pe;
925 	uint8_t high2, low6;
926 	uint64_t reg, reg2, uoff, soff, blen;
927 
928 #define	SET_BASE_OP(x)						\
929 	do {							\
930 		if (fop != NULL)				\
931 			fop[*count].fp_base_op = (x) >> 6;	\
932 		if (fop3 != NULL)				\
933 			fop3[*count].fp_base_op = (x) >> 6;	\
934 	} while(0)
935 
936 #define	SET_EXTENDED_OP(x)					\
937 	do {							\
938 		if (fop != NULL)				\
939 			fop[*count].fp_extended_op = (x);	\
940 		if (fop3 != NULL)				\
941 			fop3[*count].fp_extended_op = (x);	\
942 	} while(0)
943 
944 #define	SET_REGISTER(x)						\
945 	do {							\
946 		if (fop != NULL)				\
947 			fop[*count].fp_register = (x);		\
948 		if (fop3 != NULL)				\
949 			fop3[*count].fp_register = (x);		\
950 	} while(0)
951 
952 #define	SET_OFFSET(x)						\
953 	do {							\
954 		if (fop != NULL)				\
955 			fop[*count].fp_offset = (x);		\
956 		if (fop3 != NULL)				\
957 			fop3[*count].fp_offset_or_block_len =	\
958 			    (x);				\
959 	} while(0)
960 
961 #define	SET_INSTR_OFFSET(x)					\
962 	do {							\
963 		if (fop != NULL)				\
964 			fop[*count].fp_instr_offset = (x);	\
965 		if (fop3 != NULL)				\
966 			fop3[*count].fp_instr_offset = (x);	\
967 	} while(0)
968 
969 #define	SET_BLOCK_LEN(x)					\
970 	do {							\
971 		if (fop3 != NULL)				\
972 			fop3[*count].fp_offset_or_block_len =	\
973 			    (x);				\
974 	} while(0)
975 
976 #define	SET_EXPR_BLOCK(addr, len)					\
977 	do {								\
978 		if (fop3 != NULL) {					\
979 			fop3[*count].fp_expr_block =			\
980 			    malloc((size_t) (len));			\
981 			if (fop3[*count].fp_expr_block == NULL)	{	\
982 				DWARF_SET_ERROR(dbg, error,		\
983 				    DW_DLE_MEMORY);			\
984 				return (DW_DLE_MEMORY);			\
985 			}						\
986 			memcpy(&fop3[*count].fp_expr_block,		\
987 			    (addr), (len));				\
988 		}							\
989 	} while(0)
990 
991 	*count = 0;
992 
993 	p = insts;
994 	pe = p + len;
995 
996 	while (p < pe) {
997 
998 		SET_INSTR_OFFSET(p - insts);
999 
1000 		if (*p == DW_CFA_nop) {
1001 			p++;
1002 			(*count)++;
1003 			continue;
1004 		}
1005 
1006 		high2 = *p & 0xc0;
1007 		low6 = *p & 0x3f;
1008 		p++;
1009 
1010 		if (high2 > 0) {
1011 			switch (high2) {
1012 			case DW_CFA_advance_loc:
1013 				SET_BASE_OP(high2);
1014 				SET_OFFSET(low6);
1015 				break;
1016 			case DW_CFA_offset:
1017 				SET_BASE_OP(high2);
1018 				SET_REGISTER(low6);
1019 				uoff = _dwarf_decode_uleb128(&p);
1020 				SET_OFFSET(uoff);
1021 				break;
1022 			case DW_CFA_restore:
1023 				SET_BASE_OP(high2);
1024 				SET_REGISTER(low6);
1025 				break;
1026 			default:
1027 				DWARF_SET_ERROR(dbg, error,
1028 				    DW_DLE_FRAME_INSTR_EXEC_ERROR);
1029 				return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1030 			}
1031 
1032 			(*count)++;
1033 			continue;
1034 		}
1035 
1036 		SET_EXTENDED_OP(low6);
1037 
1038 		switch (low6) {
1039 		case DW_CFA_set_loc:
1040 			uoff = dbg->decode(&p, addr_size);
1041 			SET_OFFSET(uoff);
1042 			break;
1043 		case DW_CFA_advance_loc1:
1044 			uoff = dbg->decode(&p, 1);
1045 			SET_OFFSET(uoff);
1046 			break;
1047 		case DW_CFA_advance_loc2:
1048 			uoff = dbg->decode(&p, 2);
1049 			SET_OFFSET(uoff);
1050 			break;
1051 		case DW_CFA_advance_loc4:
1052 			uoff = dbg->decode(&p, 4);
1053 			SET_OFFSET(uoff);
1054 			break;
1055 		case DW_CFA_offset_extended:
1056 		case DW_CFA_def_cfa:
1057 		case DW_CFA_val_offset:
1058 			reg = _dwarf_decode_uleb128(&p);
1059 			uoff = _dwarf_decode_uleb128(&p);
1060 			SET_REGISTER(reg);
1061 			SET_OFFSET(uoff);
1062 			break;
1063 		case DW_CFA_restore_extended:
1064 		case DW_CFA_undefined:
1065 		case DW_CFA_same_value:
1066 		case DW_CFA_def_cfa_register:
1067 			reg = _dwarf_decode_uleb128(&p);
1068 			SET_REGISTER(reg);
1069 			break;
1070 		case DW_CFA_register:
1071 			reg = _dwarf_decode_uleb128(&p);
1072 			reg2 = _dwarf_decode_uleb128(&p);
1073 			SET_REGISTER(reg);
1074 			SET_OFFSET(reg2);
1075 			break;
1076 		case DW_CFA_remember_state:
1077 		case DW_CFA_restore_state:
1078 			break;
1079 		case DW_CFA_def_cfa_offset:
1080 			uoff = _dwarf_decode_uleb128(&p);
1081 			SET_OFFSET(uoff);
1082 			break;
1083 		case DW_CFA_def_cfa_expression:
1084 			blen = _dwarf_decode_uleb128(&p);
1085 			SET_BLOCK_LEN(blen);
1086 			SET_EXPR_BLOCK(p, blen);
1087 			p += blen;
1088 			break;
1089 		case DW_CFA_expression:
1090 		case DW_CFA_val_expression:
1091 			reg = _dwarf_decode_uleb128(&p);
1092 			blen = _dwarf_decode_uleb128(&p);
1093 			SET_REGISTER(reg);
1094 			SET_BLOCK_LEN(blen);
1095 			SET_EXPR_BLOCK(p, blen);
1096 			p += blen;
1097 			break;
1098 		case DW_CFA_offset_extended_sf:
1099 		case DW_CFA_def_cfa_sf:
1100 		case DW_CFA_val_offset_sf:
1101 			reg = _dwarf_decode_uleb128(&p);
1102 			soff = _dwarf_decode_sleb128(&p);
1103 			SET_REGISTER(reg);
1104 			SET_OFFSET(soff);
1105 			break;
1106 		case DW_CFA_def_cfa_offset_sf:
1107 			soff = _dwarf_decode_sleb128(&p);
1108 			SET_OFFSET(soff);
1109 			break;
1110 		default:
1111 			DWARF_SET_ERROR(dbg, error,
1112 			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
1113 			return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1114 		}
1115 
1116 		(*count)++;
1117 	}
1118 
1119 	return (DW_DLE_NONE);
1120 }
1121 
1122 int
_dwarf_frame_get_fop(Dwarf_Debug dbg,uint8_t addr_size,uint8_t * insts,Dwarf_Unsigned len,Dwarf_Frame_Op ** ret_oplist,Dwarf_Signed * ret_opcnt,Dwarf_Error * error)1123 _dwarf_frame_get_fop(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts,
1124     Dwarf_Unsigned len, Dwarf_Frame_Op **ret_oplist, Dwarf_Signed *ret_opcnt,
1125     Dwarf_Error *error)
1126 {
1127 	Dwarf_Frame_Op *oplist;
1128 	Dwarf_Unsigned count;
1129 	int ret;
1130 
1131 	ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count,
1132 	    NULL, NULL, error);
1133 	if (ret != DW_DLE_NONE)
1134 		return (ret);
1135 
1136 	if ((oplist = calloc(count, sizeof(Dwarf_Frame_Op))) == NULL) {
1137 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1138 		return (DW_DLE_MEMORY);
1139 	}
1140 
1141 	ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count,
1142 	    oplist, NULL, error);
1143 	if (ret != DW_DLE_NONE) {
1144 		free(oplist);
1145 		return (ret);
1146 	}
1147 
1148 	*ret_oplist = oplist;
1149 	*ret_opcnt = count;
1150 
1151 	return (DW_DLE_NONE);
1152 }
1153 
1154 int
_dwarf_frame_regtable_copy(Dwarf_Debug dbg,Dwarf_Regtable3 ** dest,Dwarf_Regtable3 * src,Dwarf_Error * error)1155 _dwarf_frame_regtable_copy(Dwarf_Debug dbg, Dwarf_Regtable3 **dest,
1156     Dwarf_Regtable3 *src, Dwarf_Error *error)
1157 {
1158 	int i;
1159 
1160 	assert(dest != NULL);
1161 	assert(src != NULL);
1162 
1163 	if (*dest == NULL) {
1164 		if ((*dest = malloc(sizeof(Dwarf_Regtable3))) == NULL) {
1165 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1166 			return (DW_DLE_MEMORY);
1167 		}
1168 		(*dest)->rt3_reg_table_size = src->rt3_reg_table_size;
1169 		(*dest)->rt3_rules = malloc(src->rt3_reg_table_size *
1170 		    sizeof(Dwarf_Regtable_Entry3));
1171 		if ((*dest)->rt3_rules == NULL) {
1172 			free(*dest);
1173 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1174 			return (DW_DLE_MEMORY);
1175 		}
1176 	}
1177 
1178 	memcpy(&(*dest)->rt3_cfa_rule, &src->rt3_cfa_rule,
1179 	    sizeof(Dwarf_Regtable_Entry3));
1180 
1181 	for (i = 0; i < (*dest)->rt3_reg_table_size &&
1182 	     i < src->rt3_reg_table_size; i++)
1183 		memcpy(&(*dest)->rt3_rules[i], &src->rt3_rules[i],
1184 		    sizeof(Dwarf_Regtable_Entry3));
1185 
1186 	for (; i < (*dest)->rt3_reg_table_size; i++)
1187 		(*dest)->rt3_rules[i].dw_regnum =
1188 		    dbg->dbg_frame_undefined_value;
1189 
1190 	return (DW_DLE_NONE);
1191 }
1192 
1193 int
_dwarf_frame_get_internal_table(Dwarf_Fde fde,Dwarf_Addr pc_req,Dwarf_Regtable3 ** ret_rt,Dwarf_Addr * ret_row_pc,Dwarf_Error * error)1194 _dwarf_frame_get_internal_table(Dwarf_Fde fde, Dwarf_Addr pc_req,
1195     Dwarf_Regtable3 **ret_rt, Dwarf_Addr *ret_row_pc, Dwarf_Error *error)
1196 {
1197 	Dwarf_Debug dbg;
1198 	Dwarf_Cie cie;
1199 	Dwarf_Regtable3 *rt;
1200 	Dwarf_Addr row_pc;
1201 	int i, ret;
1202 
1203 	assert(ret_rt != NULL);
1204 
1205 	dbg = fde->fde_dbg;
1206 	assert(dbg != NULL);
1207 
1208 	rt = dbg->dbg_internal_reg_table;
1209 
1210 	/* Clear the content of regtable from previous run. */
1211 	memset(&rt->rt3_cfa_rule, 0, sizeof(Dwarf_Regtable_Entry3));
1212 	memset(rt->rt3_rules, 0, rt->rt3_reg_table_size *
1213 	    sizeof(Dwarf_Regtable_Entry3));
1214 
1215 	/* Set rules to initial values. */
1216 	for (i = 0; i < rt->rt3_reg_table_size; i++)
1217 		rt->rt3_rules[i].dw_regnum = dbg->dbg_frame_rule_initial_value;
1218 
1219 	/* Run initial instructions in CIE. */
1220 	cie = fde->fde_cie;
1221 	assert(cie != NULL);
1222 	ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize,
1223 	    cie->cie_initinst, cie->cie_instlen, cie->cie_caf, cie->cie_daf, 0,
1224 	    ~0ULL, &row_pc, error);
1225 	if (ret != DW_DLE_NONE)
1226 		return (ret);
1227 
1228 	/* Run instructions in FDE. */
1229 	if (pc_req >= fde->fde_initloc) {
1230 		ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize,
1231 		    fde->fde_inst, fde->fde_instlen, cie->cie_caf,
1232 		    cie->cie_daf, fde->fde_initloc, pc_req, &row_pc, error);
1233 		if (ret != DW_DLE_NONE)
1234 			return (ret);
1235 	}
1236 
1237 	*ret_rt = rt;
1238 	*ret_row_pc = row_pc;
1239 
1240 	return (DW_DLE_NONE);
1241 }
1242 
1243 void
_dwarf_frame_cleanup(Dwarf_Debug dbg)1244 _dwarf_frame_cleanup(Dwarf_Debug dbg)
1245 {
1246 	Dwarf_Regtable3 *rt;
1247 
1248 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ);
1249 
1250 	if (dbg->dbg_internal_reg_table) {
1251 		rt = dbg->dbg_internal_reg_table;
1252 		free(rt->rt3_rules);
1253 		free(rt);
1254 		dbg->dbg_internal_reg_table = NULL;
1255 	}
1256 
1257 	if (dbg->dbg_frame) {
1258 		_dwarf_frame_section_cleanup(dbg->dbg_frame);
1259 		dbg->dbg_frame = NULL;
1260 	}
1261 
1262 	if (dbg->dbg_eh_frame) {
1263 		_dwarf_frame_section_cleanup(dbg->dbg_eh_frame);
1264 		dbg->dbg_eh_frame = NULL;
1265 	}
1266 }
1267 
1268 int
_dwarf_frame_section_load(Dwarf_Debug dbg,Dwarf_Error * error)1269 _dwarf_frame_section_load(Dwarf_Debug dbg, Dwarf_Error *error)
1270 {
1271 	Dwarf_Section *ds;
1272 
1273 	if ((ds = _dwarf_find_section(dbg, ".debug_frame")) != NULL) {
1274 		return (_dwarf_frame_section_init(dbg, &dbg->dbg_frame,
1275 		    ds, 0, error));
1276 	}
1277 
1278 	return (DW_DLE_NONE);
1279 }
1280 
1281 int
_dwarf_frame_section_load_eh(Dwarf_Debug dbg,Dwarf_Error * error)1282 _dwarf_frame_section_load_eh(Dwarf_Debug dbg, Dwarf_Error *error)
1283 {
1284 	Dwarf_Section *ds;
1285 
1286 	if ((ds = _dwarf_find_section(dbg, ".eh_frame")) != NULL) {
1287 		return (_dwarf_frame_section_init(dbg, &dbg->dbg_eh_frame,
1288 		    ds, 1, error));
1289 	}
1290 
1291 	return (DW_DLE_NONE);
1292 }
1293 
1294 void
_dwarf_frame_params_init(Dwarf_Debug dbg)1295 _dwarf_frame_params_init(Dwarf_Debug dbg)
1296 {
1297 
1298 	/* Initialise call frame related parameters. */
1299 	dbg->dbg_frame_rule_table_size = DW_FRAME_LAST_REG_NUM;
1300 	dbg->dbg_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE;
1301 	dbg->dbg_frame_cfa_value = DW_FRAME_CFA_COL3;
1302 	dbg->dbg_frame_same_value = DW_FRAME_SAME_VAL;
1303 	dbg->dbg_frame_undefined_value = DW_FRAME_UNDEFINED_VAL;
1304 }
1305 
1306 int
_dwarf_frame_interal_table_init(Dwarf_Debug dbg,Dwarf_Error * error)1307 _dwarf_frame_interal_table_init(Dwarf_Debug dbg, Dwarf_Error *error)
1308 {
1309 	Dwarf_Regtable3 *rt;
1310 
1311 	if (dbg->dbg_internal_reg_table != NULL)
1312 		return (DW_DLE_NONE);
1313 
1314 	/* Initialise internal register table. */
1315 	if ((rt = calloc(1, sizeof(Dwarf_Regtable3))) == NULL) {
1316 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1317 		return (DW_DLE_MEMORY);
1318 	}
1319 
1320 	rt->rt3_reg_table_size = dbg->dbg_frame_rule_table_size;
1321 	if ((rt->rt3_rules = calloc(rt->rt3_reg_table_size,
1322 	    sizeof(Dwarf_Regtable_Entry3))) == NULL) {
1323 		free(rt);
1324 		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1325 		return (DW_DLE_MEMORY);
1326 	}
1327 
1328 	dbg->dbg_internal_reg_table = rt;
1329 
1330 	return (DW_DLE_NONE);
1331 }
1332 
1333 #define	_FDE_INST_INIT_SIZE	128
1334 
1335 int
_dwarf_frame_fde_add_inst(Dwarf_P_Fde fde,Dwarf_Small op,Dwarf_Unsigned val1,Dwarf_Unsigned val2,Dwarf_Error * error)1336 _dwarf_frame_fde_add_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1,
1337     Dwarf_Unsigned val2, Dwarf_Error *error)
1338 {
1339 	Dwarf_P_Debug dbg;
1340 	uint8_t high2, low6;
1341 	int ret;
1342 
1343 #define	ds	fde
1344 #define	ds_data	fde_inst
1345 #define	ds_cap	fde_instcap
1346 #define	ds_size	fde_instlen
1347 
1348 	assert(fde != NULL && fde->fde_dbg != NULL);
1349 	dbg = fde->fde_dbg;
1350 
1351 	if (fde->fde_inst == NULL) {
1352 		fde->fde_instcap = _FDE_INST_INIT_SIZE;
1353 		fde->fde_instlen = 0;
1354 		if ((fde->fde_inst = malloc((size_t) fde->fde_instcap)) ==
1355 		    NULL) {
1356 			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1357 			return (DW_DLE_MEMORY);
1358 		}
1359 	}
1360 	assert(fde->fde_instcap != 0);
1361 
1362 	RCHECK(WRITE_VALUE(op, 1));
1363 	if (op == DW_CFA_nop)
1364 		return (DW_DLE_NONE);
1365 
1366 	high2 = op & 0xc0;
1367 	low6 = op & 0x3f;
1368 
1369 	if (high2 > 0) {
1370 		switch (high2) {
1371 		case DW_CFA_advance_loc:
1372 		case DW_CFA_restore:
1373 			break;
1374 		case DW_CFA_offset:
1375 			RCHECK(WRITE_ULEB128(val1));
1376 			break;
1377 		default:
1378 			DWARF_SET_ERROR(dbg, error,
1379 			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
1380 			return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1381 		}
1382 		return (DW_DLE_NONE);
1383 	}
1384 
1385 	switch (low6) {
1386 	case DW_CFA_set_loc:
1387 		RCHECK(WRITE_VALUE(val1, dbg->dbg_pointer_size));
1388 		break;
1389 	case DW_CFA_advance_loc1:
1390 		RCHECK(WRITE_VALUE(val1, 1));
1391 		break;
1392 	case DW_CFA_advance_loc2:
1393 		RCHECK(WRITE_VALUE(val1, 2));
1394 		break;
1395 	case DW_CFA_advance_loc4:
1396 		RCHECK(WRITE_VALUE(val1, 4));
1397 		break;
1398 	case DW_CFA_offset_extended:
1399 	case DW_CFA_def_cfa:
1400 	case DW_CFA_register:
1401 		RCHECK(WRITE_ULEB128(val1));
1402 		RCHECK(WRITE_ULEB128(val2));
1403 		break;
1404 	case DW_CFA_restore_extended:
1405 	case DW_CFA_undefined:
1406 	case DW_CFA_same_value:
1407 	case DW_CFA_def_cfa_register:
1408 	case DW_CFA_def_cfa_offset:
1409 		RCHECK(WRITE_ULEB128(val1));
1410 		break;
1411 	case DW_CFA_remember_state:
1412 	case DW_CFA_restore_state:
1413 		break;
1414 	default:
1415 		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR);
1416 		return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1417 	}
1418 
1419 	return (DW_DLE_NONE);
1420 
1421 gen_fail:
1422 	return (ret);
1423 
1424 #undef	ds
1425 #undef	ds_data
1426 #undef	ds_cap
1427 #undef	ds_size
1428 }
1429 
1430 static int
_dwarf_frame_gen_cie(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_P_Cie cie,Dwarf_Error * error)1431 _dwarf_frame_gen_cie(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_P_Cie cie,
1432     Dwarf_Error *error)
1433 {
1434 	Dwarf_Unsigned len;
1435 	uint64_t offset;
1436 	int ret;
1437 
1438 	assert(dbg != NULL && ds != NULL && cie != NULL);
1439 
1440 	cie->cie_offset = offset = ds->ds_size;
1441 	cie->cie_length = 0;
1442 	cie->cie_version = 1;
1443 
1444 	/* Length placeholder. */
1445 	RCHECK(WRITE_VALUE(cie->cie_length, 4));
1446 
1447 	/* .debug_frame use CIE id ~0. */
1448 	RCHECK(WRITE_VALUE(~0U, 4));
1449 
1450 	/* .debug_frame version is 1. (DWARF2) */
1451 	RCHECK(WRITE_VALUE(cie->cie_version, 1));
1452 
1453 	/* Write augmentation, if present. */
1454 	if (cie->cie_augment != NULL)
1455 		RCHECK(WRITE_BLOCK(cie->cie_augment,
1456 		    strlen((char *) cie->cie_augment) + 1));
1457 	else
1458 		RCHECK(WRITE_VALUE(0, 1));
1459 
1460 	/* Write caf, daf and ra. */
1461 	RCHECK(WRITE_ULEB128(cie->cie_caf));
1462 	RCHECK(WRITE_SLEB128(cie->cie_daf));
1463 	RCHECK(WRITE_VALUE(cie->cie_ra, 1));
1464 
1465 	/* Write initial instructions, if present. */
1466 	if (cie->cie_initinst != NULL)
1467 		RCHECK(WRITE_BLOCK(cie->cie_initinst, cie->cie_instlen));
1468 
1469 	/* Add padding. */
1470 	len = ds->ds_size - cie->cie_offset - 4;
1471 	cie->cie_length = roundup(len, dbg->dbg_pointer_size);
1472 	while (len++ < cie->cie_length)
1473 		RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
1474 
1475 	/* Fill in the length field. */
1476 	dbg->write(ds->ds_data, &offset, cie->cie_length, 4);
1477 
1478 	return (DW_DLE_NONE);
1479 
1480 gen_fail:
1481 	return (ret);
1482 }
1483 
1484 static int
_dwarf_frame_gen_fde(Dwarf_P_Debug dbg,Dwarf_P_Section ds,Dwarf_Rel_Section drs,Dwarf_P_Fde fde,Dwarf_Error * error)1485 _dwarf_frame_gen_fde(Dwarf_P_Debug dbg, Dwarf_P_Section ds,
1486     Dwarf_Rel_Section drs, Dwarf_P_Fde fde, Dwarf_Error *error)
1487 {
1488 	Dwarf_Unsigned len;
1489 	uint64_t offset;
1490 	int ret;
1491 
1492 	assert(dbg != NULL && ds != NULL && drs != NULL);
1493 	assert(fde != NULL && fde->fde_cie != NULL);
1494 
1495 	fde->fde_offset = offset = ds->ds_size;
1496 	fde->fde_length = 0;
1497 	fde->fde_cieoff = fde->fde_cie->cie_offset;
1498 
1499 	/* Length placeholder. */
1500 	RCHECK(WRITE_VALUE(fde->fde_length, 4));
1501 
1502 	/* Write CIE pointer. */
1503 	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4,
1504 	    ds->ds_size, 0, fde->fde_cieoff, ".debug_frame", error));
1505 
1506 	/* Write FDE initial location. */
1507 	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
1508 	    dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
1509 	    fde->fde_initloc, NULL, error));
1510 
1511 	/*
1512 	 * Write FDE address range. Use a pair of relocation entries if
1513 	 * application provided end symbol index. Otherwise write the
1514 	 * length without assoicating any relocation info.
1515 	 */
1516 	if (fde->fde_esymndx > 0)
1517 		RCHECK(_dwarf_reloc_entry_add_pair(dbg, drs, ds,
1518 		    dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
1519 		    fde->fde_esymndx, fde->fde_initloc, fde->fde_eoff, error));
1520 	else
1521 		RCHECK(WRITE_VALUE(fde->fde_adrange, dbg->dbg_pointer_size));
1522 
1523 	/* Write FDE frame instructions. */
1524 	RCHECK(WRITE_BLOCK(fde->fde_inst, fde->fde_instlen));
1525 
1526 	/* Add padding. */
1527 	len = ds->ds_size - fde->fde_offset - 4;
1528 	fde->fde_length = roundup(len, dbg->dbg_pointer_size);
1529 	while (len++ < fde->fde_length)
1530 		RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
1531 
1532 	/* Fill in the length field. */
1533 	dbg->write(ds->ds_data, &offset, fde->fde_length, 4);
1534 
1535 	return (DW_DLE_NONE);
1536 
1537 gen_fail:
1538 	return (ret);
1539 }
1540 
1541 int
_dwarf_frame_gen(Dwarf_P_Debug dbg,Dwarf_Error * error)1542 _dwarf_frame_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
1543 {
1544 	Dwarf_P_Section ds;
1545 	Dwarf_Rel_Section drs;
1546 	Dwarf_P_Cie cie;
1547 	Dwarf_P_Fde fde;
1548 	int ret;
1549 
1550 	if (STAILQ_EMPTY(&dbg->dbgp_cielist))
1551 		return (DW_DLE_NONE);
1552 
1553 	/* Create .debug_frame section. */
1554 	if ((ret = _dwarf_section_init(dbg, &ds, ".debug_frame", 0, error)) !=
1555 	    DW_DLE_NONE)
1556 		goto gen_fail0;
1557 
1558 	/* Create relocation section for .debug_frame */
1559 	RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error));
1560 
1561 	/* Generate list of CIE. */
1562 	STAILQ_FOREACH(cie, &dbg->dbgp_cielist, cie_next)
1563 		RCHECK(_dwarf_frame_gen_cie(dbg, ds, cie, error));
1564 
1565 	/* Generate list of FDE. */
1566 	STAILQ_FOREACH(fde, &dbg->dbgp_fdelist, fde_next)
1567 		RCHECK(_dwarf_frame_gen_fde(dbg, ds, drs, fde, error));
1568 
1569 	/* Inform application the creation of .debug_frame ELF section. */
1570 	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
1571 
1572 	/* Finalize relocation section for .debug_frame */
1573 	RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
1574 
1575 	return (DW_DLE_NONE);
1576 
1577 gen_fail:
1578 	_dwarf_reloc_section_free(dbg, &drs);
1579 
1580 gen_fail0:
1581 	_dwarf_section_free(dbg, &ds);
1582 
1583 	return (ret);
1584 }
1585 
1586 void
_dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg)1587 _dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg)
1588 {
1589 	Dwarf_P_Cie cie, tcie;
1590 	Dwarf_P_Fde fde, tfde;
1591 
1592 	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
1593 
1594 	STAILQ_FOREACH_SAFE(cie, &dbg->dbgp_cielist, cie_next, tcie) {
1595 		STAILQ_REMOVE(&dbg->dbgp_cielist, cie, _Dwarf_Cie, cie_next);
1596 		if (cie->cie_augment)
1597 			free(cie->cie_augment);
1598 		if (cie->cie_initinst)
1599 			free(cie->cie_initinst);
1600 		free(cie);
1601 	}
1602 	dbg->dbgp_cielen = 0;
1603 
1604 	STAILQ_FOREACH_SAFE(fde, &dbg->dbgp_fdelist, fde_next, tfde) {
1605 		STAILQ_REMOVE(&dbg->dbgp_fdelist, fde, _Dwarf_Fde, fde_next);
1606 		if (fde->fde_inst != NULL)
1607 			free(fde->fde_inst);
1608 		free(fde);
1609 	}
1610 	dbg->dbgp_fdelen = 0;
1611 }
1612