mostang.com!davidm | 66482c4 | 2004-02-14 07:53:31 +0000 | [diff] [blame] | 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 | |
| 5 | This file is part of libunwind. |
| 6 | |
| 7 | Permission is hereby granted, free of charge, to any person obtaining |
| 8 | a copy of this software and associated documentation files (the |
| 9 | "Software"), to deal in the Software without restriction, including |
| 10 | without limitation the rights to use, copy, modify, merge, publish, |
| 11 | distribute, sublicense, and/or sell copies of the Software, and to |
| 12 | permit persons to whom the Software is furnished to do so, subject to |
| 13 | the following conditions: |
| 14 | |
| 15 | The above copyright notice and this permission notice shall be |
| 16 | included in all copies or substantial portions of the Software. |
| 17 | |
| 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 24 | WITH 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 | |
hp.com!davidm | a0f3b06 | 2003-02-22 03:08:22 +0000 | [diff] [blame] | 31 | #include <stdio.h> |
| 32 | #include <stdlib.h> |
| 33 | |
| 34 | #include <libunwind.h> |
| 35 | |
| 36 | #include "ia64-test-rbs.h" |
| 37 | |
| 38 | #define panic(args...) \ |
| 39 | do { fprintf (stderr, args); ++nerrors; return -9999; } while (0) |
| 40 | |
hp.com!davidm | da5e9ba | 2005-05-20 09:48:08 +0000 | [diff] [blame] | 41 | #define ARRAY_SIZE(a) ((int) (sizeof (a) / sizeof ((a)[0]))) |
hp.com!davidm | a0f3b06 | 2003-02-22 03:08:22 +0000 | [diff] [blame] | 42 | |
| 43 | /* The loadrs field in ar.rsc is 14 bits wide, which limits all ia64 |
| 44 | implementations to at most 2048 physical stacked registers |
| 45 | (actually, slightly less than that, because loadrs also counts RNaT |
| 46 | slots). Since we can dirty 93 stacked registers per recursion, we |
| 47 | need to recurse RECURSION_DEPTH times to ensure all physical |
| 48 | stacked registers are in use. */ |
| 49 | #define MAX_PHYS_STACKED 2048 |
| 50 | #define RECURSION_DEPTH ((MAX_PHYS_STACKED + 92) / 93) |
| 51 | |
| 52 | typedef int spill_func_t (long iteration, int (*next_func[])()); |
| 53 | |
| 54 | extern int loadup (long iteration, int *values, int (*next_func[])()); |
| 55 | extern char resumption_point_label; |
| 56 | |
| 57 | #define DCL(n) \ |
| 58 | extern int rbs_spill_##n (long iteration, int (*next_func[])()) |
| 59 | DCL(2); DCL(3); DCL(4); DCL(5); DCL(6); DCL(7); |
| 60 | DCL(8); DCL(9); DCL(10); DCL(11); DCL(12); DCL(13); DCL(14); DCL(15); |
| 61 | DCL(16); DCL(17); DCL(18); DCL(19); DCL(20); DCL(21); DCL(22); DCL(23); |
| 62 | DCL(24); DCL(25); DCL(26); DCL(27); DCL(28); DCL(29); DCL(30); DCL(31); |
| 63 | DCL(32); DCL(33); DCL(34); DCL(35); DCL(36); DCL(37); DCL(38); DCL(39); |
| 64 | DCL(40); DCL(41); DCL(42); DCL(43); DCL(44); DCL(45); DCL(46); DCL(47); |
| 65 | DCL(48); DCL(49); DCL(50); DCL(51); DCL(52); DCL(53); DCL(54); DCL(55); |
| 66 | DCL(56); DCL(57); DCL(58); DCL(59); DCL(60); DCL(61); DCL(62); DCL(63); |
| 67 | DCL(64); DCL(65); DCL(66); DCL(67); DCL(68); DCL(69); DCL(70); DCL(71); |
| 68 | DCL(72); DCL(73); DCL(74); DCL(75); DCL(76); DCL(77); DCL(78); DCL(79); |
| 69 | DCL(80); DCL(81); DCL(82); DCL(83); DCL(84); DCL(85); DCL(86); DCL(87); |
| 70 | DCL(88); DCL(89); DCL(90); DCL(91); DCL(92); DCL(93); DCL(94); |
| 71 | |
| 72 | #define SPL(n) rbs_spill_##n |
| 73 | spill_func_t *spill_funcs[] = |
| 74 | { |
| 75 | SPL(2), SPL(3), SPL(4), SPL(5), SPL(6), SPL(7), |
| 76 | SPL(8), SPL(9), SPL(10), SPL(11), SPL(12), SPL(13), SPL(14), SPL(15), |
| 77 | SPL(16), SPL(17), SPL(18), SPL(19), SPL(20), SPL(21), SPL(22), SPL(23), |
| 78 | SPL(24), SPL(25), SPL(26), SPL(27), SPL(28), SPL(29), SPL(30), SPL(31), |
| 79 | SPL(32), SPL(33), SPL(34), SPL(35), SPL(36), SPL(37), SPL(38), SPL(39), |
| 80 | SPL(40), SPL(41), SPL(42), SPL(43), SPL(44), SPL(45), SPL(46), SPL(47), |
| 81 | SPL(48), SPL(49), SPL(50), SPL(51), SPL(52), SPL(53), SPL(54), SPL(55), |
| 82 | SPL(56), SPL(57), SPL(58), SPL(59), SPL(60), SPL(61), SPL(62), SPL(63), |
| 83 | SPL(64), SPL(65), SPL(66), SPL(67), SPL(68), SPL(69), SPL(70), SPL(71), |
| 84 | SPL(72), SPL(73), SPL(74), SPL(75), SPL(76), SPL(77), SPL(78), SPL(79), |
| 85 | SPL(80), SPL(81), SPL(82), SPL(83), SPL(84), SPL(85), SPL(86), SPL(87), |
| 86 | SPL(88), SPL(89), SPL(90), SPL(91), SPL(92), SPL(93), SPL(94) |
| 87 | }; |
| 88 | |
| 89 | static int verbose; |
| 90 | static int nerrors; |
| 91 | static int unwind_count; |
| 92 | |
| 93 | static int |
| 94 | unwind_and_resume (long iteration, int (*next_func[])()) |
| 95 | { |
| 96 | unw_context_t uc; |
| 97 | unw_cursor_t c; |
| 98 | unw_word_t ip; |
| 99 | int i, ret; |
| 100 | |
| 101 | if (verbose) |
| 102 | printf (" %s(iteration=%ld, next_func=%p)\n", |
| 103 | __FUNCTION__, iteration, next_func); |
| 104 | |
| 105 | unw_getcontext (&uc); |
| 106 | if ((ret = unw_init_local (&c, &uc)) < 0) |
| 107 | panic ("unw_init_local (ret=%d)", ret); |
| 108 | |
| 109 | for (i = 0; i < unwind_count; ++i) |
| 110 | if ((ret = unw_step (&c)) < 0) |
| 111 | panic ("unw_step (ret=%d)", ret); |
| 112 | |
| 113 | if (unw_get_reg (&c, UNW_REG_IP, &ip) < 0 |
| 114 | || unw_set_reg (&c, UNW_REG_IP, (unw_word_t) &resumption_point_label) < 0 |
mostang.com!davidm | 2853523 | 2003-03-06 06:14:36 +0000 | [diff] [blame] | 115 | || unw_set_reg (&c, UNW_REG_EH + 0, 0) /* ret val */ |
| 116 | || unw_set_reg (&c, UNW_REG_EH + 1, ip)) |
hp.com!davidm | a0f3b06 | 2003-02-22 03:08:22 +0000 | [diff] [blame] | 117 | panic ("failed to redirect to resumption_point\n"); |
| 118 | |
| 119 | if (verbose) |
| 120 | { |
| 121 | unw_word_t bsp; |
| 122 | if (unw_get_reg (&c, UNW_IA64_BSP, &bsp) < 0) |
| 123 | panic ("unw_get_reg() failed\n"); |
| 124 | printf (" bsp=%lx, old ip=%lx, new ip=%p\n", bsp, |
| 125 | ip, &resumption_point_label); |
| 126 | } |
| 127 | |
| 128 | ret = unw_resume (&c); |
| 129 | panic ("unw_resume() returned (ret=%d)!!\n", ret); |
| 130 | return 0; |
| 131 | } |
| 132 | |
| 133 | static int |
| 134 | run_check (int test) |
| 135 | { |
| 136 | int nfuncs, nspills, n, ret, i, reg_values[88]; |
| 137 | spill_func_t *func[NSTACKS + 1]; |
| 138 | |
| 139 | /* First, generate a set of 88 random values which loadup() will load |
| 140 | into loc2-loc89 (r37-r124). */ |
hp.com!davidm | da5e9ba | 2005-05-20 09:48:08 +0000 | [diff] [blame] | 141 | for (i = 0; i < ARRAY_SIZE (reg_values); ++i) |
hp.com!davidm | a0f3b06 | 2003-02-22 03:08:22 +0000 | [diff] [blame] | 142 | { |
| 143 | reg_values[i] = random (); |
| 144 | /* Generate NaTs with a reasonably probability (1/16th): */ |
| 145 | if (reg_values[i] < 0x10000000) |
| 146 | reg_values[i] = 0; |
| 147 | } |
| 148 | |
| 149 | nspills = 0; |
| 150 | nfuncs = 0; |
| 151 | do |
| 152 | { |
hp.com!davidm | da5e9ba | 2005-05-20 09:48:08 +0000 | [diff] [blame] | 153 | n = random () % ARRAY_SIZE (spill_funcs); |
hp.com!davidm | a0f3b06 | 2003-02-22 03:08:22 +0000 | [diff] [blame] | 154 | func[nfuncs++] = spill_funcs[n]; |
| 155 | nspills += 2 + n; |
| 156 | } |
| 157 | while (nspills < 128); |
| 158 | func[nfuncs++] = unwind_and_resume; |
| 159 | |
| 160 | unwind_count = 1 + (random () % (nfuncs + RECURSION_DEPTH - 1)); |
| 161 | |
| 162 | if (verbose) |
| 163 | printf ("test%d: nfuncs=%d, unwind_count=%d\n", |
| 164 | test, nfuncs, unwind_count); |
| 165 | |
| 166 | ret = loadup (RECURSION_DEPTH, reg_values, func); |
| 167 | if (ret < 0) |
| 168 | panic ("test%d: load() returned %d\n", test, ret); |
| 169 | else if (ret != RECURSION_DEPTH + nfuncs - unwind_count) |
| 170 | panic ("test%d: resumed wrong frame: expected %d, got %d\n", |
| 171 | test, RECURSION_DEPTH + nfuncs - unwind_count, ret); |
| 172 | return 0; |
| 173 | } |
| 174 | |
| 175 | int |
| 176 | main (int argc, char **argv) |
| 177 | { |
| 178 | int i; |
| 179 | |
| 180 | if (argc > 1) |
| 181 | verbose = 1; |
| 182 | |
| 183 | for (i = 0; i < 100000; ++i) |
| 184 | run_check (i + 1); |
| 185 | |
| 186 | if (nerrors > 0) |
| 187 | { |
| 188 | fprintf (stderr, "FAILURE: detected %d errors\n", nerrors); |
| 189 | exit (-1); |
| 190 | } |
| 191 | if (verbose) |
| 192 | printf ("SUCCESS.\n"); |
| 193 | return 0; |
| 194 | } |