Gparser.c revision d7089547e2d13c2ae5f9ad896dc4bc5dc796fb0b
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
5This file is part of libunwind.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25
26#include <stddef.h>
27#include "dwarf_i.h"
28#include "libunwind_i.h"
29
30#define alloc_reg_state()	(mempool_alloc (&dwarf_reg_state_pool))
31#define free_reg_state(rs)	(mempool_free (&dwarf_reg_state_pool, rs))
32
33static inline int
34read_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
35	     unw_word_t *valp, void *arg)
36{
37  int ret;
38
39  if ((ret = dwarf_read_uleb128 (as, a, addr, valp, arg)) < 0)
40    return ret;
41
42  if (*valp >= DWARF_NUM_PRESERVED_REGS)
43    {
44      Debug (1, "Invalid register number %u\n", (unsigned int) *valp);
45      return -UNW_EBADREG;
46    }
47  return 0;
48}
49
50static inline void
51set_reg (dwarf_state_record_t *sr, unw_word_t regnum, dwarf_where_t where,
52	 unw_word_t val)
53{
54  sr->rs_current.reg[regnum].where = where;
55  sr->rs_current.reg[regnum].val = val;
56}
57
58/* Run a CFI program to update the register state.  */
59static int
60run_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
61		 unw_word_t ip, unw_word_t *addr, unw_word_t end_addr,
62		 struct dwarf_cie_info *dci)
63{
64  unw_word_t curr_ip, operand = 0, regnum, val, len, fde_encoding;
65  dwarf_reg_state_t *rs_stack = NULL, *new_rs, *old_rs;
66  unw_addr_space_t as;
67  unw_accessors_t *a;
68  uint8_t u8, op;
69  uint16_t u16;
70  uint32_t u32;
71  void *arg;
72  int ret;
73
74  as = c->as;
75  arg = c->as_arg;
76  a = unw_get_accessors (as);
77  curr_ip = c->pi.start_ip;
78
79  while (curr_ip < ip && *addr < end_addr)
80    {
81      if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
82	return ret;
83
84      if (op & DWARF_CFA_OPCODE_MASK)
85	{
86	  operand = op & DWARF_CFA_OPERAND_MASK;
87	  op &= ~DWARF_CFA_OPERAND_MASK;
88	}
89      switch ((dwarf_cfa_t) op)
90	{
91	case DW_CFA_advance_loc:
92	  curr_ip += operand * dci->code_align;
93	  Debug (15, "CFA_advance_loc to 0x%lx\n", (long) curr_ip);
94	  break;
95
96	case DW_CFA_advance_loc1:
97	  if ((ret = dwarf_readu8 (as, a, addr, &u8, arg)) < 0)
98	    goto fail;
99	  curr_ip += u8 * dci->code_align;
100	  Debug (15, "CFA_advance_loc1 to 0x%lx\n", (long) curr_ip);
101	  break;
102
103	case DW_CFA_advance_loc2:
104	  if ((ret = dwarf_readu16 (as, a, addr, &u16, arg)) < 0)
105	    goto fail;
106	  curr_ip += u16 * dci->code_align;
107	  Debug (15, "CFA_advance_loc2 to 0x%lx\n", (long) curr_ip);
108	  break;
109
110	case DW_CFA_advance_loc4:
111	  if ((ret = dwarf_readu32 (as, a, addr, &u32, arg)) < 0)
112	    goto fail;
113	  curr_ip += u32 * dci->code_align;
114	  Debug (15, "CFA_advance_loc4 to 0x%lx\n", (long) curr_ip);
115	  break;
116
117	case DW_CFA_MIPS_advance_loc8:
118#ifdef UNW_TARGET_MIPS
119	  {
120	    uint64_t u64;
121
122	    if ((ret = dwarf_readu64 (as, a, addr, &u64, arg)) < 0)
123	      goto fail;
124	    curr_ip += u64 * dci->code_align;
125	    Debug (15, "CFA_MIPS_advance_loc8\n");
126	    break;
127	  }
128#else
129	  Debug (1, "DW_CFA_MIPS_advance_loc8 on non-MIPS target\n");
130	  ret = -UNW_EINVAL;
131	  goto fail;
132#endif
133
134	case DW_CFA_offset:
135	  regnum = operand;
136	  if (regnum >= DWARF_NUM_PRESERVED_REGS)
137	    {
138	      Debug (1, "Invalid register number %u in DW_cfa_OFFSET\n",
139		     (unsigned int) regnum);
140	      ret = -UNW_EBADREG;
141	      goto fail;
142	    }
143	  if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
144	    goto fail;
145	  set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
146	  Debug (15, "CFA_offset r%lu at cfa+0x%lx\n",
147		 (long) regnum, (long) (val * dci->data_align));
148	  break;
149
150	case DW_CFA_offset_extended:
151	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
152	      || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
153	    goto fail;
154	  set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
155	  Debug (15, "CFA_offset_extended r%lu at cf+0x%lx\n",
156		 (long) regnum, (long) (val * dci->data_align));
157	  break;
158
159	case DW_CFA_offset_extended_sf:
160	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
161	      || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
162	    goto fail;
163	  set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
164	  Debug (15, "CFA_offset_extended_sf r%lu at cf+0x%lx\n",
165		 (long) regnum, (long) (val * dci->data_align));
166	  break;
167
168	case DW_CFA_restore:
169	  regnum = operand;
170	  if (regnum >= DWARF_NUM_PRESERVED_REGS)
171	    {
172	      Debug (1, "Invalid register number %u in DW_CFA_restore\n",
173		     (unsigned int) regnum);
174	      ret = -UNW_EINVAL;
175	      goto fail;
176	    }
177	  sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
178	  Debug (15, "CFA_restore r%lu\n", (long) regnum);
179	  break;
180
181	case DW_CFA_restore_extended:
182	  if ((ret = dwarf_read_uleb128 (as, a, addr, &regnum, arg)) < 0)
183	    goto fail;
184	  if (regnum >= DWARF_NUM_PRESERVED_REGS)
185	    {
186	      Debug (1, "Invalid register number %u in "
187		     "DW_CFA_restore_extended\n", (unsigned int) regnum);
188	      ret = -UNW_EINVAL;
189	      goto fail;
190	    }
191	  sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
192	  Debug (15, "CFA_restore_extended r%lu\n", (long) regnum);
193	  break;
194
195	case DW_CFA_nop:
196	  break;
197
198	case DW_CFA_set_loc:
199	  fde_encoding = dci->fde_encoding;
200	  if ((ret = dwarf_read_encoded_pointer (as, a, addr, fde_encoding,
201						 &c->pi, &curr_ip,
202						 arg)) < 0)
203	    goto fail;
204	  Debug (15, "CFA_set_loc to 0x%lx\n", (long) curr_ip);
205	  break;
206
207	case DW_CFA_undefined:
208	  if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
209	    goto fail;
210	  set_reg (sr, regnum, DWARF_WHERE_UNDEF, 0);
211	  Debug (15, "CFA_undefined r%lu\n", (long) regnum);
212	  break;
213
214	case DW_CFA_same_value:
215	  if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
216	    goto fail;
217	  set_reg (sr, regnum, DWARF_WHERE_SAME, 0);
218	  Debug (15, "CFA_same_value r%lu\n", (long) regnum);
219	  break;
220
221	case DW_CFA_register:
222	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
223	      || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
224	    goto fail;
225	  set_reg (sr, regnum, DWARF_WHERE_REG, val);
226	  Debug (15, "CFA_register r%lu to r%lu\n", (long) regnum, (long) val);
227	  break;
228
229	case DW_CFA_remember_state:
230	  new_rs = alloc_reg_state ();
231	  if (!new_rs)
232	    {
233	      Debug (1, "Out of memory in DW_CFA_remember_state\n");
234	      ret = -UNW_ENOMEM;
235	      goto fail;
236	    }
237
238	  memcpy (new_rs->reg, sr->rs_current.reg, sizeof (new_rs->reg));
239	  new_rs->next = rs_stack;
240	  rs_stack = new_rs;
241	  Debug (15, "CFA_remember_state\n");
242	  break;
243
244	case DW_CFA_restore_state:
245	  if (!rs_stack)
246	    {
247	      Debug (1, "register-state stack underflow\n");
248	      ret = -UNW_EINVAL;
249	      goto fail;
250	    }
251	  memcpy (&sr->rs_current.reg, &rs_stack->reg, sizeof (rs_stack->reg));
252	  old_rs = rs_stack;
253	  rs_stack = rs_stack->next;
254	  free_reg_state (old_rs);
255	  Debug (15, "CFA_restore_state\n");
256	  break;
257
258	case DW_CFA_def_cfa:
259	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
260	      || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
261	    goto fail;
262	  set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
263	  set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val);	/* NOT factored! */
264	  Debug (15, "CFA_def_cfa r%lu+0x%lx\n", (long) regnum, (long) val);
265	  break;
266
267	case DW_CFA_def_cfa_sf:
268	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
269	      || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
270	    goto fail;
271	  set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
272	  set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
273		   val * dci->data_align);		/* factored! */
274	  Debug (15, "CFA_def_cfa_sf r%lu+0x%lx\n",
275		 (long) regnum, (long) (val * dci->data_align));
276	  break;
277
278	case DW_CFA_def_cfa_register:
279	  if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
280	    goto fail;
281	  set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
282	  Debug (15, "CFA_def_cfa_register r%lu\n", (long) regnum);
283	  break;
284
285	case DW_CFA_def_cfa_offset:
286	  if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
287	    goto fail;
288	  set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val);	/* NOT factored! */
289	  Debug (15, "CFA_def_cfa_offset 0x%lx\n", (long) val);
290	  break;
291
292	case DW_CFA_def_cfa_offset_sf:
293	  if ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0)
294	    goto fail;
295	  set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
296		   val * dci->data_align);	/* factored! */
297	  Debug (15, "CFA_def_cfa_offset_sf 0x%lx\n",
298		 (long) (val * dci->data_align));
299	  break;
300
301	case DW_CFA_def_cfa_expression:
302	  /* Save the address of the DW_FORM_block for later evaluation. */
303	  set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_EXPR, *addr);
304
305	  if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
306	    goto fail;
307
308	  Debug (15, "CFA_def_cfa_expr @ 0x%lx [%lu bytes]\n",
309		 (long) *addr, (long) len);
310	  *addr += len;
311	  break;
312
313	case DW_CFA_expression:
314	  if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
315	    goto fail;
316
317	  /* Save the address of the DW_FORM_block for later evaluation. */
318	  set_reg (sr, regnum, DWARF_WHERE_EXPR, *addr);
319
320	  if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
321	    goto fail;
322
323	  Debug (15, "CFA_expression r%lu @ 0x%lx [%lu bytes]\n",
324		 (long) regnum, (long) addr, (long) len);
325	  *addr += len;
326	  break;
327
328	case DW_CFA_GNU_args_size:
329	  if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
330	    goto fail;
331	  sr->args_size = val;
332	  Debug (15, "CFA_GNU_args_size %lu\n", (long) val);
333	  break;
334
335	case DW_CFA_GNU_negative_offset_extended:
336	  /* A comment in GCC says that this is obsoleted by
337	     DW_CFA_offset_extended_sf, but that it's used by older
338	     PowerPC code.  */
339	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
340	      || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
341	    goto fail;
342	  set_reg (sr, regnum, DWARF_WHERE_CFAREL, -(val * dci->data_align));
343	  Debug (15, "CFA_GNU_negative_offset_extended cfa+0x%lx\n",
344		 (long) -(val * dci->data_align));
345	  break;
346
347	case DW_CFA_GNU_window_save:
348#ifdef UNW_TARGET_SPARC
349	  /* This is a special CFA to handle all 16 windowed registers
350	     on SPARC.  */
351	  for (regnum = 16; regnum < 32; ++regnum)
352	    set_reg (sr, regnum, DWARF_WHERE_CFAREL,
353		     (regnum - 16) * sizeof (unw_word_t));
354	  Debug (15, "CFA_GNU_window_save\n");
355	  break;
356#else
357	  /* FALL THROUGH */
358#endif
359	case DW_CFA_lo_user:
360	case DW_CFA_hi_user:
361	  Debug (1, "Unexpected CFA opcode 0x%x\n", op);
362	  ret = -UNW_EINVAL;
363	  goto fail;
364	}
365    }
366  ret = 0;
367
368 fail:
369  /* Free the register-state stack, if not empty already.  */
370  while (rs_stack)
371    {
372      old_rs = rs_stack;
373      rs_stack = rs_stack->next;
374      free_reg_state (old_rs);
375    }
376  return ret;
377}
378
379static int
380fetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
381{
382  int ret, dynamic = 1;
383
384  --ip;
385
386  if (c->pi_valid && !need_unwind_info)
387    return 0;
388
389  memset (&c->pi, 0, sizeof (c->pi));
390
391  /* check dynamic info first --- it overrides everything else */
392  ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, need_unwind_info,
393				     c->as_arg);
394  if (ret == -UNW_ENOINFO)
395    {
396      dynamic = 0;
397      if ((ret = tdep_find_proc_info (c, ip, need_unwind_info)) < 0)
398	return ret;
399    }
400
401  c->pi_valid = 1;
402  c->pi_is_dynamic = dynamic;
403  return ret;
404}
405
406static int
407parse_dynamic (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
408{
409  Debug (1, "Not yet implemented\n");
410#if 0
411  /* Don't forget to set the ret_addr_column!  */
412  c->ret_addr_column = XXX;
413#endif
414  return -UNW_ENOINFO;
415}
416
417static inline void
418put_unwind_info (struct dwarf_cursor *c, unw_proc_info_t *pi)
419{
420  if (!c->pi_valid)
421    return;
422
423  if (c->pi_is_dynamic)
424    unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg);
425  else if (pi->unwind_info);
426    {
427      mempool_free (&dwarf_cie_info_pool, pi->unwind_info);
428      pi->unwind_info = NULL;
429    }
430}
431
432static inline int
433parse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
434{
435  struct dwarf_cie_info *dci;
436  unw_word_t addr;
437  int ret;
438
439  dci = c->pi.unwind_info;
440  c->ret_addr_column = dci->ret_addr_column;
441
442  addr = dci->cie_instr_start;
443  if ((ret = run_cfi_program (c, sr, ~(unw_word_t) 0, &addr,
444			      dci->cie_instr_end, dci)) < 0)
445    return ret;
446
447  memcpy (&sr->rs_initial, &sr->rs_current, sizeof (sr->rs_initial));
448
449  addr = dci->fde_instr_start;
450  if ((ret = run_cfi_program (c, sr, ip, &addr, dci->fde_instr_end, dci)) < 0)
451    return ret;
452
453  return 0;
454}
455
456static inline void
457flush_rs_cache (struct dwarf_rs_cache *cache)
458{
459  int i;
460
461  cache->lru_head = DWARF_UNW_CACHE_SIZE - 1;
462  cache->lru_tail = 0;
463
464  for (i = 0; i < DWARF_UNW_CACHE_SIZE; ++i)
465    {
466      if (i > 0)
467	cache->buckets[i].lru_chain = (i - 1);
468      cache->buckets[i].coll_chain = -1;
469      cache->buckets[i].ip = 0;
470    }
471  for (i = 0; i<DWARF_UNW_HASH_SIZE; ++i)
472    cache->hash[i] = -1;
473}
474
475static inline struct dwarf_rs_cache *
476get_rs_cache (unw_addr_space_t as, intrmask_t *saved_maskp)
477{
478  struct dwarf_rs_cache *cache = &as->global_cache;
479  unw_caching_policy_t caching = as->caching_policy;
480
481  if (caching == UNW_CACHE_NONE)
482    return NULL;
483
484  if (likely (caching == UNW_CACHE_GLOBAL))
485    {
486      Debug (16, "%s: acquiring lock\n", __FUNCTION__);
487      lock_acquire (&cache->lock, *saved_maskp);
488    }
489
490  if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation))
491    {
492      flush_rs_cache (cache);
493      cache->generation = as->cache_generation;
494    }
495
496  return cache;
497}
498
499static inline void
500put_rs_cache (unw_addr_space_t as, struct dwarf_rs_cache *cache,
501		  intrmask_t *saved_maskp)
502{
503  assert (as->caching_policy != UNW_CACHE_NONE);
504
505  Debug (16, "unmasking signals/interrupts and releasing lock\n");
506  if (likely (as->caching_policy == UNW_CACHE_GLOBAL))
507    lock_release (&cache->lock, *saved_maskp);
508}
509
510static inline unw_hash_index_t
511hash (unw_word_t ip)
512{
513  /* based on (sqrt(5)/2-1)*2^64 */
514# define magic	((unw_word_t) 0x9e3779b97f4a7c16ULL)
515
516  return ip * magic >> ((sizeof(unw_word_t) * 8) - DWARF_LOG_UNW_HASH_SIZE);
517}
518
519static inline long
520cache_match (dwarf_reg_state_t *rs, unw_word_t ip)
521{
522  if (ip == rs->ip)
523    return 1;
524  return 0;
525}
526
527static dwarf_reg_state_t *
528rs_lookup (struct dwarf_rs_cache *cache, struct dwarf_cursor *c)
529{
530  dwarf_reg_state_t *rs = cache->buckets + c->hint;
531  unsigned short index;
532  unw_word_t ip;
533
534  ip = c->ip;
535
536  if (cache_match (rs, ip))
537    return rs;
538
539  index = cache->hash[hash (ip)];
540  if (index >= DWARF_UNW_CACHE_SIZE)
541    return 0;
542
543  rs = cache->buckets + index;
544  while (1)
545    {
546      if (cache_match (rs, ip))
547        {
548          /* update hint; no locking needed: single-word writes are atomic */
549          c->hint = cache->buckets[c->prev_rs].hint =
550            (rs - cache->buckets);
551          return rs;
552        }
553      if (rs->coll_chain >= DWARF_UNW_HASH_SIZE)
554        return 0;
555      rs = cache->buckets + rs->coll_chain;
556    }
557}
558
559static inline dwarf_reg_state_t *
560rs_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c)
561{
562  dwarf_reg_state_t *rs, *prev, *tmp;
563  unw_hash_index_t index;
564  unsigned short head;
565
566  head = cache->lru_head;
567  rs = cache->buckets + head;
568  cache->lru_head = rs->lru_chain;
569
570  /* re-insert rs at the tail of the LRU chain: */
571  cache->buckets[cache->lru_tail].lru_chain = head;
572  cache->lru_tail = head;
573
574  /* remove the old rs from the hash table (if it's there): */
575  if (rs->ip)
576    {
577      index = hash (rs->ip);
578      tmp = cache->buckets + cache->hash[index];
579      prev = 0;
580      while (1)
581	{
582	  if (tmp == rs)
583	    {
584	      if (prev)
585		prev->coll_chain = tmp->coll_chain;
586	      else
587		cache->hash[index] = tmp->coll_chain;
588	      break;
589	    }
590	  else
591	    prev = tmp;
592	  if (tmp->coll_chain >= DWARF_UNW_CACHE_SIZE)
593	    /* old rs wasn't in the hash-table */
594	    break;
595	  tmp = cache->buckets + tmp->coll_chain;
596	}
597    }
598
599  /* enter new rs in the hash table */
600  index = hash (c->ip);
601  rs->coll_chain = cache->hash[index];
602  cache->hash[index] = rs - cache->buckets;
603
604  rs->hint = 0;
605  rs->ip = c->ip;
606  rs->ret_addr_column = c->ret_addr_column;
607
608  return rs;
609}
610
611static int
612create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr,
613			 unw_word_t ip)
614{
615  int i, ret;
616
617  assert (c->pi_valid);
618
619  memset (sr, 0, sizeof (*sr));
620  for (i = 0; i < DWARF_NUM_PRESERVED_REGS + 2; ++i)
621    set_reg (sr, i, DWARF_WHERE_SAME, 0);
622
623  switch (c->pi.format)
624    {
625    case UNW_INFO_FORMAT_TABLE:
626    case UNW_INFO_FORMAT_REMOTE_TABLE:
627      ret = parse_fde (c, ip, sr);
628      break;
629
630    case UNW_INFO_FORMAT_DYNAMIC:
631      ret = parse_dynamic (c, ip, sr);
632      break;
633
634    default:
635      Debug (1, "Unexpected unwind-info format %d\n", c->pi.format);
636      ret = -UNW_EINVAL;
637    }
638  return ret;
639}
640
641static inline int
642eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as,
643		    unw_accessors_t *a, unw_word_t addr,
644		    dwarf_loc_t *locp, void *arg)
645{
646  int ret, is_register;
647  unw_word_t len, val;
648
649  /* read the length of the expression: */
650  if ((ret = dwarf_read_uleb128 (as, a, &addr, &len, arg)) < 0)
651    return ret;
652
653  /* evaluate the expression: */
654  if ((ret = dwarf_eval_expr (c, &addr, len, &val, &is_register)) < 0)
655    return ret;
656
657  if (is_register)
658    *locp = DWARF_REG_LOC (c, dwarf_to_unw_regnum (val));
659  else
660    *locp = DWARF_MEM_LOC (c, val);
661
662  return 0;
663}
664
665static int
666apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
667{
668  unw_word_t regnum, addr, cfa, ip;
669  unw_word_t prev_ip, prev_cfa;
670  unw_addr_space_t as;
671  dwarf_loc_t cfa_loc;
672  unw_accessors_t *a;
673  int i, ret;
674  void *arg;
675
676  prev_ip = c->ip;
677  prev_cfa = c->cfa;
678
679  as = c->as;
680  arg = c->as_arg;
681  a = unw_get_accessors (as);
682
683  /* Evaluate the CFA first, because it may be referred to by other
684     expressions.  */
685
686  if (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
687    {
688      /* CFA is equal to [reg] + offset: */
689
690      /* As a special-case, if the stack-pointer is the CFA and the
691	 stack-pointer wasn't saved, popping the CFA implicitly pops
692	 the stack-pointer as well.  */
693      if ((rs->reg[DWARF_CFA_REG_COLUMN].val == UNW_TDEP_SP)
694          && (UNW_TDEP_SP < ARRAY_SIZE(rs->reg))
695	  && (rs->reg[UNW_TDEP_SP].where == DWARF_WHERE_SAME))
696	  cfa = c->cfa;
697      else
698	{
699	  regnum = dwarf_to_unw_regnum (rs->reg[DWARF_CFA_REG_COLUMN].val);
700	  if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0)
701	    return ret;
702	}
703      cfa += rs->reg[DWARF_CFA_OFF_COLUMN].val;
704    }
705  else
706    {
707      /* CFA is equal to EXPR: */
708
709      assert (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_EXPR);
710
711      addr = rs->reg[DWARF_CFA_REG_COLUMN].val;
712      if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0)
713	return ret;
714      /* the returned location better be a memory location... */
715      if (DWARF_IS_REG_LOC (cfa_loc))
716	return -UNW_EBADFRAME;
717      cfa = DWARF_GET_LOC (cfa_loc);
718    }
719
720  for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
721    {
722      switch ((dwarf_where_t) rs->reg[i].where)
723	{
724	case DWARF_WHERE_UNDEF:
725	  c->loc[i] = DWARF_NULL_LOC;
726	  break;
727
728	case DWARF_WHERE_SAME:
729	  break;
730
731	case DWARF_WHERE_CFAREL:
732	  c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
733	  break;
734
735	case DWARF_WHERE_REG:
736	  c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
737	  break;
738
739	case DWARF_WHERE_EXPR:
740	  addr = rs->reg[i].val;
741	  if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) , 0)
742	    return ret;
743	  break;
744	}
745    }
746  c->cfa = cfa;
747  ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip);
748  if (ret < 0)
749    return ret;
750  c->ip = ip;
751  /* XXX: check for ip to be code_aligned */
752
753  if (c->ip == prev_ip && c->cfa == prev_cfa)
754    {
755      Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
756	       __FUNCTION__, (long) c->ip);
757      return -UNW_EBADFRAME;
758    }
759  return 0;
760}
761
762static int
763uncached_dwarf_find_save_locs (struct dwarf_cursor *c)
764{
765  dwarf_state_record_t sr;
766  int ret;
767
768  if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
769    return ret;
770
771  if ((ret = create_state_record_for (c, &sr, c->ip)) < 0)
772    return ret;
773
774  if ((ret = apply_reg_state (c, &sr.rs_current)) < 0)
775    return ret;
776
777  put_unwind_info (c, &c->pi);
778  return 0;
779}
780
781/* The function finds the saved locations and applies the register
782   state as well. */
783HIDDEN int
784dwarf_find_save_locs (struct dwarf_cursor *c)
785{
786  dwarf_state_record_t sr;
787  dwarf_reg_state_t *rs, *rs1;
788  struct dwarf_rs_cache *cache;
789  int ret = 0;
790  intrmask_t saved_mask;
791
792  if (c->as->caching_policy == UNW_CACHE_NONE)
793    return uncached_dwarf_find_save_locs (c);
794
795  cache = get_rs_cache(c->as, &saved_mask);
796  if (!cache)
797    return -UNW_ENOINFO;	/* cache is busy */
798  rs = rs_lookup(cache, c);
799
800  if (rs)
801    {
802      c->ret_addr_column = rs->ret_addr_column;
803      goto apply;
804    }
805
806  if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
807    goto out;
808
809  if ((ret = create_state_record_for (c, &sr, c->ip)) < 0)
810    goto out;
811
812  rs1 = &sr.rs_current;
813  if (rs1)
814    {
815      rs = rs_new (cache, c);
816      memcpy(rs, rs1, offsetof(struct dwarf_reg_state, ip));
817      if (!rs)
818        {
819          Dprintf ("%s: failed to create unwind rs\n", __FUNCTION__);
820          ret = -UNW_EUNSPEC;
821	  goto out;
822        }
823    }
824  cache->buckets[c->prev_rs].hint = rs - cache->buckets;
825
826  c->hint = rs->hint;
827  c->prev_rs = rs - cache->buckets;
828
829  put_unwind_info (c, &c->pi);
830  ret = apply_reg_state (c, rs);
831
832out:
833  put_rs_cache (c->as, cache, &saved_mask);
834  return ret;
835
836apply:
837  put_rs_cache (c->as, cache, &saved_mask);
838  if ((ret = apply_reg_state (c, rs)) < 0)
839    return ret;
840
841  return 0;
842}
843
844/* The proc-info must be valid for IP before this routine can be
845   called.  */
846HIDDEN int
847dwarf_create_state_record (struct dwarf_cursor *c, dwarf_state_record_t *sr)
848{
849  return create_state_record_for (c, sr, c->ip);
850}
851
852HIDDEN int
853dwarf_make_proc_info (struct dwarf_cursor *c)
854{
855#if 0
856  if (c->as->caching_policy == UNW_CACHE_NONE
857      || get_cached_proc_info (c) < 0)
858#endif
859    /* Lookup it up the slow way... */
860    return fetch_proc_info (c, c->ip, 0);
861  return 0;
862}
863