162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2000 Hewlett-Packard Co
462306a36Sopenharmony_ci * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Generic IA-64 unwind info decoder.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This file is used both by the Linux kernel and objdump.  Please keep
962306a36Sopenharmony_ci * the two copies of this file in sync.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * You need to customize the decoder by defining the following
1262306a36Sopenharmony_ci * macros/constants before including this file:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Types:
1562306a36Sopenharmony_ci *	unw_word	Unsigned integer type with at least 64 bits
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *  Register names:
1862306a36Sopenharmony_ci *	UNW_REG_BSP
1962306a36Sopenharmony_ci *	UNW_REG_BSPSTORE
2062306a36Sopenharmony_ci *	UNW_REG_FPSR
2162306a36Sopenharmony_ci *	UNW_REG_LC
2262306a36Sopenharmony_ci *	UNW_REG_PFS
2362306a36Sopenharmony_ci *	UNW_REG_PR
2462306a36Sopenharmony_ci *	UNW_REG_RNAT
2562306a36Sopenharmony_ci *	UNW_REG_PSP
2662306a36Sopenharmony_ci *	UNW_REG_RP
2762306a36Sopenharmony_ci *	UNW_REG_UNAT
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci *  Decoder action macros:
3062306a36Sopenharmony_ci *	UNW_DEC_BAD_CODE(code)
3162306a36Sopenharmony_ci *	UNW_DEC_ABI(fmt,abi,context,arg)
3262306a36Sopenharmony_ci *	UNW_DEC_BR_GR(fmt,brmask,gr,arg)
3362306a36Sopenharmony_ci *	UNW_DEC_BR_MEM(fmt,brmask,arg)
3462306a36Sopenharmony_ci *	UNW_DEC_COPY_STATE(fmt,label,arg)
3562306a36Sopenharmony_ci *	UNW_DEC_EPILOGUE(fmt,t,ecount,arg)
3662306a36Sopenharmony_ci *	UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg)
3762306a36Sopenharmony_ci *	UNW_DEC_FR_MEM(fmt,frmask,arg)
3862306a36Sopenharmony_ci *	UNW_DEC_GR_GR(fmt,grmask,gr,arg)
3962306a36Sopenharmony_ci *	UNW_DEC_GR_MEM(fmt,grmask,arg)
4062306a36Sopenharmony_ci *	UNW_DEC_LABEL_STATE(fmt,label,arg)
4162306a36Sopenharmony_ci *	UNW_DEC_MEM_STACK_F(fmt,t,size,arg)
4262306a36Sopenharmony_ci *	UNW_DEC_MEM_STACK_V(fmt,t,arg)
4362306a36Sopenharmony_ci *	UNW_DEC_PRIUNAT_GR(fmt,r,arg)
4462306a36Sopenharmony_ci *	UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg)
4562306a36Sopenharmony_ci *	UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg)
4662306a36Sopenharmony_ci *	UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg)
4762306a36Sopenharmony_ci *	UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg)
4862306a36Sopenharmony_ci *	UNW_DEC_PROLOGUE(fmt,body,rlen,arg)
4962306a36Sopenharmony_ci *	UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg)
5062306a36Sopenharmony_ci *	UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg)
5162306a36Sopenharmony_ci *	UNW_DEC_REG_REG(fmt,src,dst,arg)
5262306a36Sopenharmony_ci *	UNW_DEC_REG_SPREL(fmt,reg,spoff,arg)
5362306a36Sopenharmony_ci *	UNW_DEC_REG_WHEN(fmt,reg,t,arg)
5462306a36Sopenharmony_ci *	UNW_DEC_RESTORE(fmt,t,abreg,arg)
5562306a36Sopenharmony_ci *	UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg)
5662306a36Sopenharmony_ci *	UNW_DEC_SPILL_BASE(fmt,pspoff,arg)
5762306a36Sopenharmony_ci *	UNW_DEC_SPILL_MASK(fmt,imaskp,arg)
5862306a36Sopenharmony_ci *	UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg)
5962306a36Sopenharmony_ci *	UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg)
6062306a36Sopenharmony_ci *	UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg)
6162306a36Sopenharmony_ci *	UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg)
6262306a36Sopenharmony_ci *	UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg)
6362306a36Sopenharmony_ci *	UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg)
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic unw_word
6762306a36Sopenharmony_ciunw_decode_uleb128 (unsigned char **dpp)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci  unsigned shift = 0;
7062306a36Sopenharmony_ci  unw_word byte, result = 0;
7162306a36Sopenharmony_ci  unsigned char *bp = *dpp;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci  while (1)
7462306a36Sopenharmony_ci    {
7562306a36Sopenharmony_ci      byte = *bp++;
7662306a36Sopenharmony_ci      result |= (byte & 0x7f) << shift;
7762306a36Sopenharmony_ci      if ((byte & 0x80) == 0)
7862306a36Sopenharmony_ci	break;
7962306a36Sopenharmony_ci      shift += 7;
8062306a36Sopenharmony_ci    }
8162306a36Sopenharmony_ci  *dpp = bp;
8262306a36Sopenharmony_ci  return result;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic unsigned char *
8662306a36Sopenharmony_ciunw_decode_x1 (unsigned char *dp, unsigned char code, void *arg)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci  unsigned char byte1, abreg;
8962306a36Sopenharmony_ci  unw_word t, off;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci  byte1 = *dp++;
9262306a36Sopenharmony_ci  t = unw_decode_uleb128 (&dp);
9362306a36Sopenharmony_ci  off = unw_decode_uleb128 (&dp);
9462306a36Sopenharmony_ci  abreg = (byte1 & 0x7f);
9562306a36Sopenharmony_ci  if (byte1 & 0x80)
9662306a36Sopenharmony_ci	  UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg);
9762306a36Sopenharmony_ci  else
9862306a36Sopenharmony_ci	  UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg);
9962306a36Sopenharmony_ci  return dp;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic unsigned char *
10362306a36Sopenharmony_ciunw_decode_x2 (unsigned char *dp, unsigned char code, void *arg)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci  unsigned char byte1, byte2, abreg, x, ytreg;
10662306a36Sopenharmony_ci  unw_word t;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci  byte1 = *dp++; byte2 = *dp++;
10962306a36Sopenharmony_ci  t = unw_decode_uleb128 (&dp);
11062306a36Sopenharmony_ci  abreg = (byte1 & 0x7f);
11162306a36Sopenharmony_ci  ytreg = byte2;
11262306a36Sopenharmony_ci  x = (byte1 >> 7) & 1;
11362306a36Sopenharmony_ci  if ((byte1 & 0x80) == 0 && ytreg == 0)
11462306a36Sopenharmony_ci    UNW_DEC_RESTORE(X2, t, abreg, arg);
11562306a36Sopenharmony_ci  else
11662306a36Sopenharmony_ci    UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg);
11762306a36Sopenharmony_ci  return dp;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic unsigned char *
12162306a36Sopenharmony_ciunw_decode_x3 (unsigned char *dp, unsigned char code, void *arg)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci  unsigned char byte1, byte2, abreg, qp;
12462306a36Sopenharmony_ci  unw_word t, off;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci  byte1 = *dp++; byte2 = *dp++;
12762306a36Sopenharmony_ci  t = unw_decode_uleb128 (&dp);
12862306a36Sopenharmony_ci  off = unw_decode_uleb128 (&dp);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci  qp = (byte1 & 0x3f);
13162306a36Sopenharmony_ci  abreg = (byte2 & 0x7f);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci  if (byte1 & 0x80)
13462306a36Sopenharmony_ci    UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg);
13562306a36Sopenharmony_ci  else
13662306a36Sopenharmony_ci    UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg);
13762306a36Sopenharmony_ci  return dp;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic unsigned char *
14162306a36Sopenharmony_ciunw_decode_x4 (unsigned char *dp, unsigned char code, void *arg)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci  unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg;
14462306a36Sopenharmony_ci  unw_word t;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci  byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
14762306a36Sopenharmony_ci  t = unw_decode_uleb128 (&dp);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci  qp = (byte1 & 0x3f);
15062306a36Sopenharmony_ci  abreg = (byte2 & 0x7f);
15162306a36Sopenharmony_ci  x = (byte2 >> 7) & 1;
15262306a36Sopenharmony_ci  ytreg = byte3;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci  if ((byte2 & 0x80) == 0 && byte3 == 0)
15562306a36Sopenharmony_ci    UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg);
15662306a36Sopenharmony_ci  else
15762306a36Sopenharmony_ci    UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg);
15862306a36Sopenharmony_ci  return dp;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic unsigned char *
16262306a36Sopenharmony_ciunw_decode_r1 (unsigned char *dp, unsigned char code, void *arg)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci  int body = (code & 0x20) != 0;
16562306a36Sopenharmony_ci  unw_word rlen;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci  rlen = (code & 0x1f);
16862306a36Sopenharmony_ci  UNW_DEC_PROLOGUE(R1, body, rlen, arg);
16962306a36Sopenharmony_ci  return dp;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic unsigned char *
17362306a36Sopenharmony_ciunw_decode_r2 (unsigned char *dp, unsigned char code, void *arg)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci  unsigned char byte1, mask, grsave;
17662306a36Sopenharmony_ci  unw_word rlen;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci  byte1 = *dp++;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci  mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
18162306a36Sopenharmony_ci  grsave = (byte1 & 0x7f);
18262306a36Sopenharmony_ci  rlen = unw_decode_uleb128 (&dp);
18362306a36Sopenharmony_ci  UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg);
18462306a36Sopenharmony_ci  return dp;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic unsigned char *
18862306a36Sopenharmony_ciunw_decode_r3 (unsigned char *dp, unsigned char code, void *arg)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci  unw_word rlen;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci  rlen = unw_decode_uleb128 (&dp);
19362306a36Sopenharmony_ci  UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg);
19462306a36Sopenharmony_ci  return dp;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic unsigned char *
19862306a36Sopenharmony_ciunw_decode_p1 (unsigned char *dp, unsigned char code, void *arg)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci  unsigned char brmask = (code & 0x1f);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci  UNW_DEC_BR_MEM(P1, brmask, arg);
20362306a36Sopenharmony_ci  return dp;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic unsigned char *
20762306a36Sopenharmony_ciunw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci  if ((code & 0x10) == 0)
21062306a36Sopenharmony_ci    {
21162306a36Sopenharmony_ci      unsigned char byte1 = *dp++;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci      UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1),
21462306a36Sopenharmony_ci		    (byte1 & 0x7f), arg);
21562306a36Sopenharmony_ci    }
21662306a36Sopenharmony_ci  else if ((code & 0x08) == 0)
21762306a36Sopenharmony_ci    {
21862306a36Sopenharmony_ci      unsigned char byte1 = *dp++, r, dst;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci      r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
22162306a36Sopenharmony_ci      dst = (byte1 & 0x7f);
22262306a36Sopenharmony_ci      switch (r)
22362306a36Sopenharmony_ci	{
22462306a36Sopenharmony_ci	case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break;
22562306a36Sopenharmony_ci	case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break;
22662306a36Sopenharmony_ci	case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break;
22762306a36Sopenharmony_ci	case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break;
22862306a36Sopenharmony_ci	case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break;
22962306a36Sopenharmony_ci	case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break;
23062306a36Sopenharmony_ci	case 6: UNW_DEC_RP_BR(P3, dst, arg); break;
23162306a36Sopenharmony_ci	case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break;
23262306a36Sopenharmony_ci	case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break;
23362306a36Sopenharmony_ci	case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break;
23462306a36Sopenharmony_ci	case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break;
23562306a36Sopenharmony_ci	case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break;
23662306a36Sopenharmony_ci	default: UNW_DEC_BAD_CODE(r); break;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci    }
23962306a36Sopenharmony_ci  else if ((code & 0x7) == 0)
24062306a36Sopenharmony_ci    UNW_DEC_SPILL_MASK(P4, dp, arg);
24162306a36Sopenharmony_ci  else if ((code & 0x7) == 1)
24262306a36Sopenharmony_ci    {
24362306a36Sopenharmony_ci      unw_word grmask, frmask, byte1, byte2, byte3;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci      byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
24662306a36Sopenharmony_ci      grmask = ((byte1 >> 4) & 0xf);
24762306a36Sopenharmony_ci      frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3;
24862306a36Sopenharmony_ci      UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg);
24962306a36Sopenharmony_ci    }
25062306a36Sopenharmony_ci  else
25162306a36Sopenharmony_ci    UNW_DEC_BAD_CODE(code);
25262306a36Sopenharmony_ci  return dp;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic unsigned char *
25662306a36Sopenharmony_ciunw_decode_p6 (unsigned char *dp, unsigned char code, void *arg)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci  int gregs = (code & 0x10) != 0;
25962306a36Sopenharmony_ci  unsigned char mask = (code & 0x0f);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci  if (gregs)
26262306a36Sopenharmony_ci    UNW_DEC_GR_MEM(P6, mask, arg);
26362306a36Sopenharmony_ci  else
26462306a36Sopenharmony_ci    UNW_DEC_FR_MEM(P6, mask, arg);
26562306a36Sopenharmony_ci  return dp;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic unsigned char *
26962306a36Sopenharmony_ciunw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci  unsigned char r, byte1, byte2;
27262306a36Sopenharmony_ci  unw_word t, size;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci  if ((code & 0x10) == 0)
27562306a36Sopenharmony_ci    {
27662306a36Sopenharmony_ci      r = (code & 0xf);
27762306a36Sopenharmony_ci      t = unw_decode_uleb128 (&dp);
27862306a36Sopenharmony_ci      switch (r)
27962306a36Sopenharmony_ci	{
28062306a36Sopenharmony_ci	case 0:
28162306a36Sopenharmony_ci	  size = unw_decode_uleb128 (&dp);
28262306a36Sopenharmony_ci	  UNW_DEC_MEM_STACK_F(P7, t, size, arg);
28362306a36Sopenharmony_ci	  break;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break;
28662306a36Sopenharmony_ci	case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break;
28762306a36Sopenharmony_ci	case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break;
28862306a36Sopenharmony_ci	case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break;
28962306a36Sopenharmony_ci	case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break;
29062306a36Sopenharmony_ci	case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break;
29162306a36Sopenharmony_ci	case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break;
29262306a36Sopenharmony_ci	case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break;
29362306a36Sopenharmony_ci	case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break;
29462306a36Sopenharmony_ci	case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break;
29562306a36Sopenharmony_ci	case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break;
29662306a36Sopenharmony_ci	case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break;
29762306a36Sopenharmony_ci	case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break;
29862306a36Sopenharmony_ci	case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break;
29962306a36Sopenharmony_ci	case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break;
30062306a36Sopenharmony_ci	default: UNW_DEC_BAD_CODE(r); break;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci    }
30362306a36Sopenharmony_ci  else
30462306a36Sopenharmony_ci    {
30562306a36Sopenharmony_ci      switch (code & 0xf)
30662306a36Sopenharmony_ci	{
30762306a36Sopenharmony_ci	case 0x0: /* p8 */
30862306a36Sopenharmony_ci	  {
30962306a36Sopenharmony_ci	    r = *dp++;
31062306a36Sopenharmony_ci	    t = unw_decode_uleb128 (&dp);
31162306a36Sopenharmony_ci	    switch (r)
31262306a36Sopenharmony_ci	      {
31362306a36Sopenharmony_ci	      case  1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break;
31462306a36Sopenharmony_ci	      case  2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break;
31562306a36Sopenharmony_ci	      case  3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break;
31662306a36Sopenharmony_ci	      case  4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break;
31762306a36Sopenharmony_ci	      case  5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break;
31862306a36Sopenharmony_ci	      case  6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break;
31962306a36Sopenharmony_ci	      case  7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break;
32062306a36Sopenharmony_ci	      case  8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break;
32162306a36Sopenharmony_ci	      case  9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break;
32262306a36Sopenharmony_ci	      case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break;
32362306a36Sopenharmony_ci	      case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
32462306a36Sopenharmony_ci	      case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
32562306a36Sopenharmony_ci	      case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break;
32662306a36Sopenharmony_ci	      case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break;
32762306a36Sopenharmony_ci	      case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break;
32862306a36Sopenharmony_ci	      case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break;
32962306a36Sopenharmony_ci	      case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break;
33062306a36Sopenharmony_ci	      case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break;
33162306a36Sopenharmony_ci	      case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break;
33262306a36Sopenharmony_ci	      default: UNW_DEC_BAD_CODE(r); break;
33362306a36Sopenharmony_ci	    }
33462306a36Sopenharmony_ci	  }
33562306a36Sopenharmony_ci	  break;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	case 0x1:
33862306a36Sopenharmony_ci	  byte1 = *dp++; byte2 = *dp++;
33962306a36Sopenharmony_ci	  UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg);
34062306a36Sopenharmony_ci	  break;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	case 0xf: /* p10 */
34362306a36Sopenharmony_ci	  byte1 = *dp++; byte2 = *dp++;
34462306a36Sopenharmony_ci	  UNW_DEC_ABI(P10, byte1, byte2, arg);
34562306a36Sopenharmony_ci	  break;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	case 0x9:
34862306a36Sopenharmony_ci	  return unw_decode_x1 (dp, code, arg);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	case 0xa:
35162306a36Sopenharmony_ci	  return unw_decode_x2 (dp, code, arg);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	case 0xb:
35462306a36Sopenharmony_ci	  return unw_decode_x3 (dp, code, arg);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	case 0xc:
35762306a36Sopenharmony_ci	  return unw_decode_x4 (dp, code, arg);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	default:
36062306a36Sopenharmony_ci	  UNW_DEC_BAD_CODE(code);
36162306a36Sopenharmony_ci	  break;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci    }
36462306a36Sopenharmony_ci  return dp;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic unsigned char *
36862306a36Sopenharmony_ciunw_decode_b1 (unsigned char *dp, unsigned char code, void *arg)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci  unw_word label = (code & 0x1f);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci  if ((code & 0x20) != 0)
37362306a36Sopenharmony_ci    UNW_DEC_COPY_STATE(B1, label, arg);
37462306a36Sopenharmony_ci  else
37562306a36Sopenharmony_ci    UNW_DEC_LABEL_STATE(B1, label, arg);
37662306a36Sopenharmony_ci  return dp;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic unsigned char *
38062306a36Sopenharmony_ciunw_decode_b2 (unsigned char *dp, unsigned char code, void *arg)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci  unw_word t;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci  t = unw_decode_uleb128 (&dp);
38562306a36Sopenharmony_ci  UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg);
38662306a36Sopenharmony_ci  return dp;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic unsigned char *
39062306a36Sopenharmony_ciunw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci  unw_word t, ecount, label;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci  if ((code & 0x10) == 0)
39562306a36Sopenharmony_ci    {
39662306a36Sopenharmony_ci      t = unw_decode_uleb128 (&dp);
39762306a36Sopenharmony_ci      ecount = unw_decode_uleb128 (&dp);
39862306a36Sopenharmony_ci      UNW_DEC_EPILOGUE(B3, t, ecount, arg);
39962306a36Sopenharmony_ci    }
40062306a36Sopenharmony_ci  else if ((code & 0x07) == 0)
40162306a36Sopenharmony_ci    {
40262306a36Sopenharmony_ci      label = unw_decode_uleb128 (&dp);
40362306a36Sopenharmony_ci      if ((code & 0x08) != 0)
40462306a36Sopenharmony_ci	UNW_DEC_COPY_STATE(B4, label, arg);
40562306a36Sopenharmony_ci      else
40662306a36Sopenharmony_ci	UNW_DEC_LABEL_STATE(B4, label, arg);
40762306a36Sopenharmony_ci    }
40862306a36Sopenharmony_ci  else
40962306a36Sopenharmony_ci    switch (code & 0x7)
41062306a36Sopenharmony_ci      {
41162306a36Sopenharmony_ci      case 1: return unw_decode_x1 (dp, code, arg);
41262306a36Sopenharmony_ci      case 2: return unw_decode_x2 (dp, code, arg);
41362306a36Sopenharmony_ci      case 3: return unw_decode_x3 (dp, code, arg);
41462306a36Sopenharmony_ci      case 4: return unw_decode_x4 (dp, code, arg);
41562306a36Sopenharmony_ci      default: UNW_DEC_BAD_CODE(code); break;
41662306a36Sopenharmony_ci      }
41762306a36Sopenharmony_ci  return dp;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_citypedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic unw_decoder unw_decode_table[2][8] =
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci  /* prologue table: */
42562306a36Sopenharmony_ci  {
42662306a36Sopenharmony_ci    unw_decode_r1,	/* 0 */
42762306a36Sopenharmony_ci    unw_decode_r1,
42862306a36Sopenharmony_ci    unw_decode_r2,
42962306a36Sopenharmony_ci    unw_decode_r3,
43062306a36Sopenharmony_ci    unw_decode_p1,	/* 4 */
43162306a36Sopenharmony_ci    unw_decode_p2_p5,
43262306a36Sopenharmony_ci    unw_decode_p6,
43362306a36Sopenharmony_ci    unw_decode_p7_p10
43462306a36Sopenharmony_ci  },
43562306a36Sopenharmony_ci  {
43662306a36Sopenharmony_ci    unw_decode_r1,	/* 0 */
43762306a36Sopenharmony_ci    unw_decode_r1,
43862306a36Sopenharmony_ci    unw_decode_r2,
43962306a36Sopenharmony_ci    unw_decode_r3,
44062306a36Sopenharmony_ci    unw_decode_b1,	/* 4 */
44162306a36Sopenharmony_ci    unw_decode_b1,
44262306a36Sopenharmony_ci    unw_decode_b2,
44362306a36Sopenharmony_ci    unw_decode_b3_x4
44462306a36Sopenharmony_ci  }
44562306a36Sopenharmony_ci};
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci/*
44862306a36Sopenharmony_ci * Decode one descriptor and return address of next descriptor.
44962306a36Sopenharmony_ci */
45062306a36Sopenharmony_cistatic inline unsigned char *
45162306a36Sopenharmony_ciunw_decode (unsigned char *dp, int inside_body, void *arg)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci  unw_decoder decoder;
45462306a36Sopenharmony_ci  unsigned char code;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci  code = *dp++;
45762306a36Sopenharmony_ci  decoder = unw_decode_table[inside_body][code >> 5];
45862306a36Sopenharmony_ci  dp = (*decoder) (dp, code, arg);
45962306a36Sopenharmony_ci  return dp;
46062306a36Sopenharmony_ci}
461