1 | /* Interface between analyzer and frontends. |
2 | Copyright (C) 2022-2024 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 "config.h" |
22 | #define INCLUDE_MEMORY |
23 | #include "system.h" |
24 | #include "coretypes.h" |
25 | #include "tree.h" |
26 | #include "stringpool.h" |
27 | #include "analyzer/analyzer.h" |
28 | #include "analyzer/analyzer-language.h" |
29 | #include "analyzer/analyzer-logging.h" |
30 | #include "diagnostic.h" |
31 | |
32 | /* Map from identifier to INTEGER_CST. */ |
33 | static GTY (()) hash_map <tree, tree> *analyzer_stashed_constants; |
34 | |
35 | #if ENABLE_ANALYZER |
36 | |
37 | namespace ana { |
38 | static vec<finish_translation_unit_callback> |
39 | *finish_translation_unit_callbacks; |
40 | |
41 | void |
42 | register_finish_translation_unit_callback ( |
43 | finish_translation_unit_callback callback) |
44 | { |
45 | if (!finish_translation_unit_callbacks) |
46 | vec_alloc (v&: finish_translation_unit_callbacks, nelems: 1); |
47 | finish_translation_unit_callbacks->safe_push (obj: callback); |
48 | } |
49 | |
50 | static void |
51 | run_callbacks (logger *logger, const translation_unit &tu) |
52 | { |
53 | for (auto const &cb : finish_translation_unit_callbacks) |
54 | { |
55 | cb (logger, tu); |
56 | } |
57 | } |
58 | |
59 | /* Call into TU to try to find a value for NAME. |
60 | If found, stash its value within analyzer_stashed_constants. */ |
61 | |
62 | static void |
63 | maybe_stash_named_constant (logger *logger, |
64 | const translation_unit &tu, |
65 | const char *name) |
66 | { |
67 | LOG_FUNC_1 (logger, "name: %qs" , name); |
68 | |
69 | if (!analyzer_stashed_constants) |
70 | analyzer_stashed_constants = hash_map<tree, tree>::create_ggc (); |
71 | |
72 | tree id = get_identifier (name); |
73 | if (tree t = tu.lookup_constant_by_id (id)) |
74 | { |
75 | gcc_assert (TREE_CODE (t) == INTEGER_CST); |
76 | analyzer_stashed_constants->put (k: id, v: t); |
77 | if (logger) |
78 | logger->log (fmt: "%qs: %qE" , name, t); |
79 | } |
80 | else |
81 | { |
82 | if (logger) |
83 | logger->log (fmt: "%qs: not found" , name); |
84 | } |
85 | } |
86 | |
87 | /* Call into TU to try to find values for the names we care about. |
88 | If found, stash their values within analyzer_stashed_constants. */ |
89 | |
90 | static void |
91 | stash_named_constants (logger *logger, const translation_unit &tu) |
92 | { |
93 | LOG_SCOPE (logger); |
94 | |
95 | /* Stash named constants for use by sm-fd.cc */ |
96 | maybe_stash_named_constant (logger, tu, name: "O_ACCMODE" ); |
97 | maybe_stash_named_constant (logger, tu, name: "O_RDONLY" ); |
98 | maybe_stash_named_constant (logger, tu, name: "O_WRONLY" ); |
99 | maybe_stash_named_constant (logger, tu, name: "SOCK_STREAM" ); |
100 | maybe_stash_named_constant (logger, tu, name: "SOCK_DGRAM" ); |
101 | } |
102 | |
103 | /* Hook for frontend to call into analyzer when TU finishes. |
104 | This exists so that the analyzer can stash named constant values from |
105 | header files (e.g. macros and enums) for later use when modeling the |
106 | behaviors of APIs. |
107 | |
108 | By doing it this way, the analyzer can use the precise values for those |
109 | constants from the user's headers, rather than attempting to model them |
110 | as properties of the target. */ |
111 | |
112 | void |
113 | on_finish_translation_unit (const translation_unit &tu) |
114 | { |
115 | /* Bail if the analyzer isn't enabled. */ |
116 | if (!flag_analyzer) |
117 | return; |
118 | |
119 | FILE *logfile = get_or_create_any_logfile (); |
120 | log_user the_logger (NULL); |
121 | if (logfile) |
122 | the_logger.set_logger (new logger (logfile, 0, 0, |
123 | *global_dc->printer)); |
124 | stash_named_constants (logger: the_logger.get_logger (), tu); |
125 | |
126 | run_callbacks (logger: the_logger.get_logger (), tu); |
127 | } |
128 | |
129 | /* Lookup NAME in the named constants stashed when the frontend TU finished. |
130 | Return either an INTEGER_CST, or NULL_TREE. */ |
131 | |
132 | tree |
133 | get_stashed_constant_by_name (const char *name) |
134 | { |
135 | if (!analyzer_stashed_constants) |
136 | return NULL_TREE; |
137 | tree id = get_identifier (name); |
138 | if (tree *slot = analyzer_stashed_constants->get (k: id)) |
139 | { |
140 | gcc_assert (TREE_CODE (*slot) == INTEGER_CST); |
141 | return *slot; |
142 | } |
143 | return NULL_TREE; |
144 | } |
145 | |
146 | /* Log all stashed named constants to LOGGER. */ |
147 | |
148 | void |
149 | log_stashed_constants (logger *logger) |
150 | { |
151 | gcc_assert (logger); |
152 | LOG_SCOPE (logger); |
153 | if (analyzer_stashed_constants) |
154 | for (auto iter : *analyzer_stashed_constants) |
155 | logger->log (fmt: "%qE: %qE" , iter.first, iter.second); |
156 | } |
157 | |
158 | } // namespace ana |
159 | |
160 | #endif /* #if ENABLE_ANALYZER */ |
161 | |
162 | #include "gt-analyzer-language.h" |
163 | |