File: | build/gcc/lto/lto-dump.cc |
Warning: | line 158, column 3 Potential leak of memory pointed to by 'e' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Functions for LTO dump tool. | |||
2 | Copyright (C) 2018-2023 Free Software Foundation, Inc. | |||
3 | ||||
4 | This file is part of GCC. | |||
5 | ||||
6 | GCC is free software; you can redistribute it and/or modify it under | |||
7 | the terms of the GNU General Public License as published by the Free | |||
8 | Software Foundation; either version 3, or (at your option) any later | |||
9 | version. | |||
10 | ||||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
14 | for more details. | |||
15 | ||||
16 | You should have received a copy of the GNU General Public License | |||
17 | along with GCC; see the file COPYING3. If not see | |||
18 | <http://www.gnu.org/licenses/>. */ | |||
19 | ||||
20 | #include "config.h" | |||
21 | #include "system.h" | |||
22 | #include "coretypes.h" | |||
23 | #include "tm.h" | |||
24 | #include "function.h" | |||
25 | #include "basic-block.h" | |||
26 | #include "tree.h" | |||
27 | #include "gimple.h" | |||
28 | #include "cfg.h" | |||
29 | #include "tree-cfg.h" | |||
30 | #include "tree-pass.h" | |||
31 | #include "tree-streamer.h" | |||
32 | #include "cgraph.h" | |||
33 | #include "opts.h" | |||
34 | #include "debug.h" | |||
35 | #include "lto-partition.h" | |||
36 | #include "tree-pretty-print.h" | |||
37 | #include "lto-common.h" | |||
38 | ||||
39 | /* Stores details of symbols for dumping symbol list. */ | |||
40 | ||||
41 | class symbol_entry | |||
42 | { | |||
43 | public: | |||
44 | symtab_node *node; | |||
45 | symbol_entry (symtab_node *node_): node (node_) | |||
46 | {} | |||
47 | ||||
48 | virtual ~symbol_entry () | |||
49 | {} | |||
50 | ||||
51 | char* get_name () const | |||
52 | { | |||
53 | if (flag_lto_dump_demangleglobal_options.x_flag_lto_dump_demangle) | |||
54 | return xstrdup (node->name ()); | |||
55 | else | |||
56 | return xstrdup (node->asm_name ()); | |||
57 | } | |||
58 | ||||
59 | virtual size_t get_size () const = 0; | |||
60 | ||||
61 | virtual void dump () | |||
62 | { | |||
63 | const char *name = get_name (); | |||
64 | const char *type_name = node->get_symtab_type_string (); | |||
65 | const char *visibility = node->get_visibility_string (); | |||
66 | size_t sz = get_size (); | |||
67 | printf ("%s %s %4" PRIu64"l" "u" " %s ", type_name, visibility, (uint64_t) sz, | |||
68 | name); | |||
69 | } | |||
70 | }; | |||
71 | ||||
72 | /* Stores variable specific details of symbols for dumping symbol list. */ | |||
73 | ||||
74 | class variable_entry: public symbol_entry | |||
75 | { | |||
76 | public: | |||
77 | variable_entry (varpool_node *node_): symbol_entry (node_) | |||
78 | {} | |||
79 | ||||
80 | virtual ~variable_entry () | |||
81 | {} | |||
82 | ||||
83 | size_t get_size () const final override | |||
84 | { | |||
85 | varpool_node *vnode = dyn_cast<varpool_node *> (node); | |||
86 | if (DECL_SIZE (vnode->decl)((contains_struct_check ((vnode->decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/lto/lto-dump.cc" , 86, __FUNCTION__))->decl_common.size) && tree_fits_shwi_p (DECL_SIZE (vnode->decl)((contains_struct_check ((vnode->decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/lto/lto-dump.cc" , 86, __FUNCTION__))->decl_common.size))) | |||
87 | return tree_to_shwi (DECL_SIZE (vnode->decl)((contains_struct_check ((vnode->decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/lto/lto-dump.cc" , 87, __FUNCTION__))->decl_common.size)); | |||
88 | return 0; | |||
89 | } | |||
90 | ||||
91 | void dump () final override | |||
92 | { | |||
93 | symbol_entry :: dump (); | |||
94 | varpool_node *vnode = dyn_cast<varpool_node *> (node); | |||
95 | vnode->get_constructor (); | |||
96 | tree value_tree = DECL_INITIAL (vnode->decl)((contains_struct_check ((vnode->decl), (TS_DECL_COMMON), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/lto/lto-dump.cc" , 96, __FUNCTION__))->decl_common.initial); | |||
97 | if (flag_lto_print_valueglobal_options.x_flag_lto_print_value && value_tree) | |||
98 | print_generic_expr (stdoutstdout, value_tree, TDF_NONE); | |||
99 | printf ("\n"); | |||
100 | } | |||
101 | }; | |||
102 | ||||
103 | /* Stores function specific details of symbols for dumping symbol list. */ | |||
104 | ||||
105 | class function_entry: public symbol_entry | |||
106 | { | |||
107 | public: | |||
108 | function_entry (cgraph_node *node_): symbol_entry (node_) | |||
109 | {} | |||
110 | ||||
111 | virtual ~function_entry () | |||
112 | {} | |||
113 | ||||
114 | void dump () final override | |||
115 | { | |||
116 | symbol_entry :: dump (); | |||
117 | printf ("\n"); | |||
118 | } | |||
119 | ||||
120 | size_t get_size () const final override | |||
121 | { | |||
122 | cgraph_node *cnode = dyn_cast<cgraph_node *> (node); | |||
123 | gcc_assert (cnode)((void)(!(cnode) ? fancy_abort ("/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/lto/lto-dump.cc" , 123, __FUNCTION__), 0 : 0)); | |||
124 | ||||
125 | return (cnode->definition && !cnode->thunk && !cnode->alias) | |||
126 | ? n_basic_blocks_for_fn (DECL_STRUCT_FUNCTION (cnode->decl))((((tree_check ((cnode->decl), "/buildworker/marxinbox-gcc-clang-static-analyzer/build/gcc/lto/lto-dump.cc" , 126, __FUNCTION__, (FUNCTION_DECL)))->function_decl.f))-> cfg->x_n_basic_blocks) | |||
127 | : 0; | |||
128 | } | |||
129 | }; | |||
130 | ||||
131 | /* Comparing symbols based on size. */ | |||
132 | ||||
133 | int size_compare (const void *a, const void *b) | |||
134 | { | |||
135 | const symbol_entry *e1 = *(const symbol_entry * const*) a; | |||
136 | const symbol_entry *e2 = *(const symbol_entry * const*) b; | |||
137 | ||||
138 | return e1->get_size () - e2->get_size (); | |||
139 | } | |||
140 | ||||
141 | /* Comparing symbols based on name. */ | |||
142 | ||||
143 | int name_compare (const void *a, const void *b) | |||
144 | { | |||
145 | const symbol_entry *e1 = *(const symbol_entry * const*) a; | |||
146 | const symbol_entry *e2 = *(const symbol_entry * const*) b; | |||
147 | ||||
148 | return strcmp (e1->get_name (), e2->get_name ()); | |||
149 | } | |||
150 | ||||
151 | /* Dump list of functions and their details. */ | |||
152 | ||||
153 | void dump_list_functions (void) | |||
154 | { | |||
155 | auto_vec<symbol_entry *> v; | |||
156 | ||||
157 | cgraph_node *cnode; | |||
158 | FOR_EACH_FUNCTION (cnode)for ((cnode) = symtab->first_function (); (cnode); (cnode) = symtab->next_function ((cnode))) | |||
| ||||
159 | { | |||
160 | if (cnode->definition && !cnode->alias) | |||
161 | cnode->get_untransformed_body (); | |||
162 | symbol_entry *e = new function_entry (cnode); | |||
163 | if (!flag_lto_dump_definedglobal_options.x_flag_lto_dump_defined || (cnode->definition
| |||
164 | v.safe_push (e); | |||
165 | } | |||
166 | ||||
167 | if (flag_lto_size_sortglobal_options.x_flag_lto_size_sort) | |||
168 | v.qsort (size_compare)qsort (size_compare); | |||
169 | else if (flag_lto_name_sortglobal_options.x_flag_lto_name_sort) | |||
170 | v.qsort (name_compare)qsort (name_compare); | |||
171 | if (flag_lto_reverse_sortglobal_options.x_flag_lto_reverse_sort) | |||
172 | v.reverse (); | |||
173 | ||||
174 | printf ("Type Visibility Size Name"); | |||
175 | if (flag_lto_print_valueglobal_options.x_flag_lto_print_value) | |||
176 | printf (" Value"); | |||
177 | printf ("\n"); | |||
178 | int i=0; | |||
179 | symbol_entry* e; | |||
180 | FOR_EACH_VEC_ELT (v, i, e)for (i = 0; (v).iterate ((i), &(e)); ++(i)) | |||
181 | { | |||
182 | e->dump (); | |||
183 | delete e; | |||
184 | } | |||
185 | } | |||
186 | ||||
187 | /* Dump list of variables and their details. */ | |||
188 | ||||
189 | void dump_list_variables (void) | |||
190 | { | |||
191 | auto_vec<symbol_entry *> v; | |||
192 | ||||
193 | varpool_node *vnode; | |||
194 | FOR_EACH_VARIABLE (vnode)for ((vnode) = symtab->first_variable (); (vnode); (vnode) = symtab->next_variable ((vnode))) | |||
195 | { | |||
196 | symbol_entry *e = new variable_entry (vnode); | |||
197 | if (!flag_lto_dump_definedglobal_options.x_flag_lto_dump_defined || vnode->definition) | |||
198 | v.safe_push (e); | |||
199 | } | |||
200 | ||||
201 | if (flag_lto_size_sortglobal_options.x_flag_lto_size_sort) | |||
202 | v.qsort (size_compare)qsort (size_compare); | |||
203 | else if (flag_lto_name_sortglobal_options.x_flag_lto_name_sort) | |||
204 | v.qsort (name_compare)qsort (name_compare); | |||
205 | if (flag_lto_reverse_sortglobal_options.x_flag_lto_reverse_sort) | |||
206 | v.reverse (); | |||
207 | ||||
208 | printf ("\n"); | |||
209 | int i=0; | |||
210 | symbol_entry* e; | |||
211 | FOR_EACH_VEC_ELT (v, i, e)for (i = 0; (v).iterate ((i), &(e)); ++(i)) | |||
212 | { | |||
213 | e->dump (); | |||
214 | delete e; | |||
215 | } | |||
216 | } | |||
217 | ||||
218 | /* Dump symbol table in graphviz format. */ | |||
219 | void dump_symtab_graphviz (void) | |||
220 | { | |||
221 | symtab->dump_graphviz (stdoutstdout); | |||
222 | } | |||
223 | ||||
224 | /* Dump symbol list. */ | |||
225 | ||||
226 | void dump_list (void) | |||
227 | { | |||
228 | dump_list_functions (); | |||
229 | dump_list_variables (); | |||
230 | } | |||
231 | ||||
232 | /* Dump specific variables and functions used in IL. */ | |||
233 | void dump_symbol () | |||
234 | { | |||
235 | symtab_node *node; | |||
236 | printf ("Symbol: %s\n", flag_lto_dump_symbolglobal_options.x_flag_lto_dump_symbol); | |||
237 | FOR_EACH_SYMBOL (node)for ((node) = symtab->first_symbol (); (node); (node) = (node )->next) | |||
238 | { | |||
239 | if (!strcmp (flag_lto_dump_symbolglobal_options.x_flag_lto_dump_symbol, node->name ())) | |||
240 | { | |||
241 | node->debug (); | |||
242 | printf ("\n"); | |||
243 | } | |||
244 | } | |||
245 | } | |||
246 | ||||
247 | /* Dump specific gimple body of specified function. */ | |||
248 | void dump_body () | |||
249 | { | |||
250 | int flag = 0; | |||
251 | dump_flags_t flags = TDF_NONE; | |||
252 | if (flag_dump_levelglobal_options.x_flag_dump_level) | |||
253 | flags = parse_dump_option (flag_dump_levelglobal_options.x_flag_dump_level, NULLnullptr); | |||
254 | if (flags == TDF_ERROR) | |||
255 | { | |||
256 | error_at (input_location, "Level not found, use none, slim, blocks, vops."); | |||
257 | return; | |||
258 | } | |||
259 | cgraph_node *cnode; | |||
260 | FOR_EACH_DEFINED_FUNCTION (cnode)for ((cnode) = symtab->first_defined_function (); (cnode); (cnode) = symtab->next_defined_function ((cnode))) | |||
261 | if (!cnode->alias | |||
262 | && !strcmp (cnode->asm_name (), flag_dump_bodyglobal_options.x_flag_dump_body)) | |||
263 | { | |||
264 | printf ("GIMPLE body of function: %s\n\n", cnode->asm_name ()); | |||
265 | cnode->get_untransformed_body (); | |||
266 | debug_function (cnode->decl, flags); | |||
267 | flag = 1; | |||
268 | } | |||
269 | if (!flag) | |||
270 | error_at (input_location, "Function not found."); | |||
271 | } | |||
272 | ||||
273 | /* List of command line options for dumping. */ | |||
274 | void dump_tool_help () | |||
275 | { | |||
276 | const char *msg = | |||
277 | "Usage: lto-dump [OPTION]... SUB_COMMAND [OPTION]...\n\n" | |||
278 | "LTO dump tool command line options.\n\n" | |||
279 | " -list [options] Dump the symbol list.\n" | |||
280 | " -demangle Dump the demangled output.\n" | |||
281 | " -defined-only Dump only the defined symbols.\n" | |||
282 | " -print-value Dump initial values of the variables.\n" | |||
283 | " -name-sort Sort the symbols alphabetically.\n" | |||
284 | " -size-sort Sort the symbols according to size.\n" | |||
285 | " -reverse-sort Dump the symbols in reverse order.\n" | |||
286 | " -symbol= Dump the details of specific symbol.\n" | |||
287 | " -objects Dump the details of LTO objects.\n" | |||
288 | " -callgraph Dump the callgraph in graphviz format.\n" | |||
289 | " -type-stats Dump statistics of tree types.\n" | |||
290 | " -tree-stats Dump statistics of trees.\n" | |||
291 | " -gimple-stats Dump statistics of GIMPLE statements.\n" | |||
292 | " -dump-body= Dump the specific GIMPLE body.\n" | |||
293 | " -dump-level= Deciding the optimization level of body.\n" | |||
294 | " -help Display the dump tool help.\n"; | |||
295 | ||||
296 | fputs (msg, stdoutstdout); | |||
297 | } | |||
298 | ||||
299 | unsigned int | |||
300 | lto_option_lang_mask (void) | |||
301 | { | |||
302 | return CL_LTODump(1U << 9); | |||
303 | } | |||
304 | ||||
305 | /* Functions for dumping various details in LTO dump tool are called | |||
306 | in lto_main(). The purpose of this dump tool is to analyze the LTO | |||
307 | object files. */ | |||
308 | ||||
309 | void | |||
310 | lto_main (void) | |||
311 | { | |||
312 | quiet_flagglobal_options.x_quiet_flag = true; | |||
313 | if (flag_lto_dump_tool_helpglobal_options.x_flag_lto_dump_tool_help) | |||
| ||||
314 | { | |||
315 | dump_tool_help (); | |||
316 | exit (SUCCESS_EXIT_CODE0); | |||
317 | } | |||
318 | ||||
319 | /* LTO is called as a front end, even though it is not a front end. | |||
320 | Because it is called as a front end, TV_PHASE_PARSING and | |||
321 | TV_PARSE_GLOBAL are active, and we need to turn them off while | |||
322 | doing LTO. Later we turn them back on so they are active up in | |||
323 | toplev.cc. */ | |||
324 | ||||
325 | /* Initialize the LTO front end. */ | |||
326 | lto_fe_init (); | |||
327 | g_timer = NULLnullptr; | |||
328 | /* Read all the symbols and call graph from all the files in the | |||
329 | command line. */ | |||
330 | read_cgraph_and_symbols (num_in_fnames, in_fnames); | |||
331 | ||||
332 | /* Dump symbol list. */ | |||
333 | if (flag_lto_dump_listglobal_options.x_flag_lto_dump_list) | |||
334 | dump_list (); | |||
335 | else if (flag_lto_dump_symbolglobal_options.x_flag_lto_dump_symbol) | |||
336 | { | |||
337 | /* Dump specific variables and functions used in IL. */ | |||
338 | dump_symbol (); | |||
339 | } | |||
340 | else if (flag_lto_gimple_statsglobal_options.x_flag_lto_gimple_stats) | |||
341 | { | |||
342 | /* Dump gimple statement statistics. */ | |||
343 | cgraph_node *node; | |||
344 | FOR_EACH_DEFINED_FUNCTION (node)for ((node) = symtab->first_defined_function (); (node); ( node) = symtab->next_defined_function ((node))) | |||
345 | if (!node->alias) | |||
346 | node->get_untransformed_body (); | |||
347 | if (!GATHER_STATISTICS0) | |||
348 | warning_at (input_location, 0, | |||
349 | "Not configured with " | |||
350 | "%<--enable-gather-detailed-mem-stats%>."); | |||
351 | else | |||
352 | dump_gimple_statistics (); | |||
353 | } | |||
354 | else if (flag_lto_tree_statsglobal_options.x_flag_lto_tree_stats) | |||
355 | { | |||
356 | /* Dump tree statistics. */ | |||
357 | if (!GATHER_STATISTICS0) | |||
358 | warning_at (input_location, 0, | |||
359 | "Not configured with " | |||
360 | "%<--enable-gather-detailed-mem-stats%>."); | |||
361 | else | |||
362 | { | |||
363 | printf ("Tree statistics\n"); | |||
364 | dump_tree_statistics (); | |||
365 | } | |||
366 | } | |||
367 | else if (flag_dump_bodyglobal_options.x_flag_dump_body) | |||
368 | { | |||
369 | /* Dump specific gimple body of specified function. */ | |||
370 | dump_body (); | |||
371 | } | |||
372 | else if (flag_dump_callgraphglobal_options.x_flag_dump_callgraph) | |||
373 | dump_symtab_graphviz (); | |||
374 | else | |||
375 | dump_tool_help (); | |||
376 | ||||
377 | /* Exit right now. */ | |||
378 | exit (SUCCESS_EXIT_CODE0); | |||
379 | } |