Line data Source code
1 : /* Interface between analyzer and frontends.
2 : Copyright (C) 2022-2026 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
8 : under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3, or (at your option)
10 : any later version.
11 :
12 : GCC is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : General Public License 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 "analyzer/common.h"
22 :
23 : #include "diagnostic.h"
24 : #include "stringpool.h"
25 : #include "context.h"
26 : #include "channels.h"
27 :
28 : #include "analyzer/analyzer-language.h"
29 : #include "analyzer/analyzer-logging.h"
30 :
31 : /* Map from identifier to INTEGER_CST. */
32 : static GTY (()) hash_map <tree, tree> *analyzer_stashed_constants;
33 :
34 : #if ENABLE_ANALYZER
35 :
36 : namespace ana {
37 :
38 : /* Call into TU to try to find a value for NAME.
39 : If found, stash its value within analyzer_stashed_constants. */
40 :
41 : static void
42 17100 : maybe_stash_named_constant (logger *logger,
43 : const translation_unit &tu,
44 : const char *name)
45 : {
46 17100 : LOG_FUNC_1 (logger, "name: %qs", name);
47 :
48 17100 : if (!analyzer_stashed_constants)
49 3420 : analyzer_stashed_constants = hash_map<tree, tree>::create_ggc ();
50 :
51 17100 : tree id = get_identifier (name);
52 17100 : if (tree t = tu.lookup_constant_by_id (id))
53 : {
54 78 : gcc_assert (TREE_CODE (t) == INTEGER_CST);
55 78 : analyzer_stashed_constants->put (id, t);
56 78 : if (logger)
57 0 : logger->log ("%qs: %qE", name, t);
58 : }
59 : else
60 : {
61 17022 : if (logger)
62 25 : logger->log ("%qs: not found", name);
63 : }
64 17100 : }
65 :
66 : /* Call into TU to try to find values for the names we care about.
67 : If found, stash their values within analyzer_stashed_constants. */
68 :
69 : static void
70 3420 : stash_named_constants (logger *logger, const translation_unit &tu)
71 : {
72 3420 : LOG_SCOPE (logger);
73 :
74 : /* Stash named constants for use by sm-fd.cc */
75 3420 : maybe_stash_named_constant (logger, tu, "O_ACCMODE");
76 3420 : maybe_stash_named_constant (logger, tu, "O_RDONLY");
77 3420 : maybe_stash_named_constant (logger, tu, "O_WRONLY");
78 3420 : maybe_stash_named_constant (logger, tu, "SOCK_STREAM");
79 3420 : maybe_stash_named_constant (logger, tu, "SOCK_DGRAM");
80 3420 : }
81 :
82 : /* Hook for frontend to call into analyzer when TU finishes.
83 : This exists so that the analyzer can stash named constant values from
84 : header files (e.g. macros and enums) for later use when modeling the
85 : behaviors of APIs.
86 :
87 : By doing it this way, the analyzer can use the precise values for those
88 : constants from the user's headers, rather than attempting to model them
89 : as properties of the target. */
90 :
91 : void
92 3420 : on_finish_translation_unit (const translation_unit &tu)
93 : {
94 : /* Bail if the analyzer isn't enabled. */
95 3420 : if (!flag_analyzer)
96 0 : return;
97 :
98 3420 : FILE *logfile = get_or_create_any_logfile ();
99 3420 : log_user the_logger (nullptr);
100 3420 : if (logfile)
101 5 : the_logger.set_logger (new logger (logfile, 0, 0,
102 5 : *global_dc->get_reference_printer ()));
103 3420 : stash_named_constants (the_logger.get_logger (), tu);
104 :
105 3420 : if (auto chan = g->get_channels ().analyzer_events_channel.get_if_active ())
106 : {
107 38 : gcc::topics::analyzer_events::on_tu_finished msg {the_logger.get_logger (),
108 38 : tu};
109 38 : chan->publish (msg);
110 : }
111 3420 : }
112 :
113 : /* Lookup NAME in the named constants stashed when the frontend TU finished.
114 : Return either an INTEGER_CST, or NULL_TREE. */
115 :
116 : tree
117 16979 : get_stashed_constant_by_name (const char *name)
118 : {
119 16979 : if (!analyzer_stashed_constants)
120 : return NULL_TREE;
121 16854 : tree id = get_identifier (name);
122 16854 : if (tree *slot = analyzer_stashed_constants->get (id))
123 : {
124 97 : gcc_assert (TREE_CODE (*slot) == INTEGER_CST);
125 : return *slot;
126 : }
127 : return NULL_TREE;
128 : }
129 :
130 : /* Log all stashed named constants to LOGGER. */
131 :
132 : void
133 5 : log_stashed_constants (logger *logger)
134 : {
135 5 : gcc_assert (logger);
136 5 : LOG_SCOPE (logger);
137 5 : if (analyzer_stashed_constants)
138 10 : for (auto iter : *analyzer_stashed_constants)
139 0 : logger->log ("%qE: %qE", iter.first, iter.second);
140 5 : }
141 :
142 : } // namespace ana
143 :
144 : #endif /* #if ENABLE_ANALYZER */
145 :
146 : #include "gt-analyzer-language.h"
|