• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 This file is part of libunwind.
6 
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH 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 
87 static unw_word
unw_decode_uleb128(unsigned char ** dpp)88 unw_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 
106 static unsigned char *
unw_decode_x1(unsigned char * dp,unsigned char code,void * arg)107 unw_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 
123 static unsigned char *
unw_decode_x2(unsigned char * dp,unsigned char code,void * arg)124 unw_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 
141 static unsigned char *
unw_decode_x3(unsigned char * dp,unsigned char code,void * arg)142 unw_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 
161 static unsigned char *
unw_decode_x4(unsigned char * dp,unsigned char code,void * arg)162 unw_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 
182 static inline unsigned char *
unw_decode_r1(unsigned char * dp,unsigned char code,void * arg)183 unw_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 
193 static inline unsigned char *
unw_decode_r2(unsigned char * dp,unsigned char code,void * arg)194 unw_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 
208 static inline unsigned char *
unw_decode_r3(unsigned char * dp,unsigned char code,void * arg)209 unw_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 
218 static inline unsigned char *
unw_decode_p1(unsigned char * dp,unsigned char code,void * arg)219 unw_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 
227 static inline unsigned char *
unw_decode_p2_p5(unsigned char * dp,unsigned char code,void * arg)228 unw_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 
276 static inline unsigned char *
unw_decode_p6(unsigned char * dp,unsigned char code,void * arg)277 unw_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 
289 static inline unsigned char *
unw_decode_p7_p10(unsigned char * dp,unsigned char code,void * arg)290 unw_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 
388 static inline unsigned char *
unw_decode_b1(unsigned char * dp,unsigned char code,void * arg)389 unw_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 
400 static inline unsigned char *
unw_decode_b2(unsigned char * dp,unsigned char code,void * arg)401 unw_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 
410 static inline unsigned char *
unw_decode_b3_x4(unsigned char * dp,unsigned char code,void * arg)411 unw_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 
441 typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *);
442 
443 /*
444  * Decode one descriptor and return address of next descriptor.
445  */
446 static inline unsigned char *
unw_decode(unsigned char * dp,int inside_body,void * arg)447 unw_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