1260684Skaiw/*-
2276371Semaste * Copyright (c) 2009-2011,2014 Kai Wang
3260684Skaiw * All rights reserved.
4260684Skaiw *
5260684Skaiw * Redistribution and use in source and binary forms, with or without
6260684Skaiw * modification, are permitted provided that the following conditions
7260684Skaiw * are met:
8260684Skaiw * 1. Redistributions of source code must retain the above copyright
9260684Skaiw *    notice, this list of conditions and the following disclaimer.
10260684Skaiw * 2. Redistributions in binary form must reproduce the above copyright
11260684Skaiw *    notice, this list of conditions and the following disclaimer in the
12260684Skaiw *    documentation and/or other materials provided with the distribution.
13260684Skaiw *
14260684Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15260684Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16260684Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17260684Skaiw * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18260684Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19260684Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20260684Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21260684Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22260684Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23260684Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24260684Skaiw * SUCH DAMAGE.
25260684Skaiw */
26260684Skaiw
27260684Skaiw#include "_libdwarf.h"
28260684Skaiw
29338414SemasteELFTC_VCSID("$Id: libdwarf_frame.c 3589 2018-03-13 20:34:33Z kaiwang27 $");
30260684Skaiw
31260684Skaiwstatic int
32260684Skaiw_dwarf_frame_find_cie(Dwarf_FrameSec fs, Dwarf_Unsigned offset,
33260684Skaiw    Dwarf_Cie *ret_cie)
34260684Skaiw{
35260684Skaiw	Dwarf_Cie cie;
36260684Skaiw
37260684Skaiw	STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
38260684Skaiw		if (cie->cie_offset == offset)
39260684Skaiw			break;
40260684Skaiw	}
41260684Skaiw
42260684Skaiw	if (cie == NULL)
43260684Skaiw		return (DW_DLE_NO_ENTRY);
44260684Skaiw
45260684Skaiw	if (ret_cie != NULL)
46260684Skaiw		*ret_cie = cie;
47260684Skaiw
48260684Skaiw	return (DW_DLE_NONE);
49260684Skaiw}
50260684Skaiw
51260684Skaiwstatic int
52276371Semaste_dwarf_frame_read_lsb_encoded(Dwarf_Debug dbg, Dwarf_Cie cie, uint64_t *val,
53276371Semaste    uint8_t *data, uint64_t *offsetp, uint8_t encode, Dwarf_Addr pc,
54276371Semaste    Dwarf_Error *error)
55260684Skaiw{
56260684Skaiw	uint8_t application;
57260684Skaiw
58260684Skaiw	if (encode == DW_EH_PE_omit)
59260684Skaiw		return (DW_DLE_NONE);
60260684Skaiw
61260684Skaiw	application = encode & 0xf0;
62260684Skaiw	encode &= 0x0f;
63260684Skaiw
64260684Skaiw	switch (encode) {
65260684Skaiw	case DW_EH_PE_absptr:
66276371Semaste		*val = dbg->read(data, offsetp, cie->cie_addrsize);
67260684Skaiw		break;
68260684Skaiw	case DW_EH_PE_uleb128:
69260684Skaiw		*val = _dwarf_read_uleb128(data, offsetp);
70260684Skaiw		break;
71260684Skaiw	case DW_EH_PE_udata2:
72260684Skaiw		*val = dbg->read(data, offsetp, 2);
73260684Skaiw		break;
74260684Skaiw	case DW_EH_PE_udata4:
75260684Skaiw		*val = dbg->read(data, offsetp, 4);
76260684Skaiw		break;
77260684Skaiw	case DW_EH_PE_udata8:
78260684Skaiw		*val = dbg->read(data, offsetp, 8);
79260684Skaiw		break;
80260684Skaiw	case DW_EH_PE_sleb128:
81260684Skaiw		*val = _dwarf_read_sleb128(data, offsetp);
82260684Skaiw		break;
83260684Skaiw	case DW_EH_PE_sdata2:
84260684Skaiw		*val = (int16_t) dbg->read(data, offsetp, 2);
85260684Skaiw		break;
86260684Skaiw	case DW_EH_PE_sdata4:
87260684Skaiw		*val = (int32_t) dbg->read(data, offsetp, 4);
88260684Skaiw		break;
89260684Skaiw	case DW_EH_PE_sdata8:
90260684Skaiw		*val = dbg->read(data, offsetp, 8);
91260684Skaiw		break;
92260684Skaiw	default:
93260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
94260684Skaiw		return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
95260684Skaiw	}
96260684Skaiw
97260684Skaiw	if (application == DW_EH_PE_pcrel) {
98260684Skaiw		/*
99260684Skaiw		 * Value is relative to .eh_frame section virtual addr.
100260684Skaiw		 */
101260684Skaiw		switch (encode) {
102260684Skaiw		case DW_EH_PE_uleb128:
103260684Skaiw		case DW_EH_PE_udata2:
104260684Skaiw		case DW_EH_PE_udata4:
105260684Skaiw		case DW_EH_PE_udata8:
106260684Skaiw			*val += pc;
107260684Skaiw			break;
108260684Skaiw		case DW_EH_PE_sleb128:
109260684Skaiw		case DW_EH_PE_sdata2:
110260684Skaiw		case DW_EH_PE_sdata4:
111260684Skaiw		case DW_EH_PE_sdata8:
112260684Skaiw			*val = pc + (int64_t) *val;
113260684Skaiw			break;
114260684Skaiw		default:
115260684Skaiw			/* DW_EH_PE_absptr is absolute value. */
116260684Skaiw			break;
117260684Skaiw		}
118260684Skaiw	}
119260684Skaiw
120260684Skaiw	/* XXX Applications other than DW_EH_PE_pcrel are not handled. */
121260684Skaiw
122260684Skaiw	return (DW_DLE_NONE);
123260684Skaiw}
124260684Skaiw
125260684Skaiwstatic int
126260684Skaiw_dwarf_frame_parse_lsb_cie_augment(Dwarf_Debug dbg, Dwarf_Cie cie,
127260684Skaiw    Dwarf_Error *error)
128260684Skaiw{
129260684Skaiw	uint8_t *aug_p, *augdata_p;
130260684Skaiw	uint64_t val, offset;
131260684Skaiw	uint8_t encode;
132260684Skaiw	int ret;
133260684Skaiw
134260684Skaiw	assert(cie->cie_augment != NULL && *cie->cie_augment == 'z');
135260684Skaiw
136260684Skaiw	/*
137260684Skaiw	 * Here we're only interested in the presence of augment 'R'
138260684Skaiw	 * and associated CIE augment data, which describes the
139260684Skaiw	 * encoding scheme of FDE PC begin and range.
140260684Skaiw	 */
141260684Skaiw	aug_p = &cie->cie_augment[1];
142260684Skaiw	augdata_p = cie->cie_augdata;
143260684Skaiw	while (*aug_p != '\0') {
144260684Skaiw		switch (*aug_p) {
145338414Semaste		case 'S':
146338414Semaste			break;
147260684Skaiw		case 'L':
148260684Skaiw			/* Skip one augment in augment data. */
149260684Skaiw			augdata_p++;
150260684Skaiw			break;
151260684Skaiw		case 'P':
152260684Skaiw			/* Skip two augments in augment data. */
153260684Skaiw			encode = *augdata_p++;
154260684Skaiw			offset = 0;
155276371Semaste			ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
156260684Skaiw			    augdata_p, &offset, encode, 0, error);
157260684Skaiw			if (ret != DW_DLE_NONE)
158260684Skaiw				return (ret);
159260684Skaiw			augdata_p += offset;
160260684Skaiw			break;
161260684Skaiw		case 'R':
162260684Skaiw			cie->cie_fde_encode = *augdata_p++;
163260684Skaiw			break;
164260684Skaiw		default:
165260684Skaiw			DWARF_SET_ERROR(dbg, error,
166260684Skaiw			    DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
167260684Skaiw			return (DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
168260684Skaiw		}
169260684Skaiw		aug_p++;
170260684Skaiw	}
171260684Skaiw
172260684Skaiw	return (DW_DLE_NONE);
173260684Skaiw}
174260684Skaiw
175260684Skaiwstatic int
176260684Skaiw_dwarf_frame_add_cie(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
177260684Skaiw    Dwarf_Unsigned *off, Dwarf_Cie *ret_cie, Dwarf_Error *error)
178260684Skaiw{
179260684Skaiw	Dwarf_Cie cie;
180260684Skaiw	uint64_t length;
181260684Skaiw	int dwarf_size, ret;
182260684Skaiw	char *p;
183260684Skaiw
184260684Skaiw	/* Check if we already added this CIE. */
185260684Skaiw	if (_dwarf_frame_find_cie(fs, *off, &cie) != DW_DLE_NO_ENTRY) {
186260684Skaiw		*off += cie->cie_length + 4;
187260684Skaiw		return (DW_DLE_NONE);
188260684Skaiw	}
189260684Skaiw
190260684Skaiw	if ((cie = calloc(1, sizeof(struct _Dwarf_Cie))) == NULL) {
191260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
192260684Skaiw		return (DW_DLE_MEMORY);
193260684Skaiw	}
194260684Skaiw	STAILQ_INSERT_TAIL(&fs->fs_cielist, cie, cie_next);
195260684Skaiw
196260684Skaiw	cie->cie_dbg = dbg;
197260684Skaiw	cie->cie_index = fs->fs_cielen;
198260684Skaiw	cie->cie_offset = *off;
199260684Skaiw
200260684Skaiw	length = dbg->read(ds->ds_data, off, 4);
201260684Skaiw	if (length == 0xffffffff) {
202260684Skaiw		dwarf_size = 8;
203260684Skaiw		length = dbg->read(ds->ds_data, off, 8);
204260684Skaiw	} else
205260684Skaiw		dwarf_size = 4;
206260684Skaiw
207260684Skaiw	if (length > ds->ds_size - *off) {
208260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
209260684Skaiw		return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
210260684Skaiw	}
211260684Skaiw
212260684Skaiw	(void) dbg->read(ds->ds_data, off, dwarf_size); /* Skip CIE id. */
213260684Skaiw	cie->cie_length = length;
214260684Skaiw
215260684Skaiw	cie->cie_version = dbg->read(ds->ds_data, off, 1);
216260684Skaiw	if (cie->cie_version != 1 && cie->cie_version != 3 &&
217260684Skaiw	    cie->cie_version != 4) {
218260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_VERSION_BAD);
219260684Skaiw		return (DW_DLE_FRAME_VERSION_BAD);
220260684Skaiw	}
221260684Skaiw
222260684Skaiw	cie->cie_augment = ds->ds_data + *off;
223260684Skaiw	p = (char *) ds->ds_data;
224260684Skaiw	while (p[(*off)++] != '\0')
225260684Skaiw		;
226260684Skaiw
227260684Skaiw	/* We only recognize normal .dwarf_frame and GNU .eh_frame sections. */
228260684Skaiw	if (*cie->cie_augment != 0 && *cie->cie_augment != 'z') {
229260684Skaiw		*off = cie->cie_offset + ((dwarf_size == 4) ? 4 : 12) +
230260684Skaiw		    cie->cie_length;
231260684Skaiw		return (DW_DLE_NONE);
232260684Skaiw	}
233260684Skaiw
234260684Skaiw	/* Optional EH Data field for .eh_frame section. */
235260684Skaiw	if (strstr((char *)cie->cie_augment, "eh") != NULL)
236260684Skaiw		cie->cie_ehdata = dbg->read(ds->ds_data, off,
237260684Skaiw		    dbg->dbg_pointer_size);
238260684Skaiw
239276371Semaste	/* DWARF4 added "address_size" and "segment_size". */
240276371Semaste	if (cie->cie_version == 4) {
241276371Semaste		cie->cie_addrsize = dbg->read(ds->ds_data, off, 1);
242276371Semaste		cie->cie_segmentsize = dbg->read(ds->ds_data, off, 1);
243276371Semaste	} else {
244276371Semaste		/*
245276371Semaste		 * Otherwise (DWARF[23]) we just set CIE addrsize to the
246276371Semaste		 * debug context pointer size.
247276371Semaste		 */
248276371Semaste		cie->cie_addrsize = dbg->dbg_pointer_size;
249276371Semaste	}
250276371Semaste
251260684Skaiw	cie->cie_caf = _dwarf_read_uleb128(ds->ds_data, off);
252260684Skaiw	cie->cie_daf = _dwarf_read_sleb128(ds->ds_data, off);
253260684Skaiw
254260684Skaiw	/* Return address register. */
255260684Skaiw	if (cie->cie_version == 1)
256260684Skaiw		cie->cie_ra = dbg->read(ds->ds_data, off, 1);
257260684Skaiw	else
258260684Skaiw		cie->cie_ra = _dwarf_read_uleb128(ds->ds_data, off);
259260684Skaiw
260260684Skaiw	/* Optional CIE augmentation data for .eh_frame section. */
261260684Skaiw	if (*cie->cie_augment == 'z') {
262260684Skaiw		cie->cie_auglen = _dwarf_read_uleb128(ds->ds_data, off);
263260684Skaiw		cie->cie_augdata = ds->ds_data + *off;
264260684Skaiw		*off += cie->cie_auglen;
265260684Skaiw		/*
266260684Skaiw		 * XXX Use DW_EH_PE_absptr for default FDE PC start/range,
267260684Skaiw		 * in case _dwarf_frame_parse_lsb_cie_augment fails to
268260684Skaiw		 * find out the real encode.
269260684Skaiw		 */
270260684Skaiw		cie->cie_fde_encode = DW_EH_PE_absptr;
271260684Skaiw		ret = _dwarf_frame_parse_lsb_cie_augment(dbg, cie, error);
272260684Skaiw		if (ret != DW_DLE_NONE)
273260684Skaiw			return (ret);
274260684Skaiw	}
275260684Skaiw
276260684Skaiw	/* CIE Initial instructions. */
277260684Skaiw	cie->cie_initinst = ds->ds_data + *off;
278260684Skaiw	if (dwarf_size == 4)
279260684Skaiw		cie->cie_instlen = cie->cie_offset + 4 + length - *off;
280260684Skaiw	else
281260684Skaiw		cie->cie_instlen = cie->cie_offset + 12 + length - *off;
282260684Skaiw
283260684Skaiw	*off += cie->cie_instlen;
284260684Skaiw
285260684Skaiw#ifdef FRAME_DEBUG
286260684Skaiw	printf("cie:\n");
287260684Skaiw	printf("\tcie_version=%u cie_offset=%ju cie_length=%ju cie_augment=%s"
288260684Skaiw	    " cie_instlen=%ju cie->cie_caf=%ju cie->cie_daf=%jd off=%ju\n",
289260684Skaiw	    cie->cie_version, cie->cie_offset, cie->cie_length,
290260684Skaiw	    (char *)cie->cie_augment, cie->cie_instlen, cie->cie_caf,
291260684Skaiw	    cie->cie_daf, *off);
292260684Skaiw#endif
293260684Skaiw
294260684Skaiw	if (ret_cie != NULL)
295260684Skaiw		*ret_cie = cie;
296260684Skaiw
297260684Skaiw	fs->fs_cielen++;
298260684Skaiw
299260684Skaiw	return (DW_DLE_NONE);
300260684Skaiw}
301260684Skaiw
302260684Skaiwstatic int
303260684Skaiw_dwarf_frame_add_fde(Dwarf_Debug dbg, Dwarf_FrameSec fs, Dwarf_Section *ds,
304260684Skaiw    Dwarf_Unsigned *off, int eh_frame, Dwarf_Error *error)
305260684Skaiw{
306260684Skaiw	Dwarf_Cie cie;
307260684Skaiw	Dwarf_Fde fde;
308260684Skaiw	Dwarf_Unsigned cieoff;
309260684Skaiw	uint64_t length, val;
310260684Skaiw	int dwarf_size, ret;
311260684Skaiw
312260684Skaiw	if ((fde = calloc(1, sizeof(struct _Dwarf_Fde))) == NULL) {
313260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
314260684Skaiw		return (DW_DLE_MEMORY);
315260684Skaiw	}
316260684Skaiw	STAILQ_INSERT_TAIL(&fs->fs_fdelist, fde, fde_next);
317260684Skaiw
318260684Skaiw	fde->fde_dbg = dbg;
319260684Skaiw	fde->fde_fs = fs;
320260684Skaiw	fde->fde_addr = ds->ds_data + *off;
321260684Skaiw	fde->fde_offset = *off;
322260684Skaiw
323260684Skaiw	length = dbg->read(ds->ds_data, off, 4);
324260684Skaiw	if (length == 0xffffffff) {
325260684Skaiw		dwarf_size = 8;
326260684Skaiw		length = dbg->read(ds->ds_data, off, 8);
327260684Skaiw	} else
328260684Skaiw		dwarf_size = 4;
329260684Skaiw
330260684Skaiw	if (length > ds->ds_size - *off) {
331260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
332260684Skaiw		return (DW_DLE_DEBUG_FRAME_LENGTH_BAD);
333260684Skaiw	}
334260684Skaiw
335260684Skaiw	fde->fde_length = length;
336260684Skaiw
337260684Skaiw	if (eh_frame) {
338260684Skaiw		fde->fde_cieoff = dbg->read(ds->ds_data, off, 4);
339260684Skaiw		cieoff = *off - (4 + fde->fde_cieoff);
340260684Skaiw		/* This delta should never be 0. */
341260684Skaiw		if (cieoff == fde->fde_offset) {
342260684Skaiw			DWARF_SET_ERROR(dbg, error, DW_DLE_NO_CIE_FOR_FDE);
343260684Skaiw			return (DW_DLE_NO_CIE_FOR_FDE);
344260684Skaiw		}
345260684Skaiw	} else {
346260684Skaiw		fde->fde_cieoff = dbg->read(ds->ds_data, off, dwarf_size);
347260684Skaiw		cieoff = fde->fde_cieoff;
348260684Skaiw	}
349260684Skaiw
350260684Skaiw	if (_dwarf_frame_find_cie(fs, cieoff, &cie) ==
351260684Skaiw	    DW_DLE_NO_ENTRY) {
352260684Skaiw		ret = _dwarf_frame_add_cie(dbg, fs, ds, &cieoff, &cie,
353260684Skaiw		    error);
354260684Skaiw		if (ret != DW_DLE_NONE)
355260684Skaiw			return (ret);
356260684Skaiw	}
357260684Skaiw	fde->fde_cie = cie;
358260684Skaiw	if (eh_frame) {
359260684Skaiw		/*
360260684Skaiw		 * The FDE PC start/range for .eh_frame is encoded according
361260684Skaiw		 * to the LSB spec's extension to DWARF2.
362260684Skaiw		 */
363276371Semaste		ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
364276371Semaste		    ds->ds_data, off, cie->cie_fde_encode, ds->ds_addr + *off,
365276371Semaste		    error);
366260684Skaiw		if (ret != DW_DLE_NONE)
367260684Skaiw			return (ret);
368260684Skaiw		fde->fde_initloc = val;
369260684Skaiw		/*
370260684Skaiw		 * FDE PC range should not be relative value to anything.
371260684Skaiw		 * So pass 0 for pc value.
372260684Skaiw		 */
373276371Semaste		ret = _dwarf_frame_read_lsb_encoded(dbg, cie, &val,
374276371Semaste		    ds->ds_data, off, cie->cie_fde_encode, 0, error);
375260684Skaiw		if (ret != DW_DLE_NONE)
376260684Skaiw			return (ret);
377260684Skaiw		fde->fde_adrange = val;
378260684Skaiw	} else {
379260684Skaiw		fde->fde_initloc = dbg->read(ds->ds_data, off,
380276371Semaste		    cie->cie_addrsize);
381260684Skaiw		fde->fde_adrange = dbg->read(ds->ds_data, off,
382276371Semaste		    cie->cie_addrsize);
383260684Skaiw	}
384260684Skaiw
385260684Skaiw	/* Optional FDE augmentation data for .eh_frame section. (ignored) */
386260684Skaiw	if (eh_frame && *cie->cie_augment == 'z') {
387260684Skaiw		fde->fde_auglen = _dwarf_read_uleb128(ds->ds_data, off);
388260684Skaiw		fde->fde_augdata = ds->ds_data + *off;
389260684Skaiw		*off += fde->fde_auglen;
390260684Skaiw	}
391260684Skaiw
392260684Skaiw	fde->fde_inst = ds->ds_data + *off;
393260684Skaiw	if (dwarf_size == 4)
394260684Skaiw		fde->fde_instlen = fde->fde_offset + 4 + length - *off;
395260684Skaiw	else
396260684Skaiw		fde->fde_instlen = fde->fde_offset + 12 + length - *off;
397260684Skaiw
398260684Skaiw	*off += fde->fde_instlen;
399260684Skaiw
400260684Skaiw#ifdef FRAME_DEBUG
401260684Skaiw	printf("fde:");
402260684Skaiw	if (eh_frame)
403260684Skaiw		printf("(eh_frame)");
404260684Skaiw	putchar('\n');
405260684Skaiw	printf("\tfde_offset=%ju fde_length=%ju fde_cieoff=%ju"
406260684Skaiw	    " fde_instlen=%ju off=%ju\n", fde->fde_offset, fde->fde_length,
407260684Skaiw	    fde->fde_cieoff, fde->fde_instlen, *off);
408260684Skaiw#endif
409260684Skaiw
410260684Skaiw	fs->fs_fdelen++;
411260684Skaiw
412260684Skaiw	return (DW_DLE_NONE);
413260684Skaiw}
414260684Skaiw
415260684Skaiwstatic void
416260684Skaiw_dwarf_frame_section_cleanup(Dwarf_FrameSec fs)
417260684Skaiw{
418260684Skaiw	Dwarf_Cie cie, tcie;
419260684Skaiw	Dwarf_Fde fde, tfde;
420260684Skaiw
421260684Skaiw	STAILQ_FOREACH_SAFE(cie, &fs->fs_cielist, cie_next, tcie) {
422260684Skaiw		STAILQ_REMOVE(&fs->fs_cielist, cie, _Dwarf_Cie, cie_next);
423260684Skaiw		free(cie);
424260684Skaiw	}
425260684Skaiw
426260684Skaiw	STAILQ_FOREACH_SAFE(fde, &fs->fs_fdelist, fde_next, tfde) {
427260684Skaiw		STAILQ_REMOVE(&fs->fs_fdelist, fde, _Dwarf_Fde, fde_next);
428260684Skaiw		free(fde);
429260684Skaiw	}
430260684Skaiw
431260684Skaiw	if (fs->fs_ciearray != NULL)
432260684Skaiw		free(fs->fs_ciearray);
433260684Skaiw	if (fs->fs_fdearray != NULL)
434260684Skaiw		free(fs->fs_fdearray);
435260684Skaiw
436260684Skaiw	free(fs);
437260684Skaiw}
438260684Skaiw
439260684Skaiwstatic int
440260684Skaiw_dwarf_frame_section_init(Dwarf_Debug dbg, Dwarf_FrameSec *frame_sec,
441260684Skaiw    Dwarf_Section *ds, int eh_frame, Dwarf_Error *error)
442260684Skaiw{
443260684Skaiw	Dwarf_FrameSec fs;
444260684Skaiw	Dwarf_Cie cie;
445260684Skaiw	Dwarf_Fde fde;
446260684Skaiw	uint64_t length, offset, cie_id, entry_off;
447260684Skaiw	int dwarf_size, i, ret;
448260684Skaiw
449260684Skaiw	assert(frame_sec != NULL);
450260684Skaiw	assert(*frame_sec == NULL);
451260684Skaiw
452260684Skaiw	if ((fs = calloc(1, sizeof(struct _Dwarf_FrameSec))) == NULL) {
453260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
454260684Skaiw		return (DW_DLE_MEMORY);
455260684Skaiw	}
456260684Skaiw	STAILQ_INIT(&fs->fs_cielist);
457260684Skaiw	STAILQ_INIT(&fs->fs_fdelist);
458260684Skaiw
459260684Skaiw	offset = 0;
460260684Skaiw	while (offset < ds->ds_size) {
461260684Skaiw		entry_off = offset;
462260684Skaiw		length = dbg->read(ds->ds_data, &offset, 4);
463260684Skaiw		if (length == 0xffffffff) {
464260684Skaiw			dwarf_size = 8;
465260684Skaiw			length = dbg->read(ds->ds_data, &offset, 8);
466260684Skaiw		} else
467260684Skaiw			dwarf_size = 4;
468260684Skaiw
469260684Skaiw		if (length > ds->ds_size - offset ||
470260684Skaiw		    (length == 0 && !eh_frame)) {
471367466Sdim			ret = DW_DLE_DEBUG_FRAME_LENGTH_BAD;
472367466Sdim			DWARF_SET_ERROR(dbg, error, ret);
473367466Sdim			goto fail_cleanup;
474260684Skaiw		}
475260684Skaiw
476260684Skaiw		/* Check terminator for .eh_frame */
477260684Skaiw		if (eh_frame && length == 0)
478260684Skaiw			break;
479260684Skaiw
480260684Skaiw		cie_id = dbg->read(ds->ds_data, &offset, dwarf_size);
481260684Skaiw
482260684Skaiw		if (eh_frame) {
483260684Skaiw			/* GNU .eh_frame use CIE id 0. */
484260684Skaiw			if (cie_id == 0)
485260684Skaiw				ret = _dwarf_frame_add_cie(dbg, fs, ds,
486260684Skaiw				    &entry_off, NULL, error);
487260684Skaiw			else
488260684Skaiw				ret = _dwarf_frame_add_fde(dbg, fs, ds,
489260684Skaiw				    &entry_off, 1, error);
490260684Skaiw		} else {
491260684Skaiw			/* .dwarf_frame use CIE id ~0 */
492260684Skaiw			if ((dwarf_size == 4 && cie_id == ~0U) ||
493260684Skaiw			    (dwarf_size == 8 && cie_id == ~0ULL))
494260684Skaiw				ret = _dwarf_frame_add_cie(dbg, fs, ds,
495260684Skaiw				    &entry_off, NULL, error);
496260684Skaiw			else
497260684Skaiw				ret = _dwarf_frame_add_fde(dbg, fs, ds,
498260684Skaiw				    &entry_off, 0, error);
499260684Skaiw		}
500260684Skaiw
501260684Skaiw		if (ret != DW_DLE_NONE)
502260684Skaiw			goto fail_cleanup;
503260684Skaiw
504260684Skaiw		offset = entry_off;
505260684Skaiw	}
506260684Skaiw
507260684Skaiw	/* Create CIE array. */
508260684Skaiw	if (fs->fs_cielen > 0) {
509260684Skaiw		if ((fs->fs_ciearray = malloc(sizeof(Dwarf_Cie) *
510260684Skaiw		    fs->fs_cielen)) == NULL) {
511260684Skaiw			ret = DW_DLE_MEMORY;
512260684Skaiw			DWARF_SET_ERROR(dbg, error, ret);
513260684Skaiw			goto fail_cleanup;
514260684Skaiw		}
515260684Skaiw		i = 0;
516260684Skaiw		STAILQ_FOREACH(cie, &fs->fs_cielist, cie_next) {
517260684Skaiw			fs->fs_ciearray[i++] = cie;
518260684Skaiw		}
519260684Skaiw		assert((Dwarf_Unsigned)i == fs->fs_cielen);
520260684Skaiw	}
521260684Skaiw
522260684Skaiw	/* Create FDE array. */
523260684Skaiw	if (fs->fs_fdelen > 0) {
524260684Skaiw		if ((fs->fs_fdearray = malloc(sizeof(Dwarf_Fde) *
525260684Skaiw		    fs->fs_fdelen)) == NULL) {
526260684Skaiw			ret = DW_DLE_MEMORY;
527260684Skaiw			DWARF_SET_ERROR(dbg, error, ret);
528260684Skaiw			goto fail_cleanup;
529260684Skaiw		}
530260684Skaiw		i = 0;
531260684Skaiw		STAILQ_FOREACH(fde, &fs->fs_fdelist, fde_next) {
532260684Skaiw			fs->fs_fdearray[i++] = fde;
533260684Skaiw		}
534260684Skaiw		assert((Dwarf_Unsigned)i == fs->fs_fdelen);
535260684Skaiw	}
536260684Skaiw
537260684Skaiw	*frame_sec = fs;
538260684Skaiw
539260684Skaiw	return (DW_DLE_NONE);
540260684Skaiw
541260684Skaiwfail_cleanup:
542260684Skaiw
543260684Skaiw	_dwarf_frame_section_cleanup(fs);
544260684Skaiw
545260684Skaiw	return (ret);
546260684Skaiw}
547260684Skaiw
548260684Skaiwstatic int
549276371Semaste_dwarf_frame_run_inst(Dwarf_Debug dbg, Dwarf_Regtable3 *rt, uint8_t addr_size,
550276371Semaste    uint8_t *insts, Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf,
551276371Semaste    Dwarf_Addr pc, Dwarf_Addr pc_req, Dwarf_Addr *row_pc, Dwarf_Error *error)
552260684Skaiw{
553260684Skaiw	Dwarf_Regtable3 *init_rt, *saved_rt;
554260684Skaiw	uint8_t *p, *pe;
555260684Skaiw	uint8_t high2, low6;
556260684Skaiw	uint64_t reg, reg2, uoff, soff;
557260684Skaiw	int ret;
558260684Skaiw
559260684Skaiw#define	CFA	rt->rt3_cfa_rule
560260684Skaiw#define	INITCFA	init_rt->rt3_cfa_rule
561260684Skaiw#define	RL	rt->rt3_rules
562260684Skaiw#define	INITRL	init_rt->rt3_rules
563260684Skaiw
564260684Skaiw#define CHECK_TABLE_SIZE(x)						\
565260684Skaiw	do {								\
566260684Skaiw		if ((x) >= rt->rt3_reg_table_size) {			\
567260684Skaiw			DWARF_SET_ERROR(dbg, error,			\
568260684Skaiw			    DW_DLE_DF_REG_NUM_TOO_HIGH);		\
569260684Skaiw			ret = DW_DLE_DF_REG_NUM_TOO_HIGH;		\
570260684Skaiw			goto program_done;				\
571260684Skaiw		}							\
572260684Skaiw	} while(0)
573260684Skaiw
574260684Skaiw#ifdef FRAME_DEBUG
575260684Skaiw	printf("frame_run_inst: (caf=%ju, daf=%jd)\n", caf, daf);
576260684Skaiw#endif
577260684Skaiw
578260684Skaiw	ret = DW_DLE_NONE;
579260684Skaiw	init_rt = saved_rt = NULL;
580260684Skaiw	*row_pc = pc;
581260684Skaiw
582260684Skaiw	/* Save a copy of the table as initial state. */
583260684Skaiw	_dwarf_frame_regtable_copy(dbg, &init_rt, rt, error);
584260684Skaiw
585260684Skaiw	p = insts;
586260684Skaiw	pe = p + len;
587260684Skaiw
588260684Skaiw	while (p < pe) {
589260684Skaiw
590260684Skaiw#ifdef FRAME_DEBUG
591260684Skaiw		printf("p=%p pe=%p pc=%#jx pc_req=%#jx\n", p, pe, pc, pc_req);
592260684Skaiw#endif
593260684Skaiw
594260684Skaiw		if (*p == DW_CFA_nop) {
595260684Skaiw#ifdef FRAME_DEBUG
596260684Skaiw			printf("DW_CFA_nop\n");
597260684Skaiw#endif
598260684Skaiw			p++;
599260684Skaiw			continue;
600260684Skaiw		}
601260684Skaiw
602260684Skaiw		high2 = *p & 0xc0;
603260684Skaiw		low6 = *p & 0x3f;
604260684Skaiw		p++;
605260684Skaiw
606260684Skaiw		if (high2 > 0) {
607260684Skaiw			switch (high2) {
608260684Skaiw			case DW_CFA_advance_loc:
609260684Skaiw				pc += low6 * caf;
610260684Skaiw#ifdef FRAME_DEBUG
611260684Skaiw				printf("DW_CFA_advance_loc(%#jx(%u))\n", pc,
612260684Skaiw				    low6);
613260684Skaiw#endif
614260684Skaiw				if (pc_req < pc)
615260684Skaiw					goto program_done;
616260684Skaiw				break;
617260684Skaiw			case DW_CFA_offset:
618260684Skaiw				*row_pc = pc;
619260684Skaiw				CHECK_TABLE_SIZE(low6);
620260684Skaiw				RL[low6].dw_offset_relevant = 1;
621260684Skaiw				RL[low6].dw_value_type = DW_EXPR_OFFSET;
622260684Skaiw				RL[low6].dw_regnum = dbg->dbg_frame_cfa_value;
623260684Skaiw				RL[low6].dw_offset_or_block_len =
624260684Skaiw				    _dwarf_decode_uleb128(&p) * daf;
625260684Skaiw#ifdef FRAME_DEBUG
626260684Skaiw				printf("DW_CFA_offset(%jd)\n",
627260684Skaiw				    RL[low6].dw_offset_or_block_len);
628260684Skaiw#endif
629260684Skaiw				break;
630260684Skaiw			case DW_CFA_restore:
631260684Skaiw				*row_pc = pc;
632260684Skaiw				CHECK_TABLE_SIZE(low6);
633260684Skaiw				memcpy(&RL[low6], &INITRL[low6],
634260684Skaiw				    sizeof(Dwarf_Regtable_Entry3));
635260684Skaiw#ifdef FRAME_DEBUG
636260684Skaiw				printf("DW_CFA_restore(%u)\n", low6);
637260684Skaiw#endif
638260684Skaiw				break;
639260684Skaiw			default:
640260684Skaiw				DWARF_SET_ERROR(dbg, error,
641260684Skaiw				    DW_DLE_FRAME_INSTR_EXEC_ERROR);
642260684Skaiw				ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
643260684Skaiw				goto program_done;
644260684Skaiw			}
645260684Skaiw
646260684Skaiw			continue;
647260684Skaiw		}
648260684Skaiw
649260684Skaiw		switch (low6) {
650260684Skaiw		case DW_CFA_set_loc:
651276371Semaste			pc = dbg->decode(&p, addr_size);
652260684Skaiw#ifdef FRAME_DEBUG
653260684Skaiw			printf("DW_CFA_set_loc(pc=%#jx)\n", pc);
654260684Skaiw#endif
655260684Skaiw			if (pc_req < pc)
656260684Skaiw				goto program_done;
657260684Skaiw			break;
658260684Skaiw		case DW_CFA_advance_loc1:
659260684Skaiw			pc += dbg->decode(&p, 1) * caf;
660260684Skaiw#ifdef FRAME_DEBUG
661260684Skaiw			printf("DW_CFA_set_loc1(pc=%#jx)\n", pc);
662260684Skaiw#endif
663260684Skaiw			if (pc_req < pc)
664260684Skaiw				goto program_done;
665260684Skaiw			break;
666260684Skaiw		case DW_CFA_advance_loc2:
667260684Skaiw			pc += dbg->decode(&p, 2) * caf;
668260684Skaiw#ifdef FRAME_DEBUG
669260684Skaiw			printf("DW_CFA_set_loc2(pc=%#jx)\n", pc);
670260684Skaiw#endif
671260684Skaiw			if (pc_req < pc)
672260684Skaiw				goto program_done;
673260684Skaiw			break;
674260684Skaiw		case DW_CFA_advance_loc4:
675260684Skaiw			pc += dbg->decode(&p, 4) * caf;
676260684Skaiw#ifdef FRAME_DEBUG
677260684Skaiw			printf("DW_CFA_set_loc4(pc=%#jx)\n", pc);
678260684Skaiw#endif
679260684Skaiw			if (pc_req < pc)
680260684Skaiw				goto program_done;
681260684Skaiw			break;
682260684Skaiw		case DW_CFA_offset_extended:
683260684Skaiw			*row_pc = pc;
684260684Skaiw			reg = _dwarf_decode_uleb128(&p);
685260684Skaiw			uoff = _dwarf_decode_uleb128(&p);
686260684Skaiw			CHECK_TABLE_SIZE(reg);
687260684Skaiw			RL[reg].dw_offset_relevant = 1;
688260684Skaiw			RL[reg].dw_value_type = DW_EXPR_OFFSET;
689260684Skaiw			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
690260684Skaiw			RL[reg].dw_offset_or_block_len = uoff * daf;
691260684Skaiw#ifdef FRAME_DEBUG
692260684Skaiw			printf("DW_CFA_offset_extended(reg=%ju,uoff=%ju)\n",
693260684Skaiw			    reg, uoff);
694260684Skaiw#endif
695260684Skaiw			break;
696260684Skaiw		case DW_CFA_restore_extended:
697260684Skaiw			*row_pc = pc;
698260684Skaiw			reg = _dwarf_decode_uleb128(&p);
699260684Skaiw			CHECK_TABLE_SIZE(reg);
700260684Skaiw			memcpy(&RL[reg], &INITRL[reg],
701260684Skaiw			    sizeof(Dwarf_Regtable_Entry3));
702260684Skaiw#ifdef FRAME_DEBUG
703260684Skaiw			printf("DW_CFA_restore_extended(%ju)\n", reg);
704260684Skaiw#endif
705260684Skaiw			break;
706260684Skaiw		case DW_CFA_undefined:
707260684Skaiw			*row_pc = pc;
708260684Skaiw			reg = _dwarf_decode_uleb128(&p);
709260684Skaiw			CHECK_TABLE_SIZE(reg);
710260684Skaiw			RL[reg].dw_offset_relevant = 0;
711260684Skaiw			RL[reg].dw_regnum = dbg->dbg_frame_undefined_value;
712260684Skaiw#ifdef FRAME_DEBUG
713260684Skaiw			printf("DW_CFA_undefined(%ju)\n", reg);
714260684Skaiw#endif
715260684Skaiw			break;
716260684Skaiw		case DW_CFA_same_value:
717260684Skaiw			reg = _dwarf_decode_uleb128(&p);
718260684Skaiw			CHECK_TABLE_SIZE(reg);
719260684Skaiw			RL[reg].dw_offset_relevant = 0;
720260684Skaiw			RL[reg].dw_regnum = dbg->dbg_frame_same_value;
721260684Skaiw#ifdef FRAME_DEBUG
722260684Skaiw			printf("DW_CFA_same_value(%ju)\n", reg);
723260684Skaiw#endif
724260684Skaiw			break;
725260684Skaiw		case DW_CFA_register:
726260684Skaiw			*row_pc = pc;
727260684Skaiw			reg = _dwarf_decode_uleb128(&p);
728260684Skaiw			reg2 = _dwarf_decode_uleb128(&p);
729260684Skaiw			CHECK_TABLE_SIZE(reg);
730260684Skaiw			RL[reg].dw_offset_relevant = 0;
731260684Skaiw			RL[reg].dw_regnum = reg2;
732260684Skaiw#ifdef FRAME_DEBUG
733260684Skaiw			printf("DW_CFA_register(reg=%ju,reg2=%ju)\n", reg,
734260684Skaiw			    reg2);
735260684Skaiw#endif
736260684Skaiw			break;
737260684Skaiw		case DW_CFA_remember_state:
738260684Skaiw			_dwarf_frame_regtable_copy(dbg, &saved_rt, rt, error);
739260684Skaiw#ifdef FRAME_DEBUG
740260684Skaiw			printf("DW_CFA_remember_state\n");
741260684Skaiw#endif
742260684Skaiw			break;
743260684Skaiw		case DW_CFA_restore_state:
744260684Skaiw			*row_pc = pc;
745260684Skaiw			_dwarf_frame_regtable_copy(dbg, &rt, saved_rt, error);
746260684Skaiw#ifdef FRAME_DEBUG
747260684Skaiw			printf("DW_CFA_restore_state\n");
748260684Skaiw#endif
749260684Skaiw			break;
750260684Skaiw		case DW_CFA_def_cfa:
751260684Skaiw			*row_pc = pc;
752260684Skaiw			reg = _dwarf_decode_uleb128(&p);
753260684Skaiw			uoff = _dwarf_decode_uleb128(&p);
754260684Skaiw			CFA.dw_offset_relevant = 1;
755260684Skaiw			CFA.dw_value_type = DW_EXPR_OFFSET;
756260684Skaiw			CFA.dw_regnum = reg;
757260684Skaiw			CFA.dw_offset_or_block_len = uoff;
758260684Skaiw#ifdef FRAME_DEBUG
759260684Skaiw			printf("DW_CFA_def_cfa(reg=%ju,uoff=%ju)\n", reg, uoff);
760260684Skaiw#endif
761260684Skaiw			break;
762260684Skaiw		case DW_CFA_def_cfa_register:
763260684Skaiw			*row_pc = pc;
764260684Skaiw			reg = _dwarf_decode_uleb128(&p);
765260684Skaiw			CFA.dw_regnum = reg;
766260684Skaiw			/*
767260684Skaiw			 * Note that DW_CFA_def_cfa_register change the CFA
768260684Skaiw			 * rule register while keep the old offset. So we
769260684Skaiw			 * should not touch the CFA.dw_offset_relevant flag
770260684Skaiw			 * here.
771260684Skaiw			 */
772260684Skaiw#ifdef FRAME_DEBUG
773260684Skaiw			printf("DW_CFA_def_cfa_register(%ju)\n", reg);
774260684Skaiw#endif
775260684Skaiw			break;
776260684Skaiw		case DW_CFA_def_cfa_offset:
777260684Skaiw			*row_pc = pc;
778260684Skaiw			uoff = _dwarf_decode_uleb128(&p);
779260684Skaiw			CFA.dw_offset_relevant = 1;
780260684Skaiw			CFA.dw_value_type = DW_EXPR_OFFSET;
781260684Skaiw			CFA.dw_offset_or_block_len = uoff;
782260684Skaiw#ifdef FRAME_DEBUG
783260684Skaiw			printf("DW_CFA_def_cfa_offset(%ju)\n", uoff);
784260684Skaiw#endif
785260684Skaiw			break;
786260684Skaiw		case DW_CFA_def_cfa_expression:
787260684Skaiw			*row_pc = pc;
788260684Skaiw			CFA.dw_offset_relevant = 0;
789260684Skaiw			CFA.dw_value_type = DW_EXPR_EXPRESSION;
790260684Skaiw			CFA.dw_offset_or_block_len = _dwarf_decode_uleb128(&p);
791260684Skaiw			CFA.dw_block_ptr = p;
792260684Skaiw			p += CFA.dw_offset_or_block_len;
793260684Skaiw#ifdef FRAME_DEBUG
794260684Skaiw			printf("DW_CFA_def_cfa_expression\n");
795260684Skaiw#endif
796260684Skaiw			break;
797260684Skaiw		case DW_CFA_expression:
798260684Skaiw			*row_pc = pc;
799260684Skaiw			reg = _dwarf_decode_uleb128(&p);
800260684Skaiw			CHECK_TABLE_SIZE(reg);
801260684Skaiw			RL[reg].dw_offset_relevant = 0;
802260684Skaiw			RL[reg].dw_value_type = DW_EXPR_EXPRESSION;
803260684Skaiw			RL[reg].dw_offset_or_block_len =
804260684Skaiw			    _dwarf_decode_uleb128(&p);
805260684Skaiw			RL[reg].dw_block_ptr = p;
806260684Skaiw			p += RL[reg].dw_offset_or_block_len;
807260684Skaiw#ifdef FRAME_DEBUG
808260684Skaiw			printf("DW_CFA_expression\n");
809260684Skaiw#endif
810260684Skaiw			break;
811260684Skaiw		case DW_CFA_offset_extended_sf:
812260684Skaiw			*row_pc = pc;
813260684Skaiw			reg = _dwarf_decode_uleb128(&p);
814260684Skaiw			soff = _dwarf_decode_sleb128(&p);
815260684Skaiw			CHECK_TABLE_SIZE(reg);
816260684Skaiw			RL[reg].dw_offset_relevant = 1;
817260684Skaiw			RL[reg].dw_value_type = DW_EXPR_OFFSET;
818260684Skaiw			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
819260684Skaiw			RL[reg].dw_offset_or_block_len = soff * daf;
820260684Skaiw#ifdef FRAME_DEBUG
821260684Skaiw			printf("DW_CFA_offset_extended_sf(reg=%ju,soff=%jd)\n",
822260684Skaiw			    reg, soff);
823260684Skaiw#endif
824260684Skaiw			break;
825260684Skaiw		case DW_CFA_def_cfa_sf:
826260684Skaiw			*row_pc = pc;
827260684Skaiw			reg = _dwarf_decode_uleb128(&p);
828260684Skaiw			soff = _dwarf_decode_sleb128(&p);
829260684Skaiw			CFA.dw_offset_relevant = 1;
830260684Skaiw			CFA.dw_value_type = DW_EXPR_OFFSET;
831260684Skaiw			CFA.dw_regnum = reg;
832260684Skaiw			CFA.dw_offset_or_block_len = soff * daf;
833260684Skaiw#ifdef FRAME_DEBUG
834260684Skaiw			printf("DW_CFA_def_cfa_sf(reg=%ju,soff=%jd)\n", reg,
835260684Skaiw			    soff);
836260684Skaiw#endif
837260684Skaiw			break;
838260684Skaiw		case DW_CFA_def_cfa_offset_sf:
839260684Skaiw			*row_pc = pc;
840260684Skaiw			soff = _dwarf_decode_sleb128(&p);
841260684Skaiw			CFA.dw_offset_relevant = 1;
842260684Skaiw			CFA.dw_value_type = DW_EXPR_OFFSET;
843260684Skaiw			CFA.dw_offset_or_block_len = soff * daf;
844260684Skaiw#ifdef FRAME_DEBUG
845260684Skaiw			printf("DW_CFA_def_cfa_offset_sf(soff=%jd)\n", soff);
846260684Skaiw#endif
847260684Skaiw			break;
848260684Skaiw		case DW_CFA_val_offset:
849260684Skaiw			*row_pc = pc;
850260684Skaiw			reg = _dwarf_decode_uleb128(&p);
851260684Skaiw			uoff = _dwarf_decode_uleb128(&p);
852260684Skaiw			CHECK_TABLE_SIZE(reg);
853260684Skaiw			RL[reg].dw_offset_relevant = 1;
854260684Skaiw			RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
855260684Skaiw			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
856260684Skaiw			RL[reg].dw_offset_or_block_len = uoff * daf;
857260684Skaiw#ifdef FRAME_DEBUG
858260684Skaiw			printf("DW_CFA_val_offset(reg=%ju,uoff=%ju)\n", reg,
859260684Skaiw			    uoff);
860260684Skaiw#endif
861260684Skaiw			break;
862260684Skaiw		case DW_CFA_val_offset_sf:
863260684Skaiw			*row_pc = pc;
864260684Skaiw			reg = _dwarf_decode_uleb128(&p);
865260684Skaiw			soff = _dwarf_decode_sleb128(&p);
866260684Skaiw			CHECK_TABLE_SIZE(reg);
867260684Skaiw			RL[reg].dw_offset_relevant = 1;
868260684Skaiw			RL[reg].dw_value_type = DW_EXPR_VAL_OFFSET;
869260684Skaiw			RL[reg].dw_regnum = dbg->dbg_frame_cfa_value;
870260684Skaiw			RL[reg].dw_offset_or_block_len = soff * daf;
871260684Skaiw#ifdef FRAME_DEBUG
872260684Skaiw			printf("DW_CFA_val_offset_sf(reg=%ju,soff=%jd)\n", reg,
873260684Skaiw			    soff);
874260684Skaiw#endif
875260684Skaiw			break;
876260684Skaiw		case DW_CFA_val_expression:
877260684Skaiw			*row_pc = pc;
878260684Skaiw			reg = _dwarf_decode_uleb128(&p);
879260684Skaiw			CHECK_TABLE_SIZE(reg);
880260684Skaiw			RL[reg].dw_offset_relevant = 0;
881260684Skaiw			RL[reg].dw_value_type = DW_EXPR_VAL_EXPRESSION;
882260684Skaiw			RL[reg].dw_offset_or_block_len =
883260684Skaiw			    _dwarf_decode_uleb128(&p);
884260684Skaiw			RL[reg].dw_block_ptr = p;
885260684Skaiw			p += RL[reg].dw_offset_or_block_len;
886260684Skaiw#ifdef FRAME_DEBUG
887260684Skaiw			printf("DW_CFA_val_expression\n");
888260684Skaiw#endif
889260684Skaiw			break;
890260684Skaiw		default:
891260684Skaiw			DWARF_SET_ERROR(dbg, error,
892260684Skaiw			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
893260684Skaiw			ret = DW_DLE_FRAME_INSTR_EXEC_ERROR;
894260684Skaiw			goto program_done;
895260684Skaiw		}
896260684Skaiw	}
897260684Skaiw
898260684Skaiwprogram_done:
899260684Skaiw
900260684Skaiw	free(init_rt->rt3_rules);
901260684Skaiw	free(init_rt);
902260684Skaiw	if (saved_rt) {
903260684Skaiw		free(saved_rt->rt3_rules);
904260684Skaiw		free(saved_rt);
905260684Skaiw	}
906260684Skaiw
907260684Skaiw	return (ret);
908260684Skaiw
909260684Skaiw#undef	CFA
910260684Skaiw#undef	INITCFA
911260684Skaiw#undef	RL
912260684Skaiw#undef	INITRL
913260684Skaiw#undef	CHECK_TABLE_SIZE
914260684Skaiw}
915260684Skaiw
916260684Skaiwstatic int
917276371Semaste_dwarf_frame_convert_inst(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts,
918276371Semaste    Dwarf_Unsigned len, Dwarf_Unsigned *count, Dwarf_Frame_Op *fop,
919276371Semaste    Dwarf_Frame_Op3 *fop3, Dwarf_Error *error)
920260684Skaiw{
921260684Skaiw	uint8_t *p, *pe;
922260684Skaiw	uint8_t high2, low6;
923260684Skaiw	uint64_t reg, reg2, uoff, soff, blen;
924260684Skaiw
925260684Skaiw#define	SET_BASE_OP(x)						\
926260684Skaiw	do {							\
927260684Skaiw		if (fop != NULL)				\
928260684Skaiw			fop[*count].fp_base_op = (x) >> 6;	\
929260684Skaiw		if (fop3 != NULL)				\
930260684Skaiw			fop3[*count].fp_base_op = (x) >> 6;	\
931260684Skaiw	} while(0)
932260684Skaiw
933260684Skaiw#define	SET_EXTENDED_OP(x)					\
934260684Skaiw	do {							\
935260684Skaiw		if (fop != NULL)				\
936260684Skaiw			fop[*count].fp_extended_op = (x);	\
937260684Skaiw		if (fop3 != NULL)				\
938260684Skaiw			fop3[*count].fp_extended_op = (x);	\
939260684Skaiw	} while(0)
940260684Skaiw
941260684Skaiw#define	SET_REGISTER(x)						\
942260684Skaiw	do {							\
943260684Skaiw		if (fop != NULL)				\
944260684Skaiw			fop[*count].fp_register = (x);		\
945260684Skaiw		if (fop3 != NULL)				\
946260684Skaiw			fop3[*count].fp_register = (x);		\
947260684Skaiw	} while(0)
948260684Skaiw
949260684Skaiw#define	SET_OFFSET(x)						\
950260684Skaiw	do {							\
951260684Skaiw		if (fop != NULL)				\
952260684Skaiw			fop[*count].fp_offset = (x);		\
953260684Skaiw		if (fop3 != NULL)				\
954260684Skaiw			fop3[*count].fp_offset_or_block_len =	\
955260684Skaiw			    (x);				\
956260684Skaiw	} while(0)
957260684Skaiw
958260684Skaiw#define	SET_INSTR_OFFSET(x)					\
959260684Skaiw	do {							\
960260684Skaiw		if (fop != NULL)				\
961260684Skaiw			fop[*count].fp_instr_offset = (x);	\
962260684Skaiw		if (fop3 != NULL)				\
963260684Skaiw			fop3[*count].fp_instr_offset = (x);	\
964260684Skaiw	} while(0)
965260684Skaiw
966260684Skaiw#define	SET_BLOCK_LEN(x)					\
967260684Skaiw	do {							\
968260684Skaiw		if (fop3 != NULL)				\
969260684Skaiw			fop3[*count].fp_offset_or_block_len =	\
970260684Skaiw			    (x);				\
971260684Skaiw	} while(0)
972260684Skaiw
973260684Skaiw#define	SET_EXPR_BLOCK(addr, len)					\
974260684Skaiw	do {								\
975260684Skaiw		if (fop3 != NULL) {					\
976260684Skaiw			fop3[*count].fp_expr_block =			\
977260684Skaiw			    malloc((size_t) (len));			\
978260684Skaiw			if (fop3[*count].fp_expr_block == NULL)	{	\
979260684Skaiw				DWARF_SET_ERROR(dbg, error,		\
980260684Skaiw				    DW_DLE_MEMORY);			\
981260684Skaiw				return (DW_DLE_MEMORY);			\
982260684Skaiw			}						\
983260684Skaiw			memcpy(&fop3[*count].fp_expr_block,		\
984260684Skaiw			    (addr), (len));				\
985260684Skaiw		}							\
986260684Skaiw	} while(0)
987260684Skaiw
988260684Skaiw	*count = 0;
989260684Skaiw
990260684Skaiw	p = insts;
991260684Skaiw	pe = p + len;
992260684Skaiw
993260684Skaiw	while (p < pe) {
994260684Skaiw
995260684Skaiw		SET_INSTR_OFFSET(p - insts);
996260684Skaiw
997260684Skaiw		if (*p == DW_CFA_nop) {
998260684Skaiw			p++;
999260684Skaiw			(*count)++;
1000260684Skaiw			continue;
1001260684Skaiw		}
1002260684Skaiw
1003260684Skaiw		high2 = *p & 0xc0;
1004260684Skaiw		low6 = *p & 0x3f;
1005260684Skaiw		p++;
1006260684Skaiw
1007260684Skaiw		if (high2 > 0) {
1008260684Skaiw			switch (high2) {
1009260684Skaiw			case DW_CFA_advance_loc:
1010260684Skaiw				SET_BASE_OP(high2);
1011260684Skaiw				SET_OFFSET(low6);
1012260684Skaiw				break;
1013260684Skaiw			case DW_CFA_offset:
1014260684Skaiw				SET_BASE_OP(high2);
1015260684Skaiw				SET_REGISTER(low6);
1016260684Skaiw				uoff = _dwarf_decode_uleb128(&p);
1017260684Skaiw				SET_OFFSET(uoff);
1018260684Skaiw				break;
1019260684Skaiw			case DW_CFA_restore:
1020260684Skaiw				SET_BASE_OP(high2);
1021260684Skaiw				SET_REGISTER(low6);
1022260684Skaiw				break;
1023260684Skaiw			default:
1024260684Skaiw				DWARF_SET_ERROR(dbg, error,
1025260684Skaiw				    DW_DLE_FRAME_INSTR_EXEC_ERROR);
1026260684Skaiw				return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1027260684Skaiw			}
1028260684Skaiw
1029260684Skaiw			(*count)++;
1030260684Skaiw			continue;
1031260684Skaiw		}
1032260684Skaiw
1033260684Skaiw		SET_EXTENDED_OP(low6);
1034260684Skaiw
1035260684Skaiw		switch (low6) {
1036260684Skaiw		case DW_CFA_set_loc:
1037276371Semaste			uoff = dbg->decode(&p, addr_size);
1038260684Skaiw			SET_OFFSET(uoff);
1039260684Skaiw			break;
1040260684Skaiw		case DW_CFA_advance_loc1:
1041260684Skaiw			uoff = dbg->decode(&p, 1);
1042260684Skaiw			SET_OFFSET(uoff);
1043260684Skaiw			break;
1044260684Skaiw		case DW_CFA_advance_loc2:
1045260684Skaiw			uoff = dbg->decode(&p, 2);
1046260684Skaiw			SET_OFFSET(uoff);
1047260684Skaiw			break;
1048260684Skaiw		case DW_CFA_advance_loc4:
1049260684Skaiw			uoff = dbg->decode(&p, 4);
1050260684Skaiw			SET_OFFSET(uoff);
1051260684Skaiw			break;
1052260684Skaiw		case DW_CFA_offset_extended:
1053260684Skaiw		case DW_CFA_def_cfa:
1054260684Skaiw		case DW_CFA_val_offset:
1055260684Skaiw			reg = _dwarf_decode_uleb128(&p);
1056260684Skaiw			uoff = _dwarf_decode_uleb128(&p);
1057260684Skaiw			SET_REGISTER(reg);
1058260684Skaiw			SET_OFFSET(uoff);
1059260684Skaiw			break;
1060260684Skaiw		case DW_CFA_restore_extended:
1061260684Skaiw		case DW_CFA_undefined:
1062260684Skaiw		case DW_CFA_same_value:
1063260684Skaiw		case DW_CFA_def_cfa_register:
1064260684Skaiw			reg = _dwarf_decode_uleb128(&p);
1065260684Skaiw			SET_REGISTER(reg);
1066260684Skaiw			break;
1067260684Skaiw		case DW_CFA_register:
1068260684Skaiw			reg = _dwarf_decode_uleb128(&p);
1069260684Skaiw			reg2 = _dwarf_decode_uleb128(&p);
1070260684Skaiw			SET_REGISTER(reg);
1071260684Skaiw			SET_OFFSET(reg2);
1072260684Skaiw			break;
1073260684Skaiw		case DW_CFA_remember_state:
1074260684Skaiw		case DW_CFA_restore_state:
1075260684Skaiw			break;
1076260684Skaiw		case DW_CFA_def_cfa_offset:
1077260684Skaiw			uoff = _dwarf_decode_uleb128(&p);
1078260684Skaiw			SET_OFFSET(uoff);
1079260684Skaiw			break;
1080260684Skaiw		case DW_CFA_def_cfa_expression:
1081260684Skaiw			blen = _dwarf_decode_uleb128(&p);
1082260684Skaiw			SET_BLOCK_LEN(blen);
1083260684Skaiw			SET_EXPR_BLOCK(p, blen);
1084260684Skaiw			p += blen;
1085260684Skaiw			break;
1086260684Skaiw		case DW_CFA_expression:
1087260684Skaiw		case DW_CFA_val_expression:
1088260684Skaiw			reg = _dwarf_decode_uleb128(&p);
1089260684Skaiw			blen = _dwarf_decode_uleb128(&p);
1090260684Skaiw			SET_REGISTER(reg);
1091260684Skaiw			SET_BLOCK_LEN(blen);
1092260684Skaiw			SET_EXPR_BLOCK(p, blen);
1093260684Skaiw			p += blen;
1094260684Skaiw			break;
1095260684Skaiw		case DW_CFA_offset_extended_sf:
1096260684Skaiw		case DW_CFA_def_cfa_sf:
1097260684Skaiw		case DW_CFA_val_offset_sf:
1098260684Skaiw			reg = _dwarf_decode_uleb128(&p);
1099260684Skaiw			soff = _dwarf_decode_sleb128(&p);
1100260684Skaiw			SET_REGISTER(reg);
1101260684Skaiw			SET_OFFSET(soff);
1102260684Skaiw			break;
1103260684Skaiw		case DW_CFA_def_cfa_offset_sf:
1104260684Skaiw			soff = _dwarf_decode_sleb128(&p);
1105260684Skaiw			SET_OFFSET(soff);
1106260684Skaiw			break;
1107260684Skaiw		default:
1108260684Skaiw			DWARF_SET_ERROR(dbg, error,
1109260684Skaiw			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
1110260684Skaiw			return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1111260684Skaiw		}
1112260684Skaiw
1113260684Skaiw		(*count)++;
1114260684Skaiw	}
1115260684Skaiw
1116260684Skaiw	return (DW_DLE_NONE);
1117260684Skaiw}
1118260684Skaiw
1119260684Skaiwint
1120276371Semaste_dwarf_frame_get_fop(Dwarf_Debug dbg, uint8_t addr_size, uint8_t *insts,
1121276371Semaste    Dwarf_Unsigned len, Dwarf_Frame_Op **ret_oplist, Dwarf_Signed *ret_opcnt,
1122276371Semaste    Dwarf_Error *error)
1123260684Skaiw{
1124260684Skaiw	Dwarf_Frame_Op *oplist;
1125260684Skaiw	Dwarf_Unsigned count;
1126260684Skaiw	int ret;
1127260684Skaiw
1128276371Semaste	ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count,
1129276371Semaste	    NULL, NULL, error);
1130260684Skaiw	if (ret != DW_DLE_NONE)
1131260684Skaiw		return (ret);
1132260684Skaiw
1133260684Skaiw	if ((oplist = calloc(count, sizeof(Dwarf_Frame_Op))) == NULL) {
1134260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1135260684Skaiw		return (DW_DLE_MEMORY);
1136260684Skaiw	}
1137260684Skaiw
1138276371Semaste	ret = _dwarf_frame_convert_inst(dbg, addr_size, insts, len, &count,
1139276371Semaste	    oplist, NULL, error);
1140260684Skaiw	if (ret != DW_DLE_NONE) {
1141260684Skaiw		free(oplist);
1142260684Skaiw		return (ret);
1143260684Skaiw	}
1144260684Skaiw
1145260684Skaiw	*ret_oplist = oplist;
1146260684Skaiw	*ret_opcnt = count;
1147260684Skaiw
1148260684Skaiw	return (DW_DLE_NONE);
1149260684Skaiw}
1150260684Skaiw
1151260684Skaiwint
1152260684Skaiw_dwarf_frame_regtable_copy(Dwarf_Debug dbg, Dwarf_Regtable3 **dest,
1153260684Skaiw    Dwarf_Regtable3 *src, Dwarf_Error *error)
1154260684Skaiw{
1155260684Skaiw	int i;
1156260684Skaiw
1157260684Skaiw	assert(dest != NULL);
1158260684Skaiw	assert(src != NULL);
1159260684Skaiw
1160260684Skaiw	if (*dest == NULL) {
1161260684Skaiw		if ((*dest = malloc(sizeof(Dwarf_Regtable3))) == NULL) {
1162260684Skaiw			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1163260684Skaiw			return (DW_DLE_MEMORY);
1164260684Skaiw		}
1165260684Skaiw		(*dest)->rt3_reg_table_size = src->rt3_reg_table_size;
1166260684Skaiw		(*dest)->rt3_rules = malloc(src->rt3_reg_table_size *
1167260684Skaiw		    sizeof(Dwarf_Regtable_Entry3));
1168260684Skaiw		if ((*dest)->rt3_rules == NULL) {
1169260684Skaiw			free(*dest);
1170260684Skaiw			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1171260684Skaiw			return (DW_DLE_MEMORY);
1172260684Skaiw		}
1173260684Skaiw	}
1174260684Skaiw
1175260684Skaiw	memcpy(&(*dest)->rt3_cfa_rule, &src->rt3_cfa_rule,
1176260684Skaiw	    sizeof(Dwarf_Regtable_Entry3));
1177260684Skaiw
1178260684Skaiw	for (i = 0; i < (*dest)->rt3_reg_table_size &&
1179260684Skaiw	     i < src->rt3_reg_table_size; i++)
1180260684Skaiw		memcpy(&(*dest)->rt3_rules[i], &src->rt3_rules[i],
1181260684Skaiw		    sizeof(Dwarf_Regtable_Entry3));
1182260684Skaiw
1183260684Skaiw	for (; i < (*dest)->rt3_reg_table_size; i++)
1184260684Skaiw		(*dest)->rt3_rules[i].dw_regnum =
1185260684Skaiw		    dbg->dbg_frame_undefined_value;
1186260684Skaiw
1187260684Skaiw	return (DW_DLE_NONE);
1188260684Skaiw}
1189260684Skaiw
1190260684Skaiwint
1191260684Skaiw_dwarf_frame_get_internal_table(Dwarf_Fde fde, Dwarf_Addr pc_req,
1192260684Skaiw    Dwarf_Regtable3 **ret_rt, Dwarf_Addr *ret_row_pc, Dwarf_Error *error)
1193260684Skaiw{
1194260684Skaiw	Dwarf_Debug dbg;
1195260684Skaiw	Dwarf_Cie cie;
1196260684Skaiw	Dwarf_Regtable3 *rt;
1197260684Skaiw	Dwarf_Addr row_pc;
1198260684Skaiw	int i, ret;
1199260684Skaiw
1200260684Skaiw	assert(ret_rt != NULL);
1201260684Skaiw
1202260684Skaiw	dbg = fde->fde_dbg;
1203260684Skaiw	assert(dbg != NULL);
1204260684Skaiw
1205260684Skaiw	rt = dbg->dbg_internal_reg_table;
1206260684Skaiw
1207260684Skaiw	/* Clear the content of regtable from previous run. */
1208260684Skaiw	memset(&rt->rt3_cfa_rule, 0, sizeof(Dwarf_Regtable_Entry3));
1209260684Skaiw	memset(rt->rt3_rules, 0, rt->rt3_reg_table_size *
1210260684Skaiw	    sizeof(Dwarf_Regtable_Entry3));
1211260684Skaiw
1212260684Skaiw	/* Set rules to initial values. */
1213260684Skaiw	for (i = 0; i < rt->rt3_reg_table_size; i++)
1214260684Skaiw		rt->rt3_rules[i].dw_regnum = dbg->dbg_frame_rule_initial_value;
1215260684Skaiw
1216260684Skaiw	/* Run initial instructions in CIE. */
1217260684Skaiw	cie = fde->fde_cie;
1218260684Skaiw	assert(cie != NULL);
1219276371Semaste	ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize,
1220276371Semaste	    cie->cie_initinst, cie->cie_instlen, cie->cie_caf, cie->cie_daf, 0,
1221276371Semaste	    ~0ULL, &row_pc, error);
1222260684Skaiw	if (ret != DW_DLE_NONE)
1223260684Skaiw		return (ret);
1224260684Skaiw
1225260684Skaiw	/* Run instructions in FDE. */
1226260684Skaiw	if (pc_req >= fde->fde_initloc) {
1227276371Semaste		ret = _dwarf_frame_run_inst(dbg, rt, cie->cie_addrsize,
1228276371Semaste		    fde->fde_inst, fde->fde_instlen, cie->cie_caf,
1229276371Semaste		    cie->cie_daf, fde->fde_initloc, pc_req, &row_pc, error);
1230260684Skaiw		if (ret != DW_DLE_NONE)
1231260684Skaiw			return (ret);
1232260684Skaiw	}
1233260684Skaiw
1234260684Skaiw	*ret_rt = rt;
1235260684Skaiw	*ret_row_pc = row_pc;
1236260684Skaiw
1237260684Skaiw	return (DW_DLE_NONE);
1238260684Skaiw}
1239260684Skaiw
1240260684Skaiwvoid
1241260684Skaiw_dwarf_frame_cleanup(Dwarf_Debug dbg)
1242260684Skaiw{
1243260684Skaiw	Dwarf_Regtable3 *rt;
1244260684Skaiw
1245260684Skaiw	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ);
1246260684Skaiw
1247260684Skaiw	if (dbg->dbg_internal_reg_table) {
1248260684Skaiw		rt = dbg->dbg_internal_reg_table;
1249260684Skaiw		free(rt->rt3_rules);
1250260684Skaiw		free(rt);
1251260684Skaiw		dbg->dbg_internal_reg_table = NULL;
1252260684Skaiw	}
1253260684Skaiw
1254260684Skaiw	if (dbg->dbg_frame) {
1255260684Skaiw		_dwarf_frame_section_cleanup(dbg->dbg_frame);
1256260684Skaiw		dbg->dbg_frame = NULL;
1257260684Skaiw	}
1258260684Skaiw
1259260684Skaiw	if (dbg->dbg_eh_frame) {
1260260684Skaiw		_dwarf_frame_section_cleanup(dbg->dbg_eh_frame);
1261260684Skaiw		dbg->dbg_eh_frame = NULL;
1262260684Skaiw	}
1263260684Skaiw}
1264260684Skaiw
1265260684Skaiwint
1266260684Skaiw_dwarf_frame_section_load(Dwarf_Debug dbg, Dwarf_Error *error)
1267260684Skaiw{
1268260684Skaiw	Dwarf_Section *ds;
1269260684Skaiw
1270260684Skaiw	if ((ds = _dwarf_find_section(dbg, ".debug_frame")) != NULL) {
1271260684Skaiw		return (_dwarf_frame_section_init(dbg, &dbg->dbg_frame,
1272260684Skaiw		    ds, 0, error));
1273260684Skaiw	}
1274260684Skaiw
1275260684Skaiw	return (DW_DLE_NONE);
1276260684Skaiw}
1277260684Skaiw
1278260684Skaiwint
1279260684Skaiw_dwarf_frame_section_load_eh(Dwarf_Debug dbg, Dwarf_Error *error)
1280260684Skaiw{
1281260684Skaiw	Dwarf_Section *ds;
1282260684Skaiw
1283260684Skaiw	if ((ds = _dwarf_find_section(dbg, ".eh_frame")) != NULL) {
1284260684Skaiw		return (_dwarf_frame_section_init(dbg, &dbg->dbg_eh_frame,
1285260684Skaiw		    ds, 1, error));
1286260684Skaiw	}
1287260684Skaiw
1288260684Skaiw	return (DW_DLE_NONE);
1289260684Skaiw}
1290260684Skaiw
1291260684Skaiwvoid
1292260684Skaiw_dwarf_frame_params_init(Dwarf_Debug dbg)
1293260684Skaiw{
1294260684Skaiw
1295260684Skaiw	/* Initialise call frame related parameters. */
1296260684Skaiw	dbg->dbg_frame_rule_table_size = DW_FRAME_LAST_REG_NUM;
1297260684Skaiw	dbg->dbg_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE;
1298260684Skaiw	dbg->dbg_frame_cfa_value = DW_FRAME_CFA_COL3;
1299260684Skaiw	dbg->dbg_frame_same_value = DW_FRAME_SAME_VAL;
1300260684Skaiw	dbg->dbg_frame_undefined_value = DW_FRAME_UNDEFINED_VAL;
1301260684Skaiw}
1302260684Skaiw
1303260684Skaiwint
1304260684Skaiw_dwarf_frame_interal_table_init(Dwarf_Debug dbg, Dwarf_Error *error)
1305260684Skaiw{
1306260684Skaiw	Dwarf_Regtable3 *rt;
1307260684Skaiw
1308260684Skaiw	if (dbg->dbg_internal_reg_table != NULL)
1309260684Skaiw		return (DW_DLE_NONE);
1310260684Skaiw
1311260684Skaiw	/* Initialise internal register table. */
1312260684Skaiw	if ((rt = calloc(1, sizeof(Dwarf_Regtable3))) == NULL) {
1313260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1314260684Skaiw		return (DW_DLE_MEMORY);
1315260684Skaiw	}
1316260684Skaiw
1317260684Skaiw	rt->rt3_reg_table_size = dbg->dbg_frame_rule_table_size;
1318260684Skaiw	if ((rt->rt3_rules = calloc(rt->rt3_reg_table_size,
1319260684Skaiw	    sizeof(Dwarf_Regtable_Entry3))) == NULL) {
1320260684Skaiw		free(rt);
1321260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1322260684Skaiw		return (DW_DLE_MEMORY);
1323260684Skaiw	}
1324260684Skaiw
1325260684Skaiw	dbg->dbg_internal_reg_table = rt;
1326260684Skaiw
1327260684Skaiw	return (DW_DLE_NONE);
1328260684Skaiw}
1329260684Skaiw
1330260684Skaiw#define	_FDE_INST_INIT_SIZE	128
1331260684Skaiw
1332260684Skaiwint
1333260684Skaiw_dwarf_frame_fde_add_inst(Dwarf_P_Fde fde, Dwarf_Small op, Dwarf_Unsigned val1,
1334260684Skaiw    Dwarf_Unsigned val2, Dwarf_Error *error)
1335260684Skaiw{
1336260684Skaiw	Dwarf_P_Debug dbg;
1337260684Skaiw	uint8_t high2, low6;
1338260684Skaiw	int ret;
1339260684Skaiw
1340260684Skaiw#define	ds	fde
1341260684Skaiw#define	ds_data	fde_inst
1342260684Skaiw#define	ds_cap	fde_instcap
1343260684Skaiw#define	ds_size	fde_instlen
1344260684Skaiw
1345260684Skaiw	assert(fde != NULL && fde->fde_dbg != NULL);
1346260684Skaiw	dbg = fde->fde_dbg;
1347260684Skaiw
1348260684Skaiw	if (fde->fde_inst == NULL) {
1349260684Skaiw		fde->fde_instcap = _FDE_INST_INIT_SIZE;
1350260684Skaiw		fde->fde_instlen = 0;
1351260684Skaiw		if ((fde->fde_inst = malloc((size_t) fde->fde_instcap)) ==
1352260684Skaiw		    NULL) {
1353260684Skaiw			DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
1354260684Skaiw			return (DW_DLE_MEMORY);
1355260684Skaiw		}
1356260684Skaiw	}
1357260684Skaiw	assert(fde->fde_instcap != 0);
1358260684Skaiw
1359260684Skaiw	RCHECK(WRITE_VALUE(op, 1));
1360260684Skaiw	if (op == DW_CFA_nop)
1361260684Skaiw		return (DW_DLE_NONE);
1362260684Skaiw
1363260684Skaiw	high2 = op & 0xc0;
1364260684Skaiw	low6 = op & 0x3f;
1365260684Skaiw
1366260684Skaiw	if (high2 > 0) {
1367260684Skaiw		switch (high2) {
1368260684Skaiw		case DW_CFA_advance_loc:
1369260684Skaiw		case DW_CFA_restore:
1370260684Skaiw			break;
1371260684Skaiw		case DW_CFA_offset:
1372260684Skaiw			RCHECK(WRITE_ULEB128(val1));
1373260684Skaiw			break;
1374260684Skaiw		default:
1375260684Skaiw			DWARF_SET_ERROR(dbg, error,
1376260684Skaiw			    DW_DLE_FRAME_INSTR_EXEC_ERROR);
1377260684Skaiw			return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1378260684Skaiw		}
1379260684Skaiw		return (DW_DLE_NONE);
1380260684Skaiw	}
1381260684Skaiw
1382260684Skaiw	switch (low6) {
1383260684Skaiw	case DW_CFA_set_loc:
1384260684Skaiw		RCHECK(WRITE_VALUE(val1, dbg->dbg_pointer_size));
1385260684Skaiw		break;
1386260684Skaiw	case DW_CFA_advance_loc1:
1387260684Skaiw		RCHECK(WRITE_VALUE(val1, 1));
1388260684Skaiw		break;
1389260684Skaiw	case DW_CFA_advance_loc2:
1390260684Skaiw		RCHECK(WRITE_VALUE(val1, 2));
1391260684Skaiw		break;
1392260684Skaiw	case DW_CFA_advance_loc4:
1393260684Skaiw		RCHECK(WRITE_VALUE(val1, 4));
1394260684Skaiw		break;
1395260684Skaiw	case DW_CFA_offset_extended:
1396260684Skaiw	case DW_CFA_def_cfa:
1397260684Skaiw	case DW_CFA_register:
1398260684Skaiw		RCHECK(WRITE_ULEB128(val1));
1399260684Skaiw		RCHECK(WRITE_ULEB128(val2));
1400260684Skaiw		break;
1401260684Skaiw	case DW_CFA_restore_extended:
1402260684Skaiw	case DW_CFA_undefined:
1403260684Skaiw	case DW_CFA_same_value:
1404260684Skaiw	case DW_CFA_def_cfa_register:
1405260684Skaiw	case DW_CFA_def_cfa_offset:
1406260684Skaiw		RCHECK(WRITE_ULEB128(val1));
1407260684Skaiw		break;
1408260684Skaiw	case DW_CFA_remember_state:
1409260684Skaiw	case DW_CFA_restore_state:
1410260684Skaiw		break;
1411260684Skaiw	default:
1412260684Skaiw		DWARF_SET_ERROR(dbg, error, DW_DLE_FRAME_INSTR_EXEC_ERROR);
1413260684Skaiw		return (DW_DLE_FRAME_INSTR_EXEC_ERROR);
1414260684Skaiw	}
1415260684Skaiw
1416260684Skaiw	return (DW_DLE_NONE);
1417260684Skaiw
1418260684Skaiwgen_fail:
1419260684Skaiw	return (ret);
1420260684Skaiw
1421260684Skaiw#undef	ds
1422260684Skaiw#undef	ds_data
1423260684Skaiw#undef	ds_cap
1424260684Skaiw#undef	ds_size
1425260684Skaiw}
1426260684Skaiw
1427260684Skaiwstatic int
1428260684Skaiw_dwarf_frame_gen_cie(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_P_Cie cie,
1429260684Skaiw    Dwarf_Error *error)
1430260684Skaiw{
1431260684Skaiw	Dwarf_Unsigned len;
1432260684Skaiw	uint64_t offset;
1433260684Skaiw	int ret;
1434260684Skaiw
1435260684Skaiw	assert(dbg != NULL && ds != NULL && cie != NULL);
1436260684Skaiw
1437260684Skaiw	cie->cie_offset = offset = ds->ds_size;
1438260684Skaiw	cie->cie_length = 0;
1439260684Skaiw	cie->cie_version = 1;
1440260684Skaiw
1441260684Skaiw	/* Length placeholder. */
1442260684Skaiw	RCHECK(WRITE_VALUE(cie->cie_length, 4));
1443260684Skaiw
1444260684Skaiw	/* .debug_frame use CIE id ~0. */
1445260684Skaiw	RCHECK(WRITE_VALUE(~0U, 4));
1446260684Skaiw
1447260684Skaiw	/* .debug_frame version is 1. (DWARF2) */
1448260684Skaiw	RCHECK(WRITE_VALUE(cie->cie_version, 1));
1449260684Skaiw
1450260684Skaiw	/* Write augmentation, if present. */
1451260684Skaiw	if (cie->cie_augment != NULL)
1452260684Skaiw		RCHECK(WRITE_BLOCK(cie->cie_augment,
1453260684Skaiw		    strlen((char *) cie->cie_augment) + 1));
1454260684Skaiw	else
1455260684Skaiw		RCHECK(WRITE_VALUE(0, 1));
1456260684Skaiw
1457260684Skaiw	/* Write caf, daf and ra. */
1458260684Skaiw	RCHECK(WRITE_ULEB128(cie->cie_caf));
1459260684Skaiw	RCHECK(WRITE_SLEB128(cie->cie_daf));
1460260684Skaiw	RCHECK(WRITE_VALUE(cie->cie_ra, 1));
1461260684Skaiw
1462260684Skaiw	/* Write initial instructions, if present. */
1463260684Skaiw	if (cie->cie_initinst != NULL)
1464260684Skaiw		RCHECK(WRITE_BLOCK(cie->cie_initinst, cie->cie_instlen));
1465260684Skaiw
1466260684Skaiw	/* Add padding. */
1467260684Skaiw	len = ds->ds_size - cie->cie_offset - 4;
1468260684Skaiw	cie->cie_length = roundup(len, dbg->dbg_pointer_size);
1469260684Skaiw	while (len++ < cie->cie_length)
1470260684Skaiw		RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
1471260684Skaiw
1472260684Skaiw	/* Fill in the length field. */
1473260684Skaiw	dbg->write(ds->ds_data, &offset, cie->cie_length, 4);
1474260684Skaiw
1475260684Skaiw	return (DW_DLE_NONE);
1476260684Skaiw
1477260684Skaiwgen_fail:
1478260684Skaiw	return (ret);
1479260684Skaiw}
1480260684Skaiw
1481260684Skaiwstatic int
1482260684Skaiw_dwarf_frame_gen_fde(Dwarf_P_Debug dbg, Dwarf_P_Section ds,
1483260684Skaiw    Dwarf_Rel_Section drs, Dwarf_P_Fde fde, Dwarf_Error *error)
1484260684Skaiw{
1485260684Skaiw	Dwarf_Unsigned len;
1486260684Skaiw	uint64_t offset;
1487260684Skaiw	int ret;
1488260684Skaiw
1489260684Skaiw	assert(dbg != NULL && ds != NULL && drs != NULL);
1490260684Skaiw	assert(fde != NULL && fde->fde_cie != NULL);
1491260684Skaiw
1492260684Skaiw	fde->fde_offset = offset = ds->ds_size;
1493260684Skaiw	fde->fde_length = 0;
1494260684Skaiw	fde->fde_cieoff = fde->fde_cie->cie_offset;
1495260684Skaiw
1496260684Skaiw	/* Length placeholder. */
1497260684Skaiw	RCHECK(WRITE_VALUE(fde->fde_length, 4));
1498260684Skaiw
1499260684Skaiw	/* Write CIE pointer. */
1500260684Skaiw	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4,
1501260684Skaiw	    ds->ds_size, 0, fde->fde_cieoff, ".debug_frame", error));
1502260684Skaiw
1503260684Skaiw	/* Write FDE initial location. */
1504260684Skaiw	RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
1505260684Skaiw	    dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
1506260684Skaiw	    fde->fde_initloc, NULL, error));
1507260684Skaiw
1508260684Skaiw	/*
1509260684Skaiw	 * Write FDE address range. Use a pair of relocation entries if
1510260684Skaiw	 * application provided end symbol index. Otherwise write the
1511260684Skaiw	 * length without assoicating any relocation info.
1512260684Skaiw	 */
1513260684Skaiw	if (fde->fde_esymndx > 0)
1514260684Skaiw		RCHECK(_dwarf_reloc_entry_add_pair(dbg, drs, ds,
1515260684Skaiw		    dbg->dbg_pointer_size, ds->ds_size, fde->fde_symndx,
1516260684Skaiw		    fde->fde_esymndx, fde->fde_initloc, fde->fde_eoff, error));
1517260684Skaiw	else
1518260684Skaiw		RCHECK(WRITE_VALUE(fde->fde_adrange, dbg->dbg_pointer_size));
1519260684Skaiw
1520260684Skaiw	/* Write FDE frame instructions. */
1521260684Skaiw	RCHECK(WRITE_BLOCK(fde->fde_inst, fde->fde_instlen));
1522260684Skaiw
1523260684Skaiw	/* Add padding. */
1524260684Skaiw	len = ds->ds_size - fde->fde_offset - 4;
1525260684Skaiw	fde->fde_length = roundup(len, dbg->dbg_pointer_size);
1526260684Skaiw	while (len++ < fde->fde_length)
1527260684Skaiw		RCHECK(WRITE_VALUE(DW_CFA_nop, 1));
1528260684Skaiw
1529260684Skaiw	/* Fill in the length field. */
1530260684Skaiw	dbg->write(ds->ds_data, &offset, fde->fde_length, 4);
1531260684Skaiw
1532260684Skaiw	return (DW_DLE_NONE);
1533260684Skaiw
1534260684Skaiwgen_fail:
1535260684Skaiw	return (ret);
1536260684Skaiw}
1537260684Skaiw
1538260684Skaiwint
1539260684Skaiw_dwarf_frame_gen(Dwarf_P_Debug dbg, Dwarf_Error *error)
1540260684Skaiw{
1541260684Skaiw	Dwarf_P_Section ds;
1542260684Skaiw	Dwarf_Rel_Section drs;
1543260684Skaiw	Dwarf_P_Cie cie;
1544260684Skaiw	Dwarf_P_Fde fde;
1545260684Skaiw	int ret;
1546260684Skaiw
1547260684Skaiw	if (STAILQ_EMPTY(&dbg->dbgp_cielist))
1548260684Skaiw		return (DW_DLE_NONE);
1549260684Skaiw
1550260684Skaiw	/* Create .debug_frame section. */
1551260684Skaiw	if ((ret = _dwarf_section_init(dbg, &ds, ".debug_frame", 0, error)) !=
1552260684Skaiw	    DW_DLE_NONE)
1553260684Skaiw		goto gen_fail0;
1554260684Skaiw
1555260684Skaiw	/* Create relocation section for .debug_frame */
1556260684Skaiw	RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error));
1557260684Skaiw
1558260684Skaiw	/* Generate list of CIE. */
1559260684Skaiw	STAILQ_FOREACH(cie, &dbg->dbgp_cielist, cie_next)
1560260684Skaiw		RCHECK(_dwarf_frame_gen_cie(dbg, ds, cie, error));
1561260684Skaiw
1562260684Skaiw	/* Generate list of FDE. */
1563260684Skaiw	STAILQ_FOREACH(fde, &dbg->dbgp_fdelist, fde_next)
1564260684Skaiw		RCHECK(_dwarf_frame_gen_fde(dbg, ds, drs, fde, error));
1565260684Skaiw
1566260684Skaiw	/* Inform application the creation of .debug_frame ELF section. */
1567260684Skaiw	RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error));
1568260684Skaiw
1569260684Skaiw	/* Finalize relocation section for .debug_frame */
1570260684Skaiw	RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error));
1571260684Skaiw
1572260684Skaiw	return (DW_DLE_NONE);
1573260684Skaiw
1574260684Skaiwgen_fail:
1575260684Skaiw	_dwarf_reloc_section_free(dbg, &drs);
1576260684Skaiw
1577260684Skaiwgen_fail0:
1578260684Skaiw	_dwarf_section_free(dbg, &ds);
1579260684Skaiw
1580260684Skaiw	return (ret);
1581260684Skaiw}
1582260684Skaiw
1583260684Skaiwvoid
1584260684Skaiw_dwarf_frame_pro_cleanup(Dwarf_P_Debug dbg)
1585260684Skaiw{
1586260684Skaiw	Dwarf_P_Cie cie, tcie;
1587260684Skaiw	Dwarf_P_Fde fde, tfde;
1588260684Skaiw
1589260684Skaiw	assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
1590260684Skaiw
1591260684Skaiw	STAILQ_FOREACH_SAFE(cie, &dbg->dbgp_cielist, cie_next, tcie) {
1592260684Skaiw		STAILQ_REMOVE(&dbg->dbgp_cielist, cie, _Dwarf_Cie, cie_next);
1593260684Skaiw		if (cie->cie_augment)
1594260684Skaiw			free(cie->cie_augment);
1595260684Skaiw		if (cie->cie_initinst)
1596260684Skaiw			free(cie->cie_initinst);
1597260684Skaiw		free(cie);
1598260684Skaiw	}
1599260684Skaiw	dbg->dbgp_cielen = 0;
1600260684Skaiw
1601260684Skaiw	STAILQ_FOREACH_SAFE(fde, &dbg->dbgp_fdelist, fde_next, tfde) {
1602260684Skaiw		STAILQ_REMOVE(&dbg->dbgp_fdelist, fde, _Dwarf_Fde, fde_next);
1603260684Skaiw		if (fde->fde_inst != NULL)
1604260684Skaiw			free(fde->fde_inst);
1605260684Skaiw		free(fde);
1606260684Skaiw	}
1607260684Skaiw	dbg->dbgp_fdelen = 0;
1608260684Skaiw}
1609