Gia64-test-stack.c revision 9c83634f045438d466ef9113820e8bd8b059ceec
1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2003 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/* This file tests corner-cases of unwinding across multiple stacks.
27   In particular, it verifies that the extreme case with a frame of 96
28   stacked registers that are all backed up by separate stacks works
29   as expected.  */
30
31#include <libunwind.h>
32#include <stdio.h>
33#include <stdlib.h>
34
35#include "ia64-test-stack.h"
36
37#define panic(args...)				\
38	{ printf (args); ++nerrors; }
39
40/* The loadrs field in ar.rsc is 14 bits wide, which limits all ia64
41   implementations to at most 2048 physical stacked registers
42   (actually, slightly less than that, because loadrs also counts RNaT
43   slots).  Since we can dirty 95 stacked registers per recursion, we
44   need to recurse RECURSION_DEPTH times to ensure all physical
45   stacked registers are in use. */
46#define MAX_PHYS_STACKED	2048
47#define RECURSION_DEPTH		((MAX_PHYS_STACKED + 94) / 95)
48
49extern void touch_all (unsigned long recursion_depth);
50extern void flushrs (void);
51
52int nerrors;
53int verbose;
54
55void
56do_unwind_tests (void)
57{
58  unw_word_t ip, sp, bsp, v0, v1, v2, v3, n0, n1, n2, n3, cfm, sof, sol, r32;
59  int ret, reg, i, l;
60  unw_context_t uc;
61  unw_cursor_t c;
62
63  if (verbose)
64    printf ("do_unwind_tests: here we go!\n");
65
66  /* do a full stack-dump: */
67  unw_getcontext (&uc);
68  unw_init_local (&c, &uc);
69  i = 0;
70  do
71    {
72      if (verbose)
73	{
74	  if ((ret = unw_get_reg (&c, UNW_IA64_IP, &ip)) < 0
75	      || (ret = unw_get_reg (&c, UNW_IA64_SP, &sp)) < 0
76	      || (ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0)
77	    break;
78	  printf ("ip=0x%16lx sp=0x%16lx bsp=0x%16lx\n", ip, sp, bsp);
79
80	  for (reg = 32; reg < 128; reg += 4)
81	    {
82	      v0 = v1 = v2 = v3 = 0;
83	      n0 = n1 = n2 = n3 = 0;
84	      ((ret = unw_get_reg (&c, UNW_IA64_GR + reg, &v0)) < 0
85	       || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg, &n0)) < 0
86	       || (ret = unw_get_reg (&c, UNW_IA64_GR  + reg + 1, &v1)) < 0
87	       || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg + 1, &n1)) < 0
88	       || (ret = unw_get_reg (&c, UNW_IA64_GR  + reg + 2, &v2)) < 0
89	       || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg + 2, &n2)) < 0
90	       || (ret = unw_get_reg (&c, UNW_IA64_GR  + reg + 3, &v3)) < 0
91	   || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg + 3, &n3)) < 0);
92	      if (reg < 100)
93		printf ("  r%d", reg);
94	      else
95		printf (" r%d", reg);
96	      printf (" %c%016lx %c%016lx %c%016lx %c%016lx\n",
97		      n0 ? '*' : ' ', v0, n1 ? '*' : ' ', v1,
98		      n2 ? '*' : ' ', v2, n3 ? '*' : ' ', v3);
99	      if (ret < 0)
100		break;
101	    }
102	}
103
104      if (i >= 1 && i <= NSTACKS)
105	{
106	  if ((ret = unw_get_reg (&c, UNW_IA64_CFM, &cfm)) < 0)
107	    break;
108	  sof = cfm & 0x7f;
109	  if (sof != (unw_word_t) (i & 1))
110	      panic ("\texpected sof=%d, found sof=%lu\n", i - 1, sof);
111	  if (sof == 1)
112	    {
113	      if ((ret = unw_get_reg (&c, UNW_IA64_GR + 32, &r32)) < 0)
114		break;
115	      if (r32 != (unw_word_t) (i - 1))
116		panic ("\texpected r32=%d, found r32=%lu\n", i - 1, r32);
117	    }
118	}
119      else if (i > NSTACKS && i <= NSTACKS + RECURSION_DEPTH)
120	{
121	  if ((ret = unw_get_reg (&c, UNW_IA64_CFM, &cfm)) < 0)
122	    break;
123	  sof = cfm & 0x7f;
124	  sol = (cfm >> 7) & 0x7f;
125	  if (sof != 96)
126	      panic ("\texpected sof=96, found sof=%lu\n", sof);
127	  if (sol != 95)
128	      panic ("\texpected sol=95, found sol=%lu\n", sol);
129
130	  for (l = 2; l <= 93; ++l)
131	    {
132	      if ((ret = unw_get_reg (&c, UNW_IA64_GR + 33 + l, &v0)) < 0
133		  || (ret = unw_get_reg (&c, UNW_IA64_NAT + 33 + l, &n0)) < 0)
134		break;
135	      switch (l)
136		{
137		case 2: case 31: case 73: case 93:
138		  if (!n0)
139		    panic ("\texpected loc%d to be a NaT!\n", l);
140		  break;
141
142		default:
143		  if (n0)
144		    panic ("\tloc%d is unexpectedly a NaT!\n", l);
145		  v1 = ((unw_word_t) (i - NSTACKS) << 32) + l;
146		  if (v0 != v1)
147		    panic ("\tloc%d expected to be %lx, found to be %lx\n",
148			   l, v1, v0);
149		}
150	    }
151	}
152      ++i;
153    }
154  while ((ret = unw_step (&c)) > 0);
155
156  if (ret < 0)
157    panic ("libunwind returned %d\n", ret);
158}
159
160int
161main (int argc, char **argv)
162{
163  if (argc > 1)
164    ++verbose;
165
166  touch_all (RECURSION_DEPTH);
167  if (nerrors)
168    {
169      printf ("FAILURE: detected %d errors\n", nerrors);
170      exit (-1);
171    }
172  if (verbose)
173    printf ("SUCCESS\n");
174  return 0;
175}
176