1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2003-2004 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 <stdio.h>
32#include <stdlib.h>
33
34#include <libunwind.h>
35#include "compiler.h"
36
37#include "ia64-test-rbs.h"
38
39#define panic(args...)							  \
40	do { fprintf (stderr, args); ++nerrors; return -9999; } while (0)
41
42/* The loadrs field in ar.rsc is 14 bits wide, which limits all ia64
43   implementations to at most 2048 physical stacked registers
44   (actually, slightly less than that, because loadrs also counts RNaT
45   slots).  Since we can dirty 93 stacked registers per recursion, we
46   need to recurse RECURSION_DEPTH times to ensure all physical
47   stacked registers are in use. */
48#define MAX_PHYS_STACKED	2048
49#define RECURSION_DEPTH		((MAX_PHYS_STACKED + 92) / 93)
50
51typedef int spill_func_t (long iteration, int (*next_func[])());
52
53extern int loadup (long iteration, int *values, int (*next_func[])());
54extern char resumption_point_label;
55
56#define DCL(n) \
57 extern int rbs_spill_##n (long iteration, int (*next_func[])())
58	           DCL(2);  DCL(3);  DCL(4);  DCL(5);  DCL(6);  DCL(7);
59  DCL(8);  DCL(9); DCL(10); DCL(11); DCL(12); DCL(13); DCL(14); DCL(15);
60 DCL(16); DCL(17); DCL(18); DCL(19); DCL(20); DCL(21); DCL(22); DCL(23);
61 DCL(24); DCL(25); DCL(26); DCL(27); DCL(28); DCL(29); DCL(30); DCL(31);
62 DCL(32); DCL(33); DCL(34); DCL(35); DCL(36); DCL(37); DCL(38); DCL(39);
63 DCL(40); DCL(41); DCL(42); DCL(43); DCL(44); DCL(45); DCL(46); DCL(47);
64 DCL(48); DCL(49); DCL(50); DCL(51); DCL(52); DCL(53); DCL(54); DCL(55);
65 DCL(56); DCL(57); DCL(58); DCL(59); DCL(60); DCL(61); DCL(62); DCL(63);
66 DCL(64); DCL(65); DCL(66); DCL(67); DCL(68); DCL(69); DCL(70); DCL(71);
67 DCL(72); DCL(73); DCL(74); DCL(75); DCL(76); DCL(77); DCL(78); DCL(79);
68 DCL(80); DCL(81); DCL(82); DCL(83); DCL(84); DCL(85); DCL(86); DCL(87);
69 DCL(88); DCL(89); DCL(90); DCL(91); DCL(92); DCL(93); DCL(94);
70
71#define SPL(n)  rbs_spill_##n
72spill_func_t *spill_funcs[] =
73  {
74	            SPL(2),   SPL(3),  SPL(4),  SPL(5),  SPL(6),  SPL(7),
75     SPL(8),  SPL(9), SPL(10), SPL(11), SPL(12), SPL(13), SPL(14), SPL(15),
76    SPL(16), SPL(17), SPL(18), SPL(19), SPL(20), SPL(21), SPL(22), SPL(23),
77    SPL(24), SPL(25), SPL(26), SPL(27), SPL(28), SPL(29), SPL(30), SPL(31),
78    SPL(32), SPL(33), SPL(34), SPL(35), SPL(36), SPL(37), SPL(38), SPL(39),
79    SPL(40), SPL(41), SPL(42), SPL(43), SPL(44), SPL(45), SPL(46), SPL(47),
80    SPL(48), SPL(49), SPL(50), SPL(51), SPL(52), SPL(53), SPL(54), SPL(55),
81    SPL(56), SPL(57), SPL(58), SPL(59), SPL(60), SPL(61), SPL(62), SPL(63),
82    SPL(64), SPL(65), SPL(66), SPL(67), SPL(68), SPL(69), SPL(70), SPL(71),
83    SPL(72), SPL(73), SPL(74), SPL(75), SPL(76), SPL(77), SPL(78), SPL(79),
84    SPL(80), SPL(81), SPL(82), SPL(83), SPL(84), SPL(85), SPL(86), SPL(87),
85    SPL(88), SPL(89), SPL(90), SPL(91), SPL(92), SPL(93), SPL(94)
86  };
87
88static int verbose;
89static int nerrors;
90static int unwind_count;
91
92static int
93unwind_and_resume (long iteration, int (*next_func[])())
94{
95  unw_context_t uc;
96  unw_cursor_t c;
97  unw_word_t ip;
98  int i, ret;
99
100  if (verbose)
101    printf (" %s(iteration=%ld, next_func=%p)\n",
102	    __FUNCTION__, iteration, next_func);
103
104  unw_getcontext (&uc);
105  if ((ret = unw_init_local (&c, &uc)) < 0)
106    panic ("unw_init_local (ret=%d)", ret);
107
108  for (i = 0; i < unwind_count; ++i)
109    if ((ret = unw_step (&c)) < 0)
110      panic ("unw_step (ret=%d)", ret);
111
112  if (unw_get_reg (&c, UNW_REG_IP, &ip) < 0
113      || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) &resumption_point_label) < 0
114      || unw_set_reg (&c, UNW_REG_EH + 0, 0)	/* ret val */
115      || unw_set_reg (&c, UNW_REG_EH + 1, ip))
116    panic ("failed to redirect to resumption_point\n");
117
118  if (verbose)
119    {
120      unw_word_t bsp;
121      if (unw_get_reg (&c, UNW_IA64_BSP, &bsp) < 0)
122	panic ("unw_get_reg() failed\n");
123      printf ("  bsp=%lx, old ip=%lx, new ip=%p\n", bsp,
124	      ip, &resumption_point_label);
125    }
126
127  ret = unw_resume (&c);
128  panic ("unw_resume() returned (ret=%d)!!\n", ret);
129  return 0;
130}
131
132static int
133run_check (int test)
134{
135  int nfuncs, nspills, n, ret, i, reg_values[88];
136  spill_func_t *func[NSTACKS + 1];
137
138  /* First, generate a set of 88 random values which loadup() will load
139     into loc2-loc89 (r37-r124).  */
140  for (i = 0; i < (int) ARRAY_SIZE (reg_values); ++i)
141    {
142      reg_values[i] = random ();
143      /* Generate NaTs with a reasonably probability (1/16th): */
144      if (reg_values[i] < 0x10000000)
145	reg_values[i] = 0;
146    }
147
148  nspills = 0;
149  nfuncs = 0;
150  do
151    {
152      n = random () % (int) ARRAY_SIZE (spill_funcs);
153      func[nfuncs++] = spill_funcs[n];
154      nspills += 2 + n;
155    }
156  while (nspills < 128);
157  func[nfuncs++] = unwind_and_resume;
158
159  unwind_count = 1 + (random () % (nfuncs + RECURSION_DEPTH - 1));
160
161  if (verbose)
162    printf ("test%d: nfuncs=%d, unwind_count=%d\n",
163	    test, nfuncs, unwind_count);
164
165  ret = loadup (RECURSION_DEPTH, reg_values, func);
166  if (ret < 0)
167    panic ("test%d: load() returned %d\n", test, ret);
168  else if (ret != RECURSION_DEPTH + nfuncs - unwind_count)
169    panic ("test%d: resumed wrong frame: expected %d, got %d\n",
170	   test, RECURSION_DEPTH + nfuncs - unwind_count, ret);
171  return 0;
172}
173
174int
175main (int argc, char **argv)
176{
177  int i;
178
179  if (argc > 1)
180    verbose = 1;
181
182  for (i = 0; i < 100000; ++i)
183    run_check (i + 1);
184
185  if (nerrors > 0)
186    {
187      fprintf (stderr, "FAILURE: detected %d errors\n", nerrors);
188      exit (-1);
189    }
190  if (verbose)
191    printf ("SUCCESS.\n");
192  return 0;
193}
194