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	      (void)
85	         ((ret = unw_get_reg (&c, UNW_IA64_GR  + reg, &v0)) < 0
86	       || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg, &n0)) < 0
87	       || (ret = unw_get_reg (&c, UNW_IA64_GR  + reg + 1, &v1)) < 0
88	       || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg + 1, &n1)) < 0
89	       || (ret = unw_get_reg (&c, UNW_IA64_GR  + reg + 2, &v2)) < 0
90	       || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg + 2, &n2)) < 0
91	       || (ret = unw_get_reg (&c, UNW_IA64_GR  + reg + 3, &v3)) < 0
92	       || (ret = unw_get_reg (&c, UNW_IA64_NAT + reg + 3, &n3)) < 0);
93	      if (reg < 100)
94		printf ("  r%d", reg);
95	      else
96		printf (" r%d", reg);
97	      printf (" %c%016lx %c%016lx %c%016lx %c%016lx\n",
98		      n0 ? '*' : ' ', v0, n1 ? '*' : ' ', v1,
99		      n2 ? '*' : ' ', v2, n3 ? '*' : ' ', v3);
100	      if (ret < 0)
101		break;
102	    }
103	}
104
105      if (i >= 1 && i <= NSTACKS)
106	{
107	  if ((ret = unw_get_reg (&c, UNW_IA64_CFM, &cfm)) < 0)
108	    break;
109	  sof = cfm & 0x7f;
110	  if (sof != (unw_word_t) (i & 1))
111	      panic ("\texpected sof=%d, found sof=%lu\n", i - 1, sof);
112	  if (sof == 1)
113	    {
114	      if ((ret = unw_get_reg (&c, UNW_IA64_GR + 32, &r32)) < 0)
115		break;
116	      if (r32 != (unw_word_t) (i - 1))
117		panic ("\texpected r32=%d, found r32=%lu\n", i - 1, r32);
118	    }
119	}
120      else if (i > NSTACKS && i <= NSTACKS + RECURSION_DEPTH)
121	{
122	  if ((ret = unw_get_reg (&c, UNW_IA64_CFM, &cfm)) < 0)
123	    break;
124	  sof = cfm & 0x7f;
125	  sol = (cfm >> 7) & 0x7f;
126	  if (sof != 96)
127	      panic ("\texpected sof=96, found sof=%lu\n", sof);
128	  if (sol != 95)
129	      panic ("\texpected sol=95, found sol=%lu\n", sol);
130
131	  for (l = 2; l <= 93; ++l)
132	    {
133	      if ((ret = unw_get_reg (&c, UNW_IA64_GR + 33 + l, &v0)) < 0
134		  || (ret = unw_get_reg (&c, UNW_IA64_NAT + 33 + l, &n0)) < 0)
135		break;
136	      switch (l)
137		{
138		case 2: case 31: case 73: case 93:
139		  if (!n0)
140		    panic ("\texpected loc%d to be a NaT!\n", l);
141		  break;
142
143		default:
144		  if (n0)
145		    panic ("\tloc%d is unexpectedly a NaT!\n", l);
146		  v1 = ((unw_word_t) (i - NSTACKS) << 32) + l;
147		  if (v0 != v1)
148		    panic ("\tloc%d expected to be %lx, found to be %lx\n",
149			   l, v1, v0);
150		}
151	    }
152	}
153      ++i;
154    }
155  while ((ret = unw_step (&c)) > 0);
156
157  if (ret < 0)
158    panic ("libunwind returned %d\n", ret);
159}
160
161int
162main (int argc, char **argv)
163{
164  if (argc > 1)
165    ++verbose;
166
167  touch_all (RECURSION_DEPTH);
168  if (nerrors)
169    {
170      printf ("FAILURE: detected %d errors\n", nerrors);
171      exit (-1);
172    }
173  if (verbose)
174    printf ("SUCCESS\n");
175  return 0;
176}
177