• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P.
3         Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4 
5 This file is part of libunwind.
6 
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25 
26 #include "dwarf_i.h"
27 #include "libunwind_i.h"
28 #include <stddef.h>
29 #include <limits.h>
30 
31 #define alloc_reg_state()       (mempool_alloc (&dwarf_reg_state_pool))
32 #define free_reg_state(rs)      (mempool_free (&dwarf_reg_state_pool, rs))
33 
34 #define DWARF_UNW_CACHE_SIZE(log_size)   (1 << log_size)
35 #define DWARF_UNW_HASH_SIZE(log_size)    (1 << (log_size + 1))
36 
37 static inline int
read_regnum(unw_addr_space_t as,unw_accessors_t * a,unw_word_t * addr,unw_word_t * valp,void * arg)38 read_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
39              unw_word_t *valp, void *arg)
40 {
41   int ret;
42 
43   if ((ret = dwarf_read_uleb128 (as, a, addr, valp, arg)) < 0)
44     return ret;
45 
46   if (*valp >= DWARF_NUM_PRESERVED_REGS)
47     {
48       Debug (1, "Invalid register number %u\n", (unsigned int) *valp);
49       return -UNW_EBADREG;
50     }
51   return 0;
52 }
53 
54 static inline void
set_reg(dwarf_state_record_t * sr,unw_word_t regnum,dwarf_where_t where,unw_word_t val)55 set_reg (dwarf_state_record_t *sr, unw_word_t regnum, dwarf_where_t where,
56          unw_word_t val)
57 {
58   sr->rs_current.reg.where[regnum] = where;
59   sr->rs_current.reg.val[regnum] = val;
60 }
61 
62 static inline int
push_rstate_stack(dwarf_stackable_reg_state_t ** rs_stack)63 push_rstate_stack(dwarf_stackable_reg_state_t **rs_stack)
64 {
65   dwarf_stackable_reg_state_t *old_rs = *rs_stack;
66   if (NULL == (*rs_stack = alloc_reg_state ()))
67     {
68       *rs_stack = old_rs;
69       return -1;
70     }
71   (*rs_stack)->next = old_rs;
72   return 0;
73 }
74 
75 static inline void
pop_rstate_stack(dwarf_stackable_reg_state_t ** rs_stack)76 pop_rstate_stack(dwarf_stackable_reg_state_t **rs_stack)
77 {
78   dwarf_stackable_reg_state_t *old_rs = *rs_stack;
79   *rs_stack = old_rs->next;
80   free_reg_state (old_rs);
81 }
82 
83 static inline void
empty_rstate_stack(dwarf_stackable_reg_state_t ** rs_stack)84 empty_rstate_stack(dwarf_stackable_reg_state_t **rs_stack)
85 {
86   while (*rs_stack)
87     pop_rstate_stack(rs_stack);
88 }
89 
90 #ifdef UNW_TARGET_AARCH64
91 
92 static void
93 aarch64_negate_ra_sign_state(dwarf_state_record_t *sr);
94 
95 #endif
96 
97 /* Run a CFI program to update the register state.  */
98 static int
run_cfi_program(struct dwarf_cursor * c,dwarf_state_record_t * sr,unw_word_t * ip,unw_word_t end_ip,unw_word_t * addr,unw_word_t end_addr,dwarf_stackable_reg_state_t ** rs_stack,struct dwarf_cie_info * dci)99 run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
100                  unw_word_t *ip, unw_word_t end_ip,
101 		 unw_word_t *addr, unw_word_t end_addr,
102 		 dwarf_stackable_reg_state_t **rs_stack,
103                  struct dwarf_cie_info *dci)
104 {
105   unw_addr_space_t as;
106   void *arg;
107 
108   if (c->pi.flags & UNW_PI_FLAG_DEBUG_FRAME)
109     {
110       /* .debug_frame CFI is stored in local address space.  */
111       as = unw_local_addr_space;
112       arg = NULL;
113     }
114   else
115     {
116       as = c->as;
117       arg = c->as_arg;
118     }
119   unw_accessors_t *a = unw_get_accessors_int (as);
120   int ret = 0;
121 
122   while (*ip <= end_ip && *addr < end_addr && ret >= 0)
123     {
124       unw_word_t operand = 0, regnum, val, len;
125       uint8_t u8, op;
126       uint16_t u16;
127       uint32_t u32;
128 
129       if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
130         break;
131 
132       if (op & DWARF_CFA_OPCODE_MASK)
133         {
134           operand = op & DWARF_CFA_OPERAND_MASK;
135           op &= ~DWARF_CFA_OPERAND_MASK;
136         }
137       switch ((dwarf_cfa_t) op)
138         {
139         case DW_CFA_advance_loc:
140           *ip += operand * dci->code_align;
141           Debug (15, "CFA_advance_loc to 0x%lx\n", (long) *ip);
142           break;
143 
144         case DW_CFA_advance_loc1:
145           if ((ret = dwarf_readu8 (as, a, addr, &u8, arg)) < 0)
146             break;
147           *ip += u8 * dci->code_align;
148           Debug (15, "CFA_advance_loc1 to 0x%lx\n", (long) *ip);
149           break;
150 
151         case DW_CFA_advance_loc2:
152           if ((ret = dwarf_readu16 (as, a, addr, &u16, arg)) < 0)
153             break;
154           *ip += u16 * dci->code_align;
155           Debug (15, "CFA_advance_loc2 to 0x%lx\n", (long) *ip);
156           break;
157 
158         case DW_CFA_advance_loc4:
159           if ((ret = dwarf_readu32 (as, a, addr, &u32, arg)) < 0)
160             break;
161           *ip += u32 * dci->code_align;
162           Debug (15, "CFA_advance_loc4 to 0x%lx\n", (long) *ip);
163           break;
164 
165         case DW_CFA_MIPS_advance_loc8:
166 #ifdef UNW_TARGET_MIPS
167           {
168             uint64_t u64 = 0;
169 
170             if ((ret = dwarf_readu64 (as, a, addr, &u64, arg)) < 0)
171               break;
172             *ip += u64 * dci->code_align;
173             Debug (15, "CFA_MIPS_advance_loc8\n");
174             break;
175           }
176 #else
177           Debug (1, "DW_CFA_MIPS_advance_loc8 on non-MIPS target\n");
178           ret = -UNW_EINVAL;
179           break;
180 #endif
181 
182         case DW_CFA_offset:
183           regnum = operand;
184           if (regnum >= DWARF_NUM_PRESERVED_REGS)
185             {
186               Debug (1, "Invalid register number %u in DW_cfa_OFFSET\n",
187                      (unsigned int) regnum);
188               ret = -UNW_EBADREG;
189               break;
190             }
191           if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
192             break;
193           set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
194           Debug (15, "CFA_offset r%lu at cfa+0x%lx\n",
195                  (long) regnum, (long) (val * dci->data_align));
196           break;
197 
198         case DW_CFA_offset_extended:
199           if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
200               || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
201             break;
202           set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
203           Debug (15, "CFA_offset_extended r%lu at cf+0x%lx\n",
204                  (long) regnum, (long) (val * dci->data_align));
205           break;
206 
207         case DW_CFA_offset_extended_sf:
208           if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
209               || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
210             break;
211           set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
212           Debug (15, "CFA_offset_extended_sf r%lu at cf+0x%lx\n",
213                  (long) regnum, (long) (val * dci->data_align));
214           break;
215 
216         case DW_CFA_restore:
217           regnum = operand;
218           if (regnum >= DWARF_NUM_PRESERVED_REGS)
219             {
220               Debug (1, "Invalid register number %u in DW_CFA_restore\n",
221                      (unsigned int) regnum);
222               ret = -UNW_EINVAL;
223               break;
224             }
225           sr->rs_current.reg.where[regnum] = sr->rs_initial.reg.where[regnum];
226           sr->rs_current.reg.val[regnum] = sr->rs_initial.reg.val[regnum];
227           Debug (15, "CFA_restore r%lu\n", (long) regnum);
228           break;
229 
230         case DW_CFA_restore_extended:
231           if ((ret = dwarf_read_uleb128 (as, a, addr, &regnum, arg)) < 0)
232             break;
233           if (regnum >= DWARF_NUM_PRESERVED_REGS)
234             {
235               Debug (1, "Invalid register number %u in "
236                      "DW_CFA_restore_extended\n", (unsigned int) regnum);
237               ret = -UNW_EINVAL;
238               break;
239             }
240           sr->rs_current.reg.where[regnum] = sr->rs_initial.reg.where[regnum];
241           sr->rs_current.reg.val[regnum] = sr->rs_initial.reg.val[regnum];
242           Debug (15, "CFA_restore_extended r%lu\n", (long) regnum);
243           break;
244 
245         case DW_CFA_nop:
246           break;
247 
248         case DW_CFA_set_loc:
249           if ((ret = dwarf_read_encoded_pointer (as, a, addr, dci->fde_encoding,
250                                                  &c->pi, ip,
251                                                  arg)) < 0)
252             break;
253           Debug (15, "CFA_set_loc to 0x%lx\n", (long) *ip);
254           break;
255 
256         case DW_CFA_undefined:
257           if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
258             break;
259           set_reg (sr, regnum, DWARF_WHERE_UNDEF, 0);
260           Debug (15, "CFA_undefined r%lu\n", (long) regnum);
261           break;
262 
263         case DW_CFA_same_value:
264           if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
265             break;
266           set_reg (sr, regnum, DWARF_WHERE_SAME, 0);
267           Debug (15, "CFA_same_value r%lu\n", (long) regnum);
268           break;
269 
270         case DW_CFA_register:
271           if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
272               || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
273             break;
274           set_reg (sr, regnum, DWARF_WHERE_REG, val);
275           Debug (15, "CFA_register r%lu to r%lu\n", (long) regnum, (long) val);
276           break;
277 
278         case DW_CFA_remember_state:
279 	  if (push_rstate_stack(rs_stack) < 0)
280 	    {
281               Debug (1, "Out of memory in DW_CFA_remember_state\n");
282               ret = -UNW_ENOMEM;
283               break;
284 	    }
285           (*rs_stack)->state = sr->rs_current;
286           Debug (15, "CFA_remember_state\n");
287           break;
288 
289         case DW_CFA_restore_state:
290           if (!*rs_stack)
291             {
292               Debug (1, "register-state stack underflow\n");
293               ret = -UNW_EINVAL;
294               break;
295             }
296           sr->rs_current = (*rs_stack)->state;
297           pop_rstate_stack(rs_stack);
298           Debug (15, "CFA_restore_state\n");
299           break;
300 
301         case DW_CFA_def_cfa:
302           if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
303               || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
304             break;
305           set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
306           set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val);   /* NOT factored! */
307           Debug (15, "CFA_def_cfa r%lu+0x%lx\n", (long) regnum, (long) val);
308           break;
309 
310         case DW_CFA_def_cfa_sf:
311           if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
312               || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
313             break;
314           set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
315           set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
316                    val * dci->data_align);              /* factored! */
317           Debug (15, "CFA_def_cfa_sf r%lu+0x%lx\n",
318                  (long) regnum, (long) (val * dci->data_align));
319           break;
320 
321         case DW_CFA_def_cfa_register:
322           if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
323             break;
324           set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
325           Debug (15, "CFA_def_cfa_register r%lu\n", (long) regnum);
326           break;
327 
328         case DW_CFA_def_cfa_offset:
329           if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
330             break;
331           set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val);   /* NOT factored! */
332           Debug (15, "CFA_def_cfa_offset 0x%lx\n", (long) val);
333           break;
334 
335         case DW_CFA_def_cfa_offset_sf:
336           if ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0)
337             break;
338           set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
339                    val * dci->data_align);      /* factored! */
340           Debug (15, "CFA_def_cfa_offset_sf 0x%lx\n",
341                  (long) (val * dci->data_align));
342           break;
343 
344         case DW_CFA_val_offset:
345           if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
346               || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
347             break;
348           set_reg (sr, regnum, DWARF_WHERE_VAL, val * dci->data_align);
349           Debug (15, "CFA_offset_extended_sf r%lu at cf+0x%lx\n",
350                  (long) regnum, (long) (val * dci->data_align));
351           break;
352 
353         case DW_CFA_val_offset_sf:
354           if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
355               || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
356             break;
357           set_reg (sr, regnum, DWARF_WHERE_VAL, val * dci->data_align);
358           Debug (15, "CFA_offset_extended_sf r%lu at cf+0x%lx\n",
359                  (long) regnum, (long) (val * dci->data_align));
360           break;
361 
362         case DW_CFA_def_cfa_expression:
363           /* Save the address of the DW_FORM_block for later evaluation. */
364           set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_EXPR, *addr);
365 
366           if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
367             break;
368 
369           Debug (15, "CFA_def_cfa_expr @ 0x%lx [%lu bytes]\n",
370                  (long) *addr, (long) len);
371           *addr += len;
372           break;
373 
374         case DW_CFA_expression:
375           if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
376             break;
377 
378           /* Save the address of the DW_FORM_block for later evaluation. */
379           set_reg (sr, regnum, DWARF_WHERE_EXPR, *addr);
380 
381           if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
382             break;
383 
384           Debug (15, "CFA_expression r%lu @ 0x%lx [%lu bytes]\n",
385                  (long) regnum, (long) addr, (long) len);
386           *addr += len;
387           break;
388 
389         case DW_CFA_val_expression:
390           if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
391             break;
392 
393           /* Save the address of the DW_FORM_block for later evaluation. */
394           set_reg (sr, regnum, DWARF_WHERE_VAL_EXPR, *addr);
395 
396           if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
397             break;
398 
399           Debug (15, "CFA_val_expression r%lu @ 0x%lx [%lu bytes]\n",
400                  (long) regnum, (long) addr, (long) len);
401           *addr += len;
402           break;
403 
404         case DW_CFA_GNU_args_size:
405           if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
406             break;
407           sr->args_size = val;
408           Debug (15, "CFA_GNU_args_size %lu\n", (long) val);
409           break;
410 
411         case DW_CFA_GNU_negative_offset_extended:
412           /* A comment in GCC says that this is obsoleted by
413              DW_CFA_offset_extended_sf, but that it's used by older
414              PowerPC code.  */
415           if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
416               || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
417             break;
418           set_reg (sr, regnum, DWARF_WHERE_CFAREL, ~(val * dci->data_align) + 1);
419           Debug (15, "CFA_GNU_negative_offset_extended cfa+0x%lx\n",
420                  (long) (~(val * dci->data_align) + 1));
421           break;
422 
423         case DW_CFA_GNU_window_save:
424 #ifdef UNW_TARGET_SPARC
425           /* This is a special CFA to handle all 16 windowed registers
426              on SPARC.  */
427           for (regnum = 16; regnum < 32; ++regnum)
428             set_reg (sr, regnum, DWARF_WHERE_CFAREL,
429                      (regnum - 16) * sizeof (unw_word_t));
430           Debug (15, "CFA_GNU_window_save\n");
431           break;
432 #elif UNW_TARGET_AARCH64
433           /* This is a specific opcode on aarch64, DW_CFA_AARCH64_negate_ra_state */
434           Debug (15, "DW_CFA_AARCH64_negate_ra_state\n");
435           aarch64_negate_ra_sign_state(sr);
436           break;
437 #else
438           /* FALL THROUGH */
439 #endif
440         case DW_CFA_lo_user:
441         case DW_CFA_hi_user:
442           Debug (1, "Unexpected CFA opcode 0x%x\n", op);
443           ret = -UNW_EINVAL;
444           break;
445         }
446     }
447 
448   if (ret > 0)
449     ret = 0;
450   return ret;
451 }
452 
453 static int
fetch_proc_info(struct dwarf_cursor * c,unw_word_t ip)454 fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip)
455 {
456   int ret, dynamic = 1;
457 
458   /* The 'ip' can point either to the previous or next instruction
459      depending on what type of frame we have: normal call or a place
460      to resume execution (e.g. after signal frame).
461 
462      For a normal call frame we need to back up so we point within the
463      call itself; this is important because a) the call might be the
464      very last instruction of the function and the edge of the FDE,
465      and b) so that run_cfi_program() runs locations up to the call
466      but not more.
467 
468      For signal frame, we need to do the exact opposite and look
469      up using the current 'ip' value.  That is where execution will
470      continue, and it's important we get this right, as 'ip' could be
471      right at the function entry and hence FDE edge, or at instruction
472      that manipulates CFA (push/pop). */
473 
474   if (c->use_prev_instr)
475     {
476 #if defined(__arm__)
477       /* On arm, the least bit denotes thumb/arm mode, clear it. */
478       ip &= ~(unw_word_t)0x1;
479 #endif
480       --ip;
481     }
482 
483   memset (&c->pi, 0, sizeof (c->pi));
484 
485   /* check dynamic info first --- it overrides everything else */
486   ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, 1,
487                                      c->as_arg);
488   if (ret == -UNW_ENOINFO)
489     {
490       dynamic = 0;
491       if ((ret = tdep_find_proc_info (c, ip, 1)) < 0)
492         return ret;
493     }
494 
495   if (c->pi.format != UNW_INFO_FORMAT_DYNAMIC
496       && c->pi.format != UNW_INFO_FORMAT_TABLE
497       && c->pi.format != UNW_INFO_FORMAT_REMOTE_TABLE)
498     return -UNW_ENOINFO;
499 
500   c->pi_valid = 1;
501   c->pi_is_dynamic = dynamic;
502 
503   /* Let system/machine-dependent code determine frame-specific attributes. */
504   if (ret >= 0)
505     tdep_fetch_frame (c, ip, 1);
506 
507   return ret;
508 }
509 
510 static int
parse_dynamic(struct dwarf_cursor * c,unw_word_t ip,dwarf_state_record_t * sr)511 parse_dynamic (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
512 {
513   Debug (1, "Not yet implemented\n");
514   return -UNW_ENOINFO;
515 }
516 
517 static inline void
put_unwind_info(struct dwarf_cursor * c,unw_proc_info_t * pi)518 put_unwind_info (struct dwarf_cursor *c, unw_proc_info_t *pi)
519 {
520   if (c->pi_is_dynamic)
521     unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg);
522   else if (pi->unwind_info && pi->format == UNW_INFO_FORMAT_TABLE)
523     {
524       mempool_free (&dwarf_cie_info_pool, pi->unwind_info);
525       pi->unwind_info = NULL;
526     }
527   c->pi_valid = 0;
528 }
529 
530 static inline int
setup_fde(struct dwarf_cursor * c,dwarf_state_record_t * sr)531 setup_fde (struct dwarf_cursor *c, dwarf_state_record_t *sr)
532 {
533   int i, ret;
534 
535   assert (c->pi_valid);
536 
537   memset (sr, 0, sizeof (*sr));
538   for (i = 0; i < DWARF_NUM_PRESERVED_REGS + 2; ++i)
539     set_reg (sr, i, DWARF_WHERE_SAME, 0);
540 
541   struct dwarf_cie_info *dci = c->pi.unwind_info;
542   sr->rs_current.ret_addr_column  = dci->ret_addr_column;
543   unw_word_t addr = dci->cie_instr_start;
544   unw_word_t curr_ip = 0;
545   dwarf_stackable_reg_state_t *rs_stack = NULL;
546   ret = run_cfi_program (c, sr, &curr_ip, ~(unw_word_t) 0, &addr,
547 			 dci->cie_instr_end,
548 			 &rs_stack, dci);
549   empty_rstate_stack(&rs_stack);
550   if (ret < 0)
551     return ret;
552 
553   memcpy (&sr->rs_initial, &sr->rs_current, sizeof (sr->rs_initial));
554   return 0;
555 }
556 
557 static inline int
parse_fde(struct dwarf_cursor * c,unw_word_t ip,dwarf_state_record_t * sr)558 parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
559 {
560   int ret;
561   struct dwarf_cie_info *dci = c->pi.unwind_info;
562   unw_word_t addr = dci->fde_instr_start;
563   unw_word_t curr_ip = c->pi.start_ip;
564   dwarf_stackable_reg_state_t *rs_stack = NULL;
565   /* Process up to current `ip` for signal frame and `ip - 1` for normal call frame
566      See `c->use_prev_instr` use in `fetch_proc_info` for details. */
567   ret = run_cfi_program (c, sr, &curr_ip, ip - c->use_prev_instr, &addr, dci->fde_instr_end,
568 			 &rs_stack, dci);
569   empty_rstate_stack(&rs_stack);
570   if (ret < 0)
571     return ret;
572 
573   return 0;
574 }
575 
576 HIDDEN int
dwarf_flush_rs_cache(struct dwarf_rs_cache * cache)577 dwarf_flush_rs_cache (struct dwarf_rs_cache *cache)
578 {
579   int i;
580 
581   if (cache->log_size == DWARF_DEFAULT_LOG_UNW_CACHE_SIZE
582       || !cache->hash) {
583     cache->hash = cache->default_hash;
584     cache->buckets = cache->default_buckets;
585     cache->links = cache->default_links;
586     cache->log_size = DWARF_DEFAULT_LOG_UNW_CACHE_SIZE;
587   } else {
588     if (cache->hash && cache->hash != cache->default_hash)
589       munmap(cache->hash, DWARF_UNW_HASH_SIZE(cache->prev_log_size)
590                            * sizeof (cache->hash[0]));
591     if (cache->buckets && cache->buckets != cache->default_buckets)
592       munmap(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->prev_log_size)
593 	                      * sizeof (cache->buckets[0]));
594     if (cache->links && cache->links != cache->default_links)
595       munmap(cache->links, DWARF_UNW_CACHE_SIZE(cache->prev_log_size)
596 	                      * sizeof (cache->links[0]));
597     GET_MEMORY(cache->hash, DWARF_UNW_HASH_SIZE(cache->log_size)
598                              * sizeof (cache->hash[0]));
599     GET_MEMORY(cache->buckets, DWARF_UNW_CACHE_SIZE(cache->log_size)
600                                 * sizeof (cache->buckets[0]));
601     GET_MEMORY(cache->links, DWARF_UNW_CACHE_SIZE(cache->log_size)
602                                 * sizeof (cache->links[0]));
603     if (!cache->hash || !cache->buckets || !cache->links)
604       {
605         Debug (1, "Unable to allocate cache memory");
606         return -UNW_ENOMEM;
607       }
608     cache->prev_log_size = cache->log_size;
609   }
610 
611   cache->rr_head = 0;
612 
613   for (i = 0; i < DWARF_UNW_CACHE_SIZE(cache->log_size); ++i)
614     {
615       cache->links[i].coll_chain = -1;
616       cache->links[i].ip = 0;
617       cache->links[i].valid = 0;
618     }
619   for (i = 0; i< DWARF_UNW_HASH_SIZE(cache->log_size); ++i)
620     cache->hash[i] = -1;
621 
622   return 0;
623 }
624 
625 static inline struct dwarf_rs_cache *
get_rs_cache(unw_addr_space_t as,intrmask_t * saved_maskp)626 get_rs_cache (unw_addr_space_t as, intrmask_t *saved_maskp)
627 {
628   struct dwarf_rs_cache *cache = &as->global_cache;
629   unw_caching_policy_t caching = as->caching_policy;
630 
631   if (caching == UNW_CACHE_NONE)
632     return NULL;
633 
634 #if defined(HAVE___CACHE_PER_THREAD) && HAVE___CACHE_PER_THREAD
635   if (likely (caching == UNW_CACHE_PER_THREAD))
636     {
637       static _Thread_local struct dwarf_rs_cache tls_cache __attribute__((tls_model("initial-exec")));
638       Debug (16, "using TLS cache\n");
639       cache = &tls_cache;
640     }
641   else
642 #else
643   if (likely (caching == UNW_CACHE_GLOBAL))
644 #endif
645     {
646       Debug (16, "acquiring lock\n");
647       lock_acquire (&cache->lock, *saved_maskp);
648     }
649 
650   if ((atomic_load (&as->cache_generation) != atomic_load (&cache->generation))
651        || !cache->hash)
652     {
653       /* cache_size is only set in the global_cache, copy it over before flushing */
654       cache->log_size = as->global_cache.log_size;
655       if (dwarf_flush_rs_cache (cache) < 0)
656         return NULL;
657       atomic_store (&cache->generation, atomic_load (&as->cache_generation));
658     }
659 
660   return cache;
661 }
662 
663 static inline void
put_rs_cache(unw_addr_space_t as,struct dwarf_rs_cache * cache,intrmask_t * saved_maskp)664 put_rs_cache (unw_addr_space_t as, struct dwarf_rs_cache *cache,
665                   intrmask_t *saved_maskp)
666 {
667   assert (as->caching_policy != UNW_CACHE_NONE);
668 
669   Debug (16, "unmasking signals/interrupts and releasing lock\n");
670   if (likely (as->caching_policy == UNW_CACHE_GLOBAL))
671     lock_release (&cache->lock, *saved_maskp);
672 }
673 
674 static inline unw_hash_index_t CONST_ATTR
hash(unw_word_t ip,unsigned short log_size)675 hash (unw_word_t ip, unsigned short log_size)
676 {
677   /* based on (sqrt(5)/2-1)*2^64 */
678 # define magic  ((unw_word_t) 0x9e3779b97f4a7c16ULL)
679 
680   return ip * magic >> ((sizeof(unw_word_t) * 8) - (log_size + 1));
681 }
682 
683 static inline long
cache_match(struct dwarf_rs_cache * cache,unsigned short index,unw_word_t ip)684 cache_match (struct dwarf_rs_cache *cache, unsigned short index, unw_word_t ip)
685 {
686   return (cache->links[index].valid && (ip == cache->links[index].ip));
687 }
688 
689 static dwarf_reg_state_t *
rs_lookup(struct dwarf_rs_cache * cache,struct dwarf_cursor * c)690 rs_lookup (struct dwarf_rs_cache *cache, struct dwarf_cursor *c)
691 {
692   unsigned short index;
693   unw_word_t ip = c->ip;
694 
695   if (c->hint > 0)
696     {
697       index = c->hint - 1;
698       if (cache_match (cache, index, ip))
699 	return &cache->buckets[index];
700     }
701 
702   for (index = cache->hash[hash (ip, cache->log_size)];
703        index < DWARF_UNW_CACHE_SIZE(cache->log_size);
704        index = cache->links[index].coll_chain)
705     {
706       if (cache_match (cache, index, ip))
707 	return &cache->buckets[index];
708     }
709   return NULL;
710 }
711 
712 static inline dwarf_reg_state_t *
rs_new(struct dwarf_rs_cache * cache,struct dwarf_cursor * c)713 rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c)
714 {
715   unw_hash_index_t index;
716   unsigned short head;
717 
718   head = cache->rr_head;
719   cache->rr_head = (head + 1) & (DWARF_UNW_CACHE_SIZE(cache->log_size) - 1);
720 
721   /* remove the old rs from the hash table (if it's there): */
722   if (cache->links[head].ip)
723     {
724       unsigned short *pindex;
725       for (pindex = &cache->hash[hash (cache->links[head].ip, cache->log_size)];
726 	   *pindex < DWARF_UNW_CACHE_SIZE(cache->log_size);
727 	   pindex = &cache->links[*pindex].coll_chain)
728 	{
729 	  if (*pindex == head)
730 	    {
731 	      *pindex = cache->links[*pindex].coll_chain;
732 	      break;
733 	    }
734 	}
735     }
736 
737   /* enter new rs in the hash table */
738   index = hash (c->ip, cache->log_size);
739   cache->links[head].coll_chain = cache->hash[index];
740   cache->hash[index] = head;
741 
742   cache->links[head].ip = c->ip;
743   cache->links[head].valid = 1;
744   cache->links[head].signal_frame = tdep_cache_frame(c);
745   return cache->buckets + head;
746 }
747 
748 static int
create_state_record_for(struct dwarf_cursor * c,dwarf_state_record_t * sr,unw_word_t ip)749 create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr,
750                          unw_word_t ip)
751 {
752   int ret;
753   switch (c->pi.format)
754     {
755     case UNW_INFO_FORMAT_TABLE:
756     case UNW_INFO_FORMAT_REMOTE_TABLE:
757       if ((ret = setup_fde(c, sr)) < 0)
758 	return ret;
759       ret = parse_fde (c, ip, sr);
760       break;
761 
762     case UNW_INFO_FORMAT_DYNAMIC:
763       ret = parse_dynamic (c, ip, sr);
764       break;
765 
766     default:
767       Debug (1, "Unexpected unwind-info format %d\n", c->pi.format);
768       ret = -UNW_EINVAL;
769     }
770   return ret;
771 }
772 
773 static inline int
eval_location_expr(struct dwarf_cursor * c,unw_word_t stack_val,unw_addr_space_t as,unw_accessors_t * a,unw_word_t addr,dwarf_loc_t * locp,void * arg)774 eval_location_expr (struct dwarf_cursor *c, unw_word_t stack_val, unw_addr_space_t as,
775                     unw_accessors_t *a, unw_word_t addr,
776                     dwarf_loc_t *locp, void *arg)
777 {
778   int ret, is_register;
779   unw_word_t len, val;
780 
781   /* read the length of the expression: */
782   if ((ret = dwarf_read_uleb128 (as, a, &addr, &len, arg)) < 0)
783     return ret;
784 
785   /* evaluate the expression: */
786   if ((ret = dwarf_eval_expr (c, stack_val, &addr, len, &val, &is_register)) < 0)
787     return ret;
788 
789   if (is_register)
790     *locp = DWARF_REG_LOC (c, dwarf_to_unw_regnum (val));
791   else
792     *locp = DWARF_MEM_LOC (c, val);
793 
794   return 0;
795 }
796 
797 
798 #ifdef UNW_TARGET_AARCH64
799 #include "libunwind-aarch64.h"
800 
801 static void
aarch64_negate_ra_sign_state(dwarf_state_record_t * sr)802 aarch64_negate_ra_sign_state(dwarf_state_record_t *sr)
803 {
804   unw_word_t ra_sign_state = sr->rs_current.reg.val[UNW_AARCH64_RA_SIGN_STATE];
805   ra_sign_state ^= 0x1;
806   set_reg(sr, UNW_AARCH64_RA_SIGN_STATE, DWARF_WHERE_SAME, ra_sign_state);
807 }
808 
809 static unw_word_t
aarch64_strip_pac_remote(unw_accessors_t * a,unw_addr_space_t as,void * arg,unw_word_t old_ip)810 aarch64_strip_pac_remote(unw_accessors_t *a, unw_addr_space_t as, void *arg, unw_word_t old_ip)
811 {
812   if (a->ptrauth_insn_mask)
813     {
814       unw_word_t ip, insn_mask;
815 
816       insn_mask = a->ptrauth_insn_mask(as, arg);
817       ip = old_ip & (~insn_mask);
818 
819       Debug(15, "stripping pac from address, before: %lx, after: %lx\n", old_ip, ip);
820       return ip;
821     }
822   else
823     {
824       unw_word_t insn_mask = 0xFFFFFF8000000000; // mask all bits from [63:40];
825       unw_word_t ip = old_ip & (~insn_mask);
826       Debug(15, "return address %lx might be signed, use 0xFFFFFF8000000000 as default mask\n", old_ip);
827       return ip;
828     }
829 }
830 
831 static unw_word_t
aarch64_strip_pac_local(unw_word_t in_addr)832 aarch64_strip_pac_local(unw_word_t in_addr)
833 {
834   unw_word_t out_addr = in_addr;
835 
836 #ifdef __aarch64__
837   // Strip the PAC with XPACLRI instruction
838   register unsigned long long x30 __asm__("x30") = in_addr;
839   __asm__("hint 0x7" : "+r" (x30));
840   out_addr = x30;
841 #endif
842 
843   return out_addr;
844 }
845 
846 static unw_word_t
aarch64_get_ra_sign_state(struct dwarf_reg_state * rs)847 aarch64_get_ra_sign_state(struct dwarf_reg_state *rs)
848 {
849    return rs->reg.val[UNW_AARCH64_RA_SIGN_STATE];
850 }
851 
852 #endif
853 
854 static int
apply_reg_state(struct dwarf_cursor * c,struct dwarf_reg_state * rs)855 apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
856 {
857   unw_word_t regnum, addr, cfa, ip;
858   unw_word_t prev_ip, prev_cfa;
859   unw_addr_space_t as;
860   dwarf_loc_t cfa_loc;
861   unw_accessors_t *a;
862   int i, ret;
863   void *arg;
864 
865   /* In the case that we have incorrect CFI, the return address column may be
866    * outside the valid range of data and will read invalid data.  Protect
867    * against the errant read and indicate that we have a bad frame.  */
868   if (rs->ret_addr_column >= DWARF_NUM_PRESERVED_REGS) {
869     Dprintf ("%s: return address entry %zu is outside of range of CIE",
870              __FUNCTION__, rs->ret_addr_column);
871     return -UNW_EBADFRAME;
872   }
873 
874   prev_ip = c->ip;
875   prev_cfa = c->cfa;
876 
877   as = c->as;
878   arg = c->as_arg;
879   a = unw_get_accessors_int (as);
880 
881   /* Evaluate the CFA first, because it may be referred to by other
882      expressions.  */
883 
884   if (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG)
885     {
886       /* CFA is equal to [reg] + offset: */
887 
888       /* As a special-case, if the stack-pointer is the CFA and the
889          stack-pointer wasn't saved, popping the CFA implicitly pops
890          the stack-pointer as well.  */
891       if ((rs->reg.val[DWARF_CFA_REG_COLUMN] == UNW_TDEP_SP)
892           && (UNW_TDEP_SP < ARRAY_SIZE(rs->reg.val))
893           && (rs->reg.where[UNW_TDEP_SP] == DWARF_WHERE_SAME))
894           cfa = c->cfa;
895       else
896         {
897           regnum = dwarf_to_unw_regnum (rs->reg.val[DWARF_CFA_REG_COLUMN]);
898           if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0)
899             return ret;
900         }
901       cfa += rs->reg.val[DWARF_CFA_OFF_COLUMN];
902     }
903   else
904     {
905       /* CFA is equal to EXPR: */
906 
907       assert (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_EXPR);
908 
909       addr = rs->reg.val[DWARF_CFA_REG_COLUMN];
910       /* The dwarf standard doesn't specify an initial value to be pushed on */
911       /* the stack before DW_CFA_def_cfa_expression evaluation. We push on a */
912       /* dummy value (0) to keep the eval_location_expr function consistent. */
913       if ((ret = eval_location_expr (c, 0, as, a, addr, &cfa_loc, arg)) < 0)
914         return ret;
915       /* the returned location better be a memory location... */
916       if (DWARF_IS_REG_LOC (cfa_loc))
917         return -UNW_EBADFRAME;
918       cfa = DWARF_GET_LOC (cfa_loc);
919     }
920 
921 #ifdef ONLY_RECOVER_GENERAL_REGS
922 const int32_t regCount = 33;
923 #else
924 const int32_t regCount = DWARF_NUM_PRESERVED_REGS;
925 #endif
926 
927   dwarf_loc_t new_loc[DWARF_NUM_PRESERVED_REGS];
928   memcpy(new_loc, c->loc, sizeof(new_loc));
929 
930   for (i = 0; i < regCount; ++i)
931     {
932       switch ((dwarf_where_t) rs->reg.where[i])
933         {
934         case DWARF_WHERE_UNDEF:
935           new_loc[i] = DWARF_NULL_LOC;
936           break;
937 
938         case DWARF_WHERE_SAME:
939           break;
940 
941         case DWARF_WHERE_CFAREL:
942           new_loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg.val[i]);
943           break;
944 
945         case DWARF_WHERE_REG:
946 #ifdef __s390x__
947           /* GPRs can be saved in FPRs on s390x */
948           if (unw_is_fpreg (dwarf_to_unw_regnum (rs->reg.val[i])))
949             {
950               new_loc[i] = DWARF_FPREG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i]));
951               break;
952             }
953 #endif
954           new_loc[i] = new_loc[rs->reg.val[i]];
955           break;
956 
957         case DWARF_WHERE_EXPR:
958           addr = rs->reg.val[i];
959           /* The dwarf standard requires the current CFA to be pushed on the */
960           /* stack before DW_CFA_expression evaluation. */
961           if ((ret = eval_location_expr (c, cfa, as, a, addr, new_loc + i, arg)) < 0)
962             return ret;
963           break;
964 
965         case DWARF_WHERE_VAL_EXPR:
966           addr = rs->reg.val[i];
967           /* The dwarf standard requires the current CFA to be pushed on the */
968           /* stack before DW_CFA_val_expression evaluation. */
969           if ((ret = eval_location_expr (c, cfa, as, a, addr, new_loc + i, arg)) < 0)
970             return ret;
971           new_loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (new_loc[i]));
972           break;
973 
974         case DWARF_WHERE_VAL:
975           new_loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (new_loc[i]));
976           Debug (16, "%s(%d), where[%d]=0x%x, new_loc.val=0x%x\n",
977                  __FILE__, __LINE__, i, rs->reg.where[i], new_loc[i].val);
978           break;
979         }
980     }
981 
982   memcpy(c->loc, new_loc, sizeof(new_loc));
983 
984   c->cfa = cfa;
985   /* DWARF spec says undefined return address location means end of stack. */
986   if (DWARF_IS_NULL_LOC (c->loc[rs->ret_addr_column]))
987     {
988       c->ip = 0;
989       ret = 0;
990     }
991   else
992   {
993     ret = dwarf_get (c, c->loc[rs->ret_addr_column], &ip);
994     if (ret < 0)
995       return ret;
996 #ifdef UNW_TARGET_AARCH64
997     if (aarch64_get_ra_sign_state(rs))
998       {
999         if (c->as != NULL && c->as->pid == -1)
1000           {
1001             ip = aarch64_strip_pac_local(ip);
1002           }
1003         else
1004           {
1005             ip = aarch64_strip_pac_remote(a, as, arg, ip);
1006           }
1007       }
1008 #endif
1009     c->ip = ip;
1010     ret = 1;
1011   }
1012 
1013   /* XXX: check for ip to be code_aligned */
1014   if (c->ip == prev_ip && c->cfa == prev_cfa)
1015     {
1016       Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
1017                __FUNCTION__, (long) c->ip);
1018       return -UNW_EBADFRAME;
1019     }
1020 
1021   if (c->stash_frames)
1022     tdep_stash_frame (c, rs);
1023 
1024   return ret;
1025 }
1026 
1027 /* Find the saved locations. */
1028 static int
find_reg_state(struct dwarf_cursor * c,dwarf_state_record_t * sr)1029 find_reg_state (struct dwarf_cursor *c, dwarf_state_record_t *sr)
1030 {
1031   dwarf_reg_state_t *rs = NULL;
1032   struct dwarf_rs_cache *cache;
1033   int ret = 0;
1034   intrmask_t saved_mask;
1035 
1036   if ((cache = get_rs_cache(c->as, &saved_mask)) &&
1037       (rs = rs_lookup(cache, c)))
1038     {
1039       /* update hint; no locking needed: single-word writes are atomic */
1040       unsigned short index = rs - cache->buckets;
1041       c->use_prev_instr = ! cache->links[index].signal_frame;
1042       memcpy (&sr->rs_current, rs, sizeof (*rs));
1043     }
1044   else
1045     {
1046       ret = fetch_proc_info (c, c->ip);
1047       int next_use_prev_instr = c->use_prev_instr;
1048       if (ret >= 0)
1049 	{
1050 	  /* Update use_prev_instr for the next frame. */
1051 	  assert(c->pi.unwind_info);
1052 	  struct dwarf_cie_info *dci = c->pi.unwind_info;
1053 	  next_use_prev_instr = ! dci->signal_frame;
1054 	  ret = create_state_record_for (c, sr, c->ip);
1055 	}
1056       put_unwind_info (c, &c->pi);
1057       c->use_prev_instr = next_use_prev_instr;
1058 
1059       if (cache && ret >= 0)
1060 	{
1061 	  rs = rs_new (cache, c);
1062 	  cache->links[rs - cache->buckets].hint = 0;
1063 	  memcpy(rs, &sr->rs_current, sizeof(*rs));
1064 	}
1065     }
1066 
1067   unsigned short index = -1;
1068   if (cache)
1069     {
1070       if (rs)
1071 	{
1072 	  index = rs - cache->buckets;
1073 	  c->hint = cache->links[index].hint;
1074 	  cache->links[c->prev_rs].hint = index + 1;
1075 	  c->prev_rs = index;
1076 	}
1077       if (ret >= 0)
1078         tdep_reuse_frame (c, cache->links[index].signal_frame);
1079       put_rs_cache (c->as, cache, &saved_mask);
1080     }
1081   return ret;
1082 }
1083 
1084 /* The function finds the saved locations and applies the register
1085    state as well. */
1086 HIDDEN int
dwarf_step(struct dwarf_cursor * c)1087 dwarf_step (struct dwarf_cursor *c)
1088 {
1089   int ret;
1090   dwarf_state_record_t sr;
1091   if ((ret = find_reg_state (c, &sr)) < 0)
1092     return ret;
1093   return apply_reg_state (c, &sr.rs_current);
1094 }
1095 
1096 HIDDEN int
dwarf_make_proc_info(struct dwarf_cursor * c)1097 dwarf_make_proc_info (struct dwarf_cursor *c)
1098 {
1099 #if 0
1100   if (c->as->caching_policy == UNW_CACHE_NONE
1101       || get_cached_proc_info (c) < 0)
1102 #endif
1103   /* Need to check if current frame contains
1104      args_size, and set cursor appropriately.  Only
1105      needed for unw_resume */
1106   dwarf_state_record_t sr;
1107   sr.args_size = 0;
1108   int ret;
1109 
1110   /* Lookup it up the slow way... */
1111   ret = fetch_proc_info (c, c->ip);
1112   if (ret >= 0)
1113       ret = create_state_record_for (c, &sr, c->ip);
1114   put_unwind_info (c, &c->pi);
1115   if (ret < 0)
1116     return ret;
1117   c->args_size = sr.args_size;
1118 
1119   return 0;
1120 }
1121 
1122 static int
dwarf_reg_states_dynamic_iterate(struct dwarf_cursor * c,unw_reg_states_callback cb,void * token)1123 dwarf_reg_states_dynamic_iterate(struct dwarf_cursor *c,
1124 				 unw_reg_states_callback cb,
1125 				 void *token)
1126 {
1127   Debug (1, "Not yet implemented\n");
1128   return -UNW_ENOINFO;
1129 }
1130 
1131 static int
dwarf_reg_states_table_iterate(struct dwarf_cursor * c,unw_reg_states_callback cb,void * token)1132 dwarf_reg_states_table_iterate(struct dwarf_cursor *c,
1133 			       unw_reg_states_callback cb,
1134 			       void *token)
1135 {
1136   dwarf_state_record_t sr;
1137   int ret = setup_fde(c, &sr);
1138   struct dwarf_cie_info *dci = c->pi.unwind_info;
1139   unw_word_t addr = dci->fde_instr_start;
1140   unw_word_t curr_ip = c->pi.start_ip;
1141   dwarf_stackable_reg_state_t *rs_stack = NULL;
1142   while (ret >= 0 && curr_ip < c->pi.end_ip && addr < dci->fde_instr_end)
1143     {
1144       unw_word_t prev_ip = curr_ip;
1145       ret = run_cfi_program (c, &sr, &curr_ip, prev_ip, &addr, dci->fde_instr_end,
1146 			     &rs_stack, dci);
1147       if (ret >= 0 && prev_ip < curr_ip)
1148 	ret = cb(token, &sr.rs_current, sizeof(sr.rs_current), prev_ip, curr_ip);
1149     }
1150   empty_rstate_stack(&rs_stack);
1151 #if defined(NEED_LAST_IP)
1152   if (ret >= 0 && curr_ip < c->pi.last_ip)
1153     /* report the dead zone after the procedure ends */
1154     ret = cb(token, &sr.rs_current, sizeof(sr.rs_current), curr_ip, c->pi.last_ip);
1155 #else
1156   if (ret >= 0 && curr_ip < c->pi.end_ip)
1157     /* report for whatever is left before procedure end */
1158     ret = cb(token, &sr.rs_current, sizeof(sr.rs_current), curr_ip, c->pi.end_ip);
1159 #endif
1160   return ret;
1161 }
1162 
1163 HIDDEN int
dwarf_reg_states_iterate(struct dwarf_cursor * c,unw_reg_states_callback cb,void * token)1164 dwarf_reg_states_iterate(struct dwarf_cursor *c,
1165 			 unw_reg_states_callback cb,
1166 			 void *token)
1167 {
1168   int ret = fetch_proc_info (c, c->ip);
1169   int next_use_prev_instr = c->use_prev_instr;
1170   if (ret >= 0)
1171     {
1172       /* Update use_prev_instr for the next frame. */
1173       assert(c->pi.unwind_info);
1174       struct dwarf_cie_info *dci = c->pi.unwind_info;
1175       next_use_prev_instr = ! dci->signal_frame;
1176       switch (c->pi.format)
1177 	{
1178 	case UNW_INFO_FORMAT_TABLE:
1179 	case UNW_INFO_FORMAT_REMOTE_TABLE:
1180 	  ret = dwarf_reg_states_table_iterate(c, cb, token);
1181 	  break;
1182 
1183 	case UNW_INFO_FORMAT_DYNAMIC:
1184 	  ret = dwarf_reg_states_dynamic_iterate (c, cb, token);
1185 	  break;
1186 
1187 	default:
1188 	  Debug (1, "Unexpected unwind-info format %d\n", c->pi.format);
1189 	  ret = -UNW_EINVAL;
1190 	}
1191     }
1192   put_unwind_info (c, &c->pi);
1193   c->use_prev_instr = next_use_prev_instr;
1194   return ret;
1195 }
1196 
1197 HIDDEN int
dwarf_apply_reg_state(struct dwarf_cursor * c,struct dwarf_reg_state * rs)1198 dwarf_apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
1199 {
1200   return apply_reg_state(c, rs);
1201 }
1202