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