On Tue, Jul 14, 2020 at 11:23 PM Masoud Gholami <ghol...@zib.de> wrote: > > Hi, > > I am writing a plugin that uses the PLUGIN_PRAGMAS event to register a > custom pragma that is expected to be before a function call as follows: > > int main() { > > char *filename = “path/to/file”; > #pragma inject_before_call > File *f = fopen(filename, …); // marked fopen (by the > pragma) > … > fclose(f); > char *filename2 = “path/to/file2”; > File *f2 = fopen(filename2, …); // non-marked fopen > … > fclose(f2); > return 0; > > } > > In fact, I am using the inject_before_call pragma to mark some fopen calls in > the code (in this example, the first fopen call is marked). Then, for each > marked fopen call, some extra expressions/statements/declarations are > injected into the code before calling the marked function. For example, the > above main function would be transformed as follows: > > int main() { > > char *filename = “/path/to/file”; > File *tmp_f = fopen(“/path/to/another/file”, “w+"); > fclose(tmp_f); > File *f = fopen(filename, …); > … > fclose(f); > char *filename2 = “path/to/file2”; // codes not injected for the > non-marked fopen > File *f2 = fopen(filename2, …); > … > fclose(f2); > return 0; > > } > > Here, because of the inject_before_call pragma, the grey code is injected > into the main function before calling the marked fopen. It simply opens a new > file (“/path/to/another/file”) and closes it. > The thing about the injected code is that it should be inserted only if a > fopen call is marked by a inject_before_call pragma. And if after the > inject_before_call pragma no fopen calls are made, the user gets an error > (the pragma should be only inserted before a fopen call). > > I implemented this in 3 steps as follows: > > 1. detection of the marked fopen calls: I created a pragma_handler which > remembers the location_t of all inject_before_call pragmas. Then using a pass > (before ssa), I look for the statements/expressions that are in the next line > of each remembered location. If it’s a fopen call, it is considered as a > marked call and the code should be inserted before the fopen call. If it’s > something other than a fopen call, an error will be generated. However, I’m > not aware if there are any better ways to detect the marked calls. > > Here is the simplified pass to find the marked fopen calls (generating errors > not covered): > > unsigned int execute(function *func) { > basic_block bb; > FOR_EACH_BB_FN (bb, func) { > for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); > gsi_next (&gsi)) { > gimple *stmt = gsi_stmt (gsi); > if (gimple_is_fopen(stmt)) { > if (marked_fopen(stmt)) { > handle_marked_fopen(stmt); > } > } > } > } > } > > 2. create the GIMPLE representation of the code to be injected: after finding > the marked fopen calls, I construct some declaration and expressions as > follows: > > // create the strings “/path/to/another/file" and “w+" > tree another_path = build_string (20, “/path/to/another/file"); > fix_string_type (another_path); > tree mode = build_string (3, “w+\0"); > fix_string_type (mode); > > // create a call to the fopen function with the created strings > tree fopen_decl = lookup_qualified_name (global_namespace, > get_identifier("fopen"), 0, true, false); > gimple *new_open_call = gimple_build_call(fopen_decl, 2, another_path, mode); > > // create the tmp_f declaration > f_decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, get_identifier(“tmp_f"), > fileptr_type_node); > pushdecl (f_decl); > rest_of_decl_compilation (f_decl, 0, 0);
That's the wrong interface for GIMPLE code. Is f_decl supposed to be a global variable or a function local one? For the latter simply use f_decl = create_tmp_var (fileptr_type_node, "tmp_f"); > // set the lhs of the fopen call to be f_decl > gimple_call_set_lhs(new_open_call, f_decl) > > // create a call to the fclose function with the tmp_f variable > tree fclose_decl = lookup_qualified_name (global_namespace, > get_identifier("fclose"), 0, true, false); Likewise lookup_qualified_name is a frontend specific function, since there's no builtin declaration for fclose you'll have to build one yourself. > gimple *new_close_call = gimple_build_call(fclose_decl, 1, f_decl); > > > 3. add the created GIMPLE trees to the code (basic-blocks): > > basic_block bb = gimple_bb(stmt); > for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next > (&gsi)) { gimple *st = gsi_stmt (gsi); > if (st == stmt) { // the marked fopen call > gsi_insert_before(&gsi, new_open_call, GSI_NEW_STMT); > gsi_insert_after(&gsi, new_open_call, GSI_NEW_STMT); > break; > } > } > > This is how I implemented the plugin. However, after compiling a sample code > (like the main function above), I get segmentation fault. By defining another > pass to print the statements of the code and by executing this pass after > the previous pass (that injects the code), I see correct results (i.e., the > injected code is correctly generated and inserted into the right location). > But when I debug the sample code, I see that only the last injected statement > (fclose) is executed with NULL in the f_decl variable which causes the > segmentation fault. I searched everywhere, read all the documentations I > could find, and digged into the gcc code for other pragmas (i.e. omp > parallel, etc.). But still I have no success in doing this correctly. Could > you please point me where the problem is? > > Thanks, > M. Gholami > >