132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm/* libunwind - a platform-independent unwind library
29fac7579ee3261babb6f745c8c1511c24ed88cb4hp.com!davidm   Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmThis file is part of libunwind.
632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmPermission is hereby granted, free of charge, to any person obtaining
832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidma copy of this software and associated documentation files (the
932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm"Software"), to deal in the Software without restriction, including
1032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmwithout limitation the rights to use, copy, modify, merge, publish,
1132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmdistribute, sublicense, and/or sell copies of the Software, and to
1232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmpermit persons to whom the Software is furnished to do so, subject to
1332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmthe following conditions:
1432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
1532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmThe above copyright notice and this permission notice shall be
1632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmincluded in all copies or substantial portions of the Software.
1732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
1832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
2532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
2632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm#include "dwarf_i.h"
2732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
2846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidmstatic inline int
293842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitzis_cie_id (unw_word_t val, int is_debug_frame)
3046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm{
313842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  /* The CIE ID is normally 0xffffffff (for 32-bit ELF) or
323842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz     0xffffffffffffffff (for 64-bit ELF).  However, .eh_frame
3346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm     uses 0.  */
343842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  if (is_debug_frame)
35d1c383c5bb03420decf5cf789cf14ab144b0720dChristopher Ferris    /* ANDROID support update. */
36d1c383c5bb03420decf5cf789cf14ab144b0720dChristopher Ferris    return (val == (uint32_t) -1 || val == (unw_word_t) (uint64_t) -1);
37d1c383c5bb03420decf5cf789cf14ab144b0720dChristopher Ferris    /* End of ANDROID update. */
383842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  else
393842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz    return (val == 0);
4046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm}
4146b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
4232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm/* Note: we don't need to keep track of more than the first four
4332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm   characters of the augmentation string, because we (a) ignore any
4432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm   augmentation string contents once we find an unrecognized character
4532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm   and (b) those characters that we do recognize, can't be
4632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm   repeated.  */
4732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmstatic inline int
4846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidmparse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
493842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	   const unw_proc_info_t *pi, struct dwarf_cie_info *dci,
503842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	   unw_word_t base, void *arg)
5132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm{
5232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  uint8_t version, ch, augstr[5], fde_encoding, handler_encoding;
5346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  unw_word_t len, cie_end_addr, aug_size;
5432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  uint32_t u32val;
5532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  uint64_t u64val;
5632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  size_t i;
5732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  int ret;
5832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm# define STR2(x)	#x
5932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm# define STR(x)		STR2(x)
6032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
619ac7a860d1db4e607c9cb86e70524c17fe0bc087homeip.net!davidm  /* Pick appropriate default for FDE-encoding.  DWARF spec says
629ac7a860d1db4e607c9cb86e70524c17fe0bc087homeip.net!davidm     start-IP (initial_location) and the code-size (address_range) are
639ac7a860d1db4e607c9cb86e70524c17fe0bc087homeip.net!davidm     "address-unit sized constants".  The `R' augmentation can be used
649ac7a860d1db4e607c9cb86e70524c17fe0bc087homeip.net!davidm     to override this, but by default, we pick an address-sized unit
659ac7a860d1db4e607c9cb86e70524c17fe0bc087homeip.net!davidm     for fde_encoding.  */
663842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  switch (dwarf_addr_size (as))
67077322d41429859d924a87cd3c045c64851eb024homeip.net!davidm    {
68077322d41429859d924a87cd3c045c64851eb024homeip.net!davidm    case 4:	fde_encoding = DW_EH_PE_udata4; break;
69077322d41429859d924a87cd3c045c64851eb024homeip.net!davidm    case 8:	fde_encoding = DW_EH_PE_udata8; break;
70077322d41429859d924a87cd3c045c64851eb024homeip.net!davidm    default:	fde_encoding = DW_EH_PE_omit; break;
71077322d41429859d924a87cd3c045c64851eb024homeip.net!davidm    }
72077322d41429859d924a87cd3c045c64851eb024homeip.net!davidm
7346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  dci->lsda_encoding = DW_EH_PE_omit;
7446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  dci->handler = 0;
7532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
7646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0)
7732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    return ret;
7832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
7932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  if (u32val != 0xffffffff)
8032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    {
8132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      /* the CIE is in the 32-bit DWARF format */
8232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      uint32_t cie_id;
833842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      /* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */
843842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      const uint32_t expected_id = (base) ? 0xffffffff : 0;
8532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
8632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      len = u32val;
8746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      cie_end_addr = addr + len;
8846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_readu32 (as, a, &addr, &cie_id, arg)) < 0)
8932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
903842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      if (cie_id != expected_id)
9132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	{
9232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	  Debug (1, "Unexpected CIE id %x\n", cie_id);
9332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	  return -UNW_EINVAL;
9432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	}
9532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    }
9632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  else
9732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    {
9832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      /* the CIE is in the 64-bit DWARF format */
9932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      uint64_t cie_id;
1003842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      /* DWARF says CIE id should be 0xffffffffffffffff, but in
1013842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	 .eh_frame, it's 0 */
1023842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      const uint64_t expected_id = (base) ? 0xffffffffffffffffull : 0;
10332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
10446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
10532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
10632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      len = u64val;
10746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      cie_end_addr = addr + len;
10846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_readu64 (as, a, &addr, &cie_id, arg)) < 0)
10932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
1103842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      if (cie_id != expected_id)
11132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	{
11232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	  Debug (1, "Unexpected CIE id %llx\n", (long long) cie_id);
11332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	  return -UNW_EINVAL;
11432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	}
11532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    }
11646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  dci->cie_instr_end = cie_end_addr;
11732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
11846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  if ((ret = dwarf_readu8 (as, a, &addr, &version, arg)) < 0)
11932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    return ret;
12032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
121a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui  if (version != 1 && version != 3 && version != 4)
12232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    {
123a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui      Debug (1, "Got CIE version %u, expected version 1, 3 or 4\n", version);
12432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      return -UNW_EBADVERSION;
12532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    }
12632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
12732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  /* read and parse the augmentation string: */
12832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  memset (augstr, 0, sizeof (augstr));
12932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  for (i = 0;;)
13032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    {
13146b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
13232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
13332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
13432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      if (!ch)
13532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	break;	/* end of augmentation string */
13632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
13732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      if (i < sizeof (augstr) - 1)
13832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	augstr[i++] = ch;
13932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    }
14032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
141a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui  if (version == 4) {
142a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    uint8_t address_size;
143a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    if ((ret = dwarf_readu8(as, a, &addr, &address_size, arg)) < 0) {
144a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui      return ret;
145a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    }
146a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    if (address_size != sizeof(unw_word_t)) {
147a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui      return -UNW_EBADVERSION;
148a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    }
149a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    uint8_t segment_size;
150a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    if ((ret = dwarf_readu8(as, a, &addr, &segment_size, arg)) < 0) {
151a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui      return ret;
152a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    }
153a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    // We don't support non-zero segment size.
154a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    if (segment_size != 0) {
155a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui      return -UNW_EBADVERSION;
156a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui    }
157a220bd08dd6659a3a3543825f0e0e19c9a20486bYabin Cui  }
15846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->code_align, arg)) < 0
15946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      || (ret = dwarf_read_sleb128 (as, a, &addr, &dci->data_align, arg)) < 0)
16032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    return ret;
16132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
16232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  /* Read the return-address column either as a u8 or as a uleb128.  */
16332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  if (version == 1)
16432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    {
16546b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
16632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
16746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      dci->ret_addr_column = ch;
16832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    }
16946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  else if ((ret = dwarf_read_uleb128 (as, a, &addr, &dci->ret_addr_column,
17046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm				      arg)) < 0)
17132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    return ret;
17232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
1733842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  i = 0;
17432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  if (augstr[0] == 'z')
17532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    {
17646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      dci->sized_augmentation = 1;
17746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0)
17832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
1793842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      i++;
18032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    }
18132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
1823842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  for (; i < sizeof (augstr) && augstr[i]; ++i)
18332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    switch (augstr[i])
18432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      {
18532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      case 'L':
18632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	/* read the LSDA pointer-encoding format.  */
18746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	if ((ret = dwarf_readu8 (as, a, &addr, &ch, arg)) < 0)
18832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	  return ret;
18946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	dci->lsda_encoding = ch;
19032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	break;
19132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
19232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      case 'R':
19332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	/* read the FDE pointer-encoding format.  */
19446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	if ((ret = dwarf_readu8 (as, a, &addr, &fde_encoding, arg)) < 0)
19532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	  return ret;
19632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	break;
19732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
19832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      case 'P':
19932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	/* read the personality-routine pointer-encoding format.  */
20046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	if ((ret = dwarf_readu8 (as, a, &addr, &handler_encoding, arg)) < 0)
20132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	  return ret;
20246b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	if ((ret = dwarf_read_encoded_pointer (as, a, &addr, handler_encoding,
20346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm					       pi, &dci->handler, arg)) < 0)
20432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	  return ret;
20532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	break;
20632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
20746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      case 'S':
208dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura	/* This is a signal frame. */
209dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura	dci->signal_frame = 1;
210dac2d001afb1fa7040ca7d8ae57032f684d7023eLassi Tuura
21146b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	/* Temporarily set it to one so dwarf_parse_fde() knows that
21246b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	   it should fetch the actual ABI/TAG pair from the FDE.  */
21346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	dci->have_abi_marker = 1;
21446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	break;
21546b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
21632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      default:
2173842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	Debug (1, "Unexpected augmentation string `%s'\n", augstr);
21846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	if (dci->sized_augmentation)
21932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	  /* If we have the size of the augmentation body, we can skip
22032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	     over the parts that we don't understand, so we're OK. */
2213842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	  goto done;
22232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	else
2233842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	  return -UNW_EINVAL;
22432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      }
2253842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz done:
22646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  dci->fde_encoding = fde_encoding;
22746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  dci->cie_instr_start = addr;
228077322d41429859d924a87cd3c045c64851eb024homeip.net!davidm  Debug (15, "CIE parsed OK, augmentation = \"%s\", handler=0x%lx\n",
22946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	 augstr, (long) dci->handler);
23032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  return 0;
23132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm}
23232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
2333842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz/* Extract proc-info from the FDE starting at adress ADDR.
2343842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
2353842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz   Pass BASE as zero for eh_frame behaviour, or a pointer to
2363842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz   debug_frame base for debug_frame behaviour.  */
23746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
23832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidmHIDDEN int
23946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidmdwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a,
24046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm				  unw_word_t *addrp, unw_proc_info_t *pi,
2413842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz				  int need_unwind_info, unw_word_t base,
24246b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm				  void *arg)
24332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm{
24432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0;
24546b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  unw_word_t start_ip, ip_range, aug_size, addr = *addrp;
24646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  int ret, ip_range_encoding;
24746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  struct dwarf_cie_info dci;
24832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  uint64_t u64val;
24932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  uint32_t u32val;
25032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
25146b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  Debug (12, "FDE @ 0x%lx\n", (long) addr);
25232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
25346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  memset (&dci, 0, sizeof (dci));
25432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
25546b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  if ((ret = dwarf_readu32 (as, a, &addr, &u32val, arg)) < 0)
25632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    return ret;
25732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
25832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  if (u32val != 0xffffffff)
25932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    {
2603842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      int32_t cie_offset;
26132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
26246b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      /* In some configurations, an FDE with a 0 length indicates the
26346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	 end of the FDE-table.  */
26446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if (u32val == 0)
26546b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	return -UNW_ENOINFO;
26646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
26732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      /* the FDE is in the 32-bit DWARF format */
26832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
26946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      *addrp = fde_end_addr = addr + u32val;
27046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      cie_offset_addr = addr;
27132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
27246b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_reads32 (as, a, &addr, &cie_offset, arg)) < 0)
27332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
27432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
2753842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      if (is_cie_id (cie_offset, base != 0))
27646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	/* ignore CIEs (happens during linear searches) */
27746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	return 0;
27846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
2793842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      if (base != 0)
2803842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz        cie_addr = base + cie_offset;
2813842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      else
2823842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	/* DWARF says that the CIE_pointer in the FDE is a
2833842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	   .debug_frame-relative offset, but the GCC-generated .eh_frame
2843842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	   sections instead store a "pcrelative" offset, which is just
2853842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	   as fine as it's self-contained.  */
2863842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	cie_addr = cie_offset_addr - cie_offset;
28732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    }
28832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  else
28932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    {
2903842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      int64_t cie_offset;
29132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
29232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm      /* the FDE is in the 64-bit DWARF format */
29332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
29446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
29532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
29632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
29746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      *addrp = fde_end_addr = addr + u64val;
29846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      cie_offset_addr = addr;
29932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
30046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_reads64 (as, a, &addr, &cie_offset, arg)) < 0)
30132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
30232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
3033842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      if (is_cie_id (cie_offset, base != 0))
30446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	/* ignore CIEs (happens during linear searches) */
30546b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	return 0;
30646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
3073842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      if (base != 0)
3083842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	cie_addr = base + cie_offset;
3093842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz      else
3103842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	/* DWARF says that the CIE_pointer in the FDE is a
3113842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	   .debug_frame-relative offset, but the GCC-generated .eh_frame
3123842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	   sections instead store a "pcrelative" offset, which is just
3133842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	   as fine as it's self-contained.  */
3143842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz	cie_addr = (unw_word_t) ((uint64_t) cie_offset_addr - cie_offset);
31532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    }
31632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
317250382c56d2c84fc3976cf8a4c834433bb68990dLassi Tuura  Debug (15, "looking for CIE at address %lx\n", (long) cie_addr);
3183842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz
3193842dac7333e42aa44531eda34ba55200b99ccf8Daniel Jacobowitz  if ((ret = parse_cie (as, a, cie_addr, pi, &dci, base, arg)) < 0)
32032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    return ret;
32132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
32232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  /* IP-range has same encoding as FDE pointers, except that it's
32332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm     always an absolute value: */
32446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  ip_range_encoding = dci.fde_encoding & DW_EH_PE_FORMAT_MASK;
32532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
32646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.fde_encoding,
32732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm					 pi, &start_ip, arg)) < 0
32846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      || (ret = dwarf_read_encoded_pointer (as, a, &addr, ip_range_encoding,
32932f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm					    pi, &ip_range, arg)) < 0)
33032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    return ret;
33132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  pi->start_ip = start_ip;
33232f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  pi->end_ip = start_ip + ip_range;
33346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  pi->handler = dci.handler;
33432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
33546b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  if (dci.sized_augmentation)
33632f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    {
33746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if ((ret = dwarf_read_uleb128 (as, a, &addr, &aug_size, arg)) < 0)
33832f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	return ret;
33946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      aug_end_addr = addr + aug_size;
34032f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    }
34132f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
34246b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  if ((ret = dwarf_read_encoded_pointer (as, a, &addr, dci.lsda_encoding,
34332f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm					 pi, &pi->lsda, arg)) < 0)
34432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm    return ret;
34532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm
346077322d41429859d924a87cd3c045c64851eb024homeip.net!davidm  Debug (15, "FDE covers IP 0x%lx-0x%lx, LSDA=0x%lx\n",
34732f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm	 (long) pi->start_ip, (long) pi->end_ip, (long) pi->lsda);
34846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
34946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm  if (need_unwind_info)
35046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm    {
35146b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      pi->format = UNW_INFO_FORMAT_TABLE;
35246b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      pi->unwind_info_size = sizeof (dci);
35346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      pi->unwind_info = mempool_alloc (&dwarf_cie_info_pool);
35446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if (!pi->unwind_info)
3555ed2da2a403fe091d953183449003c9df861c289Mark Wielaard	return -UNW_ENOMEM;
35646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
35746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if (dci.have_abi_marker)
35846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	{
35946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	  if ((ret = dwarf_readu16 (as, a, &addr, &dci.abi, arg)) < 0
36046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	      || (ret = dwarf_readu16 (as, a, &addr, &dci.tag, arg)) < 0)
36146b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	    return ret;
36246b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	  Debug (13, "Found ABI marker = (abi=%u, tag=%u)\n",
36346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm		 dci.abi, dci.tag);
36446b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	}
36546b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
36646b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      if (dci.sized_augmentation)
36746b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	dci.fde_instr_start = aug_end_addr;
36846b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      else
36946b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm	dci.fde_instr_start = addr;
37046b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      dci.fde_instr_end = fde_end_addr;
37146b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm
37246b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm      memcpy (pi->unwind_info, &dci, sizeof (dci));
37346b7b8196c7600aaa200e31d01a2b4df7e7760admostang.com!davidm    }
37432f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm  return 0;
37532f3a1e58f48d6ec811f54dedf74eb4b17ae4e2chomeip.net!davidm}
376