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 * Copyright 2020 Oxide Computer Company
27 */
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 case ULEB128:
377 return (extractuleb(datap));
378 case ULEB128_SREG:
379 res = (uint64_t)(*((uint8_t *)data));
380 data += 1;
381 switch (res) {
382 /* verify that register is one which is being tracked */
383 case GPR_RBX:
384 case FP_RBP:
385 case SP_RSP:
386 case EIR_R12:
387 case EIR_R13:
388 case EIR_R14:
389 case EIR_R15:
390 break;
391 default:
392 res = BAD_REG;
393 break;
394 }
395 break;
396 case UNUM6:
397 res = (uint64_t)(0x3f & *((uint8_t *)data));
398 data += 1;
399 break;
400 case UNUM8:
401 res = (uint64_t)(*((uint8_t *)data));
402 data += 1;
403 break;
404 case UNUM16:
405 res = (uint64_t)(*((uint16_t *)data));
406 data += 2;
407 break;
408 case UNUM32:
409 res = (uint64_t)(*((uint32_t *)data));
410 data += 4;
411 break;
412 case UNUM6_CFAC:
413 res = caf * (uint64_t)(0x3f & *((uint8_t *)data));
414 data += 1;
415 break;
416 case UNUM8_CFAC:
417 res = caf * (uint64_t)(*((uint8_t *)data));
418 data += 1;
419 break;
420 case UNUM16_CFAC:
421 res = caf * (uint64_t)(*((uint16_t *)data));
422 data += 2;
423 break;
424 case UNUM32_CFAC:
425 res = caf * (uint64_t)(*((uint32_t *)data));
426 data += 4;
427 break;
428 case UNUM64:
429 res = (uint64_t)(*((uint64_t *)data));
430 data += 8;
431 break;
432 case SNUM8:
433 res = (uint64_t)(int64_t)(*((int8_t *)data));
434 data += 1;
435 break;
436 case SNUM16:
437 res = (uint64_t)(int64_t)(*((int16_t *)data));
438 data += 2;
439 break;
440 case SNUM32:
441 res = (uint64_t)(int64_t)(*((int32_t *)data));
442 data += 4;
443 break;
444 case SNUM64:
445 res = (uint64_t)(*((int64_t *)data));
446 data += 8;
447 break;
448 case SLEB128_FAC:
449 return (daf * extractsleb(datap));
450 case SLEB128:
451 return (extractsleb(datap));
452 case ZTSTRING:
453 /* max length of augmentation string is 4 */
454 rp = (char *)&res;
455 dp = (char *)data;
456 while ((*rp++ = *dp++) != '\0')
457 ;
458 data = (intptr_t)dp;
459 break;
460 case ADDR:
461 return (get_encoded_val(datap, reloc, enc));
462 case SIZE:
463 return (get_encoded_val(datap, reloc, enc & 0x7));
464 case BLOCK:
465 res = 0; /* not implemented */
466 break;
467 }
468 *datap = (void*)data;
469 return (res);
470 }
471
472 static uint64_t
get_encoded_val(void ** datap,ptrdiff_t reloc,int enc)473 get_encoded_val(void **datap, ptrdiff_t reloc, int enc)
474 {
475 const uint8_t val = enc & 0xf;
476 const uint8_t rel = enc & 0x70;
477 const boolean_t indirect = (enc & 0x80) != 0;
478 intptr_t loc = ((intptr_t)*datap) + reloc;
479 uint64_t res = 0;
480
481 /*
482 * Calculate the offset represented by the pointer encoding. These
483 * DWARF extensions are defined in the Core Generic document set of the
484 * LSB specification.
485 */
486 switch (val) {
487 case 0x01:
488 res = _Unw_get_val(datap, reloc, ULEB128, 1, 1, 0);
489 break;
490 case 0x02:
491 res = _Unw_get_val(datap, reloc, UNUM16, 1, 1, 0);
492 break;
493 case 0x03:
494 res = _Unw_get_val(datap, reloc, UNUM32, 1, 1, 0);
495 break;
496 case 0x04:
497 res = _Unw_get_val(datap, reloc, UNUM64, 1, 1, 0);
498 break;
499 case 0x09:
500 res = _Unw_get_val(datap, reloc, SLEB128, 1, 1, 0);
501 break;
502 case 0x0a:
503 res = _Unw_get_val(datap, reloc, SNUM16, 1, 1, 0);
504 break;
505 case 0x0b:
506 res = _Unw_get_val(datap, reloc, SNUM32, 1, 1, 0);
507 break;
508 case 0x0c:
509 res = _Unw_get_val(datap, reloc, SNUM64, 1, 1, 0);
510 break;
511 }
512 switch (rel) {
513 case 0x00:
514 break;
515 case 0x10:
516 /* DW_EH_PE_pcrel */
517 if (res != 0)
518 res += loc;
519 break;
520 default:
521 /* remainder not implemented */
522 break;
523 }
524
525 /*
526 * The high bit of the pointer encoding (DW_EH_PE_indirect = 0x80)
527 * indicates that a pointer-sized value should be read from the
528 * calculated address as the final result.
529 *
530 * Shockingly, this is not documented in any specification to date, but
531 * has been implemented in various unwind implementations through
532 * reverse-engineering of GCC.
533 */
534 if (indirect) {
535 void *addr = (void *)(uintptr_t)res;
536
537 /*
538 * Built only for amd64, we can count on a 64-bit pointer size
539 * for the indirect handling.
540 */
541 res = _Unw_get_val(&addr, reloc, UNUM64, 1, 1, 0);
542 }
543
544 return (res);
545 }
546
547
548 int interpret_op(void **datap, ptrdiff_t reloc,
549 uint64_t *reached_pc_p, uint64_t pc,
550 struct register_state f_state[],
551 struct register_state f_start_state[],
552 int daf, int caf, int enc);
553
554 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)555 interpret_ops(void *data, void *data_end,
556 ptrdiff_t reloc,
557 uint64_t start_pc, uint64_t pc,
558 struct register_state f_state[],
559 struct register_state f_start_state[],
560 int daf, int caf, int enc)
561 {
562 void *d = data;
563 uint64_t reached_pc = start_pc;
564
565 while (d < data_end) {
566 if (interpret_op(&d, reloc, &reached_pc, pc,
567 f_state, f_start_state, daf, caf, enc))
568 break;
569 }
570 return (reached_pc);
571 }
572
573 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)574 interpret_op(void **datap, ptrdiff_t reloc,
575 uint64_t *reached_pc_p, uint64_t pc,
576 struct register_state f_state[],
577 struct register_state f_start_state[],
578 int daf, int caf, int enc)
579 {
580 enum CFA_ops op = separate_op(datap);
581 enum operand_desc opr1 = (cfa_operations[op]).op1;
582 enum operand_desc opr2 = (cfa_operations[op]).op2;
583
584 uint64_t val1 = _Unw_get_val(datap, reloc, opr1, daf, caf, enc);
585 uint64_t val2 = _Unw_get_val(datap, reloc, opr2, daf, caf, enc);
586 if ((opr1 == ULEB128_SREG && val1 == BAD_REG) ||
587 (opr2 == ULEB128_SREG && val2 == BAD_REG))
588 return (0);
589 switch (op) {
590 case DW_CFA_nop:
591 break;
592 case DW_CFA_set_loc:
593 if (val1 > pc)
594 return (1);
595 *reached_pc_p = val1;
596 break;
597 case DW_CFA_advance_loc1:
598 case DW_CFA_advance_loc2:
599 case DW_CFA_advance_loc4:
600 if (*reached_pc_p + val1 > pc)
601 return (1);
602 *reached_pc_p += val1;
603 break;
604 case DW_CFA_offset_extended:
605 f_state[val1].rule = offset_rule;
606 f_state[val1].source_reg = CF_ADDR;
607 f_state[val1].offset = val2;
608 break;
609 case DW_CFA_restore_extended:
610 if (f_start_state != 0)
611 f_state[val1] = f_start_state[val1];
612 break;
613 case DW_CFA_undefined:
614 f_state[val1].rule = undefined_rule;
615 break;
616 case DW_CFA_same_value:
617 f_state[val1].rule = same_value_rule;
618 break;
619 case DW_CFA_register:
620 f_state[val1].rule = register_rule;
621 f_state[val1].source_reg = val2;
622 f_state[val1].offset = 0;
623 break;
624 case DW_CFA_remember_state:
625 break;
626 case DW_CFA_restore_state:
627 break;
628 case DW_CFA_def_cfa:
629 f_state[CF_ADDR].rule = register_rule;
630 f_state[CF_ADDR].source_reg = val1;
631 f_state[CF_ADDR].offset = val2;
632 break;
633 case DW_CFA_def_cfa_register:
634 f_state[CF_ADDR].source_reg = val1;
635 break;
636 case DW_CFA_def_cfa_offset:
637 f_state[CF_ADDR].offset = val1;
638 break;
639 case DW_CFA_def_cfa_expression:
640 break;
641 case DW_CFA_expression:
642 break;
643 case DW_CFA_offset_extended_sf:
644 f_state[val1].rule = offset_rule;
645 f_state[val1].source_reg = CF_ADDR;
646 f_state[val1].offset = val2;
647 break;
648 case DW_CFA_def_cfa_sf:
649 f_state[CF_ADDR].rule = register_rule;
650 f_state[CF_ADDR].source_reg = val1;
651 f_state[CF_ADDR].offset = val2;
652 break;
653 case DW_CFA_def_cfa_offset_sf:
654 f_state[CF_ADDR].offset = val1;
655 break;
656 case DW_CFA_SUNW_advance_loc:
657 if (*reached_pc_p + val1 > pc)
658 return (1);
659 *reached_pc_p += val1;
660 break;
661 case DW_CFA_SUNW_offset:
662 f_state[val1].rule = offset_rule;
663 f_state[val1].source_reg = CF_ADDR;
664 f_state[val1].offset = val2;
665 break;
666 case DW_CFA_SUNW_restore:
667 if (f_start_state != 0)
668 f_state[val1] = f_start_state[val1];
669 break;
670 }
671 return (0);
672 }
673