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
_Unw_Propagate_Registers(struct _Unwind_Context * old_ctx,struct _Unwind_Context * new_ctx)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
fix_cfa(struct _Unwind_Context * ctx,struct register_state * rs)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
fix_ra(struct _Unwind_Context * ctx,struct register_state * rs)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
fix_reg(struct _Unwind_Context * ctx,struct register_state * rs,int index)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
_Unw_Rollback_Registers(struct eh_frame_fields * f,struct _Unwind_Context * ctx)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
separate_op(void ** pp)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
extractuleb(void ** datap)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
extractsleb(void ** datap)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
_Unw_get_val(void ** datap,ptrdiff_t reloc,enum operand_desc opr,int daf,int caf,int enc)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
get_encoded_val(void ** datap,ptrdiff_t reloc,int enc)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
interpret_ops(void * data,void * data_end,ptrdiff_t reloc,uint64_t start_pc,uint64_t pc,struct register_state f_state[],struct register_state f_start_state[],int daf,int caf,int enc)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
interpret_op(void ** datap,ptrdiff_t reloc,uint64_t * reached_pc_p,uint64_t pc,struct register_state f_state[],struct register_state f_start_state[],int daf,int caf,int enc)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