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