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