188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm/* libunwind - a platform-independent unwind library
2df3d6af467fa67e2a2127b9c49b71359982c099fhp.com!davidm   Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P.
388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmThis file is part of libunwind.
688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmPermission is hereby granted, free of charge, to any person obtaining
888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidma copy of this software and associated documentation files (the
988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm"Software"), to deal in the Software without restriction, including
1088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmwithout limitation the rights to use, copy, modify, merge, publish,
1188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmdistribute, sublicense, and/or sell copies of the Software, and to
1288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmpermit persons to whom the Software is furnished to do so, subject to
1388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmthe following conditions:
1488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
1588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmThe above copyright notice and this permission notice shall be
1688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmincluded in all copies or substantial portions of the Software.
1788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
1888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
2588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
2600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma#include <stddef.h>
2788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#include "dwarf_i.h"
28df3d6af467fa67e2a2127b9c49b71359982c099fhp.com!davidm#include "libunwind_i.h"
2988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
3088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#define alloc_reg_state()	(mempool_alloc (&dwarf_reg_state_pool))
3188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#define free_reg_state(rs)	(mempool_free (&dwarf_reg_state_pool, rs))
3288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
3388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic inline int
3488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmread_regnum (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
3588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	     unw_word_t *valp, void *arg)
3688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
3788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  int ret;
3888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
3988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if ((ret = dwarf_read_uleb128 (as, a, addr, valp, arg)) < 0)
4088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    return ret;
4188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
4288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if (*valp >= DWARF_NUM_PRESERVED_REGS)
4388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    {
44642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm      Debug (1, "Invalid register number %u\n", (unsigned int) *valp);
4588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      return -UNW_EBADREG;
4688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    }
4788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return 0;
4888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
4988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
5088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic inline void
5188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmset_reg (dwarf_state_record_t *sr, unw_word_t regnum, dwarf_where_t where,
5288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	 unw_word_t val)
5388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
5488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  sr->rs_current.reg[regnum].where = where;
5588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  sr->rs_current.reg[regnum].val = val;
5688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
5788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
5888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm/* Run a CFI program to update the register state.  */
5988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic int
6088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmrun_cfi_program (struct dwarf_cursor *c, dwarf_state_record_t *sr,
6188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm		 unw_word_t ip, unw_word_t *addr, unw_word_t end_addr,
62c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm		 struct dwarf_cie_info *dci)
6388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
6488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  unw_word_t curr_ip, operand = 0, regnum, val, len, fde_encoding;
6588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  dwarf_reg_state_t *rs_stack = NULL, *new_rs, *old_rs;
6688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  unw_addr_space_t as;
6788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  unw_accessors_t *a;
6888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  uint8_t u8, op;
6988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  uint16_t u16;
7088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  uint32_t u32;
7188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  void *arg;
7288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  int ret;
7388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
7488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  as = c->as;
7588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  arg = c->as_arg;
7646e10c5abeeb93345367a70db2af3aba4440a49eArun Sharma  if (c->pi.flags & UNW_PI_FLAG_DEBUG_FRAME)
7746e10c5abeeb93345367a70db2af3aba4440a49eArun Sharma    {
7846e10c5abeeb93345367a70db2af3aba4440a49eArun Sharma      /* .debug_frame CFI is stored in local address space.  */
7946e10c5abeeb93345367a70db2af3aba4440a49eArun Sharma      as = unw_local_addr_space;
8046e10c5abeeb93345367a70db2af3aba4440a49eArun Sharma      arg = NULL;
8146e10c5abeeb93345367a70db2af3aba4440a49eArun Sharma    }
8288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  a = unw_get_accessors (as);
8388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  curr_ip = c->pi.start_ip;
8488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
85a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura  /* Process everything up to and including the current 'ip',
86a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     including all the DW_CFA_advance_loc instructions.  See
87a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     'c->use_prev_instr' use in 'fetch_proc_info' for details. */
88a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura  while (curr_ip <= ip && *addr < end_addr)
8988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    {
9088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      if ((ret = dwarf_readu8 (as, a, addr, &op, arg)) < 0)
9188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	return ret;
9288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
9388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      if (op & DWARF_CFA_OPCODE_MASK)
9488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	{
9588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  operand = op & DWARF_CFA_OPERAND_MASK;
9688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  op &= ~DWARF_CFA_OPERAND_MASK;
9788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	}
9888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      switch ((dwarf_cfa_t) op)
9988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	{
10088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_advance_loc:
101c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  curr_ip += operand * dci->code_align;
102aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_advance_loc to 0x%lx\n", (long) curr_ip);
10388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
10488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
10588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_advance_loc1:
10688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_readu8 (as, a, addr, &u8, arg)) < 0)
10788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
108c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  curr_ip += u8 * dci->code_align;
109aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_advance_loc1 to 0x%lx\n", (long) curr_ip);
11088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
11188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
11288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_advance_loc2:
11388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_readu16 (as, a, addr, &u16, arg)) < 0)
11488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
115c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  curr_ip += u16 * dci->code_align;
116aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_advance_loc2 to 0x%lx\n", (long) curr_ip);
11788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
11888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
11988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_advance_loc4:
12088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_readu32 (as, a, addr, &u32, arg)) < 0)
12188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
122c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  curr_ip += u32 * dci->code_align;
123aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_advance_loc4 to 0x%lx\n", (long) curr_ip);
12488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
12588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
12688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_MIPS_advance_loc8:
12788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#ifdef UNW_TARGET_MIPS
12888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  {
12988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    uint64_t u64;
13088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
13188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    if ((ret = dwarf_readu64 (as, a, addr, &u64, arg)) < 0)
13288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      goto fail;
133c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	    curr_ip += u64 * dci->code_align;
134aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	    Debug (15, "CFA_MIPS_advance_loc8\n");
13588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    break;
13688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  }
13788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#else
13888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  Debug (1, "DW_CFA_MIPS_advance_loc8 on non-MIPS target\n");
13988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  ret = -UNW_EINVAL;
14088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  goto fail;
14188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#endif
14288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
14388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_offset:
14488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  regnum = operand;
14588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (regnum >= DWARF_NUM_PRESERVED_REGS)
14688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    {
14788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      Debug (1, "Invalid register number %u in DW_cfa_OFFSET\n",
148642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm		     (unsigned int) regnum);
14988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      ret = -UNW_EBADREG;
15088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      goto fail;
15188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    }
15288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
15388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
154c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
155aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_offset r%lu at cfa+0x%lx\n",
156c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm		 (long) regnum, (long) (val * dci->data_align));
15788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
15888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
15988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_offset_extended:
16088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
16188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
16288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
163c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
164aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_offset_extended r%lu at cf+0x%lx\n",
165c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm		 (long) regnum, (long) (val * dci->data_align));
16688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
16788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
16888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_offset_extended_sf:
16988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
17088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
17188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
172c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  set_reg (sr, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
173aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_offset_extended_sf r%lu at cf+0x%lx\n",
174c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm		 (long) regnum, (long) (val * dci->data_align));
17588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
17688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
17788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_restore:
17888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  regnum = operand;
17988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (regnum >= DWARF_NUM_PRESERVED_REGS)
18088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    {
18188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      Debug (1, "Invalid register number %u in DW_CFA_restore\n",
182642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm		     (unsigned int) regnum);
18388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      ret = -UNW_EINVAL;
18488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      goto fail;
18588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    }
18688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
187aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_restore r%lu\n", (long) regnum);
18888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
18988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
19088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_restore_extended:
19188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_read_uleb128 (as, a, addr, &regnum, arg)) < 0)
19288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
19388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (regnum >= DWARF_NUM_PRESERVED_REGS)
19488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    {
19588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      Debug (1, "Invalid register number %u in "
196642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm		     "DW_CFA_restore_extended\n", (unsigned int) regnum);
19788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      ret = -UNW_EINVAL;
19888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      goto fail;
19988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    }
20088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  sr->rs_current.reg[regnum] = sr->rs_initial.reg[regnum];
201aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_restore_extended r%lu\n", (long) regnum);
20288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
20388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
20488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_nop:
20588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
20688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
20788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_set_loc:
208c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  fde_encoding = dci->fde_encoding;
20988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_read_encoded_pointer (as, a, addr, fde_encoding,
21088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm						 &c->pi, &curr_ip,
21188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm						 arg)) < 0)
21288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
213aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_set_loc to 0x%lx\n", (long) curr_ip);
21488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
21588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
21688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_undefined:
21788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
21888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
21988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, regnum, DWARF_WHERE_UNDEF, 0);
220aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_undefined r%lu\n", (long) regnum);
22188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
22288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
22388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_same_value:
22488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
22588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
22688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, regnum, DWARF_WHERE_SAME, 0);
227aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_same_value r%lu\n", (long) regnum);
22888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
22988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
23088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_register:
23188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
23288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
23388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
23488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, regnum, DWARF_WHERE_REG, val);
235aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_register r%lu to r%lu\n", (long) regnum, (long) val);
23688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
23788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
23888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_remember_state:
23988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  new_rs = alloc_reg_state ();
24088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (!new_rs)
24188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    {
24288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      Debug (1, "Out of memory in DW_CFA_remember_state\n");
24388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      ret = -UNW_ENOMEM;
24488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      goto fail;
24588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    }
24688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
24788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  memcpy (new_rs->reg, sr->rs_current.reg, sizeof (new_rs->reg));
24888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  new_rs->next = rs_stack;
24988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  rs_stack = new_rs;
250aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_remember_state\n");
25188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
25288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
25388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_restore_state:
25488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (!rs_stack)
25588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    {
25688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      Debug (1, "register-state stack underflow\n");
25788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      ret = -UNW_EINVAL;
25888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      goto fail;
25988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    }
26088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  memcpy (&sr->rs_current.reg, &rs_stack->reg, sizeof (rs_stack->reg));
26188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  old_rs = rs_stack;
26288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  rs_stack = rs_stack->next;
26388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  free_reg_state (old_rs);
264aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_restore_state\n");
26588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
26688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
26788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_def_cfa:
26888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
26988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
27088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
27188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
27288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val);	/* NOT factored! */
273aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_def_cfa r%lu+0x%lx\n", (long) regnum, (long) val);
27488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
27588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
27688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_def_cfa_sf:
27788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
27888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      || ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0))
27988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
28088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
28188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
282c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm		   val * dci->data_align);		/* factored! */
283aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_def_cfa_sf r%lu+0x%lx\n",
284c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm		 (long) regnum, (long) (val * dci->data_align));
28588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
28688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
28788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_def_cfa_register:
28888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
28988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
29088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_REG, regnum);
291aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_def_cfa_register r%lu\n", (long) regnum);
29288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
29388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
29488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_def_cfa_offset:
29588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
29688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
29788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, DWARF_CFA_OFF_COLUMN, 0, val);	/* NOT factored! */
298c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  Debug (15, "CFA_def_cfa_offset 0x%lx\n", (long) val);
29988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
30088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
30188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_def_cfa_offset_sf:
30288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_read_sleb128 (as, a, addr, &val, arg)) < 0)
30388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
30488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, DWARF_CFA_OFF_COLUMN, 0,
305c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm		   val * dci->data_align);	/* factored! */
306c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  Debug (15, "CFA_def_cfa_offset_sf 0x%lx\n",
307c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm		 (long) (val * dci->data_align));
30888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
30988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
31088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_def_cfa_expression:
31188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  /* Save the address of the DW_FORM_block for later evaluation. */
31288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, DWARF_CFA_REG_COLUMN, DWARF_WHERE_EXPR, *addr);
31388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
31488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
31588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
31688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
317aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_def_cfa_expr @ 0x%lx [%lu bytes]\n",
31888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm		 (long) *addr, (long) len);
31988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  *addr += len;
32088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
32188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
322c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	case DW_CFA_expression:
32388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
32488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
32588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
32688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  /* Save the address of the DW_FORM_block for later evaluation. */
32788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  set_reg (sr, regnum, DWARF_WHERE_EXPR, *addr);
32888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
32988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_read_uleb128 (as, a, addr, &len, arg)) < 0)
33088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
33188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
332aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_expression r%lu @ 0x%lx [%lu bytes]\n",
33388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm		 (long) regnum, (long) addr, (long) len);
33488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  *addr += len;
33588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
33688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
33788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_GNU_args_size:
33888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0)
33988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
34088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  sr->args_size = val;
341aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_GNU_args_size %lu\n", (long) val);
34288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
34388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
34488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_GNU_negative_offset_extended:
34588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  /* A comment in GCC says that this is obsoleted by
34688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	     DW_CFA_offset_extended_sf, but that it's used by older
34788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	     PowerPC code.  */
34888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  if (((ret = read_regnum (as, a, addr, &regnum, arg)) < 0)
34988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	      || ((ret = dwarf_read_uleb128 (as, a, addr, &val, arg)) < 0))
35088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    goto fail;
351c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  set_reg (sr, regnum, DWARF_WHERE_CFAREL, -(val * dci->data_align));
352c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  Debug (15, "CFA_GNU_negative_offset_extended cfa+0x%lx\n",
353c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm		 (long) -(val * dci->data_align));
35488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
35588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
35688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_GNU_window_save:
35788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#ifdef UNW_TARGET_SPARC
35888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  /* This is a special CFA to handle all 16 windowed registers
35988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	     on SPARC.  */
36088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  for (regnum = 16; regnum < 32; ++regnum)
36188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    set_reg (sr, regnum, DWARF_WHERE_CFAREL,
36288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm		     (regnum - 16) * sizeof (unw_word_t));
363aae368ace23687c4f50f575111dc0196350b2c55homeip.net!davidm	  Debug (15, "CFA_GNU_window_save\n");
36488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
36588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#else
36688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  /* FALL THROUGH */
36788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#endif
36888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_lo_user:
36988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DW_CFA_hi_user:
370c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	  Debug (1, "Unexpected CFA opcode 0x%x\n", op);
37188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  ret = -UNW_EINVAL;
37288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  goto fail;
37388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	}
37488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    }
37588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  ret = 0;
37688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
37788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm fail:
37888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  /* Free the register-state stack, if not empty already.  */
37988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  while (rs_stack)
38088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    {
38188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      old_rs = rs_stack;
38288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      rs_stack = rs_stack->next;
38388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      free_reg_state (old_rs);
38488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    }
38588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return ret;
38688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
38788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
38888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic int
38988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmfetch_proc_info (struct dwarf_cursor *c, unw_word_t ip, int need_unwind_info)
39088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
39188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  int ret, dynamic = 1;
39288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
393a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura  /* The 'ip' can point either to the previous or next instruction
394a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     depending on what type of frame we have: normal call or a place
395a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     to resume execution (e.g. after signal frame).
396a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura
397a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     For a normal call frame we need to back up so we point within the
398a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     call itself; this is important because a) the call might be the
399a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     very last instruction of the function and the edge of the FDE,
400a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     and b) so that run_cfi_program() runs locations up to the call
401a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     but not more.
402a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura
403a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     For execution resume, we need to do the exact opposite and look
404a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     up using the current 'ip' value.  That is where execution will
405a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     continue, and it's important we get this right, as 'ip' could be
406a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     right at the function entry and hence FDE edge, or at instruction
407a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura     that manipulates CFA (push/pop). */
408a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura  if (c->use_prev_instr)
409a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura    --ip;
410c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm
41188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if (c->pi_valid && !need_unwind_info)
41288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    return 0;
41388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
414c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  memset (&c->pi, 0, sizeof (c->pi));
415c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm
41688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  /* check dynamic info first --- it overrides everything else */
41788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  ret = unwi_find_dynamic_proc_info (c->as, ip, &c->pi, need_unwind_info,
41888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm				     c->as_arg);
41988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if (ret == -UNW_ENOINFO)
42088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    {
42188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      dynamic = 0;
42288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      if ((ret = tdep_find_proc_info (c, ip, need_unwind_info)) < 0)
42388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	return ret;
42488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    }
42588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
426545023c2072975c6b85a09d5faf2cf05db10e064Ken Werner  if (c->pi.format != UNW_INFO_FORMAT_DYNAMIC
427545023c2072975c6b85a09d5faf2cf05db10e064Ken Werner      && c->pi.format != UNW_INFO_FORMAT_TABLE
428545023c2072975c6b85a09d5faf2cf05db10e064Ken Werner      && c->pi.format != UNW_INFO_FORMAT_REMOTE_TABLE)
429545023c2072975c6b85a09d5faf2cf05db10e064Ken Werner    return -UNW_ENOINFO;
430545023c2072975c6b85a09d5faf2cf05db10e064Ken Werner
43188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  c->pi_valid = 1;
43288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  c->pi_is_dynamic = dynamic;
433dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
434dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  /* Let system/machine-dependent code determine frame-specific attributes. */
435dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  if (ret >= 0)
436dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura    tdep_fetch_frame (c, ip, need_unwind_info);
437dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
438a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura  /* Update use_prev_instr for the next frame. */
439a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura  if (need_unwind_info)
440a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura  {
441a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura    assert(c->pi.unwind_info);
442a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura    struct dwarf_cie_info *dci = c->pi.unwind_info;
443a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura    c->use_prev_instr = ! dci->signal_frame;
444a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura  }
445a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura
44688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return ret;
44788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
44888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
44988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic int
45088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmparse_dynamic (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
45188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
45288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  Debug (1, "Not yet implemented\n");
45388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#if 0
45488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  /* Don't forget to set the ret_addr_column!  */
45588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  c->ret_addr_column = XXX;
45688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#endif
45788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return -UNW_ENOINFO;
45888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
45988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
46088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic inline void
46188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmput_unwind_info (struct dwarf_cursor *c, unw_proc_info_t *pi)
46288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
46388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if (c->pi_is_dynamic)
46488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    unwi_put_dynamic_unwind_info (c->as, pi, c->as_arg);
4653b8254d3b911193d1270bed6e941f56479ef5a85Matt Fischer  else if (pi->unwind_info && pi->format == UNW_INFO_FORMAT_TABLE)
466c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm    {
467c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm      mempool_free (&dwarf_cie_info_pool, pi->unwind_info);
468c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm      pi->unwind_info = NULL;
469c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm    }
47088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
47188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
47288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic inline int
47388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmparse_fde (struct dwarf_cursor *c, unw_word_t ip, dwarf_state_record_t *sr)
47488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
475c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  struct dwarf_cie_info *dci;
47688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  unw_word_t addr;
47788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  int ret;
47888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
479c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  dci = c->pi.unwind_info;
480c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  c->ret_addr_column = dci->ret_addr_column;
48188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
482c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  addr = dci->cie_instr_start;
48388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if ((ret = run_cfi_program (c, sr, ~(unw_word_t) 0, &addr,
484c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm			      dci->cie_instr_end, dci)) < 0)
48588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    return ret;
48688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
48788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  memcpy (&sr->rs_initial, &sr->rs_current, sizeof (sr->rs_initial));
48888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
489c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  addr = dci->fde_instr_start;
490c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  if ((ret = run_cfi_program (c, sr, ip, &addr, dci->fde_instr_end, dci)) < 0)
49188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    return ret;
49288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
49388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return 0;
49488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
49588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
49600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmastatic inline void
49700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmaflush_rs_cache (struct dwarf_rs_cache *cache)
49800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma{
49900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  int i;
50000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
50100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  cache->lru_head = DWARF_UNW_CACHE_SIZE - 1;
50200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  cache->lru_tail = 0;
50300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
50400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  for (i = 0; i < DWARF_UNW_CACHE_SIZE; ++i)
50500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    {
50600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      if (i > 0)
50700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	cache->buckets[i].lru_chain = (i - 1);
50800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      cache->buckets[i].coll_chain = -1;
50900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      cache->buckets[i].ip = 0;
5105e59e93d049b9c6261c0db456edb7ab323618b6cArun Sharma      cache->buckets[i].valid = 0;
51100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    }
51200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  for (i = 0; i<DWARF_UNW_HASH_SIZE; ++i)
51300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    cache->hash[i] = -1;
51400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma}
51500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
5164312719cbc30dfa9e188b24e85185c325e671d00Arun Sharmastatic inline struct dwarf_rs_cache *
5174312719cbc30dfa9e188b24e85185c325e671d00Arun Sharmaget_rs_cache (unw_addr_space_t as, intrmask_t *saved_maskp)
51800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma{
51900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  struct dwarf_rs_cache *cache = &as->global_cache;
5204312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  unw_caching_policy_t caching = as->caching_policy;
5214312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma
5224312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  if (caching == UNW_CACHE_NONE)
5234312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma    return NULL;
5244312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma
5254312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  if (likely (caching == UNW_CACHE_GLOBAL))
5264312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma    {
527e61c6f69c30d85584ece5250b8b82b03898384f5Tommi Rantala      Debug (16, "acquiring lock\n");
52884d4150668d83a98420cc91e00026159c3d74a81Paul Pluzhnikov      lock_acquire (&cache->lock, *saved_maskp);
5294312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma    }
5304312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma
53100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation))
53200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    {
53300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      flush_rs_cache (cache);
53400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      cache->generation = as->cache_generation;
53500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    }
53600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
53700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  return cache;
53800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma}
53900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
5404312719cbc30dfa9e188b24e85185c325e671d00Arun Sharmastatic inline void
5414312719cbc30dfa9e188b24e85185c325e671d00Arun Sharmaput_rs_cache (unw_addr_space_t as, struct dwarf_rs_cache *cache,
5424312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma		  intrmask_t *saved_maskp)
5434312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma{
5444312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  assert (as->caching_policy != UNW_CACHE_NONE);
5454312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma
5464312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  Debug (16, "unmasking signals/interrupts and releasing lock\n");
5474312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  if (likely (as->caching_policy == UNW_CACHE_GLOBAL))
54884d4150668d83a98420cc91e00026159c3d74a81Paul Pluzhnikov    lock_release (&cache->lock, *saved_maskp);
5494312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma}
5504312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma
5517d471b144013924f8d80e532a693fb77dbe73c2bTommi Rantalastatic inline unw_hash_index_t CONST_ATTR
55200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmahash (unw_word_t ip)
55300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma{
55400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  /* based on (sqrt(5)/2-1)*2^64 */
55500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma# define magic	((unw_word_t) 0x9e3779b97f4a7c16ULL)
55600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
55755fe524775b47f16589e3fc8f28ccffe5e88a048Arun Sharma  return ip * magic >> ((sizeof(unw_word_t) * 8) - DWARF_LOG_UNW_HASH_SIZE);
55800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma}
55900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
56000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmastatic inline long
56100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmacache_match (dwarf_reg_state_t *rs, unw_word_t ip)
56200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma{
5635e59e93d049b9c6261c0db456edb7ab323618b6cArun Sharma  if (rs->valid && (ip == rs->ip))
56400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    return 1;
56500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  return 0;
56600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma}
56700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
56800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmastatic dwarf_reg_state_t *
56900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmars_lookup (struct dwarf_rs_cache *cache, struct dwarf_cursor *c)
57000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma{
57100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  dwarf_reg_state_t *rs = cache->buckets + c->hint;
57200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  unsigned short index;
57300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  unw_word_t ip;
57400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
57500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  ip = c->ip;
57600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
57700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if (cache_match (rs, ip))
57800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    return rs;
57900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
58000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  index = cache->hash[hash (ip)];
58100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if (index >= DWARF_UNW_CACHE_SIZE)
582890e23eb9d3ffd9be2a025189a21794b5ed0e0ffTommi Rantala    return NULL;
58300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
58400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  rs = cache->buckets + index;
58500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  while (1)
58600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    {
58700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      if (cache_match (rs, ip))
58800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma        {
58900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma          /* update hint; no locking needed: single-word writes are atomic */
59000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma          c->hint = cache->buckets[c->prev_rs].hint =
59100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma            (rs - cache->buckets);
59200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma          return rs;
59300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma        }
59400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      if (rs->coll_chain >= DWARF_UNW_HASH_SIZE)
595890e23eb9d3ffd9be2a025189a21794b5ed0e0ffTommi Rantala        return NULL;
59600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      rs = cache->buckets + rs->coll_chain;
59700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    }
59800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma}
59900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
60000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmastatic inline dwarf_reg_state_t *
601c5dc3c150a4fab2962f8d32f78d80ce857e662a5Arun Sharmars_new (struct dwarf_rs_cache *cache, struct dwarf_cursor * c)
60200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma{
60300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  dwarf_reg_state_t *rs, *prev, *tmp;
60400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  unw_hash_index_t index;
60500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  unsigned short head;
60600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
60700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  head = cache->lru_head;
60800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  rs = cache->buckets + head;
60900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  cache->lru_head = rs->lru_chain;
61000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
61100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  /* re-insert rs at the tail of the LRU chain: */
61200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  cache->buckets[cache->lru_tail].lru_chain = head;
61300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  cache->lru_tail = head;
61400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
61500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  /* remove the old rs from the hash table (if it's there): */
61600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if (rs->ip)
61700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    {
61800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      index = hash (rs->ip);
61900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      tmp = cache->buckets + cache->hash[index];
620890e23eb9d3ffd9be2a025189a21794b5ed0e0ffTommi Rantala      prev = NULL;
62100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      while (1)
62200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	{
62300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	  if (tmp == rs)
62400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	    {
62500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	      if (prev)
62600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma		prev->coll_chain = tmp->coll_chain;
62700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	      else
62800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma		cache->hash[index] = tmp->coll_chain;
62900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	      break;
63000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	    }
63100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	  else
63200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	    prev = tmp;
63300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	  if (tmp->coll_chain >= DWARF_UNW_CACHE_SIZE)
63400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	    /* old rs wasn't in the hash-table */
63500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	    break;
63600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	  tmp = cache->buckets + tmp->coll_chain;
63700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	}
63800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    }
63900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
64000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  /* enter new rs in the hash table */
641c5dc3c150a4fab2962f8d32f78d80ce857e662a5Arun Sharma  index = hash (c->ip);
64200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  rs->coll_chain = cache->hash[index];
64300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  cache->hash[index] = rs - cache->buckets;
64400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
64500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  rs->hint = 0;
646c5dc3c150a4fab2962f8d32f78d80ce857e662a5Arun Sharma  rs->ip = c->ip;
6475e59e93d049b9c6261c0db456edb7ab323618b6cArun Sharma  rs->valid = 1;
648c5dc3c150a4fab2962f8d32f78d80ce857e662a5Arun Sharma  rs->ret_addr_column = c->ret_addr_column;
649dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  rs->signal_frame = 0;
650dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura  tdep_cache_frame (c, rs);
65100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
65200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  return rs;
65300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma}
65400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
65588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic int
65688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmcreate_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr,
65788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm			 unw_word_t ip)
65888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
65988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  int i, ret;
66088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
66188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  assert (c->pi_valid);
66288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
663c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  memset (sr, 0, sizeof (*sr));
664c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  for (i = 0; i < DWARF_NUM_PRESERVED_REGS + 2; ++i)
66588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    set_reg (sr, i, DWARF_WHERE_SAME, 0);
66688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
66788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  switch (c->pi.format)
66888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    {
669c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm    case UNW_INFO_FORMAT_TABLE:
670c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm    case UNW_INFO_FORMAT_REMOTE_TABLE:
67188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      ret = parse_fde (c, ip, sr);
67288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      break;
67388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
67488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    case UNW_INFO_FORMAT_DYNAMIC:
67588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      ret = parse_dynamic (c, ip, sr);
67688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      break;
67788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
67888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    default:
67988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      Debug (1, "Unexpected unwind-info format %d\n", c->pi.format);
68088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      ret = -UNW_EINVAL;
68188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    }
68288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return ret;
68388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
68488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
68588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic inline int
68688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmeval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as,
68788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm		    unw_accessors_t *a, unw_word_t addr,
68888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm		    dwarf_loc_t *locp, void *arg)
68988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
69088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  int ret, is_register;
69188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  unw_word_t len, val;
69288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
69388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  /* read the length of the expression: */
69488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if ((ret = dwarf_read_uleb128 (as, a, &addr, &len, arg)) < 0)
69588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    return ret;
69688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
69788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  /* evaluate the expression: */
69888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if ((ret = dwarf_eval_expr (c, &addr, len, &val, &is_register)) < 0)
69988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    return ret;
70088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
70188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if (is_register)
70288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    *locp = DWARF_REG_LOC (c, dwarf_to_unw_regnum (val));
70388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  else
70488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    *locp = DWARF_MEM_LOC (c, val);
70588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
70688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return 0;
70788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
70888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
70988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmstatic int
71088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmapply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
71188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
71200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  unw_word_t regnum, addr, cfa, ip;
71300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  unw_word_t prev_ip, prev_cfa;
71488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  unw_addr_space_t as;
71588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  dwarf_loc_t cfa_loc;
71688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  unw_accessors_t *a;
71788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  int i, ret;
71888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  void *arg;
71988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
72000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  prev_ip = c->ip;
72100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  prev_cfa = c->cfa;
72200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
72388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  as = c->as;
72488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  arg = c->as_arg;
72588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  a = unw_get_accessors (as);
72688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
727c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  /* Evaluate the CFA first, because it may be referred to by other
72888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm     expressions.  */
72988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
73088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
73188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    {
73288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      /* CFA is equal to [reg] + offset: */
73388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
734642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm      /* As a special-case, if the stack-pointer is the CFA and the
735642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm	 stack-pointer wasn't saved, popping the CFA implicitly pops
736642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm	 the stack-pointer as well.  */
737642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm      if ((rs->reg[DWARF_CFA_REG_COLUMN].val == UNW_TDEP_SP)
738d7089547e2d13c2ae5f9ad896dc4bc5dc796fb0bArun Sharma          && (UNW_TDEP_SP < ARRAY_SIZE(rs->reg))
739642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm	  && (rs->reg[UNW_TDEP_SP].where == DWARF_WHERE_SAME))
740642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm	  cfa = c->cfa;
741642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm      else
742642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm	{
743642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm	  regnum = dwarf_to_unw_regnum (rs->reg[DWARF_CFA_REG_COLUMN].val);
744642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm	  if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0)
745642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm	    return ret;
746642607dbaab4a55959c6ddb7f6853b2d28d935f7homeip.net!davidm	}
74788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      cfa += rs->reg[DWARF_CFA_OFF_COLUMN].val;
74888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    }
74988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  else
75088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    {
75188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      /* CFA is equal to EXPR: */
75288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
75388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      assert (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_EXPR);
75488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
75588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      addr = rs->reg[DWARF_CFA_REG_COLUMN].val;
75688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0)
75788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	return ret;
758c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm      /* the returned location better be a memory location... */
759c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm      if (DWARF_IS_REG_LOC (cfa_loc))
760c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm	return -UNW_EBADFRAME;
761c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm      cfa = DWARF_GET_LOC (cfa_loc);
76288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    }
76388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
76488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
76588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    {
76688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      switch ((dwarf_where_t) rs->reg[i].where)
76788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	{
76888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DWARF_WHERE_UNDEF:
76988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  c->loc[i] = DWARF_NULL_LOC;
77088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
77188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
77288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DWARF_WHERE_SAME:
77388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
77488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
77588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DWARF_WHERE_CFAREL:
77688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
77788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
77888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
77988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DWARF_WHERE_REG:
78088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
78188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
78288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
78388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	case DWARF_WHERE_EXPR:
78488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  addr = rs->reg[i].val;
78569e300e8f6f5e9b136a70d5f3ca80fb8deac6666Jiri Olsa	  if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0)
78688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	    return ret;
78788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	  break;
78888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm	}
78988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    }
7904c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura
791c14371409aea0c3f90cdd00f529b347d8a5954f4mostang.com!davidm  c->cfa = cfa;
7924c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura  /* DWARF spec says undefined return address location means end of stack. */
7934c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura  if (DWARF_IS_NULL_LOC (c->loc[c->ret_addr_column]))
7944c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura    c->ip = 0;
7954c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura  else
7964c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura  {
7974c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura    ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip);
7984c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura    if (ret < 0)
7994c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura      return ret;
8004c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura    c->ip = ip;
8014c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura  }
80200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
8034c553ceb2c3fcde6248b05953abc34e162917c4aLassi Tuura  /* XXX: check for ip to be code_aligned */
80400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if (c->ip == prev_ip && c->cfa == prev_cfa)
80500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    {
806ec53de82ec7c00adb56c9e8b1b03d489a69c494bArun Sharma      Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
80700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma	       __FUNCTION__, (long) c->ip);
80800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma      return -UNW_EBADFRAME;
80900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    }
8109e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura
8119e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura  if (c->stash_frames)
8129e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura    tdep_stash_frame (c, rs);
8139e98f15e9aee12e67cd5956d06ccb559f6a06213Lassi Tuura
81400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  return 0;
81500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma}
81600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
81700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmastatic int
81800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharmauncached_dwarf_find_save_locs (struct dwarf_cursor *c)
81900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma{
82000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  dwarf_state_record_t sr;
82100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  int ret;
82200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
82300db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if ((ret = fetch_proc_info (c, c->ip, 1)) < 0)
824f92ecb61273bf58f9372f96868a9b8fb4d920ad4Arun Sharma    {
825f92ecb61273bf58f9372f96868a9b8fb4d920ad4Arun Sharma      put_unwind_info (c, &c->pi);
826f92ecb61273bf58f9372f96868a9b8fb4d920ad4Arun Sharma      return ret;
827f92ecb61273bf58f9372f96868a9b8fb4d920ad4Arun Sharma    }
82800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
82900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if ((ret = create_state_record_for (c, &sr, c->ip)) < 0)
830d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris    {
831d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris      /* ANDROID support update. */
832d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris      put_unwind_info (c, &c->pi);
833d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris      /* End of ANDROID update. */
834d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris      return ret;
835d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris    }
83600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
83700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if ((ret = apply_reg_state (c, &sr.rs_current)) < 0)
838d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris    {
839d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris      /* ANDROID support update. */
840d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris      put_unwind_info (c, &c->pi);
841d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris      /* End of ANDROID update. */
842d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris      return ret;
843d3bf49b06c7d56b371fe49f13490f7e548a8455aChristopher Ferris    }
84400db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
84500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  put_unwind_info (c, &c->pi);
84688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return 0;
84788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
84888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
84960b7af702ac56265798ec7202e05f0439c992360Arun Sharma/* The function finds the saved locations and applies the register
85060b7af702ac56265798ec7202e05f0439c992360Arun Sharma   state as well. */
85188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmHIDDEN int
85288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmdwarf_find_save_locs (struct dwarf_cursor *c)
85388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
8545f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#if defined(CONSERVE_STACK)
8555f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  dwarf_reg_state_t *rs_copy;
8565f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#else
8575f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  dwarf_reg_state_t rs_copy_stack;
8585f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  dwarf_reg_state_t *rs_copy = &rs_copy_stack;
8595f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#endif
8605f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  dwarf_reg_state_t *rs;
86100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  struct dwarf_rs_cache *cache;
8624312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  int ret = 0;
8634312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  intrmask_t saved_mask;
86488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
86500db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if (c->as->caching_policy == UNW_CACHE_NONE)
86600db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma    return uncached_dwarf_find_save_locs (c);
86700db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
8684312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  cache = get_rs_cache(c->as, &saved_mask);
86900db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  rs = rs_lookup(cache, c);
87000db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
87100db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma  if (rs)
872a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura    {
873a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura      c->ret_addr_column = rs->ret_addr_column;
874a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura      c->use_prev_instr = ! rs->signal_frame;
875a9dce3c06e6ffcb83957e734d960505415118f00Lassi Tuura    }
8762648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov  else
8772648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov    {
8785f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#if !defined(CONSERVE_STACK)
8795f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris      dwarf_state_record_t sr_stack;
8805f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris      dwarf_state_record_t *sr = &sr_stack;
8815f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#else
8825f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris      dwarf_state_record_t *sr = (dwarf_state_record_t*)malloc(sizeof(dwarf_state_record_t));
8835f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris
8845f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris      if (sr == NULL)
8855f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris        return -UNW_ENOMEM;
8865f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#endif
8875f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris
8882648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov      if ((ret = fetch_proc_info (c, c->ip, 1)) < 0 ||
8895f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris	  (ret = create_state_record_for (c, sr, c->ip)) < 0)
8902648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov	{
891f92ecb61273bf58f9372f96868a9b8fb4d920ad4Arun Sharma          put_rs_cache (c->as, cache, &saved_mask);
892f92ecb61273bf58f9372f96868a9b8fb4d920ad4Arun Sharma          put_unwind_info (c, &c->pi);
8935f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#if defined(CONSERVE_STACK)
8945f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris          free(sr);
8955f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#endif
8962648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov	  return ret;
8972648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov	}
89800db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
8992648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov      rs = rs_new (cache, c);
9005f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris      memcpy(rs, &sr->rs_current, offsetof(struct dwarf_reg_state, ip));
9012648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov      cache->buckets[c->prev_rs].hint = rs - cache->buckets;
90200db7f752ac26c5aab6b4ca03531a2c3e212b135Arun Sharma
9032648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov      c->hint = rs->hint;
9042648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov      c->prev_rs = rs - cache->buckets;
9053dfde7a3f089cf5c36ff7ed14d8d31034b5eafb8Arun Sharma
9062648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov      put_unwind_info (c, &c->pi);
9075f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris
9085f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#if defined(CONSERVE_STACK)
9095f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris      free(sr);
9105f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#endif
9112648a77f0499b2aeb3d624a1b44d2f1d2dd01835Paul Pluzhnikov    }
9124312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma
9135f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#if defined(CONSERVE_STACK)
9145f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  rs_copy = (dwarf_reg_state_t*)malloc(sizeof(dwarf_reg_state_t));
9155f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  if (rs_copy == NULL)
9165f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris    return -UNW_ENOMEM;
9175f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#endif
9185f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris
9195f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  memcpy (rs_copy, rs, sizeof (*rs_copy));
9204312719cbc30dfa9e188b24e85185c325e671d00Arun Sharma  put_rs_cache (c->as, cache, &saved_mask);
921dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
9225f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  tdep_reuse_frame (c, rs_copy);
9235f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  ret = apply_reg_state (c, rs_copy);
92488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
9255f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#if defined(CONSERVE_STACK)
9265f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  free(rs_copy);
9275f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris#endif
9285f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris
9295f0e55ca7540d58e8c02dd67e1a062cad285f6c8Christopher Ferris  return ret;
93088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
93188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
93288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm/* The proc-info must be valid for IP before this routine can be
93388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm   called.  */
93488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmHIDDEN int
93588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmdwarf_create_state_record (struct dwarf_cursor *c, dwarf_state_record_t *sr)
93688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
93788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return create_state_record_for (c, sr, c->ip);
93888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
93988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm
94088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmHIDDEN int
94188160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidmdwarf_make_proc_info (struct dwarf_cursor *c)
94288160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm{
94388160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#if 0
94488160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  if (c->as->caching_policy == UNW_CACHE_NONE
94588160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm      || get_cached_proc_info (c) < 0)
94688160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm#endif
94788160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    /* Lookup it up the slow way... */
94888160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm    return fetch_proc_info (c, c->ip, 0);
94988160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm  return 0;
95088160e0f66447d25bdc4cd0024912e08175b4f58homeip.net!davidm}
951