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