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