Commit | Line | Data |
---|---|---|
4d6ed7c8 | 1 | /* unwind-ia64.c -- utility routines to dump IA-64 unwind info for readelf. |
250d07de | 2 | Copyright (C) 2000-2021 Free Software Foundation, Inc. |
df7b86aa NC |
3 | |
4 | Contributed by David Mosberger-Tang <davidm@hpl.hp.com> | |
4d6ed7c8 | 5 | |
32866df7 | 6 | This file is part of GNU Binutils. |
4d6ed7c8 | 7 | |
32866df7 NC |
8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 3, or (at your option) | |
11 | any later version. | |
4d6ed7c8 | 12 | |
32866df7 NC |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
4d6ed7c8 | 17 | |
32866df7 NC |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software | |
20 | Foundation, 51 Franklin Street - Fifth Floor, Boston, | |
21 | MA 02110-1301, USA. */ | |
4d6ed7c8 | 22 | |
df7b86aa | 23 | #include "config.h" |
5cacf1c8 | 24 | #include "sysdep.h" |
4d6ed7c8 | 25 | #include "unwind-ia64.h" |
4d6ed7c8 NC |
26 | |
27 | #if __GNUC__ >= 2 | |
28 | /* Define BFD64 here, even if our default architecture is 32 bit ELF | |
29 | as this will allow us to read in and parse 64bit and 32bit ELF files. | |
aaad4cf3 | 30 | Only do this if we believe that the compiler can support a 64 bit |
4d6ed7c8 NC |
31 | data type. For now we only rely on GCC being able to do this. */ |
32 | #define BFD64 | |
33 | #endif | |
34 | #include "bfd.h" | |
35 | ||
36 | static bfd_vma unw_rlen = 0; | |
37 | ||
2da42df6 AJ |
38 | static void unw_print_brmask (char *, unsigned int); |
39 | static void unw_print_grmask (char *, unsigned int); | |
40 | static void unw_print_frmask (char *, unsigned int); | |
41 | static void unw_print_abreg (char *, unsigned int); | |
42 | static void unw_print_xyreg (char *, unsigned int, unsigned int); | |
c32144ff | 43 | |
4d6ed7c8 | 44 | static void |
2da42df6 | 45 | unw_print_brmask (char *cp, unsigned int mask) |
4d6ed7c8 | 46 | { |
3eee1e9d | 47 | int sep = 0; |
4d6ed7c8 NC |
48 | int i; |
49 | ||
50 | for (i = 0; mask && (i < 5); ++i) | |
51 | { | |
52 | if (mask & 1) | |
53 | { | |
3eee1e9d AM |
54 | if (sep) |
55 | *cp++ = ','; | |
56 | *cp++ = 'b'; | |
57 | *cp++ = i + 1 + '0'; | |
58 | sep = 1; | |
4d6ed7c8 NC |
59 | } |
60 | mask >>= 1; | |
61 | } | |
62 | *cp = '\0'; | |
63 | } | |
64 | ||
65 | static void | |
2da42df6 | 66 | unw_print_grmask (char *cp, unsigned int mask) |
4d6ed7c8 | 67 | { |
3eee1e9d | 68 | int sep = 0; |
4d6ed7c8 NC |
69 | int i; |
70 | ||
4d6ed7c8 NC |
71 | for (i = 0; i < 4; ++i) |
72 | { | |
73 | if (mask & 1) | |
74 | { | |
3eee1e9d AM |
75 | if (sep) |
76 | *cp++ = ','; | |
77 | *cp++ = 'r'; | |
78 | *cp++ = i + 4 + '0'; | |
79 | sep = 1; | |
4d6ed7c8 NC |
80 | } |
81 | mask >>= 1; | |
82 | } | |
3eee1e9d | 83 | *cp = '\0'; |
4d6ed7c8 NC |
84 | } |
85 | ||
86 | static void | |
2da42df6 | 87 | unw_print_frmask (char *cp, unsigned int mask) |
4d6ed7c8 | 88 | { |
3eee1e9d | 89 | int sep = 0; |
4d6ed7c8 NC |
90 | int i; |
91 | ||
4d6ed7c8 NC |
92 | for (i = 0; i < 20; ++i) |
93 | { | |
94 | if (mask & 1) | |
95 | { | |
3eee1e9d AM |
96 | if (sep) |
97 | *cp++ = ','; | |
98 | *cp++ = 'f'; | |
99 | if (i < 4) | |
100 | *cp++ = i + 2 + '0'; | |
101 | else | |
102 | { | |
103 | *cp++ = (i + 2) / 10 + 1 + '0'; | |
104 | *cp++ = (i + 2) % 10 + '0'; | |
105 | } | |
106 | sep = 1; | |
4d6ed7c8 NC |
107 | } |
108 | mask >>= 1; | |
109 | } | |
3eee1e9d | 110 | *cp = '\0'; |
4d6ed7c8 NC |
111 | } |
112 | ||
113 | static void | |
2da42df6 | 114 | unw_print_abreg (char *cp, unsigned int abreg) |
4d6ed7c8 | 115 | { |
9bcd0325 | 116 | static const char * const special_reg[16] = |
4d6ed7c8 NC |
117 | { |
118 | "pr", "psp", "@priunat", "rp", "ar.bsp", "ar.bspstore", "ar.rnat", | |
119 | "ar.unat", "ar.fpsr", "ar.pfs", "ar.lc", | |
120 | "Unknown11", "Unknown12", "Unknown13", "Unknown14", "Unknown15" | |
121 | }; | |
122 | ||
123 | switch ((abreg >> 5) & 0x3) | |
124 | { | |
125 | case 0: /* gr */ | |
126 | sprintf (cp, "r%u", (abreg & 0x1f)); | |
127 | break; | |
128 | ||
129 | case 1: /* fr */ | |
130 | sprintf (cp, "f%u", (abreg & 0x1f)); | |
131 | break; | |
132 | ||
133 | case 2: /* br */ | |
134 | sprintf (cp, "b%u", (abreg & 0x1f)); | |
135 | break; | |
136 | ||
137 | case 3: /* special */ | |
138 | strcpy (cp, special_reg[abreg & 0xf]); | |
139 | break; | |
140 | } | |
141 | } | |
142 | ||
143 | static void | |
2da42df6 | 144 | unw_print_xyreg (char *cp, unsigned int x, unsigned int ytreg) |
4d6ed7c8 NC |
145 | { |
146 | switch ((x << 1) | ((ytreg >> 7) & 1)) | |
147 | { | |
148 | case 0: /* gr */ | |
149 | sprintf (cp, "r%u", (ytreg & 0x1f)); | |
150 | break; | |
151 | ||
152 | case 1: /* fr */ | |
153 | sprintf (cp, "f%u", (ytreg & 0x1f)); | |
154 | break; | |
155 | ||
156 | case 2: /* br */ | |
157 | sprintf (cp, "b%u", (ytreg & 0x1f)); | |
158 | break; | |
de8d4203 AM |
159 | |
160 | default: | |
161 | strcpy (cp, "invalid"); | |
162 | break; | |
4d6ed7c8 NC |
163 | } |
164 | } | |
165 | ||
166 | #define UNW_REG_BSP "bsp" | |
167 | #define UNW_REG_BSPSTORE "bspstore" | |
168 | #define UNW_REG_FPSR "fpsr" | |
169 | #define UNW_REG_LC "lc" | |
170 | #define UNW_REG_PFS "pfs" | |
171 | #define UNW_REG_PR "pr" | |
172 | #define UNW_REG_PSP "psp" | |
173 | #define UNW_REG_RNAT "rnat" | |
174 | #define UNW_REG_RP "rp" | |
175 | #define UNW_REG_UNAT "unat" | |
176 | ||
177 | typedef bfd_vma unw_word; | |
178 | ||
4d6ed7c8 | 179 | #define UNW_DEC_BAD_CODE(code) \ |
5cacf1c8 | 180 | printf (_("Unknown code 0x%02x\n"), code) |
4d6ed7c8 NC |
181 | |
182 | #define UNW_DEC_PROLOGUE(fmt, body, rlen, arg) \ | |
183 | do \ | |
184 | { \ | |
185 | unw_rlen = rlen; \ | |
186 | *(int *)arg = body; \ | |
3c44da9a MS |
187 | printf (" %s:%s(rlen=%lu)\n", \ |
188 | fmt, body ? "body" : "prologue", (unsigned long) rlen); \ | |
4d6ed7c8 NC |
189 | } \ |
190 | while (0) | |
191 | ||
192 | #define UNW_DEC_PROLOGUE_GR(fmt, rlen, mask, grsave, arg) \ | |
193 | do \ | |
194 | { \ | |
195 | char regname[16], maskstr[64], *sep; \ | |
196 | \ | |
197 | unw_rlen = rlen; \ | |
198 | *(int *)arg = 0; \ | |
199 | \ | |
200 | maskstr[0] = '\0'; \ | |
201 | sep = ""; \ | |
202 | if (mask & 0x8) \ | |
203 | { \ | |
204 | strcat (maskstr, "rp"); \ | |
205 | sep = ","; \ | |
206 | } \ | |
207 | if (mask & 0x4) \ | |
208 | { \ | |
209 | strcat (maskstr, sep); \ | |
210 | strcat (maskstr, "ar.pfs"); \ | |
211 | sep = ","; \ | |
212 | } \ | |
213 | if (mask & 0x2) \ | |
214 | { \ | |
215 | strcat (maskstr, sep); \ | |
216 | strcat (maskstr, "psp"); \ | |
217 | sep = ","; \ | |
218 | } \ | |
219 | if (mask & 0x1) \ | |
220 | { \ | |
221 | strcat (maskstr, sep); \ | |
222 | strcat (maskstr, "pr"); \ | |
223 | } \ | |
224 | sprintf (regname, "r%u", grsave); \ | |
3c44da9a MS |
225 | printf (" %s:prologue_gr(mask=[%s],grsave=%s,rlen=%lu)\n", \ |
226 | fmt, maskstr, regname, (unsigned long) rlen); \ | |
4d6ed7c8 NC |
227 | } \ |
228 | while (0) | |
229 | ||
230 | #define UNW_DEC_FR_MEM(fmt, frmask, arg) \ | |
231 | do \ | |
232 | { \ | |
233 | char frstr[200]; \ | |
234 | \ | |
235 | unw_print_frmask (frstr, frmask); \ | |
3c44da9a | 236 | printf ("\t%s:fr_mem(frmask=[%s])\n", fmt, frstr); \ |
4d6ed7c8 NC |
237 | } \ |
238 | while (0) | |
239 | ||
240 | #define UNW_DEC_GR_MEM(fmt, grmask, arg) \ | |
241 | do \ | |
242 | { \ | |
243 | char grstr[200]; \ | |
244 | \ | |
245 | unw_print_grmask (grstr, grmask); \ | |
3c44da9a | 246 | printf ("\t%s:gr_mem(grmask=[%s])\n", fmt, grstr); \ |
4d6ed7c8 NC |
247 | } \ |
248 | while (0) | |
249 | ||
2da42df6 | 250 | #define UNW_DEC_FRGR_MEM(fmt, grmask, frmask, arg) \ |
4d6ed7c8 | 251 | do \ |
2da42df6 | 252 | { \ |
4d6ed7c8 | 253 | char frstr[200], grstr[20]; \ |
2da42df6 AJ |
254 | \ |
255 | unw_print_grmask (grstr, grmask); \ | |
256 | unw_print_frmask (frstr, frmask); \ | |
3c44da9a | 257 | printf ("\t%s:frgr_mem(grmask=[%s],frmask=[%s])\n", fmt, grstr, frstr); \ |
4d6ed7c8 NC |
258 | } \ |
259 | while (0) | |
260 | ||
261 | #define UNW_DEC_BR_MEM(fmt, brmask, arg) \ | |
262 | do \ | |
263 | { \ | |
264 | char brstr[20]; \ | |
265 | \ | |
266 | unw_print_brmask (brstr, brmask); \ | |
3c44da9a | 267 | printf ("\t%s:br_mem(brmask=[%s])\n", fmt, brstr); \ |
4d6ed7c8 NC |
268 | } \ |
269 | while (0) | |
270 | ||
271 | #define UNW_DEC_BR_GR(fmt, brmask, gr, arg) \ | |
272 | do \ | |
273 | { \ | |
274 | char brstr[20]; \ | |
275 | \ | |
276 | unw_print_brmask (brstr, brmask); \ | |
3c44da9a | 277 | printf ("\t%s:br_gr(brmask=[%s],gr=r%u)\n", fmt, brstr, gr); \ |
4d6ed7c8 NC |
278 | } \ |
279 | while (0) | |
280 | ||
281 | #define UNW_DEC_REG_GR(fmt, src, dst, arg) \ | |
3c44da9a | 282 | printf ("\t%s:%s_gr(reg=r%u)\n", fmt, src, dst) |
4d6ed7c8 NC |
283 | |
284 | #define UNW_DEC_RP_BR(fmt, dst, arg) \ | |
3c44da9a | 285 | printf ("\t%s:rp_br(reg=b%u)\n", fmt, dst) |
4d6ed7c8 NC |
286 | |
287 | #define UNW_DEC_REG_WHEN(fmt, reg, t, arg) \ | |
3c44da9a | 288 | printf ("\t%s:%s_when(t=%lu)\n", fmt, reg, (unsigned long) t) |
4d6ed7c8 NC |
289 | |
290 | #define UNW_DEC_REG_SPREL(fmt, reg, spoff, arg) \ | |
3c44da9a MS |
291 | printf ("\t%s:%s_sprel(spoff=0x%lx)\n", \ |
292 | fmt, reg, 4*(unsigned long)spoff) | |
4d6ed7c8 NC |
293 | |
294 | #define UNW_DEC_REG_PSPREL(fmt, reg, pspoff, arg) \ | |
3c44da9a MS |
295 | printf ("\t%s:%s_psprel(pspoff=0x10-0x%lx)\n", \ |
296 | fmt, reg, 4*(unsigned long)pspoff) | |
4d6ed7c8 NC |
297 | |
298 | #define UNW_DEC_GR_GR(fmt, grmask, gr, arg) \ | |
299 | do \ | |
300 | { \ | |
301 | char grstr[20]; \ | |
302 | \ | |
303 | unw_print_grmask (grstr, grmask); \ | |
3c44da9a | 304 | printf ("\t%s:gr_gr(grmask=[%s],r%u)\n", fmt, grstr, gr); \ |
4d6ed7c8 NC |
305 | } \ |
306 | while (0) | |
307 | ||
308 | #define UNW_DEC_ABI(fmt, abi, context, arg) \ | |
309 | do \ | |
310 | { \ | |
9bcd0325 | 311 | static const char * const abiname[] = \ |
4d6ed7c8 NC |
312 | { \ |
313 | "@svr4", "@hpux", "@nt" \ | |
314 | }; \ | |
315 | char buf[20]; \ | |
316 | const char *abistr = buf; \ | |
317 | \ | |
318 | if (abi < 3) \ | |
319 | abistr = abiname[abi]; \ | |
320 | else \ | |
321 | sprintf (buf, "0x%x", abi); \ | |
3c44da9a MS |
322 | printf ("\t%s:unwabi(abi=%s,context=0x%02x)\n", \ |
323 | fmt, abistr, context); \ | |
4d6ed7c8 NC |
324 | } \ |
325 | while (0) | |
326 | ||
327 | #define UNW_DEC_PRIUNAT_GR(fmt, r, arg) \ | |
3c44da9a | 328 | printf ("\t%s:priunat_gr(reg=r%u)\n", fmt, r) |
4d6ed7c8 NC |
329 | |
330 | #define UNW_DEC_PRIUNAT_WHEN_GR(fmt, t, arg) \ | |
3c44da9a | 331 | printf ("\t%s:priunat_when_gr(t=%lu)\n", fmt, (unsigned long) t) |
4d6ed7c8 NC |
332 | |
333 | #define UNW_DEC_PRIUNAT_WHEN_MEM(fmt, t, arg) \ | |
3c44da9a | 334 | printf ("\t%s:priunat_when_mem(t=%lu)\n", fmt, (unsigned long) t) |
4d6ed7c8 NC |
335 | |
336 | #define UNW_DEC_PRIUNAT_PSPREL(fmt, pspoff, arg) \ | |
3c44da9a MS |
337 | printf ("\t%s:priunat_psprel(pspoff=0x10-0x%lx)\n", \ |
338 | fmt, 4*(unsigned long)pspoff) | |
4d6ed7c8 NC |
339 | |
340 | #define UNW_DEC_PRIUNAT_SPREL(fmt, spoff, arg) \ | |
3c44da9a MS |
341 | printf ("\t%s:priunat_sprel(spoff=0x%lx)\n", \ |
342 | fmt, 4*(unsigned long)spoff) | |
4d6ed7c8 NC |
343 | |
344 | #define UNW_DEC_MEM_STACK_F(fmt, t, size, arg) \ | |
3c44da9a MS |
345 | printf ("\t%s:mem_stack_f(t=%lu,size=%lu)\n", \ |
346 | fmt, (unsigned long) t, 16*(unsigned long)size) | |
4d6ed7c8 NC |
347 | |
348 | #define UNW_DEC_MEM_STACK_V(fmt, t, arg) \ | |
3c44da9a | 349 | printf ("\t%s:mem_stack_v(t=%lu)\n", fmt, (unsigned long) t) |
4d6ed7c8 NC |
350 | |
351 | #define UNW_DEC_SPILL_BASE(fmt, pspoff, arg) \ | |
3c44da9a MS |
352 | printf ("\t%s:spill_base(pspoff=0x10-0x%lx)\n", \ |
353 | fmt, 4*(unsigned long)pspoff) | |
4d6ed7c8 | 354 | |
b4477bc8 NC |
355 | #define UNW_DEC_SPILL_MASK(fmt, dp, arg, end) \ |
356 | do \ | |
357 | { \ | |
358 | static const char *spill_type = "-frb"; \ | |
2da42df6 | 359 | unsigned const char *imaskp = dp; \ |
b4477bc8 NC |
360 | unsigned char mask = 0; \ |
361 | bfd_vma insn = 0; \ | |
362 | \ | |
363 | /* PR 18420. */ \ | |
364 | if ((dp + (unw_rlen / 4)) > end) \ | |
365 | { \ | |
5cacf1c8 | 366 | printf (_("\nERROR: unwind length too long (0x%lx > 0x%lx)\n\n"), \ |
b4477bc8 NC |
367 | (long) (unw_rlen / 4), (long)(end - dp)); \ |
368 | /* FIXME: Should we reset unw_rlen ? */ \ | |
369 | break; \ | |
370 | } \ | |
3c44da9a | 371 | printf ("\t%s:spill_mask(imask=[", fmt); \ |
4d6ed7c8 NC |
372 | for (insn = 0; insn < unw_rlen; ++insn) \ |
373 | { \ | |
374 | if ((insn % 4) == 0) \ | |
375 | mask = *imaskp++; \ | |
376 | if (insn > 0 && (insn % 3) == 0) \ | |
377 | putchar (','); \ | |
378 | putchar (spill_type[(mask >> (2 * (3 - (insn & 0x3)))) & 0x3]); \ | |
379 | } \ | |
380 | printf ("])\n"); \ | |
381 | dp = imaskp; \ | |
382 | } \ | |
383 | while (0) | |
384 | ||
385 | #define UNW_DEC_SPILL_SPREL(fmt, t, abreg, spoff, arg) \ | |
386 | do \ | |
387 | { \ | |
09ff3500 | 388 | char regname[20]; \ |
4d6ed7c8 NC |
389 | \ |
390 | unw_print_abreg (regname, abreg); \ | |
3c44da9a MS |
391 | printf ("\t%s:spill_sprel(reg=%s,t=%lu,spoff=0x%lx)\n", \ |
392 | fmt, regname, (unsigned long) t, 4*(unsigned long)off); \ | |
4d6ed7c8 NC |
393 | } \ |
394 | while (0) | |
395 | ||
2da42df6 | 396 | #define UNW_DEC_SPILL_PSPREL(fmt, t, abreg, pspoff, arg) \ |
4d6ed7c8 | 397 | do \ |
2da42df6 | 398 | { \ |
09ff3500 | 399 | char regname[20]; \ |
2da42df6 AJ |
400 | \ |
401 | unw_print_abreg (regname, abreg); \ | |
402 | printf ("\t%s:spill_psprel(reg=%s,t=%lu,pspoff=0x10-0x%lx)\n", \ | |
3c44da9a | 403 | fmt, regname, (unsigned long) t, 4*(unsigned long)pspoff); \ |
4d6ed7c8 NC |
404 | } \ |
405 | while (0) | |
406 | ||
407 | #define UNW_DEC_RESTORE(fmt, t, abreg, arg) \ | |
408 | do \ | |
409 | { \ | |
09ff3500 | 410 | char regname[20]; \ |
4d6ed7c8 NC |
411 | \ |
412 | unw_print_abreg (regname, abreg); \ | |
3c44da9a MS |
413 | printf ("\t%s:restore(t=%lu,reg=%s)\n", \ |
414 | fmt, (unsigned long) t, regname); \ | |
4d6ed7c8 NC |
415 | } \ |
416 | while (0) | |
417 | ||
418 | #define UNW_DEC_SPILL_REG(fmt, t, abreg, x, ytreg, arg) \ | |
419 | do \ | |
420 | { \ | |
09ff3500 | 421 | char abregname[20], tregname[20]; \ |
4d6ed7c8 NC |
422 | \ |
423 | unw_print_abreg (abregname, abreg); \ | |
424 | unw_print_xyreg (tregname, x, ytreg); \ | |
3c44da9a MS |
425 | printf ("\t%s:spill_reg(t=%lu,reg=%s,treg=%s)\n", \ |
426 | fmt, (unsigned long) t, abregname, tregname); \ | |
4d6ed7c8 NC |
427 | } \ |
428 | while (0) | |
429 | ||
2da42df6 | 430 | #define UNW_DEC_SPILL_SPREL_P(fmt, qp, t, abreg, spoff, arg) \ |
4d6ed7c8 | 431 | do \ |
2da42df6 AJ |
432 | { \ |
433 | char regname[20]; \ | |
434 | \ | |
435 | unw_print_abreg (regname, abreg); \ | |
3c44da9a MS |
436 | printf ("\t%s:spill_sprel_p(qp=p%u,t=%lu,reg=%s,spoff=0x%lx)\n", \ |
437 | fmt, qp, (unsigned long) t, regname, 4 * (unsigned long)spoff); \ | |
4d6ed7c8 NC |
438 | } \ |
439 | while (0) | |
440 | ||
441 | #define UNW_DEC_SPILL_PSPREL_P(fmt, qp, t, abreg, pspoff, arg) \ | |
442 | do \ | |
443 | { \ | |
444 | char regname[20]; \ | |
445 | \ | |
446 | unw_print_abreg (regname, abreg); \ | |
3c44da9a MS |
447 | printf ("\t%s:spill_psprel_p(qp=p%u,t=%lu,reg=%s,pspoff=0x10-0x%lx)\n",\ |
448 | fmt, qp, (unsigned long) t, regname, 4*(unsigned long)pspoff);\ | |
4d6ed7c8 NC |
449 | } \ |
450 | while (0) | |
451 | ||
452 | #define UNW_DEC_RESTORE_P(fmt, qp, t, abreg, arg) \ | |
453 | do \ | |
454 | { \ | |
455 | char regname[20]; \ | |
456 | \ | |
457 | unw_print_abreg (regname, abreg); \ | |
3c44da9a MS |
458 | printf ("\t%s:restore_p(qp=p%u,t=%lu,reg=%s)\n", \ |
459 | fmt, qp, (unsigned long) t, regname); \ | |
4d6ed7c8 NC |
460 | } \ |
461 | while (0) | |
462 | ||
463 | #define UNW_DEC_SPILL_REG_P(fmt, qp, t, abreg, x, ytreg, arg) \ | |
464 | do \ | |
465 | { \ | |
466 | char regname[20], tregname[20]; \ | |
467 | \ | |
468 | unw_print_abreg (regname, abreg); \ | |
469 | unw_print_xyreg (tregname, x, ytreg); \ | |
3c44da9a MS |
470 | printf ("\t%s:spill_reg_p(qp=p%u,t=%lu,reg=%s,treg=%s)\n", \ |
471 | fmt, qp, (unsigned long) t, regname, tregname); \ | |
4d6ed7c8 NC |
472 | } \ |
473 | while (0) | |
474 | ||
475 | #define UNW_DEC_LABEL_STATE(fmt, label, arg) \ | |
3c44da9a | 476 | printf ("\t%s:label_state(label=%lu)\n", fmt, (unsigned long) label) |
4d6ed7c8 NC |
477 | |
478 | #define UNW_DEC_COPY_STATE(fmt, label, arg) \ | |
3c44da9a | 479 | printf ("\t%s:copy_state(label=%lu)\n", fmt, (unsigned long) label) |
4d6ed7c8 NC |
480 | |
481 | #define UNW_DEC_EPILOGUE(fmt, t, ecount, arg) \ | |
3c44da9a MS |
482 | printf ("\t%s:epilogue(t=%lu,ecount=%lu)\n", \ |
483 | fmt, (unsigned long) t, (unsigned long) ecount) | |
4d6ed7c8 NC |
484 | |
485 | /* | |
486 | * Generic IA-64 unwind info decoder. | |
487 | * | |
488 | * This file is used both by the Linux kernel and objdump. Please | |
489 | * keep the two copies of this file in sync (modulo differences in the | |
490 | * prototypes...). | |
491 | * | |
492 | * You need to customize the decoder by defining the following | |
493 | * macros/constants before including this file: | |
494 | * | |
495 | * Types: | |
9f66665a | 496 | * unw_word Unsigned integer type with at least 64 bits |
4d6ed7c8 NC |
497 | * |
498 | * Register names: | |
499 | * UNW_REG_BSP | |
500 | * UNW_REG_BSPSTORE | |
501 | * UNW_REG_FPSR | |
502 | * UNW_REG_LC | |
503 | * UNW_REG_PFS | |
504 | * UNW_REG_PR | |
505 | * UNW_REG_RNAT | |
506 | * UNW_REG_PSP | |
507 | * UNW_REG_RP | |
508 | * UNW_REG_UNAT | |
509 | * | |
510 | * Decoder action macros: | |
511 | * UNW_DEC_BAD_CODE(code) | |
512 | * UNW_DEC_ABI(fmt,abi,context,arg) | |
513 | * UNW_DEC_BR_GR(fmt,brmask,gr,arg) | |
514 | * UNW_DEC_BR_MEM(fmt,brmask,arg) | |
515 | * UNW_DEC_COPY_STATE(fmt,label,arg) | |
516 | * UNW_DEC_EPILOGUE(fmt,t,ecount,arg) | |
517 | * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg) | |
518 | * UNW_DEC_FR_MEM(fmt,frmask,arg) | |
519 | * UNW_DEC_GR_GR(fmt,grmask,gr,arg) | |
520 | * UNW_DEC_GR_MEM(fmt,grmask,arg) | |
521 | * UNW_DEC_LABEL_STATE(fmt,label,arg) | |
522 | * UNW_DEC_MEM_STACK_F(fmt,t,size,arg) | |
523 | * UNW_DEC_MEM_STACK_V(fmt,t,arg) | |
524 | * UNW_DEC_PRIUNAT_GR(fmt,r,arg) | |
525 | * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) | |
526 | * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) | |
527 | * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg) | |
528 | * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg) | |
529 | * UNW_DEC_PROLOGUE(fmt,body,rlen,arg) | |
530 | * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg) | |
531 | * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg) | |
532 | * UNW_DEC_REG_REG(fmt,src,dst,arg) | |
533 | * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg) | |
534 | * UNW_DEC_REG_WHEN(fmt,reg,t,arg) | |
535 | * UNW_DEC_RESTORE(fmt,t,abreg,arg) | |
536 | * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg) | |
537 | * UNW_DEC_SPILL_BASE(fmt,pspoff,arg) | |
538 | * UNW_DEC_SPILL_MASK(fmt,imaskp,arg) | |
539 | * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg) | |
540 | * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg) | |
541 | * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg) | |
542 | * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg) | |
543 | * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg) | |
544 | * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg) | |
545 | */ | |
546 | ||
4d6ed7c8 | 547 | static unw_word |
171375c6 | 548 | unw_decode_uleb128 (const unsigned char **dpp, const unsigned char * end) |
4d6ed7c8 NC |
549 | { |
550 | unsigned shift = 0; | |
60e63c3e | 551 | int status = 1; |
4d6ed7c8 NC |
552 | unw_word byte, result = 0; |
553 | const unsigned char *bp = *dpp; | |
554 | ||
171375c6 | 555 | while (bp < end) |
4d6ed7c8 NC |
556 | { |
557 | byte = *bp++; | |
60e63c3e AM |
558 | if (shift < sizeof (result) * 8) |
559 | { | |
560 | result |= (byte & 0x7f) << shift; | |
561 | if ((result >> shift) != (byte & 0x7f)) | |
562 | /* Overflow. */ | |
563 | status |= 2; | |
564 | shift += 7; | |
565 | } | |
566 | else if ((byte & 0x7f) != 0) | |
567 | status |= 2; | |
4d6ed7c8 NC |
568 | |
569 | if ((byte & 0x80) == 0) | |
60e63c3e AM |
570 | { |
571 | status &= ~1; | |
572 | break; | |
573 | } | |
4d6ed7c8 NC |
574 | } |
575 | ||
576 | *dpp = bp; | |
60e63c3e AM |
577 | if (status != 0) |
578 | printf (_("Bad uleb128\n")); | |
4d6ed7c8 NC |
579 | |
580 | return result; | |
581 | } | |
582 | ||
583 | static const unsigned char * | |
2da42df6 | 584 | unw_decode_x1 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED, |
171375c6 | 585 | void *arg ATTRIBUTE_UNUSED, const unsigned char * end) |
4d6ed7c8 NC |
586 | { |
587 | unsigned char byte1, abreg; | |
588 | unw_word t, off; | |
589 | ||
5cacf1c8 NC |
590 | if ((end - dp) < 3) |
591 | { | |
592 | printf (_("\t<corrupt X1>\n")); | |
593 | return end; | |
594 | } | |
595 | ||
4d6ed7c8 | 596 | byte1 = *dp++; |
171375c6 NC |
597 | t = unw_decode_uleb128 (&dp, end); |
598 | off = unw_decode_uleb128 (&dp, end); | |
4d6ed7c8 NC |
599 | abreg = (byte1 & 0x7f); |
600 | if (byte1 & 0x80) | |
3c44da9a | 601 | UNW_DEC_SPILL_SPREL ("X1", t, abreg, off, arg); |
4d6ed7c8 | 602 | else |
3c44da9a | 603 | UNW_DEC_SPILL_PSPREL ("X1", t, abreg, off, arg); |
4d6ed7c8 NC |
604 | return dp; |
605 | } | |
606 | ||
607 | static const unsigned char * | |
2da42df6 | 608 | unw_decode_x2 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED, |
171375c6 | 609 | void *arg ATTRIBUTE_UNUSED, const unsigned char * end) |
4d6ed7c8 NC |
610 | { |
611 | unsigned char byte1, byte2, abreg, x, ytreg; | |
612 | unw_word t; | |
613 | ||
5cacf1c8 NC |
614 | if ((end - dp) < 3) |
615 | { | |
616 | printf (_("\t<corrupt X2>\n")); | |
617 | return end; | |
618 | } | |
619 | ||
4d6ed7c8 NC |
620 | byte1 = *dp++; |
621 | byte2 = *dp++; | |
171375c6 | 622 | t = unw_decode_uleb128 (&dp, end); |
4d6ed7c8 NC |
623 | abreg = (byte1 & 0x7f); |
624 | ytreg = byte2; | |
625 | x = (byte1 >> 7) & 1; | |
626 | if ((byte1 & 0x80) == 0 && ytreg == 0) | |
3c44da9a | 627 | UNW_DEC_RESTORE ("X2", t, abreg, arg); |
4d6ed7c8 | 628 | else |
3c44da9a | 629 | UNW_DEC_SPILL_REG ("X2", t, abreg, x, ytreg, arg); |
4d6ed7c8 NC |
630 | return dp; |
631 | } | |
632 | ||
633 | static const unsigned char * | |
2da42df6 | 634 | unw_decode_x3 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED, |
171375c6 | 635 | void *arg ATTRIBUTE_UNUSED, const unsigned char * end) |
4d6ed7c8 NC |
636 | { |
637 | unsigned char byte1, byte2, abreg, qp; | |
638 | unw_word t, off; | |
639 | ||
5cacf1c8 NC |
640 | if ((end - dp) < 4) |
641 | { | |
642 | printf (_("\t<corrupt X3>\n")); | |
643 | return end; | |
644 | } | |
645 | ||
4d6ed7c8 NC |
646 | byte1 = *dp++; |
647 | byte2 = *dp++; | |
171375c6 NC |
648 | t = unw_decode_uleb128 (&dp, end); |
649 | off = unw_decode_uleb128 (&dp, end); | |
4d6ed7c8 NC |
650 | |
651 | qp = (byte1 & 0x3f); | |
652 | abreg = (byte2 & 0x7f); | |
653 | ||
654 | if (byte1 & 0x80) | |
3c44da9a | 655 | UNW_DEC_SPILL_SPREL_P ("X3", qp, t, abreg, off, arg); |
4d6ed7c8 | 656 | else |
3c44da9a | 657 | UNW_DEC_SPILL_PSPREL_P ("X3", qp, t, abreg, off, arg); |
4d6ed7c8 NC |
658 | return dp; |
659 | } | |
660 | ||
661 | static const unsigned char * | |
2da42df6 | 662 | unw_decode_x4 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED, |
171375c6 | 663 | void *arg ATTRIBUTE_UNUSED, const unsigned char * end) |
4d6ed7c8 NC |
664 | { |
665 | unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg; | |
666 | unw_word t; | |
667 | ||
5cacf1c8 NC |
668 | if ((end - dp) < 4) |
669 | { | |
670 | printf (_("\t<corrupt X4>\n")); | |
671 | return end; | |
672 | } | |
673 | ||
4d6ed7c8 NC |
674 | byte1 = *dp++; |
675 | byte2 = *dp++; | |
676 | byte3 = *dp++; | |
171375c6 | 677 | t = unw_decode_uleb128 (&dp, end); |
4d6ed7c8 NC |
678 | |
679 | qp = (byte1 & 0x3f); | |
680 | abreg = (byte2 & 0x7f); | |
681 | x = (byte2 >> 7) & 1; | |
682 | ytreg = byte3; | |
683 | ||
684 | if ((byte2 & 0x80) == 0 && byte3 == 0) | |
3c44da9a | 685 | UNW_DEC_RESTORE_P ("X4", qp, t, abreg, arg); |
4d6ed7c8 | 686 | else |
3c44da9a | 687 | UNW_DEC_SPILL_REG_P ("X4", qp, t, abreg, x, ytreg, arg); |
4d6ed7c8 NC |
688 | return dp; |
689 | } | |
690 | ||
691 | static const unsigned char * | |
b4477bc8 NC |
692 | unw_decode_r1 (const unsigned char *dp, unsigned int code, void *arg, |
693 | const unsigned char * end ATTRIBUTE_UNUSED) | |
4d6ed7c8 NC |
694 | { |
695 | int body = (code & 0x20) != 0; | |
696 | unw_word rlen; | |
697 | ||
698 | rlen = (code & 0x1f); | |
3c44da9a | 699 | UNW_DEC_PROLOGUE ("R1", body, rlen, arg); |
4d6ed7c8 NC |
700 | return dp; |
701 | } | |
702 | ||
703 | static const unsigned char * | |
b4477bc8 | 704 | unw_decode_r2 (const unsigned char *dp, unsigned int code, void *arg, |
171375c6 | 705 | const unsigned char * end) |
4d6ed7c8 NC |
706 | { |
707 | unsigned char byte1, mask, grsave; | |
708 | unw_word rlen; | |
709 | ||
5cacf1c8 NC |
710 | if ((end - dp) < 2) |
711 | { | |
712 | printf (_("\t<corrupt R2>\n")); | |
713 | return end; | |
714 | } | |
715 | ||
4d6ed7c8 NC |
716 | byte1 = *dp++; |
717 | ||
718 | mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); | |
719 | grsave = (byte1 & 0x7f); | |
171375c6 | 720 | rlen = unw_decode_uleb128 (& dp, end); |
3c44da9a | 721 | UNW_DEC_PROLOGUE_GR ("R2", rlen, mask, grsave, arg); |
4d6ed7c8 NC |
722 | return dp; |
723 | } | |
724 | ||
725 | static const unsigned char * | |
b4477bc8 | 726 | unw_decode_r3 (const unsigned char *dp, unsigned int code, void *arg, |
171375c6 | 727 | const unsigned char * end) |
4d6ed7c8 NC |
728 | { |
729 | unw_word rlen; | |
730 | ||
171375c6 | 731 | rlen = unw_decode_uleb128 (& dp, end); |
3c44da9a | 732 | UNW_DEC_PROLOGUE ("R3", ((code & 0x3) == 1), rlen, arg); |
4d6ed7c8 NC |
733 | return dp; |
734 | } | |
735 | ||
736 | static const unsigned char * | |
2da42df6 | 737 | unw_decode_p1 (const unsigned char *dp, unsigned int code, |
b4477bc8 NC |
738 | void *arg ATTRIBUTE_UNUSED, |
739 | const unsigned char * end ATTRIBUTE_UNUSED) | |
4d6ed7c8 NC |
740 | { |
741 | unsigned char brmask = (code & 0x1f); | |
742 | ||
3c44da9a | 743 | UNW_DEC_BR_MEM ("P1", brmask, arg); |
4d6ed7c8 NC |
744 | return dp; |
745 | } | |
746 | ||
747 | static const unsigned char * | |
2da42df6 | 748 | unw_decode_p2_p5 (const unsigned char *dp, unsigned int code, |
b4477bc8 NC |
749 | void *arg ATTRIBUTE_UNUSED, |
750 | const unsigned char * end) | |
4d6ed7c8 NC |
751 | { |
752 | if ((code & 0x10) == 0) | |
753 | { | |
5cacf1c8 NC |
754 | unsigned char byte1; |
755 | ||
756 | if ((end - dp) < 1) | |
757 | { | |
758 | printf (_("\t<corrupt P2>\n")); | |
759 | return end; | |
760 | } | |
761 | ||
762 | byte1 = *dp++; | |
4d6ed7c8 | 763 | |
3c44da9a | 764 | UNW_DEC_BR_GR ("P2", ((code & 0xf) << 1) | ((byte1 >> 7) & 1), |
4d6ed7c8 NC |
765 | (byte1 & 0x7f), arg); |
766 | } | |
767 | else if ((code & 0x08) == 0) | |
768 | { | |
5cacf1c8 NC |
769 | unsigned char byte1, r, dst; |
770 | ||
771 | if ((end - dp) < 1) | |
772 | { | |
773 | printf (_("\t<corrupt P3>\n")); | |
774 | return end; | |
775 | } | |
776 | ||
777 | byte1 = *dp++; | |
4d6ed7c8 NC |
778 | |
779 | r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); | |
780 | dst = (byte1 & 0x7f); | |
781 | switch (r) | |
782 | { | |
783 | case 0: | |
3c44da9a | 784 | UNW_DEC_REG_GR ("P3", UNW_REG_PSP, dst, arg); |
4d6ed7c8 NC |
785 | break; |
786 | case 1: | |
3c44da9a | 787 | UNW_DEC_REG_GR ("P3", UNW_REG_RP, dst, arg); |
4d6ed7c8 NC |
788 | break; |
789 | case 2: | |
3c44da9a | 790 | UNW_DEC_REG_GR ("P3", UNW_REG_PFS, dst, arg); |
4d6ed7c8 NC |
791 | break; |
792 | case 3: | |
3c44da9a | 793 | UNW_DEC_REG_GR ("P3", UNW_REG_PR, dst, arg); |
4d6ed7c8 NC |
794 | break; |
795 | case 4: | |
3c44da9a | 796 | UNW_DEC_REG_GR ("P3", UNW_REG_UNAT, dst, arg); |
4d6ed7c8 NC |
797 | break; |
798 | case 5: | |
3c44da9a | 799 | UNW_DEC_REG_GR ("P3", UNW_REG_LC, dst, arg); |
4d6ed7c8 NC |
800 | break; |
801 | case 6: | |
3c44da9a | 802 | UNW_DEC_RP_BR ("P3", dst, arg); |
4d6ed7c8 NC |
803 | break; |
804 | case 7: | |
3c44da9a | 805 | UNW_DEC_REG_GR ("P3", UNW_REG_RNAT, dst, arg); |
4d6ed7c8 NC |
806 | break; |
807 | case 8: | |
3c44da9a | 808 | UNW_DEC_REG_GR ("P3", UNW_REG_BSP, dst, arg); |
4d6ed7c8 NC |
809 | break; |
810 | case 9: | |
3c44da9a | 811 | UNW_DEC_REG_GR ("P3", UNW_REG_BSPSTORE, dst, arg); |
4d6ed7c8 NC |
812 | break; |
813 | case 10: | |
3c44da9a | 814 | UNW_DEC_REG_GR ("P3", UNW_REG_FPSR, dst, arg); |
4d6ed7c8 NC |
815 | break; |
816 | case 11: | |
3c44da9a | 817 | UNW_DEC_PRIUNAT_GR ("P3", dst, arg); |
4d6ed7c8 NC |
818 | break; |
819 | default: | |
820 | UNW_DEC_BAD_CODE (r); | |
821 | break; | |
822 | } | |
823 | } | |
824 | else if ((code & 0x7) == 0) | |
b4477bc8 | 825 | UNW_DEC_SPILL_MASK ("P4", dp, arg, end); |
4d6ed7c8 NC |
826 | else if ((code & 0x7) == 1) |
827 | { | |
828 | unw_word grmask, frmask, byte1, byte2, byte3; | |
829 | ||
5cacf1c8 NC |
830 | if ((end - dp) < 3) |
831 | { | |
832 | printf (_("\t<corrupt P5>\n")); | |
833 | return end; | |
834 | } | |
4d6ed7c8 NC |
835 | byte1 = *dp++; |
836 | byte2 = *dp++; | |
837 | byte3 = *dp++; | |
838 | grmask = ((byte1 >> 4) & 0xf); | |
839 | frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3; | |
3c44da9a | 840 | UNW_DEC_FRGR_MEM ("P5", grmask, frmask, arg); |
4d6ed7c8 NC |
841 | } |
842 | else | |
843 | UNW_DEC_BAD_CODE (code); | |
844 | ||
845 | return dp; | |
846 | } | |
847 | ||
848 | static const unsigned char * | |
2da42df6 | 849 | unw_decode_p6 (const unsigned char *dp, unsigned int code, |
b4477bc8 NC |
850 | void *arg ATTRIBUTE_UNUSED, |
851 | const unsigned char * end ATTRIBUTE_UNUSED) | |
4d6ed7c8 NC |
852 | { |
853 | int gregs = (code & 0x10) != 0; | |
854 | unsigned char mask = (code & 0x0f); | |
855 | ||
856 | if (gregs) | |
3c44da9a | 857 | UNW_DEC_GR_MEM ("P6", mask, arg); |
4d6ed7c8 | 858 | else |
3c44da9a | 859 | UNW_DEC_FR_MEM ("P6", mask, arg); |
4d6ed7c8 NC |
860 | return dp; |
861 | } | |
862 | ||
863 | static const unsigned char * | |
b4477bc8 | 864 | unw_decode_p7_p10 (const unsigned char *dp, unsigned int code, void *arg, |
171375c6 | 865 | const unsigned char * end) |
4d6ed7c8 NC |
866 | { |
867 | unsigned char r, byte1, byte2; | |
868 | unw_word t, size; | |
869 | ||
870 | if ((code & 0x10) == 0) | |
871 | { | |
872 | r = (code & 0xf); | |
171375c6 | 873 | t = unw_decode_uleb128 (&dp, end); |
4d6ed7c8 NC |
874 | switch (r) |
875 | { | |
876 | case 0: | |
171375c6 | 877 | size = unw_decode_uleb128 (&dp, end); |
3c44da9a | 878 | UNW_DEC_MEM_STACK_F ("P7", t, size, arg); |
4d6ed7c8 NC |
879 | break; |
880 | ||
881 | case 1: | |
3c44da9a | 882 | UNW_DEC_MEM_STACK_V ("P7", t, arg); |
4d6ed7c8 NC |
883 | break; |
884 | case 2: | |
3c44da9a | 885 | UNW_DEC_SPILL_BASE ("P7", t, arg); |
4d6ed7c8 NC |
886 | break; |
887 | case 3: | |
3c44da9a | 888 | UNW_DEC_REG_SPREL ("P7", UNW_REG_PSP, t, arg); |
4d6ed7c8 NC |
889 | break; |
890 | case 4: | |
3c44da9a | 891 | UNW_DEC_REG_WHEN ("P7", UNW_REG_RP, t, arg); |
4d6ed7c8 NC |
892 | break; |
893 | case 5: | |
3c44da9a | 894 | UNW_DEC_REG_PSPREL ("P7", UNW_REG_RP, t, arg); |
4d6ed7c8 NC |
895 | break; |
896 | case 6: | |
3c44da9a | 897 | UNW_DEC_REG_WHEN ("P7", UNW_REG_PFS, t, arg); |
4d6ed7c8 NC |
898 | break; |
899 | case 7: | |
3c44da9a | 900 | UNW_DEC_REG_PSPREL ("P7", UNW_REG_PFS, t, arg); |
4d6ed7c8 NC |
901 | break; |
902 | case 8: | |
3c44da9a | 903 | UNW_DEC_REG_WHEN ("P7", UNW_REG_PR, t, arg); |
4d6ed7c8 NC |
904 | break; |
905 | case 9: | |
3c44da9a | 906 | UNW_DEC_REG_PSPREL ("P7", UNW_REG_PR, t, arg); |
4d6ed7c8 NC |
907 | break; |
908 | case 10: | |
3c44da9a | 909 | UNW_DEC_REG_WHEN ("P7", UNW_REG_LC, t, arg); |
4d6ed7c8 NC |
910 | break; |
911 | case 11: | |
3c44da9a | 912 | UNW_DEC_REG_PSPREL ("P7", UNW_REG_LC, t, arg); |
4d6ed7c8 NC |
913 | break; |
914 | case 12: | |
3c44da9a | 915 | UNW_DEC_REG_WHEN ("P7", UNW_REG_UNAT, t, arg); |
4d6ed7c8 NC |
916 | break; |
917 | case 13: | |
3c44da9a | 918 | UNW_DEC_REG_PSPREL ("P7", UNW_REG_UNAT, t, arg); |
4d6ed7c8 NC |
919 | break; |
920 | case 14: | |
3c44da9a | 921 | UNW_DEC_REG_WHEN ("P7", UNW_REG_FPSR, t, arg); |
4d6ed7c8 NC |
922 | break; |
923 | case 15: | |
3c44da9a | 924 | UNW_DEC_REG_PSPREL ("P7", UNW_REG_FPSR, t, arg); |
4d6ed7c8 NC |
925 | break; |
926 | default: | |
927 | UNW_DEC_BAD_CODE (r); | |
928 | break; | |
929 | } | |
930 | } | |
931 | else | |
932 | { | |
933 | switch (code & 0xf) | |
934 | { | |
935 | case 0x0: /* p8 */ | |
936 | { | |
5cacf1c8 NC |
937 | if ((end - dp) < 2) |
938 | { | |
939 | printf (_("\t<corrupt P8>\n")); | |
940 | return end; | |
941 | } | |
942 | ||
4d6ed7c8 | 943 | r = *dp++; |
171375c6 | 944 | t = unw_decode_uleb128 (&dp, end); |
4d6ed7c8 NC |
945 | switch (r) |
946 | { | |
947 | case 1: | |
3c44da9a | 948 | UNW_DEC_REG_SPREL ("P8", UNW_REG_RP, t, arg); |
4d6ed7c8 NC |
949 | break; |
950 | case 2: | |
3c44da9a | 951 | UNW_DEC_REG_SPREL ("P8", UNW_REG_PFS, t, arg); |
4d6ed7c8 NC |
952 | break; |
953 | case 3: | |
3c44da9a | 954 | UNW_DEC_REG_SPREL ("P8", UNW_REG_PR, t, arg); |
4d6ed7c8 NC |
955 | break; |
956 | case 4: | |
3c44da9a | 957 | UNW_DEC_REG_SPREL ("P8", UNW_REG_LC, t, arg); |
4d6ed7c8 NC |
958 | break; |
959 | case 5: | |
3c44da9a | 960 | UNW_DEC_REG_SPREL ("P8", UNW_REG_UNAT, t, arg); |
4d6ed7c8 NC |
961 | break; |
962 | case 6: | |
3c44da9a | 963 | UNW_DEC_REG_SPREL ("P8", UNW_REG_FPSR, t, arg); |
4d6ed7c8 NC |
964 | break; |
965 | case 7: | |
3c44da9a | 966 | UNW_DEC_REG_WHEN ("P8", UNW_REG_BSP, t, arg); |
4d6ed7c8 NC |
967 | break; |
968 | case 8: | |
3c44da9a | 969 | UNW_DEC_REG_PSPREL ("P8", UNW_REG_BSP, t, arg); |
4d6ed7c8 NC |
970 | break; |
971 | case 9: | |
3c44da9a | 972 | UNW_DEC_REG_SPREL ("P8", UNW_REG_BSP, t, arg); |
4d6ed7c8 NC |
973 | break; |
974 | case 10: | |
3c44da9a | 975 | UNW_DEC_REG_WHEN ("P8", UNW_REG_BSPSTORE, t, arg); |
4d6ed7c8 NC |
976 | break; |
977 | case 11: | |
3c44da9a | 978 | UNW_DEC_REG_PSPREL ("P8", UNW_REG_BSPSTORE, t, arg); |
4d6ed7c8 NC |
979 | break; |
980 | case 12: | |
3c44da9a | 981 | UNW_DEC_REG_SPREL ("P8", UNW_REG_BSPSTORE, t, arg); |
4d6ed7c8 NC |
982 | break; |
983 | case 13: | |
3c44da9a | 984 | UNW_DEC_REG_WHEN ("P8", UNW_REG_RNAT, t, arg); |
4d6ed7c8 NC |
985 | break; |
986 | case 14: | |
3c44da9a | 987 | UNW_DEC_REG_PSPREL ("P8", UNW_REG_RNAT, t, arg); |
4d6ed7c8 NC |
988 | break; |
989 | case 15: | |
3c44da9a | 990 | UNW_DEC_REG_SPREL ("P8", UNW_REG_RNAT, t, arg); |
4d6ed7c8 NC |
991 | break; |
992 | case 16: | |
3c44da9a | 993 | UNW_DEC_PRIUNAT_WHEN_GR ("P8", t, arg); |
4d6ed7c8 NC |
994 | break; |
995 | case 17: | |
3c44da9a | 996 | UNW_DEC_PRIUNAT_PSPREL ("P8", t, arg); |
4d6ed7c8 NC |
997 | break; |
998 | case 18: | |
3c44da9a | 999 | UNW_DEC_PRIUNAT_SPREL ("P8", t, arg); |
4d6ed7c8 NC |
1000 | break; |
1001 | case 19: | |
3c44da9a | 1002 | UNW_DEC_PRIUNAT_WHEN_MEM ("P8", t, arg); |
4d6ed7c8 NC |
1003 | break; |
1004 | default: | |
1005 | UNW_DEC_BAD_CODE (r); | |
1006 | break; | |
1007 | } | |
1008 | } | |
1009 | break; | |
1010 | ||
1011 | case 0x1: | |
5cacf1c8 NC |
1012 | if ((end - dp) < 2) |
1013 | { | |
1014 | printf (_("\t<corrupt P9>\n")); | |
1015 | return end; | |
1016 | } | |
1017 | ||
4d6ed7c8 NC |
1018 | byte1 = *dp++; |
1019 | byte2 = *dp++; | |
3c44da9a | 1020 | UNW_DEC_GR_GR ("P9", (byte1 & 0xf), (byte2 & 0x7f), arg); |
4d6ed7c8 NC |
1021 | break; |
1022 | ||
1023 | case 0xf: /* p10 */ | |
5cacf1c8 NC |
1024 | if ((end - dp) < 2) |
1025 | { | |
1026 | printf (_("\t<corrupt P10>\n")); | |
1027 | return end; | |
1028 | } | |
1029 | ||
4d6ed7c8 NC |
1030 | byte1 = *dp++; |
1031 | byte2 = *dp++; | |
3c44da9a | 1032 | UNW_DEC_ABI ("P10", byte1, byte2, arg); |
4d6ed7c8 NC |
1033 | break; |
1034 | ||
1035 | case 0x9: | |
171375c6 | 1036 | return unw_decode_x1 (dp, code, arg, end); |
4d6ed7c8 NC |
1037 | |
1038 | case 0xa: | |
171375c6 | 1039 | return unw_decode_x2 (dp, code, arg, end); |
4d6ed7c8 NC |
1040 | |
1041 | case 0xb: | |
171375c6 | 1042 | return unw_decode_x3 (dp, code, arg, end); |
4d6ed7c8 NC |
1043 | |
1044 | case 0xc: | |
171375c6 | 1045 | return unw_decode_x4 (dp, code, arg, end); |
4d6ed7c8 NC |
1046 | |
1047 | default: | |
1048 | UNW_DEC_BAD_CODE (code); | |
1049 | break; | |
1050 | } | |
1051 | } | |
1052 | return dp; | |
1053 | } | |
1054 | ||
1055 | static const unsigned char * | |
2da42df6 | 1056 | unw_decode_b1 (const unsigned char *dp, unsigned int code, |
b4477bc8 NC |
1057 | void *arg ATTRIBUTE_UNUSED, |
1058 | const unsigned char * end ATTRIBUTE_UNUSED) | |
4d6ed7c8 NC |
1059 | { |
1060 | unw_word label = (code & 0x1f); | |
1061 | ||
1062 | if ((code & 0x20) != 0) | |
3c44da9a | 1063 | UNW_DEC_COPY_STATE ("B1", label, arg); |
4d6ed7c8 | 1064 | else |
3c44da9a | 1065 | UNW_DEC_LABEL_STATE ("B1", label, arg); |
4d6ed7c8 NC |
1066 | return dp; |
1067 | } | |
1068 | ||
1069 | static const unsigned char * | |
2da42df6 | 1070 | unw_decode_b2 (const unsigned char *dp, unsigned int code, |
b4477bc8 | 1071 | void *arg ATTRIBUTE_UNUSED, |
171375c6 | 1072 | const unsigned char * end) |
4d6ed7c8 NC |
1073 | { |
1074 | unw_word t; | |
1075 | ||
171375c6 | 1076 | t = unw_decode_uleb128 (& dp, end); |
3c44da9a | 1077 | UNW_DEC_EPILOGUE ("B2", t, (code & 0x1f), arg); |
4d6ed7c8 NC |
1078 | return dp; |
1079 | } | |
1080 | ||
1081 | static const unsigned char * | |
b4477bc8 | 1082 | unw_decode_b3_x4 (const unsigned char *dp, unsigned int code, void *arg, |
171375c6 | 1083 | const unsigned char * end) |
4d6ed7c8 NC |
1084 | { |
1085 | unw_word t, ecount, label; | |
1086 | ||
1087 | if ((code & 0x10) == 0) | |
1088 | { | |
171375c6 NC |
1089 | t = unw_decode_uleb128 (&dp, end); |
1090 | ecount = unw_decode_uleb128 (&dp, end); | |
3c44da9a | 1091 | UNW_DEC_EPILOGUE ("B3", t, ecount, arg); |
4d6ed7c8 NC |
1092 | } |
1093 | else if ((code & 0x07) == 0) | |
1094 | { | |
171375c6 | 1095 | label = unw_decode_uleb128 (&dp, end); |
4d6ed7c8 | 1096 | if ((code & 0x08) != 0) |
3c44da9a | 1097 | UNW_DEC_COPY_STATE ("B4", label, arg); |
4d6ed7c8 | 1098 | else |
3c44da9a | 1099 | UNW_DEC_LABEL_STATE ("B4", label, arg); |
4d6ed7c8 NC |
1100 | } |
1101 | else | |
1102 | switch (code & 0x7) | |
1103 | { | |
1104 | case 1: | |
171375c6 | 1105 | return unw_decode_x1 (dp, code, arg, end); |
4d6ed7c8 | 1106 | case 2: |
171375c6 | 1107 | return unw_decode_x2 (dp, code, arg, end); |
4d6ed7c8 | 1108 | case 3: |
171375c6 | 1109 | return unw_decode_x3 (dp, code, arg, end); |
4d6ed7c8 | 1110 | case 4: |
171375c6 | 1111 | return unw_decode_x4 (dp, code, arg, end); |
4d6ed7c8 NC |
1112 | default: |
1113 | UNW_DEC_BAD_CODE (code); | |
1114 | break; | |
1115 | } | |
1116 | return dp; | |
1117 | } | |
1118 | ||
1119 | typedef const unsigned char *(*unw_decoder) | |
b4477bc8 | 1120 | (const unsigned char *, unsigned int, void *, const unsigned char *); |
4d6ed7c8 | 1121 | |
9bcd0325 | 1122 | static const unw_decoder unw_decode_table[2][8] = |
4d6ed7c8 NC |
1123 | { |
1124 | /* prologue table: */ | |
1125 | { | |
1126 | unw_decode_r1, /* 0 */ | |
1127 | unw_decode_r1, | |
1128 | unw_decode_r2, | |
1129 | unw_decode_r3, | |
1130 | unw_decode_p1, /* 4 */ | |
1131 | unw_decode_p2_p5, | |
1132 | unw_decode_p6, | |
1133 | unw_decode_p7_p10 | |
1134 | }, | |
1135 | { | |
1136 | unw_decode_r1, /* 0 */ | |
1137 | unw_decode_r1, | |
1138 | unw_decode_r2, | |
1139 | unw_decode_r3, | |
1140 | unw_decode_b1, /* 4 */ | |
1141 | unw_decode_b1, | |
1142 | unw_decode_b2, | |
1143 | unw_decode_b3_x4 | |
1144 | } | |
1145 | }; | |
1146 | ||
1147 | /* Decode one descriptor and return address of next descriptor. */ | |
1148 | const unsigned char * | |
2da42df6 | 1149 | unw_decode (const unsigned char *dp, int inside_body, |
b4477bc8 | 1150 | void *ptr_inside_body, const unsigned char * end) |
4d6ed7c8 NC |
1151 | { |
1152 | unw_decoder decoder; | |
1153 | unsigned char code; | |
1154 | ||
5cacf1c8 NC |
1155 | if ((end - dp) < 1) |
1156 | { | |
1157 | printf (_("\t<corrupt IA64 descriptor>\n")); | |
1158 | return end; | |
1159 | } | |
1160 | ||
4d6ed7c8 NC |
1161 | code = *dp++; |
1162 | decoder = unw_decode_table[inside_body][code >> 5]; | |
b4477bc8 | 1163 | return (*decoder) (dp, code, ptr_inside_body, end); |
4d6ed7c8 | 1164 | } |