Search code examples
c++function-pointerspointer-to-memberbfd

Make BFD library find the location of a class member function


I am using the function bfd_find_nearest_line to find the source location of a function (from an executable with debugging symbols --compiled with -g). Naturally one of the arguments is a pointer to the function I want to locate:

boolean
_bfd_elf_find_nearest_line (abfd, 
                section, 
                symbols, 
                offset, 
                filename_ptr, 
                functionname_ptr, // <- HERE!
                line_ptr)

https://sourceware.org/ml/binutils/2000-08/msg00248.html

After quite a bit of (pure C) boiler plate, I managed this to work with normal functions (where the normal function pointer is casted to *void).

For example, this works:

int my_function(){return 5;}

int main(){
    _bfd_elf_find_nearest_line (...,
                (void*)(&my_function), 
                ...);
}

The question is if bfd_find_nearest_line can be used to locate the source code of a class member function.

struct A{
   int my_member_function(){return 5.;}
};

_bfd_elf_find_nearest_line (...,
                what_should_I_put_here??, 
                ...)

Class member function (in this case if type int (A::*)()) are not functions, an in particular cannot be cast to any function pointer, not even to void*. See here: https://isocpp.org/wiki/faq/pointers-to-members#cant-cvt-memfnptr-to-voidptr

I completely understand the logic behind this, how ever the member-function pointer is the only handle from which I have information of a member function in order to make BFD identify the function. I don't want this pointer to call a function.

I know more or less how C++ works, the compiler will generate silently an equivalent free-C function,

__A_my_member_function(A* this){...}

But I don't know how to access the address of this free function or if that is even possible,and whether the bfd library will be able to locate the source location of the original my_member_function via this pointer. (For the moment at least I am not interested in virtual functions.)

In other words,

1) I need to know if bfd will be able to locate a member function,

2) and if it can how can I map the member function pointer of type int (A::*)() to an argument that bfd can take (void*).


I know by other means (stack trace) that the pointer exists, for example I can get that the free function is called in this case _ZN1A18my_member_functionEv, but the problem is how I can get this from &(A::my_member_function).


Solution

  • Ok, I found a way. First, I discovered that bfd is pretty happy detecting member functions debug information from member pointers, as long as the pointer can be converted to void*.

    I was using clang which wouldn't allow me to cast the member function pointer to any kind of pointer or integer. GCC allows to do this but emits a warning. There is even a flag to allow pointer to member cast called -Wno-pmf-conversions.

    With that information in mind I did my best to convert a member function pointer into void* and I ended up doing this using unions.

    struct A{
       int my_member_function(){return 5.;}
    };
    
    union void_caster_t{
        int (A::*p)(void) value;
        void* casted_value;
    };
    void_caster_t void_caster = {&A::my_member_function};
    
    _bfd_elf_find_nearest_line (...,
                    void_caster.casted_value, 
                    ...)
    

    Finally bfd is able to give me debug information of a member function.


    What I didn't figure out yet, is how to get the pointer to the constructor and the destructor member functions.

    For example

    void_caster_t void_caster = {&A::~A};
    

    Gives compiler error: "you can't take the address of the destructor".

    For the constructor I wasn't even able to find the correct syntax, since this fails as a syntax error.

    void_caster_t void_caster = {&A::A};
    

    Again all the logic behind not being able involves non-sensical callbacks, but this is different because I want the pointer (or address) to get debug information, not callbacks.