178844Sobrien/* unwind-ia64.c -- utility routines to dump IA-64 unwind info for readelf.
2218822Sdim   Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
378844Sobrien	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
478844Sobrien
578844SobrienThis file is part of GNU Binutils.
678844Sobrien
778844SobrienThis program is free software; you can redistribute it and/or modify
878844Sobrienit under the terms of the GNU General Public License as published by
978844Sobrienthe Free Software Foundation; either version 2, or (at your option)
1078844Sobrienany later version.
1178844Sobrien
1278844SobrienThis program is distributed in the hope that it will be useful,
1378844Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1478844SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1578844SobrienGNU General Public License for more details.
1678844Sobrien
1778844SobrienYou should have received a copy of the GNU General Public License
1878844Sobrienalong with this program; if not, write to the Free Software
19218822SdimFoundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2078844Sobrien
2178844Sobrien#include "unwind-ia64.h"
2278844Sobrien#include <stdio.h>
2378844Sobrien#include <string.h>
2478844Sobrien
2578844Sobrien#if __GNUC__ >= 2
2678844Sobrien/* Define BFD64 here, even if our default architecture is 32 bit ELF
2778844Sobrien   as this will allow us to read in and parse 64bit and 32bit ELF files.
28130561Sobrien   Only do this if we believe that the compiler can support a 64 bit
2978844Sobrien   data type.  For now we only rely on GCC being able to do this.  */
3078844Sobrien#define BFD64
3178844Sobrien#endif
3278844Sobrien#include "bfd.h"
3378844Sobrien
3478844Sobrienstatic bfd_vma unw_rlen = 0;
3578844Sobrien
36130561Sobrienstatic void unw_print_brmask (char *, unsigned int);
37130561Sobrienstatic void unw_print_grmask (char *, unsigned int);
38130561Sobrienstatic void unw_print_frmask (char *, unsigned int);
39130561Sobrienstatic void unw_print_abreg (char *, unsigned int);
40130561Sobrienstatic void unw_print_xyreg (char *, unsigned int, unsigned int);
4189857Sobrien
4278844Sobrienstatic void
43130561Sobrienunw_print_brmask (char *cp, unsigned int mask)
4478844Sobrien{
45104834Sobrien  int sep = 0;
4678844Sobrien  int i;
4778844Sobrien
4878844Sobrien  for (i = 0; mask && (i < 5); ++i)
4978844Sobrien    {
5078844Sobrien      if (mask & 1)
5178844Sobrien	{
52104834Sobrien	  if (sep)
53104834Sobrien	    *cp++ = ',';
54104834Sobrien	  *cp++ = 'b';
55104834Sobrien	  *cp++ = i + 1 + '0';
56104834Sobrien	  sep = 1;
5778844Sobrien	}
5878844Sobrien      mask >>= 1;
5978844Sobrien    }
6078844Sobrien  *cp = '\0';
6178844Sobrien}
6278844Sobrien
6378844Sobrienstatic void
64130561Sobrienunw_print_grmask (char *cp, unsigned int mask)
6578844Sobrien{
66104834Sobrien  int sep = 0;
6778844Sobrien  int i;
6878844Sobrien
6978844Sobrien  for (i = 0; i < 4; ++i)
7078844Sobrien    {
7178844Sobrien      if (mask & 1)
7278844Sobrien	{
73104834Sobrien	  if (sep)
74104834Sobrien	    *cp++ = ',';
75104834Sobrien	  *cp++ = 'r';
76104834Sobrien	  *cp++ = i + 4 + '0';
77104834Sobrien	  sep = 1;
7878844Sobrien	}
7978844Sobrien      mask >>= 1;
8078844Sobrien    }
81104834Sobrien  *cp = '\0';
8278844Sobrien}
8378844Sobrien
8478844Sobrienstatic void
85130561Sobrienunw_print_frmask (char *cp, unsigned int mask)
8678844Sobrien{
87104834Sobrien  int sep = 0;
8878844Sobrien  int i;
8978844Sobrien
9078844Sobrien  for (i = 0; i < 20; ++i)
9178844Sobrien    {
9278844Sobrien      if (mask & 1)
9378844Sobrien	{
94104834Sobrien	  if (sep)
95104834Sobrien	    *cp++ = ',';
96104834Sobrien	  *cp++ = 'f';
97104834Sobrien	  if (i < 4)
98104834Sobrien	    *cp++ = i + 2 + '0';
99104834Sobrien	  else
100104834Sobrien	    {
101104834Sobrien	      *cp++ = (i + 2) / 10 + 1 + '0';
102104834Sobrien	      *cp++ = (i + 2) % 10 + '0';
103104834Sobrien	    }
104104834Sobrien	  sep = 1;
10578844Sobrien	}
10678844Sobrien      mask >>= 1;
10778844Sobrien    }
108104834Sobrien  *cp = '\0';
10978844Sobrien}
11078844Sobrien
11178844Sobrienstatic void
112130561Sobrienunw_print_abreg (char *cp, unsigned int abreg)
11378844Sobrien{
11478844Sobrien  static const char *special_reg[16] =
11578844Sobrien  {
11678844Sobrien    "pr", "psp", "@priunat", "rp", "ar.bsp", "ar.bspstore", "ar.rnat",
11778844Sobrien    "ar.unat", "ar.fpsr", "ar.pfs", "ar.lc",
11878844Sobrien    "Unknown11", "Unknown12", "Unknown13", "Unknown14", "Unknown15"
11978844Sobrien  };
12078844Sobrien
12178844Sobrien  switch ((abreg >> 5) & 0x3)
12278844Sobrien    {
12378844Sobrien    case 0: /* gr */
12478844Sobrien      sprintf (cp, "r%u", (abreg & 0x1f));
12578844Sobrien      break;
12678844Sobrien
12778844Sobrien    case 1: /* fr */
12878844Sobrien      sprintf (cp, "f%u", (abreg & 0x1f));
12978844Sobrien      break;
13078844Sobrien
13178844Sobrien    case 2: /* br */
13278844Sobrien      sprintf (cp, "b%u", (abreg & 0x1f));
13378844Sobrien      break;
13478844Sobrien
13578844Sobrien    case 3: /* special */
13678844Sobrien      strcpy (cp, special_reg[abreg & 0xf]);
13778844Sobrien      break;
13878844Sobrien    }
13978844Sobrien}
14078844Sobrien
14178844Sobrienstatic void
142130561Sobrienunw_print_xyreg (char *cp, unsigned int x, unsigned int ytreg)
14378844Sobrien{
14478844Sobrien  switch ((x << 1) | ((ytreg >> 7) & 1))
14578844Sobrien    {
14678844Sobrien    case 0: /* gr */
14778844Sobrien      sprintf (cp, "r%u", (ytreg & 0x1f));
14878844Sobrien      break;
14978844Sobrien
15078844Sobrien    case 1: /* fr */
15178844Sobrien      sprintf (cp, "f%u", (ytreg & 0x1f));
15278844Sobrien      break;
15378844Sobrien
15478844Sobrien    case 2: /* br */
15578844Sobrien      sprintf (cp, "b%u", (ytreg & 0x1f));
15678844Sobrien      break;
15778844Sobrien    }
15878844Sobrien}
15978844Sobrien
16078844Sobrien#define UNW_REG_BSP		"bsp"
16178844Sobrien#define UNW_REG_BSPSTORE	"bspstore"
16278844Sobrien#define UNW_REG_FPSR		"fpsr"
16378844Sobrien#define UNW_REG_LC		"lc"
16478844Sobrien#define UNW_REG_PFS		"pfs"
16578844Sobrien#define UNW_REG_PR		"pr"
16678844Sobrien#define UNW_REG_PSP		"psp"
16778844Sobrien#define UNW_REG_RNAT		"rnat"
16878844Sobrien#define UNW_REG_RP		"rp"
16978844Sobrien#define UNW_REG_UNAT		"unat"
17078844Sobrien
17178844Sobrientypedef bfd_vma unw_word;
17278844Sobrien
17378844Sobrien#define UNW_DEC_BAD_CODE(code)			\
17478844Sobrien    printf ("Unknown code 0x%02x\n", code)
17578844Sobrien
17678844Sobrien#define UNW_DEC_PROLOGUE(fmt, body, rlen, arg)					\
17778844Sobrien  do										\
17878844Sobrien    {										\
17978844Sobrien      unw_rlen = rlen;								\
18078844Sobrien      *(int *)arg = body;							\
18178844Sobrien      printf ("    %s:%s(rlen=%lu)\n",						\
18278844Sobrien	      fmt, body ? "body" : "prologue", (unsigned long) rlen);		\
18378844Sobrien    }										\
18478844Sobrien  while (0)
18578844Sobrien
18678844Sobrien#define UNW_DEC_PROLOGUE_GR(fmt, rlen, mask, grsave, arg)			\
18778844Sobrien  do										\
18878844Sobrien    {										\
18978844Sobrien      char regname[16], maskstr[64], *sep;					\
19078844Sobrien										\
19178844Sobrien      unw_rlen = rlen;								\
19278844Sobrien      *(int *)arg = 0;								\
19378844Sobrien										\
19478844Sobrien      maskstr[0] = '\0';							\
19578844Sobrien      sep = "";									\
19678844Sobrien      if (mask & 0x8)								\
19778844Sobrien	{									\
19878844Sobrien	  strcat (maskstr, "rp");						\
19978844Sobrien	  sep = ",";								\
20078844Sobrien	}									\
20178844Sobrien      if (mask & 0x4)								\
20278844Sobrien	{									\
20378844Sobrien	  strcat (maskstr, sep);						\
20478844Sobrien	  strcat (maskstr, "ar.pfs");						\
20578844Sobrien	  sep = ",";								\
20678844Sobrien	}									\
20778844Sobrien      if (mask & 0x2)								\
20878844Sobrien	{									\
20978844Sobrien	  strcat (maskstr, sep);						\
21078844Sobrien	  strcat (maskstr, "psp");						\
21178844Sobrien	  sep = ",";								\
21278844Sobrien	}									\
21378844Sobrien      if (mask & 0x1)								\
21478844Sobrien	{									\
21578844Sobrien	  strcat (maskstr, sep);						\
21678844Sobrien	  strcat (maskstr, "pr");						\
21778844Sobrien	}									\
21878844Sobrien      sprintf (regname, "r%u", grsave);						\
21978844Sobrien      printf ("    %s:prologue_gr(mask=[%s],grsave=%s,rlen=%lu)\n",		\
22078844Sobrien	      fmt, maskstr, regname, (unsigned long) rlen);			\
22178844Sobrien    }										\
22278844Sobrien  while (0)
22378844Sobrien
22478844Sobrien#define UNW_DEC_FR_MEM(fmt, frmask, arg)			\
22578844Sobrien  do								\
22678844Sobrien    {								\
22778844Sobrien      char frstr[200];						\
22878844Sobrien								\
22978844Sobrien      unw_print_frmask (frstr, frmask);				\
23078844Sobrien      printf ("\t%s:fr_mem(frmask=[%s])\n", fmt, frstr);	\
23178844Sobrien    }								\
23278844Sobrien  while (0)
23378844Sobrien
23478844Sobrien#define UNW_DEC_GR_MEM(fmt, grmask, arg)			\
23578844Sobrien  do								\
23678844Sobrien    {								\
23778844Sobrien      char grstr[200];						\
23878844Sobrien								\
23978844Sobrien      unw_print_grmask (grstr, grmask);				\
24078844Sobrien      printf ("\t%s:gr_mem(grmask=[%s])\n", fmt, grstr);	\
24178844Sobrien    }								\
24278844Sobrien  while (0)
24378844Sobrien
244130561Sobrien#define UNW_DEC_FRGR_MEM(fmt, grmask, frmask, arg)				\
24578844Sobrien  do										\
246130561Sobrien    {										\
24778844Sobrien      char frstr[200], grstr[20];						\
248130561Sobrien										\
249130561Sobrien      unw_print_grmask (grstr, grmask);						\
250130561Sobrien      unw_print_frmask (frstr, frmask);						\
25178844Sobrien      printf ("\t%s:frgr_mem(grmask=[%s],frmask=[%s])\n", fmt, grstr, frstr);	\
25278844Sobrien    }										\
25378844Sobrien  while (0)
25478844Sobrien
25578844Sobrien#define UNW_DEC_BR_MEM(fmt, brmask, arg)				\
25678844Sobrien  do									\
25778844Sobrien    {									\
25878844Sobrien      char brstr[20];							\
25978844Sobrien									\
26078844Sobrien      unw_print_brmask (brstr, brmask);					\
26178844Sobrien      printf ("\t%s:br_mem(brmask=[%s])\n", fmt, brstr);		\
26278844Sobrien    }									\
26378844Sobrien  while (0)
26478844Sobrien
26578844Sobrien#define UNW_DEC_BR_GR(fmt, brmask, gr, arg)				\
26678844Sobrien  do									\
26778844Sobrien    {									\
26878844Sobrien      char brstr[20];							\
26978844Sobrien									\
27078844Sobrien      unw_print_brmask (brstr, brmask);					\
27178844Sobrien      printf ("\t%s:br_gr(brmask=[%s],gr=r%u)\n", fmt, brstr, gr);	\
27278844Sobrien    }									\
27378844Sobrien  while (0)
27478844Sobrien
27578844Sobrien#define UNW_DEC_REG_GR(fmt, src, dst, arg)		\
27678844Sobrien  printf ("\t%s:%s_gr(reg=r%u)\n", fmt, src, dst)
27778844Sobrien
27878844Sobrien#define UNW_DEC_RP_BR(fmt, dst, arg)		\
27978844Sobrien  printf ("\t%s:rp_br(reg=b%u)\n", fmt, dst)
28078844Sobrien
28178844Sobrien#define UNW_DEC_REG_WHEN(fmt, reg, t, arg)				\
28278844Sobrien  printf ("\t%s:%s_when(t=%lu)\n", fmt, reg, (unsigned long) t)
28378844Sobrien
28478844Sobrien#define UNW_DEC_REG_SPREL(fmt, reg, spoff, arg)		\
28578844Sobrien  printf ("\t%s:%s_sprel(spoff=0x%lx)\n",		\
28678844Sobrien	  fmt, reg, 4*(unsigned long)spoff)
28778844Sobrien
28878844Sobrien#define UNW_DEC_REG_PSPREL(fmt, reg, pspoff, arg)		\
28978844Sobrien  printf ("\t%s:%s_psprel(pspoff=0x10-0x%lx)\n",		\
29078844Sobrien	  fmt, reg, 4*(unsigned long)pspoff)
29178844Sobrien
29278844Sobrien#define UNW_DEC_GR_GR(fmt, grmask, gr, arg)				\
29378844Sobrien  do									\
29478844Sobrien    {									\
29578844Sobrien      char grstr[20];							\
29678844Sobrien									\
29778844Sobrien      unw_print_grmask (grstr, grmask);					\
29878844Sobrien      printf ("\t%s:gr_gr(grmask=[%s],r%u)\n", fmt, grstr, gr);		\
29978844Sobrien    }									\
30078844Sobrien  while (0)
30178844Sobrien
30278844Sobrien#define UNW_DEC_ABI(fmt, abi, context, arg)			\
30378844Sobrien  do								\
30478844Sobrien    {								\
30578844Sobrien      static const char *abiname[] =				\
30678844Sobrien      {								\
30778844Sobrien	"@svr4", "@hpux", "@nt"					\
30878844Sobrien      };							\
30978844Sobrien      char buf[20];						\
31078844Sobrien      const char *abistr = buf;					\
31178844Sobrien								\
31278844Sobrien      if (abi < 3)						\
31378844Sobrien	abistr = abiname[abi];					\
31478844Sobrien      else							\
31578844Sobrien	sprintf (buf, "0x%x", abi);				\
31678844Sobrien      printf ("\t%s:unwabi(abi=%s,context=0x%02x)\n",		\
31778844Sobrien	      fmt, abistr, context);				\
31878844Sobrien    }								\
31978844Sobrien  while (0)
32078844Sobrien
32178844Sobrien#define UNW_DEC_PRIUNAT_GR(fmt, r, arg)		\
32278844Sobrien  printf ("\t%s:priunat_gr(reg=r%u)\n", fmt, r)
32378844Sobrien
32478844Sobrien#define UNW_DEC_PRIUNAT_WHEN_GR(fmt, t, arg)				\
32578844Sobrien  printf ("\t%s:priunat_when_gr(t=%lu)\n", fmt, (unsigned long) t)
32678844Sobrien
32778844Sobrien#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt, t, arg)				\
32878844Sobrien  printf ("\t%s:priunat_when_mem(t=%lu)\n", fmt, (unsigned long) t)
32978844Sobrien
33078844Sobrien#define UNW_DEC_PRIUNAT_PSPREL(fmt, pspoff, arg)		\
33178844Sobrien  printf ("\t%s:priunat_psprel(pspoff=0x10-0x%lx)\n",		\
33278844Sobrien	  fmt, 4*(unsigned long)pspoff)
33378844Sobrien
33478844Sobrien#define UNW_DEC_PRIUNAT_SPREL(fmt, spoff, arg)		\
33578844Sobrien  printf ("\t%s:priunat_sprel(spoff=0x%lx)\n",		\
33678844Sobrien	  fmt, 4*(unsigned long)spoff)
33778844Sobrien
33878844Sobrien#define UNW_DEC_MEM_STACK_F(fmt, t, size, arg)		\
33978844Sobrien  printf ("\t%s:mem_stack_f(t=%lu,size=%lu)\n",		\
34078844Sobrien	  fmt, (unsigned long) t, 16*(unsigned long)size)
34178844Sobrien
34278844Sobrien#define UNW_DEC_MEM_STACK_V(fmt, t, arg)				\
34378844Sobrien  printf ("\t%s:mem_stack_v(t=%lu)\n", fmt, (unsigned long) t)
34478844Sobrien
34578844Sobrien#define UNW_DEC_SPILL_BASE(fmt, pspoff, arg)			\
34678844Sobrien  printf ("\t%s:spill_base(pspoff=0x10-0x%lx)\n",		\
34778844Sobrien	  fmt, 4*(unsigned long)pspoff)
34878844Sobrien
34978844Sobrien#define UNW_DEC_SPILL_MASK(fmt, dp, arg)					\
35078844Sobrien  do										\
35178844Sobrien    {										\
352130561Sobrien      static const char *spill_type = "-frb";					\
353130561Sobrien      unsigned const char *imaskp = dp;					\
35478844Sobrien      unsigned char mask = 0;							\
35578844Sobrien      bfd_vma insn = 0;								\
35678844Sobrien										\
35778844Sobrien      printf ("\t%s:spill_mask(imask=[", fmt);					\
35878844Sobrien      for (insn = 0; insn < unw_rlen; ++insn)					\
35978844Sobrien	{									\
36078844Sobrien	  if ((insn % 4) == 0)							\
36178844Sobrien	    mask = *imaskp++;							\
36278844Sobrien	  if (insn > 0 && (insn % 3) == 0)					\
36378844Sobrien	    putchar (',');							\
36478844Sobrien	  putchar (spill_type[(mask >> (2 * (3 - (insn & 0x3)))) & 0x3]);	\
36578844Sobrien	}									\
36678844Sobrien      printf ("])\n");								\
36778844Sobrien      dp = imaskp;								\
36878844Sobrien    }										\
36978844Sobrien  while (0)
37078844Sobrien
37178844Sobrien#define UNW_DEC_SPILL_SPREL(fmt, t, abreg, spoff, arg)				\
37278844Sobrien  do										\
37378844Sobrien    {										\
374218822Sdim      char regname[20];								\
37578844Sobrien										\
37678844Sobrien      unw_print_abreg (regname, abreg);						\
37778844Sobrien      printf ("\t%s:spill_sprel(reg=%s,t=%lu,spoff=0x%lx)\n",			\
37878844Sobrien	      fmt, regname, (unsigned long) t, 4*(unsigned long)off);		\
37978844Sobrien    }										\
38078844Sobrien  while (0)
38178844Sobrien
382130561Sobrien#define UNW_DEC_SPILL_PSPREL(fmt, t, abreg, pspoff, arg)			\
38378844Sobrien  do										\
384130561Sobrien    {										\
385218822Sdim      char regname[20];								\
386130561Sobrien										\
387130561Sobrien      unw_print_abreg (regname, abreg);						\
388130561Sobrien      printf ("\t%s:spill_psprel(reg=%s,t=%lu,pspoff=0x10-0x%lx)\n",		\
38978844Sobrien	      fmt, regname, (unsigned long) t, 4*(unsigned long)pspoff);	\
39078844Sobrien    }										\
39178844Sobrien  while (0)
39278844Sobrien
39378844Sobrien#define UNW_DEC_RESTORE(fmt, t, abreg, arg)			\
39478844Sobrien  do								\
39578844Sobrien    {								\
396218822Sdim      char regname[20];						\
39778844Sobrien								\
39878844Sobrien      unw_print_abreg (regname, abreg);				\
39978844Sobrien      printf ("\t%s:restore(t=%lu,reg=%s)\n",			\
40078844Sobrien	      fmt, (unsigned long) t, regname);			\
40178844Sobrien    }								\
40278844Sobrien  while (0)
40378844Sobrien
40478844Sobrien#define UNW_DEC_SPILL_REG(fmt, t, abreg, x, ytreg, arg)		\
40578844Sobrien  do								\
40678844Sobrien    {								\
407218822Sdim      char abregname[20], tregname[20];				\
40878844Sobrien								\
40978844Sobrien      unw_print_abreg (abregname, abreg);			\
41078844Sobrien      unw_print_xyreg (tregname, x, ytreg);			\
41178844Sobrien      printf ("\t%s:spill_reg(t=%lu,reg=%s,treg=%s)\n",		\
41278844Sobrien	      fmt, (unsigned long) t, abregname, tregname);	\
41378844Sobrien    }								\
41478844Sobrien  while (0)
41578844Sobrien
416130561Sobrien#define UNW_DEC_SPILL_SPREL_P(fmt, qp, t, abreg, spoff, arg)			    \
41778844Sobrien  do										    \
418130561Sobrien    {										    \
419130561Sobrien      char regname[20];								    \
420130561Sobrien										    \
421130561Sobrien      unw_print_abreg (regname, abreg);						    \
42278844Sobrien      printf ("\t%s:spill_sprel_p(qp=p%u,t=%lu,reg=%s,spoff=0x%lx)\n",		    \
42378844Sobrien	      fmt, qp, (unsigned long) t, regname, 4 * (unsigned long)spoff);	    \
42478844Sobrien    }										    \
42578844Sobrien  while (0)
42678844Sobrien
42778844Sobrien#define UNW_DEC_SPILL_PSPREL_P(fmt, qp, t, abreg, pspoff, arg)		\
42878844Sobrien  do									\
42978844Sobrien    {									\
43078844Sobrien      char regname[20];							\
43178844Sobrien									\
43278844Sobrien      unw_print_abreg (regname, abreg);					\
43378844Sobrien      printf ("\t%s:spill_psprel_p(qp=p%u,t=%lu,reg=%s,pspoff=0x10-0x%lx)\n",\
43478844Sobrien	      fmt, qp, (unsigned long) t, regname, 4*(unsigned long)pspoff);\
43578844Sobrien    }									\
43678844Sobrien  while (0)
43778844Sobrien
43878844Sobrien#define UNW_DEC_RESTORE_P(fmt, qp, t, abreg, arg)			\
43978844Sobrien  do									\
44078844Sobrien    {									\
44178844Sobrien      char regname[20];							\
44278844Sobrien									\
44378844Sobrien      unw_print_abreg (regname, abreg);					\
44478844Sobrien      printf ("\t%s:restore_p(qp=p%u,t=%lu,reg=%s)\n",			\
44578844Sobrien	      fmt, qp, (unsigned long) t, regname);			\
44678844Sobrien    }									\
44778844Sobrien  while (0)
44878844Sobrien
44978844Sobrien#define UNW_DEC_SPILL_REG_P(fmt, qp, t, abreg, x, ytreg, arg)		\
45078844Sobrien  do									\
45178844Sobrien    {									\
45278844Sobrien      char regname[20], tregname[20];					\
45378844Sobrien									\
45478844Sobrien      unw_print_abreg (regname, abreg);					\
45578844Sobrien      unw_print_xyreg (tregname, x, ytreg);				\
45678844Sobrien      printf ("\t%s:spill_reg_p(qp=p%u,t=%lu,reg=%s,treg=%s)\n",	\
45778844Sobrien	      fmt, qp, (unsigned long) t, regname, tregname);		\
45878844Sobrien    }									\
45978844Sobrien  while (0)
46078844Sobrien
46178844Sobrien#define UNW_DEC_LABEL_STATE(fmt, label, arg)				\
46278844Sobrien  printf ("\t%s:label_state(label=%lu)\n", fmt, (unsigned long) label)
46378844Sobrien
46478844Sobrien#define UNW_DEC_COPY_STATE(fmt, label, arg)				\
46578844Sobrien  printf ("\t%s:copy_state(label=%lu)\n", fmt, (unsigned long) label)
46678844Sobrien
46778844Sobrien#define UNW_DEC_EPILOGUE(fmt, t, ecount, arg)		\
46878844Sobrien  printf ("\t%s:epilogue(t=%lu,ecount=%lu)\n",		\
46978844Sobrien	  fmt, (unsigned long) t, (unsigned long) ecount)
47078844Sobrien
47178844Sobrien/*
47278844Sobrien * Generic IA-64 unwind info decoder.
47378844Sobrien *
47478844Sobrien * This file is used both by the Linux kernel and objdump.  Please
47578844Sobrien * keep the two copies of this file in sync (modulo differences in the
47678844Sobrien * prototypes...).
47778844Sobrien *
47878844Sobrien * You need to customize the decoder by defining the following
47978844Sobrien * macros/constants before including this file:
48078844Sobrien *
48178844Sobrien *  Types:
482104834Sobrien *	unw_word	Unsigned integer type with at least 64 bits
48378844Sobrien *
48478844Sobrien *  Register names:
48578844Sobrien *	UNW_REG_BSP
48678844Sobrien *	UNW_REG_BSPSTORE
48778844Sobrien *	UNW_REG_FPSR
48878844Sobrien *	UNW_REG_LC
48978844Sobrien *	UNW_REG_PFS
49078844Sobrien *	UNW_REG_PR
49178844Sobrien *	UNW_REG_RNAT
49278844Sobrien *	UNW_REG_PSP
49378844Sobrien *	UNW_REG_RP
49478844Sobrien *	UNW_REG_UNAT
49578844Sobrien *
49678844Sobrien *  Decoder action macros:
49778844Sobrien *	UNW_DEC_BAD_CODE(code)
49878844Sobrien *	UNW_DEC_ABI(fmt,abi,context,arg)
49978844Sobrien *	UNW_DEC_BR_GR(fmt,brmask,gr,arg)
50078844Sobrien *	UNW_DEC_BR_MEM(fmt,brmask,arg)
50178844Sobrien *	UNW_DEC_COPY_STATE(fmt,label,arg)
50278844Sobrien *	UNW_DEC_EPILOGUE(fmt,t,ecount,arg)
50378844Sobrien *	UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg)
50478844Sobrien *	UNW_DEC_FR_MEM(fmt,frmask,arg)
50578844Sobrien *	UNW_DEC_GR_GR(fmt,grmask,gr,arg)
50678844Sobrien *	UNW_DEC_GR_MEM(fmt,grmask,arg)
50778844Sobrien *	UNW_DEC_LABEL_STATE(fmt,label,arg)
50878844Sobrien *	UNW_DEC_MEM_STACK_F(fmt,t,size,arg)
50978844Sobrien *	UNW_DEC_MEM_STACK_V(fmt,t,arg)
51078844Sobrien *	UNW_DEC_PRIUNAT_GR(fmt,r,arg)
51178844Sobrien *	UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg)
51278844Sobrien *	UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg)
51378844Sobrien *	UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg)
51478844Sobrien *	UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg)
51578844Sobrien *	UNW_DEC_PROLOGUE(fmt,body,rlen,arg)
51678844Sobrien *	UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg)
51778844Sobrien *	UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg)
51878844Sobrien *	UNW_DEC_REG_REG(fmt,src,dst,arg)
51978844Sobrien *	UNW_DEC_REG_SPREL(fmt,reg,spoff,arg)
52078844Sobrien *	UNW_DEC_REG_WHEN(fmt,reg,t,arg)
52178844Sobrien *	UNW_DEC_RESTORE(fmt,t,abreg,arg)
52278844Sobrien *	UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg)
52378844Sobrien *	UNW_DEC_SPILL_BASE(fmt,pspoff,arg)
52478844Sobrien *	UNW_DEC_SPILL_MASK(fmt,imaskp,arg)
52578844Sobrien *	UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg)
52678844Sobrien *	UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg)
52778844Sobrien *	UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg)
52878844Sobrien *	UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg)
52978844Sobrien *	UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg)
53078844Sobrien *	UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg)
53178844Sobrien */
53278844Sobrien
533130561Sobrienstatic unw_word unw_decode_uleb128 (const unsigned char **);
534130561Sobrienstatic const unsigned char *unw_decode_x1
535130561Sobrien  (const unsigned char *, unsigned int, void *);
536130561Sobrienstatic const unsigned char *unw_decode_x2
537130561Sobrien  (const unsigned char *, unsigned int, void *);
538130561Sobrienstatic const unsigned char *unw_decode_x3
539130561Sobrien  (const unsigned char *, unsigned int, void *);
540130561Sobrienstatic const unsigned char *unw_decode_x4
541130561Sobrien  (const unsigned char *, unsigned int, void *);
542130561Sobrienstatic const unsigned char *unw_decode_r1
543130561Sobrien  (const unsigned char *, unsigned int, void *);
544130561Sobrienstatic const unsigned char *unw_decode_r2
545130561Sobrien  (const unsigned char *, unsigned int, void *);
546130561Sobrienstatic const unsigned char *unw_decode_r3
547130561Sobrien  (const unsigned char *, unsigned int, void *);
548130561Sobrienstatic const unsigned char *unw_decode_p1
549130561Sobrien  (const unsigned char *, unsigned int, void *);
550130561Sobrienstatic const unsigned char *unw_decode_p2_p5
551130561Sobrien  (const unsigned char *, unsigned int, void *);
552130561Sobrienstatic const unsigned char *unw_decode_p6
553130561Sobrien  (const unsigned char *, unsigned int, void *);
554130561Sobrienstatic const unsigned char *unw_decode_p7_p10
555130561Sobrien  (const unsigned char *, unsigned int, void *);
556130561Sobrienstatic const unsigned char *unw_decode_b1
557130561Sobrien  (const unsigned char *, unsigned int, void *);
558130561Sobrienstatic const unsigned char *unw_decode_b2
559130561Sobrien  (const unsigned char *, unsigned int, void *);
560130561Sobrienstatic const unsigned char *unw_decode_b3_x4
561130561Sobrien  (const unsigned char *, unsigned int, void *);
56278844Sobrien
56378844Sobrienstatic unw_word
564130561Sobrienunw_decode_uleb128 (const unsigned char **dpp)
56578844Sobrien{
56678844Sobrien  unsigned shift = 0;
56778844Sobrien  unw_word byte, result = 0;
56878844Sobrien  const unsigned char *bp = *dpp;
56978844Sobrien
57078844Sobrien  while (1)
57178844Sobrien    {
57278844Sobrien      byte = *bp++;
57378844Sobrien      result |= (byte & 0x7f) << shift;
57478844Sobrien
57578844Sobrien      if ((byte & 0x80) == 0)
57678844Sobrien	break;
57778844Sobrien
57878844Sobrien      shift += 7;
57978844Sobrien    }
58078844Sobrien
58178844Sobrien  *dpp = bp;
58278844Sobrien
58378844Sobrien  return result;
58478844Sobrien}
58578844Sobrien
58678844Sobrienstatic const unsigned char *
587130561Sobrienunw_decode_x1 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED,
588130561Sobrien	       void *arg ATTRIBUTE_UNUSED)
58978844Sobrien{
59078844Sobrien  unsigned char byte1, abreg;
59178844Sobrien  unw_word t, off;
59278844Sobrien
59378844Sobrien  byte1 = *dp++;
59478844Sobrien  t = unw_decode_uleb128 (&dp);
59578844Sobrien  off = unw_decode_uleb128 (&dp);
59678844Sobrien  abreg = (byte1 & 0x7f);
59778844Sobrien  if (byte1 & 0x80)
59878844Sobrien    UNW_DEC_SPILL_SPREL ("X1", t, abreg, off, arg);
59978844Sobrien  else
60078844Sobrien    UNW_DEC_SPILL_PSPREL ("X1", t, abreg, off, arg);
60178844Sobrien  return dp;
60278844Sobrien}
60378844Sobrien
60478844Sobrienstatic const unsigned char *
605130561Sobrienunw_decode_x2 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED,
606130561Sobrien	       void *arg ATTRIBUTE_UNUSED)
60778844Sobrien{
60878844Sobrien  unsigned char byte1, byte2, abreg, x, ytreg;
60978844Sobrien  unw_word t;
61078844Sobrien
61178844Sobrien  byte1 = *dp++;
61278844Sobrien  byte2 = *dp++;
61378844Sobrien  t = unw_decode_uleb128 (&dp);
61478844Sobrien  abreg = (byte1 & 0x7f);
61578844Sobrien  ytreg = byte2;
61678844Sobrien  x = (byte1 >> 7) & 1;
61778844Sobrien  if ((byte1 & 0x80) == 0 && ytreg == 0)
61878844Sobrien    UNW_DEC_RESTORE ("X2", t, abreg, arg);
61978844Sobrien  else
62078844Sobrien    UNW_DEC_SPILL_REG ("X2", t, abreg, x, ytreg, arg);
62178844Sobrien  return dp;
62278844Sobrien}
62378844Sobrien
62478844Sobrienstatic const unsigned char *
625130561Sobrienunw_decode_x3 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED,
626130561Sobrien	       void *arg ATTRIBUTE_UNUSED)
62778844Sobrien{
62878844Sobrien  unsigned char byte1, byte2, abreg, qp;
62978844Sobrien  unw_word t, off;
63078844Sobrien
63178844Sobrien  byte1 = *dp++;
63278844Sobrien  byte2 = *dp++;
63378844Sobrien  t = unw_decode_uleb128 (&dp);
63478844Sobrien  off = unw_decode_uleb128 (&dp);
63578844Sobrien
63678844Sobrien  qp = (byte1 & 0x3f);
63778844Sobrien  abreg = (byte2 & 0x7f);
63878844Sobrien
63978844Sobrien  if (byte1 & 0x80)
64078844Sobrien    UNW_DEC_SPILL_SPREL_P ("X3", qp, t, abreg, off, arg);
64178844Sobrien  else
64278844Sobrien    UNW_DEC_SPILL_PSPREL_P ("X3", qp, t, abreg, off, arg);
64378844Sobrien  return dp;
64478844Sobrien}
64578844Sobrien
64678844Sobrienstatic const unsigned char *
647130561Sobrienunw_decode_x4 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED,
648130561Sobrien	       void *arg ATTRIBUTE_UNUSED)
64978844Sobrien{
65078844Sobrien  unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg;
65178844Sobrien  unw_word t;
65278844Sobrien
65378844Sobrien  byte1 = *dp++;
65478844Sobrien  byte2 = *dp++;
65578844Sobrien  byte3 = *dp++;
65678844Sobrien  t = unw_decode_uleb128 (&dp);
65778844Sobrien
65878844Sobrien  qp = (byte1 & 0x3f);
65978844Sobrien  abreg = (byte2 & 0x7f);
66078844Sobrien  x = (byte2 >> 7) & 1;
66178844Sobrien  ytreg = byte3;
66278844Sobrien
66378844Sobrien  if ((byte2 & 0x80) == 0 && byte3 == 0)
66478844Sobrien    UNW_DEC_RESTORE_P ("X4", qp, t, abreg, arg);
66578844Sobrien  else
66678844Sobrien    UNW_DEC_SPILL_REG_P ("X4", qp, t, abreg, x, ytreg, arg);
66778844Sobrien  return dp;
66878844Sobrien}
66978844Sobrien
67078844Sobrienstatic const unsigned char *
671130561Sobrienunw_decode_r1 (const unsigned char *dp, unsigned int code, void *arg)
67278844Sobrien{
67378844Sobrien  int body = (code & 0x20) != 0;
67478844Sobrien  unw_word rlen;
67578844Sobrien
67678844Sobrien  rlen = (code & 0x1f);
67778844Sobrien  UNW_DEC_PROLOGUE ("R1", body, rlen, arg);
67878844Sobrien  return dp;
67978844Sobrien}
68078844Sobrien
68178844Sobrienstatic const unsigned char *
682130561Sobrienunw_decode_r2 (const unsigned char *dp, unsigned int code, void *arg)
68378844Sobrien{
68478844Sobrien  unsigned char byte1, mask, grsave;
68578844Sobrien  unw_word rlen;
68678844Sobrien
68778844Sobrien  byte1 = *dp++;
68878844Sobrien
68978844Sobrien  mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
69078844Sobrien  grsave = (byte1 & 0x7f);
69178844Sobrien  rlen = unw_decode_uleb128 (& dp);
69278844Sobrien  UNW_DEC_PROLOGUE_GR ("R2", rlen, mask, grsave, arg);
69378844Sobrien  return dp;
69478844Sobrien}
69578844Sobrien
69678844Sobrienstatic const unsigned char *
697130561Sobrienunw_decode_r3 (const unsigned char *dp, unsigned int code, void *arg)
69878844Sobrien{
69978844Sobrien  unw_word rlen;
70078844Sobrien
70178844Sobrien  rlen = unw_decode_uleb128 (& dp);
70278844Sobrien  UNW_DEC_PROLOGUE ("R3", ((code & 0x3) == 1), rlen, arg);
70378844Sobrien  return dp;
70478844Sobrien}
70578844Sobrien
70678844Sobrienstatic const unsigned char *
707130561Sobrienunw_decode_p1 (const unsigned char *dp, unsigned int code,
708130561Sobrien	       void *arg ATTRIBUTE_UNUSED)
70978844Sobrien{
71078844Sobrien  unsigned char brmask = (code & 0x1f);
71178844Sobrien
71278844Sobrien  UNW_DEC_BR_MEM ("P1", brmask, arg);
71378844Sobrien  return dp;
71478844Sobrien}
71578844Sobrien
71678844Sobrienstatic const unsigned char *
717130561Sobrienunw_decode_p2_p5 (const unsigned char *dp, unsigned int code,
718130561Sobrien		  void *arg ATTRIBUTE_UNUSED)
71978844Sobrien{
72078844Sobrien  if ((code & 0x10) == 0)
72178844Sobrien    {
72278844Sobrien      unsigned char byte1 = *dp++;
72378844Sobrien
72478844Sobrien      UNW_DEC_BR_GR ("P2", ((code & 0xf) << 1) | ((byte1 >> 7) & 1),
72578844Sobrien		     (byte1 & 0x7f), arg);
72678844Sobrien    }
72778844Sobrien  else if ((code & 0x08) == 0)
72878844Sobrien    {
72978844Sobrien      unsigned char byte1 = *dp++, r, dst;
73078844Sobrien
73178844Sobrien      r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
73278844Sobrien      dst = (byte1 & 0x7f);
73378844Sobrien      switch (r)
73478844Sobrien	{
73578844Sobrien	case 0:
73678844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_PSP, dst, arg);
73778844Sobrien	  break;
73878844Sobrien	case 1:
73978844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_RP, dst, arg);
74078844Sobrien	  break;
74178844Sobrien	case 2:
74278844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_PFS, dst, arg);
74378844Sobrien	  break;
74478844Sobrien	case 3:
74578844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_PR, dst, arg);
74678844Sobrien	  break;
74778844Sobrien	case 4:
74878844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_UNAT, dst, arg);
74978844Sobrien	  break;
75078844Sobrien	case 5:
75178844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_LC, dst, arg);
75278844Sobrien	  break;
75378844Sobrien	case 6:
75478844Sobrien	  UNW_DEC_RP_BR ("P3", dst, arg);
75578844Sobrien	  break;
75678844Sobrien	case 7:
75778844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_RNAT, dst, arg);
75878844Sobrien	  break;
75978844Sobrien	case 8:
76078844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_BSP, dst, arg);
76178844Sobrien	  break;
76278844Sobrien	case 9:
76378844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_BSPSTORE, dst, arg);
76478844Sobrien	  break;
76578844Sobrien	case 10:
76678844Sobrien	  UNW_DEC_REG_GR ("P3", UNW_REG_FPSR, dst, arg);
76778844Sobrien	  break;
76878844Sobrien	case 11:
76978844Sobrien	  UNW_DEC_PRIUNAT_GR ("P3", dst, arg);
77078844Sobrien	  break;
77178844Sobrien	default:
77278844Sobrien	  UNW_DEC_BAD_CODE (r);
77378844Sobrien	  break;
77478844Sobrien	}
77578844Sobrien    }
77678844Sobrien  else if ((code & 0x7) == 0)
77778844Sobrien    UNW_DEC_SPILL_MASK ("P4", dp, arg);
77878844Sobrien  else if ((code & 0x7) == 1)
77978844Sobrien    {
78078844Sobrien      unw_word grmask, frmask, byte1, byte2, byte3;
78178844Sobrien
78278844Sobrien      byte1 = *dp++;
78378844Sobrien      byte2 = *dp++;
78478844Sobrien      byte3 = *dp++;
78578844Sobrien      grmask = ((byte1 >> 4) & 0xf);
78678844Sobrien      frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3;
78778844Sobrien      UNW_DEC_FRGR_MEM ("P5", grmask, frmask, arg);
78878844Sobrien    }
78978844Sobrien  else
79078844Sobrien    UNW_DEC_BAD_CODE (code);
79178844Sobrien
79278844Sobrien  return dp;
79378844Sobrien}
79478844Sobrien
79578844Sobrienstatic const unsigned char *
796130561Sobrienunw_decode_p6 (const unsigned char *dp, unsigned int code,
797130561Sobrien	       void *arg ATTRIBUTE_UNUSED)
79878844Sobrien{
79978844Sobrien  int gregs = (code & 0x10) != 0;
80078844Sobrien  unsigned char mask = (code & 0x0f);
80178844Sobrien
80278844Sobrien  if (gregs)
80378844Sobrien    UNW_DEC_GR_MEM ("P6", mask, arg);
80478844Sobrien  else
80578844Sobrien    UNW_DEC_FR_MEM ("P6", mask, arg);
80678844Sobrien  return dp;
80778844Sobrien}
80878844Sobrien
80978844Sobrienstatic const unsigned char *
810130561Sobrienunw_decode_p7_p10 (const unsigned char *dp, unsigned int code, void *arg)
81178844Sobrien{
81278844Sobrien  unsigned char r, byte1, byte2;
81378844Sobrien  unw_word t, size;
81478844Sobrien
81578844Sobrien  if ((code & 0x10) == 0)
81678844Sobrien    {
81778844Sobrien      r = (code & 0xf);
81878844Sobrien      t = unw_decode_uleb128 (&dp);
81978844Sobrien      switch (r)
82078844Sobrien	{
82178844Sobrien	case 0:
82278844Sobrien	  size = unw_decode_uleb128 (&dp);
82378844Sobrien	  UNW_DEC_MEM_STACK_F ("P7", t, size, arg);
82478844Sobrien	  break;
82578844Sobrien
82678844Sobrien	case 1:
82778844Sobrien	  UNW_DEC_MEM_STACK_V ("P7", t, arg);
82878844Sobrien	  break;
82978844Sobrien	case 2:
83078844Sobrien	  UNW_DEC_SPILL_BASE ("P7", t, arg);
83178844Sobrien	  break;
83278844Sobrien	case 3:
83378844Sobrien	  UNW_DEC_REG_SPREL ("P7", UNW_REG_PSP, t, arg);
83478844Sobrien	  break;
83578844Sobrien	case 4:
83678844Sobrien	  UNW_DEC_REG_WHEN ("P7", UNW_REG_RP, t, arg);
83778844Sobrien	  break;
83878844Sobrien	case 5:
83978844Sobrien	  UNW_DEC_REG_PSPREL ("P7", UNW_REG_RP, t, arg);
84078844Sobrien	  break;
84178844Sobrien	case 6:
84278844Sobrien	  UNW_DEC_REG_WHEN ("P7", UNW_REG_PFS, t, arg);
84378844Sobrien	  break;
84478844Sobrien	case 7:
84578844Sobrien	  UNW_DEC_REG_PSPREL ("P7", UNW_REG_PFS, t, arg);
84678844Sobrien	  break;
84778844Sobrien	case 8:
84878844Sobrien	  UNW_DEC_REG_WHEN ("P7", UNW_REG_PR, t, arg);
84978844Sobrien	  break;
85078844Sobrien	case 9:
85178844Sobrien	  UNW_DEC_REG_PSPREL ("P7", UNW_REG_PR, t, arg);
85278844Sobrien	  break;
85378844Sobrien	case 10:
85478844Sobrien	  UNW_DEC_REG_WHEN ("P7", UNW_REG_LC, t, arg);
85578844Sobrien	  break;
85678844Sobrien	case 11:
85778844Sobrien	  UNW_DEC_REG_PSPREL ("P7", UNW_REG_LC, t, arg);
85878844Sobrien	  break;
85978844Sobrien	case 12:
86078844Sobrien	  UNW_DEC_REG_WHEN ("P7", UNW_REG_UNAT, t, arg);
86178844Sobrien	  break;
86278844Sobrien	case 13:
86378844Sobrien	  UNW_DEC_REG_PSPREL ("P7", UNW_REG_UNAT, t, arg);
86478844Sobrien	  break;
86578844Sobrien	case 14:
86678844Sobrien	  UNW_DEC_REG_WHEN ("P7", UNW_REG_FPSR, t, arg);
86778844Sobrien	  break;
86878844Sobrien	case 15:
86978844Sobrien	  UNW_DEC_REG_PSPREL ("P7", UNW_REG_FPSR, t, arg);
87078844Sobrien	  break;
87178844Sobrien	default:
87278844Sobrien	  UNW_DEC_BAD_CODE (r);
87378844Sobrien	  break;
87478844Sobrien	}
87578844Sobrien    }
87678844Sobrien  else
87778844Sobrien    {
87878844Sobrien      switch (code & 0xf)
87978844Sobrien	{
88078844Sobrien	case 0x0:		/* p8 */
88178844Sobrien	  {
88278844Sobrien	    r = *dp++;
88378844Sobrien	    t = unw_decode_uleb128 (&dp);
88478844Sobrien	    switch (r)
88578844Sobrien	      {
88678844Sobrien	      case 1:
88778844Sobrien		UNW_DEC_REG_SPREL ("P8", UNW_REG_RP, t, arg);
88878844Sobrien		break;
88978844Sobrien	      case 2:
89078844Sobrien		UNW_DEC_REG_SPREL ("P8", UNW_REG_PFS, t, arg);
89178844Sobrien		break;
89278844Sobrien	      case 3:
89378844Sobrien		UNW_DEC_REG_SPREL ("P8", UNW_REG_PR, t, arg);
89478844Sobrien		break;
89578844Sobrien	      case 4:
89678844Sobrien		UNW_DEC_REG_SPREL ("P8", UNW_REG_LC, t, arg);
89778844Sobrien		break;
89878844Sobrien	      case 5:
89978844Sobrien		UNW_DEC_REG_SPREL ("P8", UNW_REG_UNAT, t, arg);
90078844Sobrien		break;
90178844Sobrien	      case 6:
90278844Sobrien		UNW_DEC_REG_SPREL ("P8", UNW_REG_FPSR, t, arg);
90378844Sobrien		break;
90478844Sobrien	      case 7:
90578844Sobrien		UNW_DEC_REG_WHEN ("P8", UNW_REG_BSP, t, arg);
90678844Sobrien		break;
90778844Sobrien	      case 8:
90878844Sobrien		UNW_DEC_REG_PSPREL ("P8", UNW_REG_BSP, t, arg);
90978844Sobrien		break;
91078844Sobrien	      case 9:
91178844Sobrien		UNW_DEC_REG_SPREL ("P8", UNW_REG_BSP, t, arg);
91278844Sobrien		break;
91378844Sobrien	      case 10:
91478844Sobrien		UNW_DEC_REG_WHEN ("P8", UNW_REG_BSPSTORE, t, arg);
91578844Sobrien		break;
91678844Sobrien	      case 11:
91778844Sobrien		UNW_DEC_REG_PSPREL ("P8", UNW_REG_BSPSTORE, t, arg);
91878844Sobrien		break;
91978844Sobrien	      case 12:
92078844Sobrien		UNW_DEC_REG_SPREL ("P8", UNW_REG_BSPSTORE, t, arg);
92178844Sobrien		break;
92278844Sobrien	      case 13:
92378844Sobrien		UNW_DEC_REG_WHEN ("P8", UNW_REG_RNAT, t, arg);
92478844Sobrien		break;
92578844Sobrien	      case 14:
92678844Sobrien		UNW_DEC_REG_PSPREL ("P8", UNW_REG_RNAT, t, arg);
92778844Sobrien		break;
92878844Sobrien	      case 15:
92978844Sobrien		UNW_DEC_REG_SPREL ("P8", UNW_REG_RNAT, t, arg);
93078844Sobrien		break;
93178844Sobrien	      case 16:
93278844Sobrien		UNW_DEC_PRIUNAT_WHEN_GR ("P8", t, arg);
93378844Sobrien		break;
93478844Sobrien	      case 17:
93578844Sobrien		UNW_DEC_PRIUNAT_PSPREL ("P8", t, arg);
93678844Sobrien		break;
93778844Sobrien	      case 18:
93878844Sobrien		UNW_DEC_PRIUNAT_SPREL ("P8", t, arg);
93978844Sobrien		break;
94078844Sobrien	      case 19:
94178844Sobrien		UNW_DEC_PRIUNAT_WHEN_MEM ("P8", t, arg);
94278844Sobrien		break;
94378844Sobrien	      default:
94478844Sobrien		UNW_DEC_BAD_CODE (r);
94578844Sobrien		break;
94678844Sobrien	      }
94778844Sobrien	  }
94878844Sobrien	  break;
94978844Sobrien
95078844Sobrien	case 0x1:
95178844Sobrien	  byte1 = *dp++;
95278844Sobrien	  byte2 = *dp++;
95378844Sobrien	  UNW_DEC_GR_GR ("P9", (byte1 & 0xf), (byte2 & 0x7f), arg);
95478844Sobrien	  break;
95578844Sobrien
95678844Sobrien	case 0xf:		/* p10 */
95778844Sobrien	  byte1 = *dp++;
95878844Sobrien	  byte2 = *dp++;
95978844Sobrien	  UNW_DEC_ABI ("P10", byte1, byte2, arg);
96078844Sobrien	  break;
96178844Sobrien
96278844Sobrien	case 0x9:
96378844Sobrien	  return unw_decode_x1 (dp, code, arg);
96478844Sobrien
96578844Sobrien	case 0xa:
96678844Sobrien	  return unw_decode_x2 (dp, code, arg);
96778844Sobrien
96878844Sobrien	case 0xb:
96978844Sobrien	  return unw_decode_x3 (dp, code, arg);
97078844Sobrien
97178844Sobrien	case 0xc:
97278844Sobrien	  return unw_decode_x4 (dp, code, arg);
97378844Sobrien
97478844Sobrien	default:
97578844Sobrien	  UNW_DEC_BAD_CODE (code);
97678844Sobrien	  break;
97778844Sobrien	}
97878844Sobrien    }
97978844Sobrien  return dp;
98078844Sobrien}
98178844Sobrien
98278844Sobrienstatic const unsigned char *
983130561Sobrienunw_decode_b1 (const unsigned char *dp, unsigned int code,
984130561Sobrien	       void *arg ATTRIBUTE_UNUSED)
98578844Sobrien{
98678844Sobrien  unw_word label = (code & 0x1f);
98778844Sobrien
98878844Sobrien  if ((code & 0x20) != 0)
98978844Sobrien    UNW_DEC_COPY_STATE ("B1", label, arg);
99078844Sobrien  else
99178844Sobrien    UNW_DEC_LABEL_STATE ("B1", label, arg);
99278844Sobrien  return dp;
99378844Sobrien}
99478844Sobrien
99578844Sobrienstatic const unsigned char *
996130561Sobrienunw_decode_b2 (const unsigned char *dp, unsigned int code,
997130561Sobrien	       void *arg ATTRIBUTE_UNUSED)
99878844Sobrien{
99978844Sobrien  unw_word t;
100078844Sobrien
100178844Sobrien  t = unw_decode_uleb128 (& dp);
100278844Sobrien  UNW_DEC_EPILOGUE ("B2", t, (code & 0x1f), arg);
100378844Sobrien  return dp;
100478844Sobrien}
100578844Sobrien
100678844Sobrienstatic const unsigned char *
1007130561Sobrienunw_decode_b3_x4 (const unsigned char *dp, unsigned int code, void *arg)
100878844Sobrien{
100978844Sobrien  unw_word t, ecount, label;
101078844Sobrien
101178844Sobrien  if ((code & 0x10) == 0)
101278844Sobrien    {
101378844Sobrien      t = unw_decode_uleb128 (&dp);
101478844Sobrien      ecount = unw_decode_uleb128 (&dp);
101578844Sobrien      UNW_DEC_EPILOGUE ("B3", t, ecount, arg);
101678844Sobrien    }
101778844Sobrien  else if ((code & 0x07) == 0)
101878844Sobrien    {
101978844Sobrien      label = unw_decode_uleb128 (&dp);
102078844Sobrien      if ((code & 0x08) != 0)
102178844Sobrien	UNW_DEC_COPY_STATE ("B4", label, arg);
102278844Sobrien      else
102378844Sobrien	UNW_DEC_LABEL_STATE ("B4", label, arg);
102478844Sobrien    }
102578844Sobrien  else
102678844Sobrien    switch (code & 0x7)
102778844Sobrien      {
102878844Sobrien      case 1:
102978844Sobrien	return unw_decode_x1 (dp, code, arg);
103078844Sobrien      case 2:
103178844Sobrien	return unw_decode_x2 (dp, code, arg);
103278844Sobrien      case 3:
103378844Sobrien	return unw_decode_x3 (dp, code, arg);
103478844Sobrien      case 4:
103578844Sobrien	return unw_decode_x4 (dp, code, arg);
103678844Sobrien      default:
103778844Sobrien	UNW_DEC_BAD_CODE (code);
103878844Sobrien	break;
103978844Sobrien      }
104078844Sobrien  return dp;
104178844Sobrien}
104278844Sobrien
104378844Sobrientypedef const unsigned char *(*unw_decoder)
1044130561Sobrien     (const unsigned char *, unsigned int, void *);
104578844Sobrien
104678844Sobrienstatic unw_decoder unw_decode_table[2][8] =
104778844Sobrien  {
104878844Sobrien    /* prologue table: */
104978844Sobrien    {
105078844Sobrien      unw_decode_r1,		/* 0 */
105178844Sobrien      unw_decode_r1,
105278844Sobrien      unw_decode_r2,
105378844Sobrien      unw_decode_r3,
105478844Sobrien      unw_decode_p1,		/* 4 */
105578844Sobrien      unw_decode_p2_p5,
105678844Sobrien      unw_decode_p6,
105778844Sobrien      unw_decode_p7_p10
105878844Sobrien    },
105978844Sobrien    {
106078844Sobrien      unw_decode_r1,		/* 0 */
106178844Sobrien      unw_decode_r1,
106278844Sobrien      unw_decode_r2,
106378844Sobrien      unw_decode_r3,
106478844Sobrien      unw_decode_b1,		/* 4 */
106578844Sobrien      unw_decode_b1,
106678844Sobrien      unw_decode_b2,
106778844Sobrien      unw_decode_b3_x4
106878844Sobrien    }
106978844Sobrien  };
107078844Sobrien
107178844Sobrien/* Decode one descriptor and return address of next descriptor.  */
107278844Sobrienconst unsigned char *
1073130561Sobrienunw_decode (const unsigned char *dp, int inside_body,
1074130561Sobrien	    void *ptr_inside_body)
107578844Sobrien{
107678844Sobrien  unw_decoder decoder;
107778844Sobrien  unsigned char code;
107878844Sobrien
107978844Sobrien  code = *dp++;
108078844Sobrien  decoder = unw_decode_table[inside_body][code >> 5];
108178844Sobrien  return (*decoder) (dp, code, ptr_inside_body);
108278844Sobrien}
1083