Branch data Line data Source code
1 : : /* Debug counter for debugging support
2 : : Copyright (C) 2006-2024 Free Software Foundation, Inc.
3 : :
4 : : This file is part of GCC.
5 : :
6 : : GCC is free software; you can redistribute it and/or modify it under
7 : : the terms of the GNU General Public License as published by the Free
8 : : Software Foundation; either version 3, or (at your option) any later
9 : : version.
10 : :
11 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : : for more details.
15 : :
16 : : You should have received a copy of the GNU General Public License
17 : : along with GCC; see the file COPYING3. If not see
18 : : <http://www.gnu.org/licenses/>.
19 : :
20 : : See dbgcnt.def for usage information. */
21 : :
22 : : #include "config.h"
23 : : #include "system.h"
24 : : #include "coretypes.h"
25 : : #include "diagnostic-core.h"
26 : : #include "dumpfile.h"
27 : : #include "selftest.h"
28 : : #include "intl.h"
29 : :
30 : : #include "dbgcnt.h"
31 : :
32 : : struct string2counter_map {
33 : : const char *name;
34 : : enum debug_counter counter;
35 : : };
36 : :
37 : : #define DEBUG_COUNTER(a) { #a , a },
38 : :
39 : : static struct string2counter_map map[debug_counter_number_of_counters] =
40 : : {
41 : : #include "dbgcnt.def"
42 : : };
43 : : #undef DEBUG_COUNTER
44 : :
45 : : typedef std::pair<unsigned int, unsigned int> limit_tuple;
46 : :
47 : : static vec<limit_tuple> limits[debug_counter_number_of_counters];
48 : : static vec<limit_tuple> original_limits[debug_counter_number_of_counters];
49 : :
50 : : static unsigned int count[debug_counter_number_of_counters];
51 : :
52 : : static void
53 : 6 : print_limit_reach (const char *counter, int limit, bool upper_p)
54 : : {
55 : 6 : char buffer[128];
56 : 6 : sprintf (buffer, "***dbgcnt: %s limit %d reached for %s.***\n",
57 : : upper_p ? "upper" : "lower", limit, counter);
58 : 6 : fputs (buffer, stderr);
59 : 6 : if (dump_file)
60 : 2 : fputs (buffer, dump_file);
61 : 6 : }
62 : :
63 : : bool
64 : 852548873 : dbg_cnt (enum debug_counter index)
65 : : {
66 : 852548873 : unsigned v = ++count[index];
67 : :
68 : 852548873 : if (!limits[index].exists ())
69 : : return true;
70 : 12 : else if (limits[index].is_empty ())
71 : : return false;
72 : :
73 : 4 : unsigned last = limits[index].length () - 1;
74 : 4 : unsigned int min = limits[index][last].first;
75 : 4 : unsigned int max = limits[index][last].second;
76 : :
77 : 4 : if (v < min)
78 : : return false;
79 : 4 : else if (v == min)
80 : : {
81 : 3 : print_limit_reach (map[index].name, v, false);
82 : 3 : if (min == max)
83 : : {
84 : 2 : print_limit_reach (map[index].name, v, true);
85 : 2 : limits[index].pop ();
86 : : }
87 : 3 : return true;
88 : : }
89 : 1 : else if (v < max)
90 : : return true;
91 : 1 : else if (v == max)
92 : : {
93 : 1 : print_limit_reach (map[index].name, v, true);
94 : 1 : limits[index].pop ();
95 : 1 : return true;
96 : : }
97 : : else
98 : : return false;
99 : : }
100 : :
101 : : /* Return the counter for INDEX. */
102 : :
103 : : unsigned
104 : 116 : dbg_cnt_counter (enum debug_counter index)
105 : : {
106 : 116 : return count[index];
107 : : }
108 : :
109 : : /* Compare limit_tuple intervals by first item in descending order. */
110 : :
111 : : static int
112 : 0 : cmp_tuples (const void *ptr1, const void *ptr2)
113 : : {
114 : 0 : const limit_tuple *p1 = (const limit_tuple *)ptr1;
115 : 0 : const limit_tuple *p2 = (const limit_tuple *)ptr2;
116 : :
117 : 0 : if (p1->first < p2->first)
118 : : return 1;
119 : 0 : else if (p1->first > p2->first)
120 : 0 : return -1;
121 : : return 0;
122 : : }
123 : :
124 : : static bool
125 : 3 : dbg_cnt_set_limit_by_index (enum debug_counter index, const char *name,
126 : : unsigned int low, unsigned int high)
127 : : {
128 : 3 : if (!limits[index].exists ())
129 : 3 : limits[index].create (1);
130 : :
131 : 3 : limits[index].safe_push (limit_tuple (low, high));
132 : 3 : limits[index].qsort (cmp_tuples);
133 : :
134 : 6 : for (unsigned i = 0; i < limits[index].length () - 1; i++)
135 : : {
136 : 0 : limit_tuple t1 = limits[index][i];
137 : 0 : limit_tuple t2 = limits[index][i + 1];
138 : 0 : if (t1.first <= t2.second)
139 : : {
140 : 0 : error ("Interval overlap of %<-fdbg-cnt=%s%>: [%u, %u] and "
141 : : "[%u, %u]", name, t2.first, t2.second, t1.first, t1.second);
142 : 0 : return false;
143 : : }
144 : : }
145 : :
146 : 3 : original_limits[index] = limits[index].copy ();
147 : :
148 : 3 : return true;
149 : : }
150 : :
151 : : static bool
152 : 3 : dbg_cnt_set_limit_by_name (const char *name, unsigned int low,
153 : : unsigned int high)
154 : : {
155 : 3 : if (high < low)
156 : : {
157 : 0 : error ("%<-fdbg-cnt=%s:%d-%d%> has smaller upper limit than the lower",
158 : : name, low, high);
159 : 0 : return false;
160 : : }
161 : :
162 : : int i;
163 : 29 : for (i = debug_counter_number_of_counters - 1; i >= 0; i--)
164 : 29 : if (strcmp (map[i].name, name) == 0)
165 : : break;
166 : :
167 : 3 : if (i < 0)
168 : : {
169 : 0 : error ("cannot find a valid counter name %qs of %<-fdbg-cnt=%> option",
170 : : name);
171 : 0 : return false;
172 : : }
173 : :
174 : 3 : return dbg_cnt_set_limit_by_index ((enum debug_counter) i, name, low, high);
175 : : }
176 : :
177 : : /* Process a single "low:high" pair.
178 : : Returns NULL if there's no valid pair is found.
179 : : Otherwise returns a pointer to the end of the pair. */
180 : :
181 : : static bool
182 : 3 : dbg_cnt_process_single_pair (char *name, char *str)
183 : : {
184 : 3 : char *value1 = strtok (str, "-");
185 : 3 : char *value2 = strtok (NULL, "-");
186 : :
187 : 3 : unsigned int high, low;
188 : :
189 : 3 : if (value1 == NULL)
190 : : return false;
191 : :
192 : 3 : if (value2 == NULL)
193 : : {
194 : 2 : high = strtol (value1, NULL, 10);
195 : : /* Let's allow 0:0. */
196 : 2 : low = high == 0 ? 0 : 1;
197 : : }
198 : : else
199 : : {
200 : 1 : low = strtol (value1, NULL, 10);
201 : 1 : high = strtol (value2, NULL, 10);
202 : : }
203 : :
204 : 3 : return dbg_cnt_set_limit_by_name (name, low, high);
205 : : }
206 : :
207 : : void
208 : 3 : dbg_cnt_process_opt (const char *arg)
209 : : {
210 : 3 : char *str = xstrdup (arg);
211 : :
212 : 3 : auto_vec<char *> tokens;
213 : 6 : for (char *next = strtok (str, ","); next != NULL; next = strtok (NULL, ","))
214 : 3 : tokens.safe_push (next);
215 : :
216 : 3 : unsigned i;
217 : 12 : for (i = 0; i < tokens.length (); i++)
218 : : {
219 : 3 : auto_vec<char *> ranges;
220 : 3 : char *name = strtok (tokens[i], ":");
221 : 6 : for (char *part = strtok (NULL, ":"); part; part = strtok (NULL, ":"))
222 : 3 : ranges.safe_push (part);
223 : :
224 : 12 : for (unsigned j = 0; j < ranges.length (); j++)
225 : : {
226 : 3 : if (!dbg_cnt_process_single_pair (name, ranges[j]))
227 : : break;
228 : : }
229 : 3 : }
230 : 3 : }
231 : :
232 : : /* Print name, limit and count of all counters. */
233 : :
234 : : void
235 : 0 : dbg_cnt_list_all_counters (void)
236 : : {
237 : 0 : int i;
238 : 0 : fprintf (stderr, " %-30s%-15s %s\n", G_("counter name"),
239 : : G_("counter value"), G_("closed intervals"));
240 : 0 : fprintf (stderr, "-----------------------------------------------------------------\n");
241 : 0 : for (i = 0; i < debug_counter_number_of_counters; i++)
242 : : {
243 : 0 : fprintf (stderr, " %-30s%-15d ", map[i].name, count[i]);
244 : 0 : if (original_limits[i].exists ())
245 : : {
246 : 0 : for (int j = original_limits[i].length () - 1; j >= 0; j--)
247 : : {
248 : 0 : fprintf (stderr, "[%u, %u]", original_limits[i][j].first,
249 : 0 : original_limits[i][j].second);
250 : 0 : if (j > 0)
251 : 0 : fprintf (stderr, ", ");
252 : : }
253 : 0 : fprintf (stderr, "\n");
254 : : }
255 : : else
256 : 0 : fprintf (stderr, "unset\n");
257 : : }
258 : 0 : fprintf (stderr, "\n");
259 : 0 : }
260 : :
261 : : #if CHECKING_P
262 : :
263 : : namespace selftest {
264 : :
265 : : /* Selftests. */
266 : :
267 : : static void
268 : 4 : test_sorted_dbg_counters ()
269 : : {
270 : 300 : for (unsigned i = 0; i < debug_counter_number_of_counters - 1; i++)
271 : 296 : ASSERT_LT (strcmp (map[i].name, map[i + 1].name), 0);
272 : 4 : }
273 : :
274 : : void
275 : 4 : dbgcnt_cc_tests ()
276 : : {
277 : 4 : test_sorted_dbg_counters ();
278 : 4 : }
279 : :
280 : : } // namespace selftest
281 : :
282 : : #endif /* #if CHECKING_P */
|