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
_Unw_Propagate_Registers(struct _Unwind_Context * old_ctx,struct _Unwind_Context * new_ctx)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
fix_cfa(struct _Unwind_Context * ctx,struct register_state * rs)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
fix_ra(struct _Unwind_Context * ctx,struct register_state * rs)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
fix_reg(struct _Unwind_Context * ctx,struct register_state * rs,int index)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
_Unw_Rollback_Registers(struct eh_frame_fields * f,struct _Unwind_Context * ctx)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
separate_op(void ** pp)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
extractuleb(void ** datap)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
extractsleb(void ** datap)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
_Unw_get_val(void ** datap,ptrdiff_t reloc,enum operand_desc opr,int daf,int caf,int enc)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
get_encoded_val(void ** datap,ptrdiff_t reloc,int enc)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
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)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
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)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