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