Search code examples
c++linuxdllsymbol-tabledladdr

Name of a function defined in executable (using dladdr)


I have a program (an application, not a shared library):

void func() {
    int RESULT = UNW_ESUCCESS;
    unw_context_t context;
    unw_getcontext(&context);

    unw_cursor_t cursor;
    RESULT = unw_init_local(&cursor, &context);
    assert(RESULT == UNW_ESUCCESS);

    const int BUFFER_SIZE = 512;
    char functionName[BUFFER_SIZE] = {"<unknown>"};
    unw_word_t offset;
    RESULT = unw_get_proc_name(&cursor, functionName, BUFFER_SIZE, &offset);
}

int main() {
    func();
}

I expect functionName to be "func" - the name of the function from which I make a call to unw_get_proc_name(). But unw_get_proc_name() fails. I've debugged it and found out that it uses a function dladdr() to get the name of a function:

Dl_info dyldInfo;
if (dladdr((void *)addr, &dyldInfo)) {
    if (dyldInfo.dli_sname != NULL) {
      snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
      *offset = (addr - (pint_t) dyldInfo.dli_saddr);
      return true;
    }
  }

For some reason dyldInfo.dli_sname is 0. Why? How can I fix this?

I also use the function unw_get_proc_name() from a shared library and in this case it succeeds. So the question is why does it fail to retrieve a function name ("func" in the program above) when being called from an application (not a shared library)? And how can I fix it?

I tried to add attributes __attribute__((noinline)) and __attribute__((visibility("default"))) to my func() function, but it didn't help.


Solution

  • My reading of the man page for dladdr is that it can only locate symbols located in shared objects, aka shared libraries. The relevant section reads (emphasis mine):

    The function dladdr() determines whether the address specified in addr is located in one of the shared objects loaded by the calling application.

    However, I found this link which suggests that linking with -Wl,-E might help, so you could try that.