analyzer: fix feasibility false +ve on jumps through function ptrs [PR107582]
[platform/upstream/gcc.git] / gcc / genhooks.cc
1 /* Process target.def to create initialization macros definition in
2    target-hooks-def.h and documentation in target-hooks.texi.
3    Copyright (C) 2009-2022 Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 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 #include "bconfig.h"
21 #include "system.h"
22 #include "errors.h"
23
24 struct hook_desc { const char *doc, *type, *name, *param, *init, *docname; };
25 static struct hook_desc hook_array[] = {
26 #define HOOK_VECTOR_1(NAME, FRAGMENT)   \
27   { 0, 0, #NAME, 0, 0, HOOK_TYPE },
28 #define DEFHOOKPOD(NAME, DOC, TYPE, INIT) \
29   { DOC, #TYPE, HOOK_PREFIX #NAME, 0, #INIT, HOOK_TYPE },
30 #define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) \
31   { DOC, #TYPE, HOOK_PREFIX #NAME, #PARAMS, #INIT, HOOK_TYPE },
32 #define DEFHOOK_UNDOC(NAME, DOC, TYPE, PARAMS, INIT) \
33   { "*", #TYPE, HOOK_PREFIX #NAME, #PARAMS, #INIT, HOOK_TYPE },
34 #include "target.def"
35 #include "c-family/c-target.def"
36 #include "common/common-target.def"
37 #include "d/d-target.def"
38 #undef DEFHOOK
39 };
40
41 /* Return an upper-case copy of IN.  */
42 static char *
43 upstrdup (const char *in)
44 {
45   char *p, *ret = xstrdup (in);
46   for (p = ret; *p; p++)
47     *p = TOUPPER (*p);
48   return ret;
49 }
50
51 /* Struct for 'start hooks' which start a sequence of consecutive hooks
52    that are defined in target.def and to be documented in tm.texi.  */
53 struct s_hook
54 {
55   char *name;
56   int pos;
57 };
58
59 static hashval_t
60 s_hook_hash (const void *p)
61 {
62   const struct s_hook *s_hook = (const struct s_hook *)p;
63   return htab_hash_string (s_hook->name);
64 }
65
66 static int
67 s_hook_eq_p (const void *p1, const void *p2)
68 {
69   return (strcmp (((const struct s_hook *) p1)->name, 
70                   ((const struct s_hook *) p2)->name) == 0);
71 }
72
73 /* Read the documentation file with name IN_FNAME, perform substitutions
74    to incorporate information from hook_array, and emit the result on stdout.
75    Hooks defined with DEFHOOK / DEFHOOKPOD are emitted at the place of a
76    matching @hook in the input file; if there is no matching @hook, the
77    hook is emitted after the hook that precedes it in target.def .
78    Usually, the emitted hook documentation starts with the hook
79    signature, followed by the string from the doc field.
80    The documentation is bracketed in @deftypefn / @deftypevr and a matching
81    @end.
82    While emitting the doc field, an @findex entry is added
83    to the affected paragraph.
84    If the doc field starts with '*', the leading '*' is stripped, and the doc
85    field is otherwise emitted unaltered; no function signature/
86    @deftypefn/deftypevr/@end is emitted.
87    In particular, a doc field of "*" means not to emit any ocumentation for
88    this target.def / hook_array entry at all (there might be documentation
89    for this hook in the file named IN_FNAME, though).
90    A doc field of 0 is used to append the hook signature after the previous
91    hook's signture, so that one description can be used for a group of hooks.
92    When the doc field is "", @deftypefn/@deftypevr and the hook signature
93    is emitted, but not the matching @end.  This allows all the free-form
94    documentation to be placed in IN_FNAME, to work around GPL/GFDL
95    licensing incompatibility issues.  */
96 static void
97 emit_documentation (const char *in_fname)
98 {
99   int i, j;
100   char buf[1000];
101   htab_t start_hooks = htab_create (99, s_hook_hash, s_hook_eq_p, (htab_del) 0);
102   FILE *f;
103
104   /* Enter all the start hooks in start_hooks.  */
105   f = fopen (in_fname, "r");
106   if (!f)
107     {
108       perror ("");
109       fatal ("Couldn't open input file");
110     }
111   while (fscanf (f, "%*[^@]"), buf[0] = '\0',
112          fscanf (f, "@%5[^ \n]", buf) != EOF)
113     {
114       void **p;
115       struct s_hook *shp;
116
117       if (strcmp (buf, "hook") != 0)
118         continue;
119       buf[0] = '\0';
120       fscanf (f, "%999s", buf);
121       shp = XNEW (struct s_hook);
122       shp->name = upstrdup (buf);
123       shp->pos = -1;
124       p = htab_find_slot (start_hooks, shp, INSERT);
125       if (*p != HTAB_EMPTY_ENTRY)
126         fatal ("Duplicate placement for hook %s\n", shp->name);
127       *(struct s_hook **) p = shp;
128     }
129   fclose (f);
130   /* For each hook in hook_array, if it is a start hook, store its position.  */
131   for (i = 0; i < (int) (ARRAY_SIZE (hook_array)); i++)
132     {
133       struct s_hook sh, *shp;
134       void *p;
135
136       if (!hook_array[i].doc || strcmp (hook_array[i].doc, "*") == 0)
137         continue;
138       sh.name = upstrdup (hook_array[i].name);
139       p = htab_find (start_hooks, &sh);
140       if (p)
141         {
142           shp = (struct s_hook *) p;
143           if (shp->pos >= 0)
144             fatal ("Duplicate hook %s\n", sh.name);
145           shp->pos = i;
146         }
147       else
148         fatal ("No place specified to document hook %s\n", sh.name);
149       free (sh.name);
150     }
151   /* Copy input file to stdout, substituting @hook directives with the
152      corresponding hook documentation sequences.  */
153   f = fopen (in_fname, "r");
154   if (!f)
155     {
156       perror ("");
157       fatal ("Couldn't open input file");
158     }
159   for (;;)
160     {
161       struct s_hook sh, *shp;
162       int c = getc (f);
163       char *name;
164
165       if (c == EOF)
166         break;
167       if (c != '@')
168         {
169           putchar (c);
170           continue;
171         }
172       buf[0] = '\0';
173       fscanf (f, "%5[^ \n]", buf);
174       if (strcmp (buf, "hook") != 0)
175         {
176           printf ("@%s", buf);
177           continue;
178         }
179       fscanf (f, "%999s", buf);
180       sh.name = name = upstrdup (buf);
181       shp = (struct s_hook *) htab_find (start_hooks, &sh);
182       if (!shp || shp->pos < 0)
183         fatal ("No documentation for hook %s\n", sh.name);
184       i = shp->pos;
185       do
186         {
187           const char *q, *e;
188           const char *deftype;
189           const char *doc, *p_end;
190
191           /* A leading '*' means to output the documentation string without
192              further processing.  */
193           if (*hook_array[i].doc == '*')
194             printf ("%s", hook_array[i].doc + 1);
195           else
196             {
197               if (i != shp->pos)
198                 printf ("\n\n");
199
200               /* Print header.  Function-valued hooks have a parameter list, 
201                  unlike POD-valued ones.  */
202               deftype = hook_array[i].param ? "deftypefn" : "deftypevr";
203               printf ("@%s {%s} ", deftype, hook_array[i].docname);
204               if (strchr (hook_array[i].type, ' '))
205                 printf ("{%s}", hook_array[i].type);
206               else
207                 printf ("%s", hook_array[i].type);
208               printf (" %s", name);
209               if (hook_array[i].param)
210                 {
211                   /* Print the parameter list, with the parameter names
212                      enclosed in @var{}.  */
213                   printf (" ");
214                   for (q = hook_array[i].param; (e = strpbrk (q, " *,)"));
215                        q = e + 1)
216                     /* Type names like 'int' are followed by a space, sometimes
217                        also by '*'.  'void' should appear only in "(void)".  */
218                     if (*e == ' ' || *e == '*' || *q == '(')
219                       printf ("%.*s", (int) (e - q + 1), q);
220                     else
221                       printf ("@var{%.*s}%c", (int) (e - q), q, *e);
222                 }
223               /* POD-valued hooks sometimes come in groups with common
224                  documentation.*/
225               for (j = i + 1;
226                    j < (int) (ARRAY_SIZE (hook_array))
227                    && hook_array[j].doc == 0 && hook_array[j].type; j++)
228                 {
229                   char *namex = upstrdup (hook_array[j].name);
230
231                   printf ("\n@%sx {%s} {%s} %s",
232                           deftype, hook_array[j].docname,
233                           hook_array[j].type, namex);
234                 }
235               if (hook_array[i].doc[0])
236                 {
237                   printf ("\n");
238                   /* Print each documentation paragraph in turn.  */
239                   for (doc = hook_array[i].doc; *doc; doc = p_end)
240                     {
241                       /* Find paragraph end.  */
242                       p_end = strstr (doc, "\n\n");
243                       p_end = (p_end ? p_end + 2 : doc + strlen (doc));
244                       printf ("%.*s", (int) (p_end - doc), doc);
245                     }
246                   printf ("\n@end %s", deftype);
247                 }
248             }
249           if (++i >= (int) (ARRAY_SIZE (hook_array)) || !hook_array[i].doc)
250             break;
251           free (name);
252           sh.name = name = upstrdup (hook_array[i].name);
253         }
254       while (!htab_find (start_hooks, &sh));
255       free (name);
256     }
257 }
258
259 /* Emit #defines to stdout (this will be redirected to generate
260    target-hook-def.h) which set target hooks initializer macros
261    to their default values.  These should only be emitted for hooks
262    whose type is given by DOCNAME.  */
263 static void
264 emit_init_macros (const char *docname)
265 {
266   int i;
267   const int MAX_NEST = 2;
268   int print_nest, nest = 0;
269
270   for (print_nest = 0; print_nest <= MAX_NEST; print_nest++)
271     {
272       for (i = 0; i < (int) (ARRAY_SIZE (hook_array)); i++)
273         {
274           char *name = upstrdup (hook_array[i].name);
275
276           if (strcmp (hook_array[i].docname, docname) != 0)
277             continue;
278
279           if (!hook_array[i].type)
280             {
281               if (*name)
282                 {
283                   if (nest && nest == print_nest)
284                     printf ("    %s, \\\n", name);
285                   nest++;
286                   if (nest > MAX_NEST)
287                     fatal ("Unexpected nesting of %s\n", name);
288                   if (nest == print_nest)
289                     printf ("\n#define %s \\\n  { \\\n", name);
290                 }
291               else
292                 {
293                   if (nest == print_nest)
294                     printf ("  }\n");
295                   nest--;
296                 }
297               continue;
298             }
299           if (print_nest == 0)
300             {
301               /* Output default definitions of target hooks.  */
302               printf ("#ifndef %s\n#define %s %s\n#endif\n",
303                       name, name, hook_array[i].init);
304             }
305           if (nest == print_nest)
306             printf ("    %s, \\\n", name);
307         }
308     }
309 }
310
311 int
312 main (int argc, char **argv)
313 {
314   progname = "genhooks";
315
316   if (argc >= 3)
317     emit_documentation (argv[2]);
318   else
319     emit_init_macros (argv[1]);
320   return 0;
321 }