1 /* Utility functions for the analyzer.
2 Copyright (C) 2019-2020 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 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "function.h"
26 #include "basic-block.h"
27 #include "gimple.h"
28 #include "diagnostic.h"
29 #include "intl.h"
30 #include "function.h"
31 #include "analyzer/analyzer.h"
32
33 #if ENABLE_ANALYZER
34
35 /* Helper function for checkers. Is the CALL to the given function name,
36 and with the given number of arguments?
37
38 This doesn't resolve function pointers via the region model;
39 is_named_call_p should be used instead, using a fndecl from
40 get_fndecl_for_call; this function should only be used for special cases
41 where it's not practical to get at the region model, or for special
42 analyzer functions such as __analyzer_dump. */
43
44 bool
is_special_named_call_p(const gcall * call,const char * funcname,unsigned int num_args)45 is_special_named_call_p (const gcall *call, const char *funcname,
46 unsigned int num_args)
47 {
48 gcc_assert (funcname);
49
50 tree fndecl = gimple_call_fndecl (call);
51 if (!fndecl)
52 return false;
53
54 return is_named_call_p (fndecl, funcname, call, num_args);
55 }
56
57 /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
58 that has the given FUNCNAME?
59
60 Compare with special_function_p in calls.c. */
61
62 bool
is_named_call_p(tree fndecl,const char * funcname)63 is_named_call_p (tree fndecl, const char *funcname)
64 {
65 gcc_assert (fndecl);
66 gcc_assert (funcname);
67
68 if (!maybe_special_function_p (fndecl))
69 return false;
70
71 tree identifier = DECL_NAME (fndecl);
72 const char *name = IDENTIFIER_POINTER (identifier);
73 const char *tname = name;
74
75 /* Potentially disregard prefix _ or __ in FNDECL's name, but not if
76 FUNCNAME itself has leading underscores (e.g. when looking for
77 "__analyzer_eval"). */
78 if (funcname[0] != '_' && name[0] == '_')
79 {
80 if (name[1] == '_')
81 tname += 2;
82 else
83 tname += 1;
84 }
85
86 return 0 == strcmp (tname, funcname);
87 }
88
89 /* Return true if FNDECL is within the namespace "std".
90 Compare with cp/typeck.c: decl_in_std_namespace_p, but this doesn't
91 rely on being the C++ FE (or handle inline namespaces inside of std). */
92
93 static inline bool
is_std_function_p(const_tree fndecl)94 is_std_function_p (const_tree fndecl)
95 {
96 tree name_decl = DECL_NAME (fndecl);
97 if (!name_decl)
98 return false;
99 if (!DECL_CONTEXT (fndecl))
100 return false;
101 if (TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
102 return false;
103 tree ns = DECL_CONTEXT (fndecl);
104 if (!(DECL_CONTEXT (ns) == NULL_TREE
105 || TREE_CODE (DECL_CONTEXT (ns)) == TRANSLATION_UNIT_DECL))
106 return false;
107 if (!DECL_NAME (ns))
108 return false;
109 return id_equal ("std", DECL_NAME (ns));
110 }
111
112 /* Like is_named_call_p, but look for std::FUNCNAME. */
113
114 bool
is_std_named_call_p(tree fndecl,const char * funcname)115 is_std_named_call_p (tree fndecl, const char *funcname)
116 {
117 gcc_assert (fndecl);
118 gcc_assert (funcname);
119
120 if (!is_std_function_p (fndecl))
121 return false;
122
123 tree identifier = DECL_NAME (fndecl);
124 const char *name = IDENTIFIER_POINTER (identifier);
125 const char *tname = name;
126
127 /* Don't disregard prefix _ or __ in FNDECL's name. */
128
129 return 0 == strcmp (tname, funcname);
130 }
131
132 /* Helper function for checkers. Is FNDECL an extern fndecl at file scope
133 that has the given FUNCNAME, and does CALL have the given number of
134 arguments? */
135
136 bool
is_named_call_p(tree fndecl,const char * funcname,const gcall * call,unsigned int num_args)137 is_named_call_p (tree fndecl, const char *funcname,
138 const gcall *call, unsigned int num_args)
139 {
140 gcc_assert (fndecl);
141 gcc_assert (funcname);
142
143 if (!is_named_call_p (fndecl, funcname))
144 return false;
145
146 if (gimple_call_num_args (call) != num_args)
147 return false;
148
149 return true;
150 }
151
152 /* Like is_named_call_p, but check for std::FUNCNAME. */
153
154 bool
is_std_named_call_p(tree fndecl,const char * funcname,const gcall * call,unsigned int num_args)155 is_std_named_call_p (tree fndecl, const char *funcname,
156 const gcall *call, unsigned int num_args)
157 {
158 gcc_assert (fndecl);
159 gcc_assert (funcname);
160
161 if (!is_std_named_call_p (fndecl, funcname))
162 return false;
163
164 if (gimple_call_num_args (call) != num_args)
165 return false;
166
167 return true;
168 }
169
170 /* Return true if stmt is a setjmp or sigsetjmp call. */
171
172 bool
is_setjmp_call_p(const gcall * call)173 is_setjmp_call_p (const gcall *call)
174 {
175 if (is_special_named_call_p (call, "setjmp", 1)
176 || is_special_named_call_p (call, "sigsetjmp", 2))
177 return true;
178
179 return false;
180 }
181
182 /* Return true if stmt is a longjmp or siglongjmp call. */
183
184 bool
is_longjmp_call_p(const gcall * call)185 is_longjmp_call_p (const gcall *call)
186 {
187 if (is_special_named_call_p (call, "longjmp", 2)
188 || is_special_named_call_p (call, "siglongjmp", 2))
189 return true;
190
191 return false;
192 }
193
194 /* For a CALL that matched is_special_named_call_p or is_named_call_p for
195 some name, return a name for the called function suitable for use in
196 diagnostics (stripping the leading underscores). */
197
198 const char *
get_user_facing_name(const gcall * call)199 get_user_facing_name (const gcall *call)
200 {
201 tree fndecl = gimple_call_fndecl (call);
202 gcc_assert (fndecl);
203
204 tree identifier = DECL_NAME (fndecl);
205 gcc_assert (identifier);
206
207 const char *name = IDENTIFIER_POINTER (identifier);
208
209 /* Strip prefix _ or __ in FNDECL's name. */
210 if (name[0] == '_')
211 {
212 if (name[1] == '_')
213 return name + 2;
214 else
215 return name + 1;
216 }
217
218 return name;
219 }
220
221 /* Generate a label_text instance by formatting FMT, using a
222 temporary clone of the global_dc's printer (thus using its
223 formatting callbacks).
224
225 Colorize if the global_dc supports colorization and CAN_COLORIZE is
226 true. */
227
228 label_text
make_label_text(bool can_colorize,const char * fmt,...)229 make_label_text (bool can_colorize, const char *fmt, ...)
230 {
231 pretty_printer *pp = global_dc->printer->clone ();
232 pp_clear_output_area (pp);
233
234 if (!can_colorize)
235 pp_show_color (pp) = false;
236
237 text_info ti;
238 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
239
240 va_list ap;
241
242 va_start (ap, fmt);
243
244 ti.format_spec = _(fmt);
245 ti.args_ptr = ≈
246 ti.err_no = 0;
247 ti.x_data = NULL;
248 ti.m_richloc = &rich_loc;
249
250 pp_format (pp, &ti);
251 pp_output_formatted_text (pp);
252
253 va_end (ap);
254
255 label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
256 delete pp;
257 return result;
258 }
259
260 #endif /* #if ENABLE_ANALYZER */
261