Branch data Line data Source code
1 : : /* Paths through the code associated with a diagnostic.
2 : : Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : : #include "config.h"
22 : : #define INCLUDE_ALGORITHM
23 : : #define INCLUDE_MAP
24 : : #define INCLUDE_STRING
25 : : #define INCLUDE_VECTOR
26 : : #include "system.h"
27 : : #include "coretypes.h"
28 : : #include "diagnostic.h"
29 : : #include "diagnostic-path.h"
30 : : #include "xml.h"
31 : :
32 : : /* Disable warnings about missing quoting in GCC diagnostics for the print
33 : : calls below. */
34 : : #if __GNUC__ >= 10
35 : : # pragma GCC diagnostic push
36 : : # pragma GCC diagnostic ignored "-Wformat-diag"
37 : : #endif
38 : :
39 : : /* class diagnostic_event. */
40 : :
41 : : /* struct diagnostic_event::meaning. */
42 : :
43 : : void
44 : 144 : diagnostic_event::meaning::dump_to_pp (pretty_printer *pp) const
45 : : {
46 : 144 : bool need_comma = false;
47 : 144 : pp_character (pp, '{');
48 : 144 : if (const char *verb_str = maybe_get_verb_str (m_verb))
49 : : {
50 : 112 : pp_printf (pp, "verb: %qs", verb_str);
51 : 112 : need_comma = true;
52 : : }
53 : 144 : if (const char *noun_str = maybe_get_noun_str (m_noun))
54 : : {
55 : 112 : if (need_comma)
56 : 112 : pp_string (pp, ", ");
57 : 112 : pp_printf (pp, "noun: %qs", noun_str);
58 : 112 : need_comma = true;
59 : : }
60 : 144 : if (const char *property_str = maybe_get_property_str (m_property))
61 : : {
62 : 0 : if (need_comma)
63 : 0 : pp_string (pp, ", ");
64 : 0 : pp_printf (pp, "property: %qs", property_str);
65 : 0 : need_comma = true;
66 : : }
67 : 144 : pp_character (pp, '}');
68 : 144 : }
69 : :
70 : : /* Get a string (or nullptr) for V suitable for use within a SARIF
71 : : threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
72 : :
73 : : const char *
74 : 212 : diagnostic_event::meaning::maybe_get_verb_str (enum verb v)
75 : : {
76 : 212 : switch (v)
77 : : {
78 : 0 : default:
79 : 0 : gcc_unreachable ();
80 : : case verb::unknown:
81 : : return nullptr;
82 : 81 : case verb::acquire:
83 : 81 : return "acquire";
84 : 50 : case verb::release:
85 : 50 : return "release";
86 : 4 : case verb::enter:
87 : 4 : return "enter";
88 : 0 : case verb::exit:
89 : 0 : return "exit";
90 : 3 : case verb::call:
91 : 3 : return "call";
92 : 3 : case verb::return_:
93 : 3 : return "return";
94 : 20 : case verb::branch:
95 : 20 : return "branch";
96 : 19 : case verb::danger:
97 : 19 : return "danger";
98 : : }
99 : : }
100 : :
101 : : /* Get a string (or nullptr) for N suitable for use within a SARIF
102 : : threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
103 : :
104 : : const char *
105 : 212 : diagnostic_event::meaning::maybe_get_noun_str (enum noun n)
106 : : {
107 : 212 : switch (n)
108 : : {
109 : 0 : default:
110 : 0 : gcc_unreachable ();
111 : : case noun::unknown:
112 : : return nullptr;
113 : 0 : case noun::taint:
114 : 0 : return "taint";
115 : 0 : case noun::sensitive:
116 : 0 : return "sensitive";
117 : 10 : case noun::function:
118 : 10 : return "function";
119 : 0 : case noun::lock:
120 : 0 : return "lock";
121 : 35 : case noun::memory:
122 : 35 : return "memory";
123 : 96 : case noun::resource:
124 : 96 : return "resource";
125 : : }
126 : : }
127 : :
128 : : /* Get a string (or nullptr) for P suitable for use within a SARIF
129 : : threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
130 : :
131 : : const char *
132 : 212 : diagnostic_event::meaning::maybe_get_property_str (enum property p)
133 : : {
134 : 212 : switch (p)
135 : : {
136 : 0 : default:
137 : 0 : gcc_unreachable ();
138 : : case property::unknown:
139 : : return nullptr;
140 : 8 : case property::true_:
141 : 8 : return "true";
142 : 12 : case property::false_:
143 : 12 : return "false";
144 : : }
145 : : }
146 : :
147 : : /* Generate a label_text containing the description of this event
148 : : (for debugging/logging purposes). */
149 : :
150 : : label_text
151 : 16 : diagnostic_event::get_desc (pretty_printer &ref_pp) const
152 : : {
153 : 16 : auto pp = ref_pp.clone ();
154 : 16 : pp_show_color (pp.get ()) = false;
155 : 16 : print_desc (*pp.get ());
156 : 16 : return label_text::take (xstrdup (pp_formatted_text (pp.get ())));
157 : 16 : }
158 : :
159 : : // Base implementation of diagnostic_event::maybe_make_xml_state
160 : :
161 : : std::unique_ptr<xml::document>
162 : 0 : diagnostic_event::maybe_make_xml_state (bool) const
163 : : {
164 : : // Don't attempt to make a state document:
165 : 0 : return nullptr;
166 : : }
167 : :
168 : : /* class diagnostic_path. */
169 : :
170 : : /* Subroutine of diagnostic_path::interprocedural_p.
171 : : Look for the first event in this path that is within a function
172 : : i.e. has a non-null logical location for which function_p is true.
173 : : If found, write its index to *OUT_IDX and return true.
174 : : Otherwise return false. */
175 : :
176 : : bool
177 : 4011 : diagnostic_path::get_first_event_in_a_function (unsigned *out_idx) const
178 : : {
179 : 4011 : const unsigned num = num_events ();
180 : 4148 : for (unsigned i = 0; i < num; i++)
181 : : {
182 : 4143 : const diagnostic_event &event = get_event (i);
183 : 4143 : if (logical_location logical_loc = event.get_logical_location ())
184 : 4006 : if (m_logical_loc_mgr.function_p (logical_loc))
185 : : {
186 : 4006 : *out_idx = i;
187 : 4006 : return true;
188 : : }
189 : : }
190 : : return false;
191 : : }
192 : :
193 : : /* Return true if the events in this path involve more than one
194 : : function, or false if it is purely intraprocedural. */
195 : :
196 : : bool
197 : 4011 : diagnostic_path::interprocedural_p () const
198 : : {
199 : : /* Ignore leading events that are outside of any function. */
200 : 4011 : unsigned first_fn_event_idx;
201 : 4011 : if (!get_first_event_in_a_function (&first_fn_event_idx))
202 : : return false;
203 : :
204 : 4006 : const diagnostic_event &first_fn_event = get_event (first_fn_event_idx);
205 : 4006 : int first_fn_stack_depth = first_fn_event.get_stack_depth ();
206 : :
207 : 4006 : const unsigned num = num_events ();
208 : 12400 : for (unsigned i = first_fn_event_idx + 1; i < num; i++)
209 : : {
210 : 9202 : if (!same_function_p (first_fn_event_idx, i))
211 : : return true;
212 : 8621 : if (get_event (i).get_stack_depth () != first_fn_stack_depth)
213 : : return true;
214 : : }
215 : : return false;
216 : : }
217 : :
218 : : /* Print PATH by emitting a dummy "note" associated with it. */
219 : :
220 : : DEBUG_FUNCTION
221 : 0 : void debug (diagnostic_path *path)
222 : : {
223 : 0 : rich_location richloc (line_table, UNKNOWN_LOCATION);
224 : 0 : richloc.set_path (path);
225 : 0 : inform (&richloc, "debug path");
226 : 0 : }
227 : :
228 : : #if __GNUC__ >= 10
229 : : # pragma GCC diagnostic pop
230 : : #endif
|