1/* 2 * Copyright (C) 2000 Hewlett-Packard Co 3 * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> 4 * 5 * Generic IA-64 unwind info decoder. 6 * 7 * This file is used both by the Linux kernel and objdump. Please keep 8 * the two copies of this file in sync. 9 * 10 * You need to customize the decoder by defining the following 11 * macros/constants before including this file: 12 * 13 * Types: 14 * unw_word Unsigned integer type with at least 64 bits 15 * 16 * Register names: 17 * UNW_REG_BSP 18 * UNW_REG_BSPSTORE 19 * UNW_REG_FPSR 20 * UNW_REG_LC 21 * UNW_REG_PFS 22 * UNW_REG_PR 23 * UNW_REG_RNAT 24 * UNW_REG_PSP 25 * UNW_REG_RP 26 * UNW_REG_UNAT 27 * 28 * Decoder action macros: 29 * UNW_DEC_BAD_CODE(code) 30 * UNW_DEC_ABI(fmt,abi,context,arg) 31 * UNW_DEC_BR_GR(fmt,brmask,gr,arg) 32 * UNW_DEC_BR_MEM(fmt,brmask,arg) 33 * UNW_DEC_COPY_STATE(fmt,label,arg) 34 * UNW_DEC_EPILOGUE(fmt,t,ecount,arg) 35 * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg) 36 * UNW_DEC_FR_MEM(fmt,frmask,arg) 37 * UNW_DEC_GR_GR(fmt,grmask,gr,arg) 38 * UNW_DEC_GR_MEM(fmt,grmask,arg) 39 * UNW_DEC_LABEL_STATE(fmt,label,arg) 40 * UNW_DEC_MEM_STACK_F(fmt,t,size,arg) 41 * UNW_DEC_MEM_STACK_V(fmt,t,arg) 42 * UNW_DEC_PRIUNAT_GR(fmt,r,arg) 43 * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) 44 * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) 45 * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg) 46 * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg) 47 * UNW_DEC_PROLOGUE(fmt,body,rlen,arg) 48 * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg) 49 * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg) 50 * UNW_DEC_REG_REG(fmt,src,dst,arg) 51 * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg) 52 * UNW_DEC_REG_WHEN(fmt,reg,t,arg) 53 * UNW_DEC_RESTORE(fmt,t,abreg,arg) 54 * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg) 55 * UNW_DEC_SPILL_BASE(fmt,pspoff,arg) 56 * UNW_DEC_SPILL_MASK(fmt,imaskp,arg) 57 * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg) 58 * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg) 59 * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg) 60 * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg) 61 * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg) 62 * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg) 63 */ 64 65static unw_word 66unw_decode_uleb128 (unsigned char **dpp) 67{ 68 unsigned shift = 0; 69 unw_word byte, result = 0; 70 unsigned char *bp = *dpp; 71 72 while (1) 73 { 74 byte = *bp++; 75 result |= (byte & 0x7f) << shift; 76 if ((byte & 0x80) == 0) 77 break; 78 shift += 7; 79 } 80 *dpp = bp; 81 return result; 82} 83 84static unsigned char * 85unw_decode_x1 (unsigned char *dp, unsigned char code, void *arg) 86{ 87 unsigned char byte1, abreg; 88 unw_word t, off; 89 90 byte1 = *dp++; 91 t = unw_decode_uleb128 (&dp); 92 off = unw_decode_uleb128 (&dp); 93 abreg = (byte1 & 0x7f); 94 if (byte1 & 0x80) 95 UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg); 96 else 97 UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg); 98 return dp; 99} 100 101static unsigned char * 102unw_decode_x2 (unsigned char *dp, unsigned char code, void *arg) 103{ 104 unsigned char byte1, byte2, abreg, x, ytreg; 105 unw_word t; 106 107 byte1 = *dp++; byte2 = *dp++; 108 t = unw_decode_uleb128 (&dp); 109 abreg = (byte1 & 0x7f); 110 ytreg = byte2; 111 x = (byte1 >> 7) & 1; 112 if ((byte1 & 0x80) == 0 && ytreg == 0) 113 UNW_DEC_RESTORE(X2, t, abreg, arg); 114 else 115 UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg); 116 return dp; 117} 118 119static unsigned char * 120unw_decode_x3 (unsigned char *dp, unsigned char code, void *arg) 121{ 122 unsigned char byte1, byte2, abreg, qp; 123 unw_word t, off; 124 125 byte1 = *dp++; byte2 = *dp++; 126 t = unw_decode_uleb128 (&dp); 127 off = unw_decode_uleb128 (&dp); 128 129 qp = (byte1 & 0x3f); 130 abreg = (byte2 & 0x7f); 131 132 if (byte1 & 0x80) 133 UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg); 134 else 135 UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg); 136 return dp; 137} 138 139static unsigned char * 140unw_decode_x4 (unsigned char *dp, unsigned char code, void *arg) 141{ 142 unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg; 143 unw_word t; 144 145 byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; 146 t = unw_decode_uleb128 (&dp); 147 148 qp = (byte1 & 0x3f); 149 abreg = (byte2 & 0x7f); 150 x = (byte2 >> 7) & 1; 151 ytreg = byte3; 152 153 if ((byte2 & 0x80) == 0 && byte3 == 0) 154 UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg); 155 else 156 UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg); 157 return dp; 158} 159 160static unsigned char * 161unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg) 162{ 163 int body = (code & 0x20) != 0; 164 unw_word rlen; 165 166 rlen = (code & 0x1f); 167 UNW_DEC_PROLOGUE(R1, body, rlen, arg); 168 return dp; 169} 170 171static unsigned char * 172unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg) 173{ 174 unsigned char byte1, mask, grsave; 175 unw_word rlen; 176 177 byte1 = *dp++; 178 179 mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); 180 grsave = (byte1 & 0x7f); 181 rlen = unw_decode_uleb128 (&dp); 182 UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg); 183 return dp; 184} 185 186static unsigned char * 187unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg) 188{ 189 unw_word rlen; 190 191 rlen = unw_decode_uleb128 (&dp); 192 UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg); 193 return dp; 194} 195 196static unsigned char * 197unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg) 198{ 199 unsigned char brmask = (code & 0x1f); 200 201 UNW_DEC_BR_MEM(P1, brmask, arg); 202 return dp; 203} 204 205static unsigned char * 206unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg) 207{ 208 if ((code & 0x10) == 0) 209 { 210 unsigned char byte1 = *dp++; 211 212 UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1), 213 (byte1 & 0x7f), arg); 214 } 215 else if ((code & 0x08) == 0) 216 { 217 unsigned char byte1 = *dp++, r, dst; 218 219 r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); 220 dst = (byte1 & 0x7f); 221 switch (r) 222 { 223 case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break; 224 case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break; 225 case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break; 226 case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break; 227 case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break; 228 case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break; 229 case 6: UNW_DEC_RP_BR(P3, dst, arg); break; 230 case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break; 231 case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break; 232 case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break; 233 case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break; 234 case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break; 235 default: UNW_DEC_BAD_CODE(r); break; 236 } 237 } 238 else if ((code & 0x7) == 0) 239 UNW_DEC_SPILL_MASK(P4, dp, arg); 240 else if ((code & 0x7) == 1) 241 { 242 unw_word grmask, frmask, byte1, byte2, byte3; 243 244 byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; 245 grmask = ((byte1 >> 4) & 0xf); 246 frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3; 247 UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg); 248 } 249 else 250 UNW_DEC_BAD_CODE(code); 251 return dp; 252} 253 254static unsigned char * 255unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg) 256{ 257 int gregs = (code & 0x10) != 0; 258 unsigned char mask = (code & 0x0f); 259 260 if (gregs) 261 UNW_DEC_GR_MEM(P6, mask, arg); 262 else 263 UNW_DEC_FR_MEM(P6, mask, arg); 264 return dp; 265} 266 267static unsigned char * 268unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg) 269{ 270 unsigned char r, byte1, byte2; 271 unw_word t, size; 272 273 if ((code & 0x10) == 0) 274 { 275 r = (code & 0xf); 276 t = unw_decode_uleb128 (&dp); 277 switch (r) 278 { 279 case 0: 280 size = unw_decode_uleb128 (&dp); 281 UNW_DEC_MEM_STACK_F(P7, t, size, arg); 282 break; 283 284 case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break; 285 case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break; 286 case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break; 287 case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break; 288 case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break; 289 case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break; 290 case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break; 291 case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break; 292 case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break; 293 case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break; 294 case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break; 295 case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break; 296 case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break; 297 case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break; 298 case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break; 299 default: UNW_DEC_BAD_CODE(r); break; 300 } 301 } 302 else 303 { 304 switch (code & 0xf) 305 { 306 case 0x0: /* p8 */ 307 { 308 r = *dp++; 309 t = unw_decode_uleb128 (&dp); 310 switch (r) 311 { 312 case 1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break; 313 case 2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break; 314 case 3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break; 315 case 4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break; 316 case 5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break; 317 case 6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break; 318 case 7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break; 319 case 8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break; 320 case 9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break; 321 case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break; 322 case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break; 323 case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break; 324 case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break; 325 case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break; 326 case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break; 327 case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break; 328 case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break; 329 case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break; 330 case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break; 331 default: UNW_DEC_BAD_CODE(r); break; 332 } 333 } 334 break; 335 336 case 0x1: 337 byte1 = *dp++; byte2 = *dp++; 338 UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg); 339 break; 340 341 case 0xf: /* p10 */ 342 byte1 = *dp++; byte2 = *dp++; 343 UNW_DEC_ABI(P10, byte1, byte2, arg); 344 break; 345 346 case 0x9: 347 return unw_decode_x1 (dp, code, arg); 348 349 case 0xa: 350 return unw_decode_x2 (dp, code, arg); 351 352 case 0xb: 353 return unw_decode_x3 (dp, code, arg); 354 355 case 0xc: 356 return unw_decode_x4 (dp, code, arg); 357 358 default: 359 UNW_DEC_BAD_CODE(code); 360 break; 361 } 362 } 363 return dp; 364} 365 366static unsigned char * 367unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg) 368{ 369 unw_word label = (code & 0x1f); 370 371 if ((code & 0x20) != 0) 372 UNW_DEC_COPY_STATE(B1, label, arg); 373 else 374 UNW_DEC_LABEL_STATE(B1, label, arg); 375 return dp; 376} 377 378static unsigned char * 379unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg) 380{ 381 unw_word t; 382 383 t = unw_decode_uleb128 (&dp); 384 UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg); 385 return dp; 386} 387 388static unsigned char * 389unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg) 390{ 391 unw_word t, ecount, label; 392 393 if ((code & 0x10) == 0) 394 { 395 t = unw_decode_uleb128 (&dp); 396 ecount = unw_decode_uleb128 (&dp); 397 UNW_DEC_EPILOGUE(B3, t, ecount, arg); 398 } 399 else if ((code & 0x07) == 0) 400 { 401 label = unw_decode_uleb128 (&dp); 402 if ((code & 0x08) != 0) 403 UNW_DEC_COPY_STATE(B4, label, arg); 404 else 405 UNW_DEC_LABEL_STATE(B4, label, arg); 406 } 407 else 408 switch (code & 0x7) 409 { 410 case 1: return unw_decode_x1 (dp, code, arg); 411 case 2: return unw_decode_x2 (dp, code, arg); 412 case 3: return unw_decode_x3 (dp, code, arg); 413 case 4: return unw_decode_x4 (dp, code, arg); 414 default: UNW_DEC_BAD_CODE(code); break; 415 } 416 return dp; 417} 418 419typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *); 420 421static unw_decoder unw_decode_table[2][8] = 422{ 423 /* prologue table: */ 424 { 425 unw_decode_r1, /* 0 */ 426 unw_decode_r1, 427 unw_decode_r2, 428 unw_decode_r3, 429 unw_decode_p1, /* 4 */ 430 unw_decode_p2_p5, 431 unw_decode_p6, 432 unw_decode_p7_p10 433 }, 434 { 435 unw_decode_r1, /* 0 */ 436 unw_decode_r1, 437 unw_decode_r2, 438 unw_decode_r3, 439 unw_decode_b1, /* 4 */ 440 unw_decode_b1, 441 unw_decode_b2, 442 unw_decode_b3_x4 443 } 444}; 445 446/* 447 * Decode one descriptor and return address of next descriptor. 448 */ 449static inline unsigned char * 450unw_decode (unsigned char *dp, int inside_body, void *arg) 451{ 452 unw_decoder decoder; 453 unsigned char code; 454 455 code = *dp++; 456 decoder = unw_decode_table[inside_body][code >> 5]; 457 dp = (*decoder) (dp, code, arg); 458 return dp; 459} 460