xref: /illumos-gate/usr/src/lib/libc/amd64/unwind/call_frame_inst.c (revision eb9a1df2aeb866bf1de4494433b6d7e5fa07b3ae)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  */
27 
28 /*
29  * interface used by unwind support to query frame descriptor info
30  */
31 
32 #ifndef _LIBCRUN_
33 #include "lint.h"
34 #endif
35 #include <sys/types.h>
36 #include "stack_unwind.h"
37 #include "unwind_context.h"
38 #include "reg_num.h"
39 
40 enum CFA_ops {
41 	DW_CFA_nop = 0x00,
42 	DW_CFA_set_loc = 0x01,
43 	DW_CFA_advance_loc1 = 0x02,
44 	DW_CFA_advance_loc2 = 0x03,
45 	DW_CFA_advance_loc4 = 0x04,
46 	DW_CFA_offset_extended = 0x05,
47 	DW_CFA_restore_extended = 0x06,
48 	DW_CFA_undefined = 0x07,
49 	DW_CFA_same_value = 0x08,
50 	DW_CFA_register = 0x09,
51 	DW_CFA_remember_state = 0x0a,
52 	DW_CFA_restore_state = 0x0b,
53 	DW_CFA_def_cfa = 0x0c,
54 	DW_CFA_def_cfa_register = 0x0d,
55 	DW_CFA_def_cfa_offset = 0x0e,
56 	DW_CFA_def_cfa_expression = 0x0f,
57 	DW_CFA_expression = 0x10,
58 	DW_CFA_offset_extended_sf = 0x11,
59 	DW_CFA_def_cfa_sf = 0x12,
60 	DW_CFA_def_cfa_offset_sf = 0x13,
61 	/* skip 9 values */
62 	DW_CFA_SUNW_advance_loc = 0x1d,
63 	DW_CFA_SUNW_offset = 0x1e,
64 	DW_CFA_SUNW_restore = 0x1f,
65 	DW_CFA_advance_loc = 0x40,
66 	DW_CFA_offset = 0x80,
67 	DW_CFA_restore = 0xc0
68 };
69 
70 struct operation_desc {
71 	enum operand_desc op1;
72 	enum operand_desc op2;
73 };
74 
75 struct operation_desc cfa_operations[] = {
76 	{NO_OPR, NO_OPR},	/* DW_CFA_nop */
77 	{ADDR, NO_OPR},		/* DW_CFA_set_loc - address */
78 	{UNUM8, NO_OPR},	/* DW_CFA_advance_loc1 - delta */
79 	{UNUM16, NO_OPR},	/* DW_CFA_advance_loc2 - delta */
80 	{UNUM32, NO_OPR},	/* DW_CFA_advance_loc4 - delta */
81 	{ULEB128, ULEB128_FAC},	/* DW_CFA_offset_extended - reg, */
82 				/* data factored offset */
83 	{ULEB128, NO_OPR},	/* DW_CFA_restore_extended - register */
84 	{ULEB128, NO_OPR},	/* DW_CFA_undefined - register */
85 	{ULEB128, NO_OPR},	/* DW_CFA_same_value - register */
86 	{ULEB128, ULEB128_SREG}, /* DW_CFA_register - register, register */
87 	{NO_OPR, NO_OPR},	/* DW_CFA_remember_state */
88 	{NO_OPR, NO_OPR},	/* DW_CFA_restore_state */
89 	{ULEB128_SREG, ULEB128}, /* DW_CFA_def_cfa - register, offset */
90 	{ULEB128_SREG, NO_OPR},	/* DW_CFA_def_cfa_register - register */
91 	{ULEB128, NO_OPR},	/* DW_CFA_def_cfa_offset - offset */
92 	{BLOCK, NO_OPR},	/* DW_CFA_def_cfa_expression - expression */
93 	{ULEB128, BLOCK},	/* DW_CFA_expression - reg, expression */
94 	{ULEB128, SLEB128_FAC},	/* DW_CFA_offset_extended_sf - reg, */
95 				/* data factored offset */
96 	{ULEB128_SREG, SLEB128_FAC},	/* DW_CFA_def_cfa_sf - reg, */
97 					/* data factored offset */
98 	{SLEB128_FAC, NO_OPR},	/* DW_CFA_def_cfa_offset_sf - */
99 				/* data fctored offset */
100 	{NO_OPR, NO_OPR},
101 	{NO_OPR, NO_OPR},
102 	{NO_OPR, NO_OPR},
103 	{NO_OPR, NO_OPR},
104 	{NO_OPR, NO_OPR},
105 	{NO_OPR, NO_OPR},
106 	{NO_OPR, NO_OPR},
107 	{NO_OPR, NO_OPR},
108 	{NO_OPR, NO_OPR},
109 	{UNUM6_CFAC, NO_OPR},	/* DW_CFA_SUNW_advance_loc - */
110 				/* code factored delta */
111 	{UNUM6, ULEB128_FAC},	/* DW_CFA_SUNW_offset - reg */
112 				/* data factored offset */
113 	{UNUM6, NO_OPR}		/* DW_CFA_SUNW_restore */
114 };
115 
116 uint64_t interpret_ops(void *data, void *data_end,
117 		ptrdiff_t reloc, uint64_t current_loc, uint64_t pc,
118 		struct register_state f_state[],
119 		struct register_state f_start_state[],
120 		int daf, int caf, int enc);
121 
122 /*
123  * The entry-point state of old_ctx defines the current
124  * suspended state of the caller (in new_ctx). If the old info
125  * will not be refered to again, old_ctx == new_ctx is OK
126  */
127 void
128 _Unw_Propagate_Registers(struct _Unwind_Context *old_ctx,
129 	struct _Unwind_Context *new_ctx)
130 {
131 	new_ctx->current_regs[SP_RSP] = old_ctx->cfa;
132 	new_ctx->pc = old_ctx->ra;
133 	new_ctx->current_regs[FP_RBP] = old_ctx->entry_regs[FP_RBP];
134 	new_ctx->current_regs[GPR_RBX] = old_ctx->entry_regs[GPR_RBX];
135 	new_ctx->current_regs[EIR_R12] = old_ctx->entry_regs[EIR_R12];
136 	new_ctx->current_regs[EIR_R13] = old_ctx->entry_regs[EIR_R13];
137 	new_ctx->current_regs[EIR_R14] = old_ctx->entry_regs[EIR_R14];
138 	new_ctx->current_regs[EIR_R15] = old_ctx->entry_regs[EIR_R15];
139 }
140 
141 void
142 fix_cfa(struct _Unwind_Context *ctx, struct register_state *rs)
143 {
144 	switch (rs[CF_ADDR].rule) {
145 	default:
146 		ctx->cfa = 0;
147 		break;
148 	case register_rule:	/* CFA = offset + source_reg */
149 		ctx->cfa = (ctx->current_regs)[rs[CF_ADDR].source_reg] +
150 		    rs[CF_ADDR].offset;
151 		break;
152 	case constant_rule:	/* CFA = offset */
153 		ctx->cfa = rs[CF_ADDR].offset;
154 		break;
155 	case indirect_rule:	/* CFA = *(offset + source_reg) */
156 		ctx->cfa = *(uint64_t *)
157 		    (ctx->current_regs[rs[CF_ADDR].source_reg] +
158 		    rs[CF_ADDR].offset);
159 		break;
160 	}
161 	ctx->entry_regs[SP_RSP] = ctx->cfa;
162 }
163 
164 void
165 fix_ra(struct _Unwind_Context *ctx, struct register_state *rs)
166 {
167 	switch (rs[RET_ADD].rule) {
168 	case undefined_rule:
169 	default:
170 		ctx->ra = 0;
171 		break;
172 	case offset_rule:	/* RA = *(offset + CFA) */
173 		ctx->ra = *(uint64_t *)(ctx->cfa + rs[RET_ADD].offset);
174 		break;
175 	case register_rule:	/* RA = offset + source_reg */
176 		ctx->ra = ctx->current_regs[rs[RET_ADD].source_reg] +
177 		    rs[RET_ADD].offset;
178 		break;
179 	case indirect_rule:	/* RA = *(offset + source_reg) */
180 		ctx->ra = *(uint64_t *)
181 		    (ctx->current_regs[rs[RET_ADD].source_reg] +
182 		    rs[RET_ADD].offset);
183 		break;
184 	}
185 }
186 
187 void
188 fix_reg(struct _Unwind_Context *ctx, struct register_state *rs, int index)
189 {
190 	switch (rs[index].rule) {
191 	default:
192 		ctx->entry_regs[index] = ctx->current_regs[index];
193 		break;
194 	case offset_rule:	/* target_reg = *(offset + CFA) */
195 		ctx->entry_regs[index] = *(uint64_t *)
196 		    (ctx->cfa + rs[index].offset);
197 		break;
198 	case is_offset_rule:	/* target_reg = offset + CFA */
199 		ctx->entry_regs[index] = ctx->cfa + rs[index].offset;
200 		break;
201 	case register_rule:	/* target_reg = offset + source_reg */
202 		ctx->entry_regs[index] =
203 		    ctx->current_regs[rs[index].source_reg] +
204 		    rs[index].offset;
205 		break;
206 	case constant_rule:	/* target_reg = offset */
207 		ctx->entry_regs[index] = rs[index].offset;
208 		break;
209 	case indirect_rule:	/* target_reg = *(offset + source_reg) */
210 		ctx->entry_regs[index] = *(uint64_t *)
211 		    (ctx->current_regs[rs[index].source_reg] +
212 		    rs[index].offset);
213 		break;
214 	}
215 }
216 
217 
218 /*
219  * Input: f->{cie_ops, cie_ops_end, fde_ops, fde_ops_end}
220  *			+ location of DWARF opcodes
221  *		  ctx->{current_regs, pc}
222  *			+ register values and pc at point of suspension
223  * Output: ctx->{entry_regs, cfa, ra}
224  *			+ register values when function was entered
225  *			+ Cannonical Frame Address
226  *			+ return address
227  */
228 uint64_t
229 _Unw_Rollback_Registers(struct eh_frame_fields *f,
230 	struct _Unwind_Context *ctx)
231 {
232 	/* GPRs, RET_ADD, and CF_ADDR */
233 	struct register_state func_state[18];
234 	struct register_state func_start_state[18];
235 	struct register_state nop = { 0, undefined_rule, 0 };
236 	int i;
237 	uint64_t  first_pc;
238 
239 	if (f == 0) {
240 		/*
241 		 * When no FDE we assume all routines have a frame pointer
242 		 * and pass back existing callee saves registers
243 		 */
244 		if (ctx->current_regs[FP_RBP] < ctx->current_regs[SP_RSP]) {
245 			ctx->cfa = 0;
246 			ctx->ra = 0;
247 			ctx->pc = 0;
248 			return (0);
249 		}
250 		ctx->entry_regs[FP_RBP] = ((uint64_t *)
251 		    (ctx->current_regs[FP_RBP]))[0];
252 		ctx->cfa = ctx->current_regs[FP_RBP] + 16;
253 		ctx->entry_regs[SP_RSP] = ctx->cfa;
254 		ctx->entry_regs[GPR_RBX] = ctx->current_regs[GPR_RBX];
255 		ctx->entry_regs[EIR_R12] = ctx->current_regs[EIR_R12];
256 		ctx->entry_regs[EIR_R13] = ctx->current_regs[EIR_R13];
257 		ctx->entry_regs[EIR_R14] = ctx->current_regs[EIR_R14];
258 		ctx->entry_regs[EIR_R15] = ctx->current_regs[EIR_R15];
259 		ctx->ra = ((uint64_t *)ctx->cfa)[-1];
260 		return (ctx->cfa);
261 	}
262 
263 	for (i = 0; i < 18; i++)
264 		func_start_state[i] = nop;
265 	first_pc = interpret_ops(f->cie_ops, f->cie_ops_end,
266 	    f->cie_reloc, ctx->func, ctx->pc, func_start_state, 0,
267 	    f->data_align, f->code_align, f->code_enc);
268 	for (i = 0; i < 18; i++)
269 		func_state[i] = func_start_state[i];
270 	(void) interpret_ops(f->fde_ops, f->fde_ops_end,
271 	    f->fde_reloc, first_pc, ctx->pc, func_state, func_start_state,
272 	    f->data_align, f->code_align, f->code_enc);
273 
274 	fix_cfa(ctx, func_state);
275 	if (ctx->cfa < ctx->current_regs[SP_RSP]) {
276 		ctx->cfa = 0;
277 		ctx->ra = 0;
278 		ctx->pc = 0;
279 		return (0);
280 	}
281 	fix_ra(ctx, func_state);
282 	fix_reg(ctx, func_state, GPR_RBX);
283 	fix_reg(ctx, func_state, FP_RBP);
284 	fix_reg(ctx, func_state, EIR_R12);
285 	fix_reg(ctx, func_state, EIR_R13);
286 	fix_reg(ctx, func_state, EIR_R14);
287 	fix_reg(ctx, func_state, EIR_R15);
288 
289 	return (ctx->cfa);
290 }
291 
292 /*
293  * remap two-bit opcodes into a separate range or grab eight-bit opcode
294  * and advance pointer past it.
295  */
296 static enum CFA_ops
297 separate_op(void **pp)
298 {
299 	uint8_t c = **((uint8_t **)pp);
300 
301 	if (c & 0xc0) {
302 		switch (c & 0xc0) {
303 		case DW_CFA_advance_loc:
304 			return (DW_CFA_SUNW_advance_loc);
305 		case DW_CFA_offset:
306 			return (DW_CFA_SUNW_offset);
307 		case DW_CFA_restore:
308 			return (DW_CFA_SUNW_restore);
309 		}
310 	} else {
311 		*pp = (void *)((*(intptr_t *)pp) + 1);
312 	}
313 	return (c);
314 }
315 
316 static uint64_t
317 extractuleb(void **datap)
318 {
319 	uint8_t *data = *(uint8_t **)datap;
320 	uint64_t res = 0;
321 	int more = 1;
322 	int shift = 0;
323 	int val;
324 
325 	while (more) {
326 		val = (*data) & 0x7f;
327 		more = ((*data++) & 0x80) >> 7;
328 		res = res | val << shift;
329 		shift += 7;
330 	}
331 	*datap = (void *)data;
332 	return (res);
333 }
334 
335 static uint64_t
336 extractsleb(void** datap)
337 {
338 	uint8_t *data = *datap;
339 	int64_t res = 0;
340 	int more = 1;
341 	int shift = 0;
342 	unsigned int val;
343 
344 	while (more) {
345 		val = (*data) & 0x7f;
346 		more = ((*data++) & 0x80) >> 7;
347 		res = res | val<< shift;
348 		shift += 7;
349 	}
350 	*datap = (void*) data;
351 	res = (res << (64 - shift)) >> (64 - shift);
352 	return (res);
353 }
354 
355 static uint64_t get_encoded_val(void **datap, ptrdiff_t reloc, int enc);
356 
357 /*
358  * do all field extractions needed for CFA operands and encoded FDE
359  * fields
360  */
361 uint64_t
362 _Unw_get_val(void **datap, ptrdiff_t reloc,
363 	enum operand_desc opr, int daf, int caf, int enc)
364 {
365 	intptr_t data = (intptr_t)*datap;
366 	uint64_t res;
367 	char *dp, *rp;
368 
369 	switch (opr) {
370 	case NO_OPR:
371 		res = 0;
372 		break;
373 	case ULEB128_FAC:
374 		return (daf * extractuleb(datap));
375 	case ULEB128:
376 		return (extractuleb(datap));
377 	case ULEB128_SREG:
378 		res = (uint64_t)(*((uint8_t *)data));
379 		data += 1;
380 		switch (res) {
381 			/* verify that register is one which is being tracked */
382 		case GPR_RBX:
383 		case FP_RBP:
384 		case SP_RSP:
385 		case EIR_R12:
386 		case EIR_R13:
387 		case EIR_R14:
388 		case EIR_R15:
389 			break;
390 		default:
391 			res = BAD_REG;
392 			break;
393 		}
394 		break;
395 	case UNUM6:
396 		res = (uint64_t)(0x3f & *((uint8_t *)data));
397 		data += 1;
398 		break;
399 	case UNUM8:
400 		res = (uint64_t)(*((uint8_t *)data));
401 		data += 1;
402 		break;
403 	case UNUM16:
404 		res = (uint64_t)(*((uint16_t *)data));
405 		data += 2;
406 		break;
407 	case UNUM32:
408 		res = (uint64_t)(*((uint32_t *)data));
409 		data += 4;
410 		break;
411 	case UNUM6_CFAC:
412 		res = caf * (uint64_t)(0x3f & *((uint8_t *)data));
413 		data += 1;
414 		break;
415 	case UNUM8_CFAC:
416 		res = caf * (uint64_t)(*((uint8_t *)data));
417 		data += 1;
418 		break;
419 	case UNUM16_CFAC:
420 		res = caf * (uint64_t)(*((uint16_t *)data));
421 		data += 2;
422 		break;
423 	case UNUM32_CFAC:
424 		res = caf * (uint64_t)(*((uint32_t *)data));
425 		data += 4;
426 		break;
427 	case UNUM64:
428 		res = (uint64_t)(*((uint64_t *)data));
429 		data += 8;
430 		break;
431 	case SNUM8:
432 		res = (uint64_t)(int64_t)(*((int8_t *)data));
433 		data += 1;
434 		break;
435 	case SNUM16:
436 		res = (uint64_t)(int64_t)(*((int16_t *)data));
437 		data += 2;
438 		break;
439 	case SNUM32:
440 		res = (uint64_t)(int64_t)(*((int32_t *)data));
441 		data += 4;
442 		break;
443 	case SNUM64:
444 		res = (uint64_t)(*((int64_t *)data));
445 		data += 8;
446 		break;
447 	case SLEB128_FAC:
448 		return (daf * extractsleb(datap));
449 	case SLEB128:
450 		return (extractsleb(datap));
451 	case ZTSTRING:
452 		/* max length of augmentation string is 4 */
453 		rp = (char *)&res;
454 		dp = (char *)data;
455 		while (*rp++ = *dp++)
456 			;
457 		data = (intptr_t)dp;
458 		break;
459 	case ADDR:
460 		return (get_encoded_val(datap, reloc, enc));
461 	case SIZE:
462 		return (get_encoded_val(datap, reloc, enc & 0x7));
463 	case BLOCK:
464 		res = 0;  /* not implemented */
465 		break;
466 	}
467 	*datap = (void*)data;
468 	return (res);
469 }
470 
471 static uint64_t
472 get_encoded_val(void **datap, ptrdiff_t reloc, int enc)
473 {
474 	int val = enc & 0xf;
475 	int rel = (enc >> 4) & 0xf;
476 	intptr_t loc = ((intptr_t)*datap) + reloc;
477 	uint64_t res = 0;
478 
479 	switch (val) {
480 	case 0x01:
481 		res = _Unw_get_val(datap, reloc, ULEB128, 1, 1, 0);
482 		break;
483 	case 0x2:
484 		res = _Unw_get_val(datap, reloc, UNUM16, 1, 1, 0);
485 		break;
486 	case 0x3:
487 		res = _Unw_get_val(datap, reloc, UNUM32, 1, 1, 0);
488 		break;
489 	case 0x04:
490 		res = _Unw_get_val(datap, reloc, UNUM64, 1, 1, 0);
491 		break;
492 	case 0x09:
493 		res = _Unw_get_val(datap, reloc, SLEB128, 1, 1, 0);
494 		break;
495 	case 0x0a:
496 		res = _Unw_get_val(datap, reloc, SNUM16, 1, 1, 0);
497 		break;
498 	case 0x0b:
499 		res = _Unw_get_val(datap, reloc, SNUM32, 1, 1, 0);
500 		break;
501 	case 0x0c:
502 		res = _Unw_get_val(datap, reloc, SNUM64, 1, 1, 0);
503 		break;
504 	}
505 
506 	switch (rel) {
507 	case 0:
508 		break;
509 	case 1:
510 		if (res != 0)
511 			res += loc;
512 		break;
513 	default:
514 		/* remainder not implemented */
515 		break;
516 	}
517 	return (res);
518 }
519 
520 
521 int interpret_op(void **datap, ptrdiff_t reloc,
522 	uint64_t *reached_pc_p, uint64_t pc,
523 	struct register_state f_state[],
524 	struct register_state f_start_state[],
525 	int daf, int caf, int enc);
526 
527 uint64_t
528 interpret_ops(void *data, void *data_end,
529 	ptrdiff_t reloc,
530 	uint64_t start_pc, uint64_t pc,
531 	struct register_state f_state[],
532 	struct register_state f_start_state[],
533 	int daf, int caf, int enc)
534 {
535 	void *d = data;
536 	uint64_t reached_pc = start_pc;
537 
538 	while (d < data_end) {
539 		if (interpret_op(&d, reloc, &reached_pc, pc,
540 		    f_state, f_start_state, daf, caf, enc))
541 			break;
542 	}
543 	return (reached_pc);
544 }
545 
546 int
547 interpret_op(void **datap, ptrdiff_t reloc,
548 	uint64_t *reached_pc_p, uint64_t pc,
549 	struct register_state f_state[],
550 	struct register_state f_start_state[],
551 	int daf, int caf, int enc)
552 {
553 	enum CFA_ops op = separate_op(datap);
554 	enum operand_desc opr1 = (cfa_operations[op]).op1;
555 	enum operand_desc opr2 = (cfa_operations[op]).op2;
556 
557 	uint64_t val1 = _Unw_get_val(datap, reloc, opr1, daf, caf, enc);
558 	uint64_t val2 = _Unw_get_val(datap, reloc, opr2, daf, caf, enc);
559 	if ((opr1 == ULEB128_SREG && val1 == BAD_REG) ||
560 	    (opr2 == ULEB128_SREG && val2 == BAD_REG))
561 		return (0);
562 	switch (op) {
563 	case DW_CFA_nop:
564 		break;
565 	case DW_CFA_set_loc:
566 		if (val1 > pc)
567 			return (1);
568 		*reached_pc_p = val1;
569 		break;
570 	case DW_CFA_advance_loc1:
571 	case DW_CFA_advance_loc2:
572 	case DW_CFA_advance_loc4:
573 		if (*reached_pc_p + val1 > pc)
574 			return (1);
575 		*reached_pc_p += val1;
576 		break;
577 	case DW_CFA_offset_extended:
578 		f_state[val1].rule = offset_rule;
579 		f_state[val1].source_reg = CF_ADDR;
580 		f_state[val1].offset = val2;
581 		break;
582 	case DW_CFA_restore_extended:
583 		if (f_start_state != 0)
584 			f_state[val1] = f_start_state[val1];
585 		break;
586 	case DW_CFA_undefined:
587 		f_state[val1].rule = undefined_rule;
588 		break;
589 	case DW_CFA_same_value:
590 		f_state[val1].rule = same_value_rule;
591 		break;
592 	case DW_CFA_register:
593 		f_state[val1].rule = register_rule;
594 		f_state[val1].source_reg = val2;
595 		f_state[val1].offset = 0;
596 		break;
597 	case DW_CFA_remember_state:
598 		break;
599 	case DW_CFA_restore_state:
600 		break;
601 	case DW_CFA_def_cfa:
602 		f_state[CF_ADDR].rule = register_rule;
603 		f_state[CF_ADDR].source_reg = val1;
604 		f_state[CF_ADDR].offset = val2;
605 		break;
606 	case DW_CFA_def_cfa_register:
607 		f_state[CF_ADDR].source_reg = val1;
608 		break;
609 	case DW_CFA_def_cfa_offset:
610 		f_state[CF_ADDR].offset = val1;
611 		break;
612 	case DW_CFA_def_cfa_expression:
613 		break;
614 	case DW_CFA_expression:
615 		break;
616 	case DW_CFA_offset_extended_sf:
617 		f_state[val1].rule = offset_rule;
618 		f_state[val1].source_reg = CF_ADDR;
619 		f_state[val1].offset = val2;
620 		break;
621 	case DW_CFA_def_cfa_sf:
622 		f_state[CF_ADDR].rule = register_rule;
623 		f_state[CF_ADDR].source_reg = val1;
624 		f_state[CF_ADDR].offset = val2;
625 		break;
626 	case DW_CFA_def_cfa_offset_sf:
627 		f_state[CF_ADDR].offset = val1;
628 		break;
629 	case DW_CFA_SUNW_advance_loc:
630 		if (*reached_pc_p + val1 > pc)
631 			return (1);
632 		*reached_pc_p += val1;
633 		break;
634 	case DW_CFA_SUNW_offset:
635 		f_state[val1].rule = offset_rule;
636 		f_state[val1].source_reg = CF_ADDR;
637 		f_state[val1].offset = val2;
638 		break;
639 	case DW_CFA_SUNW_restore:
640 		if (f_start_state != 0)
641 			f_state[val1] = f_start_state[val1];
642 		break;
643 	}
644 	return (0);
645 }
646