Line data Source code
1 : /* Debug counter for debugging support
2 : Copyright (C) 2006-2026 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 1047248213 : dbg_cnt (enum debug_counter index)
65 : {
66 1047248213 : unsigned v = ++count[index];
67 :
68 1047248213 : 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 126 : dbg_cnt_counter (enum debug_counter index)
105 : {
106 126 : 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 6 : 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 6 : 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 */
|