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