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