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