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