aboutsummaryrefslogtreecommitdiff
path: root/gcc/diagnostics/paths.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/diagnostics/paths.cc')
-rw-r--r--gcc/diagnostics/paths.cc233
1 files changed, 233 insertions, 0 deletions
diff --git a/gcc/diagnostics/paths.cc b/gcc/diagnostics/paths.cc
new file mode 100644
index 0000000..bc769c4
--- /dev/null
+++ b/gcc/diagnostics/paths.cc
@@ -0,0 +1,233 @@
+/* Paths through the code associated with a diagnostic.
+ Copyright (C) 2019-2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#define INCLUDE_ALGORITHM
+#define INCLUDE_MAP
+#define INCLUDE_STRING
+#define INCLUDE_VECTOR
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic.h"
+#include "diagnostics/paths.h"
+#include "diagnostics/state-graphs.h"
+
+/* Disable warnings about missing quoting in GCC diagnostics for the print
+ calls below. */
+#if __GNUC__ >= 10
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
+
+using namespace diagnostics;
+using namespace diagnostics::paths;
+
+/* class diagnostics::paths::event. */
+
+/* struct event::meaning. */
+
+void
+event::meaning::dump_to_pp (pretty_printer *pp) const
+{
+ bool need_comma = false;
+ pp_character (pp, '{');
+ if (const char *verb_str = maybe_get_verb_str (m_verb))
+ {
+ pp_printf (pp, "verb: %qs", verb_str);
+ need_comma = true;
+ }
+ if (const char *noun_str = maybe_get_noun_str (m_noun))
+ {
+ if (need_comma)
+ pp_string (pp, ", ");
+ pp_printf (pp, "noun: %qs", noun_str);
+ need_comma = true;
+ }
+ if (const char *property_str = maybe_get_property_str (m_property))
+ {
+ if (need_comma)
+ pp_string (pp, ", ");
+ pp_printf (pp, "property: %qs", property_str);
+ need_comma = true;
+ }
+ pp_character (pp, '}');
+}
+
+/* Get a string (or nullptr) for V suitable for use within a SARIF
+ threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
+
+const char *
+event::meaning::maybe_get_verb_str (enum verb v)
+{
+ switch (v)
+ {
+ default:
+ gcc_unreachable ();
+ case verb::unknown:
+ return nullptr;
+ case verb::acquire:
+ return "acquire";
+ case verb::release:
+ return "release";
+ case verb::enter:
+ return "enter";
+ case verb::exit:
+ return "exit";
+ case verb::call:
+ return "call";
+ case verb::return_:
+ return "return";
+ case verb::branch:
+ return "branch";
+ case verb::danger:
+ return "danger";
+ }
+}
+
+/* Get a string (or nullptr) for N suitable for use within a SARIF
+ threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
+
+const char *
+event::meaning::maybe_get_noun_str (enum noun n)
+{
+ switch (n)
+ {
+ default:
+ gcc_unreachable ();
+ case noun::unknown:
+ return nullptr;
+ case noun::taint:
+ return "taint";
+ case noun::sensitive:
+ return "sensitive";
+ case noun::function:
+ return "function";
+ case noun::lock:
+ return "lock";
+ case noun::memory:
+ return "memory";
+ case noun::resource:
+ return "resource";
+ }
+}
+
+/* Get a string (or nullptr) for P suitable for use within a SARIF
+ threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
+
+const char *
+event::meaning::maybe_get_property_str (enum property p)
+{
+ switch (p)
+ {
+ default:
+ gcc_unreachable ();
+ case property::unknown:
+ return nullptr;
+ case property::true_:
+ return "true";
+ case property::false_:
+ return "false";
+ }
+}
+
+/* Generate a label_text containing the description of this event
+ (for debugging/logging purposes). */
+
+label_text
+event::get_desc (pretty_printer &ref_pp) const
+{
+ auto pp = ref_pp.clone ();
+ pp_show_color (pp.get ()) = false;
+ print_desc (*pp.get ());
+ return label_text::take (xstrdup (pp_formatted_text (pp.get ())));
+}
+
+// Base implementation of event::maybe_make_diagnostic_state_graph
+
+std::unique_ptr<digraphs::digraph>
+event::maybe_make_diagnostic_state_graph (bool) const
+{
+ // Don't attempt to make a state graph:
+ return nullptr;
+}
+
+/* class diagnostics::paths::path. */
+
+/* Subroutine of path::interprocedural_p.
+ Look for the first event in this path that is within a function
+ i.e. has a non-null logical location for which function_p is true.
+ If found, write its index to *OUT_IDX and return true.
+ Otherwise return false. */
+
+bool
+path::get_first_event_in_a_function (unsigned *out_idx) const
+{
+ const unsigned num = num_events ();
+ for (unsigned i = 0; i < num; i++)
+ {
+ const event &event = get_event (i);
+ if (logical_locations::key logical_loc = event.get_logical_location ())
+ if (m_logical_loc_mgr.function_p (logical_loc))
+ {
+ *out_idx = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Return true if the events in this path involve more than one
+ function, or false if it is purely intraprocedural. */
+
+bool
+path::interprocedural_p () const
+{
+ /* Ignore leading events that are outside of any function. */
+ unsigned first_fn_event_idx;
+ if (!get_first_event_in_a_function (&first_fn_event_idx))
+ return false;
+
+ const event &first_fn_event = get_event (first_fn_event_idx);
+ int first_fn_stack_depth = first_fn_event.get_stack_depth ();
+
+ const unsigned num = num_events ();
+ for (unsigned i = first_fn_event_idx + 1; i < num; i++)
+ {
+ if (!same_function_p (first_fn_event_idx, i))
+ return true;
+ if (get_event (i).get_stack_depth () != first_fn_stack_depth)
+ return true;
+ }
+ return false;
+}
+
+/* Print PATH by emitting a dummy "note" associated with it. */
+
+DEBUG_FUNCTION
+void debug (path *p)
+{
+ rich_location richloc (line_table, UNKNOWN_LOCATION);
+ richloc.set_path (p);
+ inform (&richloc, "debug path");
+}
+
+#if __GNUC__ >= 10
+# pragma GCC diagnostic pop
+#endif