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