18

is there a magic variable in gcc holding a pointer to the current function ?

I would like to have a kind of table containing for each function pointer a set of information.

I know there's a __func__ variable containing the name of the current function as a string but not as a function pointer.

This is not to call the function then but just to be used as an index.

EDIT Basically what i would like to do is being able to run nested functions just before the execution of the current function (and also capturing the return to perform some things.) Basically, this is like __cyg_profile_func_enter and __cyg_profile_func_exit (the instrumentation functions)... But the problem is that these instrumentation functions are global and not function-dedicated.

EDIT In the linux kernel, you can use unsigned long kallsyms_lookup_name(const char *name) from include/linux/kallsyms.h ... Note that the CONFIG_KALLSYMS option must be activated.

LB40
  • 12,041
  • 17
  • 72
  • 107
  • 4
    May I ask why are you trying to do this, there might be more suitable alternatives ? – Hassan Syed Jan 28 '10 at 13:44
  • i would like to be able to register and replay (in any order) nested functions inside this function without making an actual code. The thing is that i'm generating the nested functions but i don't really know the name of the function in which i generate my nested functions. I wanted to avoid modifications to the parser. – LB40 Jan 28 '10 at 13:51
  • Are the amount of functions in the design finite ? or will you be adding functions *ad hoc* ? – Hassan Syed Jan 28 '10 at 13:54
  • No i will add functions in an ad hoc way – LB40 Jan 28 '10 at 14:36
  • I suggest using the C++ functors idiom then -- If you can, it wouldn't be that much overhead compared to plain C. You don't have to use boost -- functors are quite simple to implement. http://loki-lib.sourceforge.net/index.php?n=Pattern.Command There are some more links in my answer below :D – Hassan Syed Jan 28 '10 at 14:39
  • If you only need an inde, can't you simply use the address of the __func__ string literal? Of course this only works if you don't have two (static) functions with the same name, else they may use the same string (address). – quinmars Jan 28 '10 at 22:32
  • Oh wait, even better for you, it is not a string literal, but a static const array, so different functions with the same name should have different __func__ addresses. http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Function-Names.html – quinmars Jan 28 '10 at 22:41
  • Why don't you write an if block at the start of the function and check the return address register when inside of it? – user3191613 Jan 13 '14 at 19:45

13 Answers13

13
void f() {
   void (*fpointer)() = &f;
}
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • yep , that's how you would hard code the information inside the function :D swings and roundabouts really. This solution is not as elegant as doing this work outside the function --- than that work can potentially be code generated. – Hassan Syed Jan 28 '10 at 13:46
  • 3
    :-D... I wanted something more generic...without knowing the name of f. a kind of generic line you could in any function ... – LB40 Jan 28 '10 at 13:48
  • @LB yep this solution is messy, generating out a framework is probably your best bet (but explain the problem further please). – Hassan Syed Jan 28 '10 at 13:50
  • With more info on what you are actually trying to achieve you could get alternatives. – David Rodríguez - dribeas Jan 28 '10 at 13:51
  • @LB Post some code in your question that illustrates what you would like your usage of such a feature (if it existed) to look like. –  Jan 28 '10 at 13:51
  • @LB, Neil is not asking to see your actual code, but a mock-up to illustrate what you would like to be able to do. – Trent Jan 28 '10 at 23:43
7

Here's a trick that gets the address of the caller, it can probably be cleaned up a bit. Relies on a GCC extension for getting a label's value.

#include <stdio.h>

#define MKLABEL2(x) label ## x
#define MKLABEL(x) MKLABEL2(x)
#define CALLFOO do { MKLABEL(__LINE__): foo(&&MKLABEL(__LINE__));} while(0)

void foo(void *addr)
{
    printf("Caller address %p\n", addr);
}

int main(int argc, char **argv)
{
    CALLFOO;
    return 0;
}
Hasturkun
  • 35,395
  • 6
  • 71
  • 104
  • 12
    Using `__builtin_return_address(0)` inside `foo()`, instead of passing the address of a label, is a simpler way of doing pretty much the same thing. (That gives the address of the instruction after the call to `foo()`, rather than the address of a constant load just before the call; but neither of those are the actual address of the function anyway...) – Matthew Slattery Jan 28 '10 at 23:59
  • @Matthew: That's so much nicer than this hack. – Hasturkun Jan 29 '10 at 00:15
4
#define FUNC_ADDR (dlsym(dlopen(NULL, RTLD_NOW), __func__))

And compile your program like

gcc -rdynamic -o foo foo.c -ldl
qrdl
  • 34,062
  • 14
  • 56
  • 86
  • :-)... sneaky, but i fear that changing the compilation flag to include all the symbols + the inclusion of dlfcn.h, is not possible. – LB40 Jan 28 '10 at 16:09
3

I also had the problem that I needed the current function's address when I created a macro template coroutine abstraction that people can use like modern coroutine language features (await and async). It compensates for a missing RTOS when there is a central loop which schedules different asynchronous functions as (cooperative) tasks. Turning interrupt handlers into asynchronous functions even causes race conditions like in a preemptive multi-tasking system.

I noticed that I need to know the caller function's address for the final return address of a coroutine (which is not return address of the initial call of course). Only asynchronous functions need to know their own address so that they can pass it as hidden first argument in an AWAIT() macro. Since instrumenting the code with a macro solution is as simple as just defining the function it suffices to have an async-keyword-like macro.

This is a solution with GCC extensions:

#define _VARGS(...) _VARGS0(__VA_ARGS__)
#define _VARGS0(...) ,##__VA_ARGS__

typedef union async_arg async_arg_t;
union async_arg {
    void (*caller)(void*);
    void *retval;
};
#define ASYNC(FUNCNAME, FUNCARGS, ...)            \
void FUNCNAME (async_arg_t _arg _VARGS FUNCARGS)  \
GENERATOR(                                        \
    void (*const THIS)(void*) = (void*) &FUNCNAME;\
    static void (*CALLER)(void*),                 \
    CALLER = _arg.caller;                         \
    __VA_ARGS__                                   \
)

#define GENERATOR(INIT,...) {                     \
    __label__ _entry, _start, _end;               \
    static void *_state = (void*)0;               \
    INIT;                                         \
_entry:;                                          \
    if (_state - &&_start <= &&_end - &&_start)   \
        goto *_state;                             \
    _state = &&_start;                            \
_start:;                                          \
    __VA_ARGS__;                                  \
_end: _state = &&_entry;                          \
}

#define AWAIT(FUNCNAME,...) ({          \
    __label__ _next;                    \
    _state = &&_next;                   \
    return FUNCNAME((async_arg_t)THIS,##__VA_ARGS__);\
    _next: _arg.retval;                 \
})

#define _I(...) __VA_ARGS__
#define IF(COND,THEN) _IF(_I(COND),_I(THEN))
#define _IF(COND,THEN) _IF0(_VARGS(COND),_I(THEN))
#define _IF0(A,B) _IF1(A,_I(B),)
#define _IF1(A,B,C,...) C

#define IFNOT(COND,ELSE) _IFNOT(_I(COND),_I(ELSE))
#define _IFNOT(COND,ELSE) _IFNOT0(_VARGS(COND),_I(ELSE))
#define _IFNOT0(A,B) _IFNOT1(A,,_I(B))
#define _IFNOT1(A,B,C,...) C

#define IF_ELSE(COND,THEN,ELSE) IF(_I(COND),_I(THEN))IFNOT(_I(COND),_I(ELSE))

#define WAIT(...) ({                 \
    __label__ _next;                 \
    _state = &&_next;                \
    IF_ELSE(_I(__VA_ARGS__),         \
        static __typeof__(__VA_ARGS__) _value;\
        _value = (__VA_ARGS__);      \
        return;                      \
        _next: _value;               \
    , return; _next:;)               \
})

#define YIELD(...) do {              \
    __label__ _next;                 \
    _state = &&_next;                \
    return IF(_I(__VA_ARGS__),(__VA_ARGS__));\
_next:;                              \
} while(0)

#define RETURN(VALUE) do {   \
    _state = &&_entry;       \
    if (CALLER != 0)         \
        CALLER((void*)(VALUE +0));\
    return;                  \
} while(0)

#define ASYNCALL(FUNC, ...) FUNC ((void*)0,__VA_ARGS__)

I know, a more portable (and maybe secure) solution would use the switch-case statement instead of label addresses but I think, gotos are more efficient than switch-case-statements. It also has the advantage that you can use the macros within any other control structures easily and break will have no unexpected effects.

You can use it like this:

#include <stdint.h>
int spi_start_transfer(uint16_t, void *, uint16_t, void(*)());
#define SPI_ADDR_PRESSURE 0x24

ASYNC(spi_read_pressure, (void* dest, uint16_t num),
    void (*callback)(void) = (void*)THIS;    //see here! THIS == &spi_read_pressure
    int status = WAIT(spi_start_transfer(SPI_ADDR_PRESSURE,dest,num,callback));
    RETURN(status);
)

int my_gen() GENERATOR(static int i,
    while(1) {
        for(i=0; i<5; i++)
            YIELD(i);
    }
)

extern volatile int a;
ASYNC(task_read, (uint16_t threshold),
    while(1) {
        static uint16_t pressure;
        int status = (int)AWAIT(spi_read_pressure, &pressure, sizeof pressure);
        if (pressure > threshold) {
            a = my_gen();
        }
    }
)

You must use AWAIT to call asynchronous functions for return value and ASYNCALL without return value. AWAIT can only be called by ASYNC-functions. You can use WAIT with or without value. WAIT results in the expression which was given as argument, which is returned AFTER the function is resumed. WAIT can be used in ASYNC-functions only. Keeping the argument with WAIT wastes one new piece of static memory for each WAIT() call with argument though so it is recommended to use WAIT() without argument. It could be improved, if all WAIT calls would use the same single static variable for the entire function.

It is only a very simple version of a coroutine abstraction. This implementation cannot have nested or intertwinned calls of the same function because all static variables comprise one static stack frame.

If you want to solve this problem, you also need to distinguish resuming an old and starting a new function call. You can add details like a stack-frame queue at the function start in the ASYNC macro. Create a custom struct for each function's stack frame (which also can be done within the macro and an additional macro argument). This custom stack frame type is loaded from a queue when entering the macro, is stored back when exiting it or is removed when the call finishes. You could use a stack frame index as alternative argument in the async_arg_t union. When the argument is an address, it starts a new call or when given a stack frame index it resumes an old call. The stack frame index or continuation must be passed as user-defined argument to the callback that resumes the coroutine.

ChrisoLosoph
  • 459
  • 4
  • 8
2

I think you could build your table using strings (the function names) as keys, then look up by comparing with the __func__ builtin variable.

To enforce having a valid function name, you could use a macro that gets the function pointer, does some dummy operation with it (e.g. assigning it to a compatible function type temporary variable) to check that it's indeed a valid function identifier, and then stringifies (with #) the function name before being used as a key.

UPDATE:

What I mean is something like:

typedef struct {
  char[MAX_FUNC_NAME_LENGTH] func_name;
  //rest of the info here
} func_info;

func_info table[N_FUNCS];

#define CHECK_AND_GET_FUNC_NAME(f) ({void (*tmp)(int); tmp = f; #f})

void fill_it()
{
  int i = -1;
  strcpy(table[++i].func_name, CHECK_AND_GET_FUNC_NAME(foo));
  strcpy(table[++i].func_name, CHECK_AND_GET_FUNC_NAME(bar));
  //fill the rest
}

void lookup(char *name) {
  int i = -1;
  while(strcmp(name, table[++i]));
  //now i points to your entry, do whatever you need
}

void foo(int arg) {
  lookup(__func__);
  //do something
}

void bar(int arg) {
  lookup(__func__);
  //do something
}

(the code might need some fixes, I haven't tried to compile it, it's just to illustrate the idea)

fortran
  • 74,053
  • 25
  • 135
  • 175
  • 1
    I'm not sure to understand what you mean. I may be wrong but __FUNC__ is a string (AFAIK this is not a preprocessor variable but part of the C standard) and node an identifier, this is equals to the name of the function with quotes. What is the macro that gets the function pointer ? – LB40 Jan 28 '10 at 15:26
  • @LB The preprocessor *is* part of the C standard. AFAIK `__FUNC__` is a preprocessor variable/macro, just as `__FILE__` and `__LINE__`. About getting the pointer, that is what my solution tries to avoid. I'll update the answer to make it clearer. – fortran Jan 28 '10 at 17:09
  • It's actually `__func__`, and unlike `__FILE__` and `__LINE__` it's a predefined identifier (not macro). It has to be done at the compiling stage rather than preprocessing, because the extent of a function (and therefore which one you're inside, if any) depends on the result of preprocessing. – caf Jan 28 '10 at 20:59
  • good to know, but there actually is a macro called `__FUNCTION__` that is what I meant... I got confused by reading `__func__` in the question. I'll update the answer. – fortran Jan 28 '10 at 23:37
  • Bear in mind that `__FUNCTION__` is an MSVC extension, whereas `__func__` is standard C. – caf Jan 29 '10 at 03:39
  • I'd swear that I used that in GCC once, but now you're making me doubt... I'll check it out... update: definitively it works with GCC too (tested with 4.4.1) – fortran Jan 29 '10 at 10:19
  • 1
    I don't understand why, but one of my previous comments was removed. To know more about \__FUNCTION__ go to : http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html – LB40 Jan 29 '10 at 13:23
  • @LB good link, anyway, it doesn't make any difference here how is it implemented, the idea was about to get the table indexed by function name, whatever the means or keyword used. I'd update the answer though, to accommodate it better to the C99 standard (even the braced expression used in the check macro is a GCC extension). – fortran Jan 29 '10 at 13:29
1

If you went for C++ the following information might help you:

Objects are typed, functors are functions wrapped as objects, RTTI allows the identification of type at runtime.

Functors carry a runtime overhead with them, and if this is a problem for you I would suggest hard-coding the knowledge using code-generation or leveraging a OO-heirarchy of functors.

Community
  • 1
  • 1
Hassan Syed
  • 20,075
  • 11
  • 87
  • 171
0

static const char * const cookie = __FUNCTION__;

__FUNCTION__ will be stored at the text segment at your binary and a pointer will always be unique and valid.

Asciiom
  • 9,867
  • 7
  • 38
  • 57
  • 1
    ok, maybe we got a problem if two functions have the same name. (namespaces). – decembersoul Sep 17 '12 at 11:41
  • 4
    `__func__` is the same as `__FUNCTION__` so this is useless. The author needs a pointer to function not pointer to string. [Function Names - GCC](http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html) – cprogcr Sep 22 '12 at 07:57
  • @cprogcr `__func__` is not the same as `__FUNCTION__`. The former evaluates to a string while the later doesn't – smac89 Nov 17 '16 at 18:46
0

No, the function is not aware of itself. You will have to build the table you are talking about yourself, and then if you want a function to be aware of itself you will have to pass the index into the global table (or the pointer of the function) as a parameter.

Note: if you want to do this you should have a consistent naming scheme of the parameter.

Hassan Syed
  • 20,075
  • 11
  • 87
  • 171
0

If you want to do this in a 'generic' way, then you should use the facilities you already mention (__cyg_profile_func*) since that is what they are designed for. Anything else will have to be as ad hoc as your profile.

Honestly, doing things the generic way (with a filter) is probably less error prone than any new method that you will insert on-the-fly.

ezpz
  • 11,767
  • 6
  • 38
  • 39
  • 1
    sure, but there's no way to select a different behavior for different behavior and the instrument-functions flag is not something i want to turn everywhere... – LB40 Jan 28 '10 at 15:05
0

You can capture this information with setjmp(). Since it saves enough information to return to your current function, it must include that information in the provided jmp_buf.

This structure is highly nonportable, but you mention GCC explicitly so that's probably not a blocking issue. See this GCC/x86 example to get an idea how it roughly works.

MSalters
  • 173,980
  • 10
  • 155
  • 350
0

If you want to do code generation I would recomend GSLGen from Imatix. It uses XML to structure a model of your code and then a simple PHP like top-down generation language to spit out the code -- it has been used to generate C code.

I have personally been toying arround with lua to generate code.

Hassan Syed
  • 20,075
  • 11
  • 87
  • 171
-2

If all you need is a unique identifier for each function, then at the start of every function, put this:

static const void * const cookie = &cookie;

The value of cookie is then guaranteed to be a value uniquely identifying that function.

caf
  • 233,326
  • 40
  • 323
  • 462
  • another trick hard coded inside the function rather then externally. – Hassan Syed Jan 28 '10 at 14:05
  • This will break if the compiler optimizes for space by giving two cookies the same address - given that the cookies are const, I am pretty sure this optimization would be allowed. – Justin Smith Jan 28 '10 at 16:03
  • 3
    I'm sure the compiler wouldn't -- two different objects must have addresses that compare non-equal. – ephemient Jan 28 '10 at 16:08
  • 1
    As ephemient points out, we prevent that optimisation when we take the address of the object. The only exception to the rule about distinct objects having unique addresses is string literals, which may be merged - but that is *explicitly* allowed. – caf Jan 28 '10 at 20:56
-2

Another option, if portability is not an issue, would be to tweak the GCC source-code... any volunteers?!

Mr. Boy
  • 60,845
  • 93
  • 320
  • 589