Creating a function dynamically

Taro Okumichi tarookumichi@gmail.com
Wed Nov 11 16:45:00 GMT 2009


I am hacking in the gcc code and come to a point where I cant come
any further: I want to expand the "-finstrument-functions" to create a dynamic
dump function in the background, instead of  calling a fixed
__cyg_profile_func_enter/exit
I.e:
 if I have
 f1(int a,int b) { }
 I would like to create a dynamic function
 _trace_f1(int a,int b) {
    __trace_int(a);
    __trace_int(b);
 }

I apended the code I use below. the function
gimplify_create_trace_func (shown below) is
called from:

gimplify_function_tree (tree fndecl)->
  gimplify_create_trace_func(fndecl,"_trace_f1");


These are the steps I do in gimplify_create_trace_func():

1. Build function definition for _trace_f1:   build_decl
(FUNCTION_DECL, get_identifier (n), fntyp);
2. Declare function parameters for "a" and "b": build_decl (PARM_DECL,
get_identifier (argname), TREE_TYPE(param));
3. Output each parameter:          build_function_call_expr (trace ,
thisparaml );
   where "thisparaml" is "a" or "b" and trace is a external function
ref repending on the typ:

The problem now is this:
The assembler output is:

_trace_f1:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	movl	$0, (%esp)
	call	__trace__int
	movl	$0, (%esp)
	call	__trace__int
	leave
	ret

whereas I would expect:

_trace_f1:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	movl	8(%ebp), %eax
	movl	%eax, (%esp)
	call	__trace__int
	movl	12(%ebp), %eax
	movl	%eax, (%esp)
	call	__trace__int
        ...

Can anyone tell me what I am doing wrong. The compiler oututs
__trace__int(0) instead of using the function parameter as an argument:
 _trace_f1(int a,int b) {
    __trace_int(a);
   ...

Or can somebody point me to a codesnippet in  gcc that
does the same (create functions dynamically on the fly) so
I can  take a look and learn...


Greetings



----------- create a dynamic funtion ------------------------

void
gimplify_create_trace_func (tree fndecl, char *n)
{
	int i;
	tree body = NULL;
	tree ir, prev, param, fn, fntyp, parm, tdef, argstyp = NULL_TREE,
argslist = NULL_TREE ;
	char argname[256];

	/* create function type */
	for (i = 0,param = DECL_ARGUMENTS (fndecl); param ; i++,param =
TREE_CHAIN (param)) {
		argstyp = tree_cons (NULL_TREE, TREE_TYPE(param), argstyp);		
	}
	if (argstyp == NULL_TREE)
		argstyp = void_list_node;
	else {
		tree last = argstyp;
		argstyp = nreverse (argstyp);
		TREE_CHAIN (last) = void_list_node;
	}
	fntyp = build_function_type (void_type_node, argstyp);

	/* build function prototype */
	fn = build_decl (FUNCTION_DECL, get_identifier (n), fntyp);

	pushdecl (fn);

	prev = current_function_decl;
	current_function_decl = fn;
		
	push_scope();
	declare_parm_level ();
	
	/* build function argument list */
	for (i = 0,param = DECL_ARGUMENTS (fndecl); param ; i++,param =
TREE_CHAIN (param)) {
		tree argdecl;
		sprintf(argname,"a%d",i);
		argdecl = build_decl (PARM_DECL, get_identifier (argname), TREE_TYPE(param));
		argslist = chainon (argdecl, argslist);
		printf("decl:%x\n",argdecl);
		pushdecl(argdecl);
		DECL_ARTIFICIAL(argdecl) = 1;
		

		/* if (DECL_NAME (argdecl)) { */
		/* 	bind (DECL_NAME (decl), decl, current_scope, */
		/* 	      /\*invisible=*\/false, /\*nested=*\/false); */
		/* } */
		
		DECL_CONTEXT (argdecl) = fn;
	}
	argslist = nreverse (argslist);
	DECL_ARGUMENTS (fn) = argslist;
	
	
	ir = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
	DECL_CONTEXT (ir) = fn;
	DECL_ARTIFICIAL (ir) = 1;
	DECL_IGNORED_P (ir) = 1;
	DECL_RESULT (fn) = ir;

	
	TREE_STATIC (fn) = 0;
	TREE_USED (fn) = 1;
	DECL_ARTIFICIAL (fn) = 1;
	DECL_IGNORED_P (fn) = 1;
	DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fn) = 1;

	allocate_struct_function (fn);
	
	if (tracetype == trace_out_none) {
		
		DECL_SAVED_TREE (fn) = build_empty_stmt();
		
	} else if (tracetype == trace_out_all) {

		tree thisp, stmts;
		
		stmts = alloc_stmt_list();
		
		/* output one call for each argument */
		for (i = 0,thisp = argslist, param = DECL_ARGUMENTS (fndecl); param
; i++,thisp = TREE_CHAIN (thisp), param = TREE_CHAIN (param)) {
			tree trace, thisparaml = NULL, x;
			char *name = gen_aux_info_type_str_canonical(TREE_TYPE(param));
			name = concat("__trace__", name, NULL);
			fprintf(stderr, "typ: \"%s\" \n", name);
			
			trace = build_function_type_list (void_type_node, TREE_TYPE(thisp), NULL);
			trace = build_decl (FUNCTION_DECL, get_identifier (name), trace);
			TREE_PUBLIC (trace) = 1;
			DECL_EXTERNAL (trace) = 1;

			thisparaml = tree_cons (NULL, thisp, thisparaml);

			x = build_function_call_expr (trace , thisparaml );

			dump_node(x, 0, stderr);

			append_to_statement_list (x, &stmts);
			
		}
		
		DECL_SAVED_TREE (fn) = stmts /*body*/;
	}
	
	TREE_PUBLIC (fn) = 1; /*! targetm.have_ctors_dtors;*/
	DECL_UNINLINABLE (fn) = 1;
	
	DECL_INITIAL (fn) = make_node (BLOCK);
	TREE_USED (DECL_INITIAL (fn)) = 1;

	pop_scope();
	
	/* output function */
	gimplify_function_tree (fn);

		if (cgraph_global_info_ready)
			{
				tree_lowering_passes (fn);
				tree_rest_of_compilation (fn);
			}
		else
			cgraph_finalize_function (fn, 0);
	
	current_function_decl = prev;
	
}



More information about the Gcc-help mailing list