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