| 1 | #include <stdio.h> |
| 2 | #include <unistd.h> |
| 3 | /* |
| 4 | * Since using watchpoints can be very slow, we have to take some pains to |
| 5 | * ensure that we don't run too long with them enabled or we run the risk |
| 6 | * of having the test timeout. To help avoid this, we insert some marker |
| 7 | * functions in the execution stream so we can set breakpoints at known |
| 8 | * locations, without worrying about invalidating line numbers by changing |
| 9 | * this file. We use null bodied functions are markers since gdb does |
| 10 | * not support breakpoints at labeled text points at this time. |
| 11 | * |
| 12 | * One place we need is a marker for when we start executing our tests |
| 13 | * instructions rather than any process startup code, so we insert one |
| 14 | * right after entering main(). Another is right before we finish, before |
| 15 | * we start executing any process termination code. |
| 16 | * |
| 17 | * Another problem we have to guard against, at least for the test |
| 18 | * suite, is that we need to ensure that the line that causes the |
| 19 | * watchpoint to be hit is still the current line when gdb notices |
| 20 | * the hit. Depending upon the specific code generated by the compiler, |
| 21 | * the instruction after the one that triggers the hit may be part of |
| 22 | * the same line or part of the next line. Thus we ensure that there |
| 23 | * are always some instructions to execute on the same line after the |
| 24 | * code that should trigger the hit. |
| 25 | */ |
| 26 | |
| 27 | int count = -1; |
| 28 | int ival1 = -1; |
| 29 | int ival2 = -1; |
| 30 | int ival3 = -1; |
| 31 | int ival4 = -1; |
| 32 | int ival5 = -1; |
| 33 | char buf[10]; |
| 34 | struct foo |
| 35 | { |
| 36 | int val; |
| 37 | }; |
| 38 | struct foo struct1, struct2, *ptr1, *ptr2; |
| 39 | |
| 40 | int doread = 0; |
| 41 | |
| 42 | void marker1 () |
| 43 | { |
| 44 | } |
| 45 | |
| 46 | void marker2 () |
| 47 | { |
| 48 | } |
| 49 | |
| 50 | void marker4 () |
| 51 | { |
| 52 | } |
| 53 | |
| 54 | void marker5 () |
| 55 | { |
| 56 | } |
| 57 | |
| 58 | void marker6 () |
| 59 | { |
| 60 | } |
| 61 | |
| 62 | #ifdef PROTOTYPES |
| 63 | void recurser (int x) |
| 64 | #else |
| 65 | void recurser (x) int x; |
| 66 | #endif |
| 67 | { |
| 68 | int local_x; |
| 69 | |
| 70 | if (x > 0) |
| 71 | recurser (x-1); |
| 72 | local_x = x; |
| 73 | } |
| 74 | |
| 75 | void |
| 76 | func2 () |
| 77 | { |
| 78 | int local_a; |
| 79 | static int static_b; |
| 80 | |
| 81 | ival5++; |
| 82 | local_a = ival5; |
| 83 | static_b = local_a; |
| 84 | } |
| 85 | |
| 86 | void |
| 87 | func3 () |
| 88 | { |
| 89 | int x; |
| 90 | int y; |
| 91 | |
| 92 | x = 0; |
| 93 | x = 1; /* second x assignment */ |
| 94 | y = 1; |
| 95 | y = 2; |
| 96 | } |
| 97 | |
| 98 | int |
| 99 | func1 () |
| 100 | { |
| 101 | /* The point of this is that we will set a breakpoint at this call. |
| 102 | |
| 103 | Then, if DECR_PC_AFTER_BREAK equals the size of a function call |
| 104 | instruction (true on a sun3 if this is gcc-compiled--FIXME we |
| 105 | should use asm() to make it work for any compiler, present or |
| 106 | future), then we will end up branching to the location just after |
| 107 | the breakpoint. And we better not confuse that with hitting the |
| 108 | breakpoint. */ |
| 109 | func2 (); |
| 110 | return 73; |
| 111 | } |
| 112 | |
| 113 | int main () |
| 114 | { |
| 115 | #ifdef usestubs |
| 116 | set_debug_traps(); |
| 117 | breakpoint(); |
| 118 | #endif |
| 119 | struct1.val = 1; |
| 120 | struct2.val = 2; |
| 121 | ptr1 = &struct1; |
| 122 | ptr2 = &struct2; |
| 123 | marker1 (); |
| 124 | func1 (); |
| 125 | for (count = 0; count < 4; count++) { |
| 126 | ival1 = count; |
| 127 | ival3 = count; ival4 = count; |
| 128 | } |
| 129 | ival1 = count; /* Outside loop */ |
| 130 | ival2 = count; |
| 131 | ival3 = count; ival4 = count; |
| 132 | marker2 (); |
| 133 | if (doread) |
| 134 | { |
| 135 | static char msg[] = "type stuff for buf now:"; |
| 136 | write (1, msg, sizeof (msg) - 1); |
| 137 | read (0, &buf[0], 5); |
| 138 | } |
| 139 | marker4 (); |
| 140 | |
| 141 | /* We have a watchpoint on ptr1->val. It should be triggered if |
| 142 | ptr1's value changes. */ |
| 143 | ptr1 = ptr2; |
| 144 | |
| 145 | /* This should not trigger the watchpoint. If it does, then we |
| 146 | used the wrong value chain to re-insert the watchpoints or we |
| 147 | are not evaluating the watchpoint expression correctly. */ |
| 148 | struct1.val = 5; |
| 149 | marker5 (); |
| 150 | |
| 151 | /* We have a watchpoint on ptr1->val. It should be triggered if |
| 152 | ptr1's value changes. */ |
| 153 | ptr1 = ptr2; |
| 154 | |
| 155 | /* This should not trigger the watchpoint. If it does, then we |
| 156 | used the wrong value chain to re-insert the watchpoints or we |
| 157 | are not evaluating the watchpoint expression correctly. */ |
| 158 | struct1.val = 5; |
| 159 | marker5 (); |
| 160 | |
| 161 | /* We're going to watch locals of func2, to see that out-of-scope |
| 162 | watchpoints are detected and properly deleted. |
| 163 | */ |
| 164 | marker6 (); |
| 165 | |
| 166 | /* This invocation is used for watches of a single |
| 167 | local variable. */ |
| 168 | func2 (); |
| 169 | |
| 170 | /* This invocation is used for watches of an expression |
| 171 | involving a local variable. */ |
| 172 | func2 (); |
| 173 | |
| 174 | /* This invocation is used for watches of a static |
| 175 | (non-stack-based) local variable. */ |
| 176 | func2 (); |
| 177 | |
| 178 | /* This invocation is used for watches of a local variable |
| 179 | when recursion happens. |
| 180 | */ |
| 181 | marker6 (); |
| 182 | recurser (2); |
| 183 | |
| 184 | marker6 (); |
| 185 | |
| 186 | func3 (); |
| 187 | |
| 188 | return 0; |
| 189 | } |