1/* Utility functions for the analyzer. 2 Copyright (C) 2019-2020 Free Software Foundation, Inc. 3 Contributed by David Malcolm <dmalcolm@redhat.com>. 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify it 8under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 3, or (at your option) 10any later version. 11 12GCC is distributed in the hope that it will be useful, but 13WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along 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 44bool 45is_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 62bool 63is_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 93static inline bool 94is_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 114bool 115is_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 136bool 137is_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 154bool 155is_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 172bool 173is_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 184bool 185is_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 198const char * 199get_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 228label_text 229make_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