Как процесс Solaris может читать свою собственную таблицу символов?

У меня есть процесс Solaris, который является приложением C++, которое загружается ld с несколькими .so библиотеки. Это приложение имеет функцию, которая получает адрес возврата в вызывающей функции и затем пытается определить имя указанной вызывающей функции.

Если я использую dladdr(3) для этого он не всегда помещает то, что я ожидаю увидеть в Dl_info::dli_sname. Похоже, он возвращает имя функции, которая не находится ниже или ниже значения указателя. Если я возьму значение указателя и посмотрю на вывод nmЯ могу сопоставить значение с точной функцией, которую я ожидаю.

Мне интересно, есть ли способ получить карту символов для процесса и позволить ему искать имя функции без использования dladdr(3), Мне особенно интересно получить карту символов не только для самого исполняемого файла, но и для всех .so библиотеки, которые он загрузил.

Я использую Solaris10/SPARC и использую gcc 4.2.x.

Спасибо!

2 ответа

Решение

Я попробовал простой тест, используя dladdr() на Solaris 10/SPARC (но предостережения: GCC 3.4, прямой C), и это прекрасно работает для меня:

#include <dlfcn.h>
#include <stdio.h>

void print_name(char *name, void *addr);
void print_name_by_dladdr(void *addr);

int main(int argc, const char *argv[])
{
    print_name("main", (void *)&main);
    print_name("print_name", (void *)&print_name);
    print_name("printf", (void *)&printf);
    return 0;
}

void print_name(char *name, void *addr)
{
    (void)printf("Getting name of function %s() at 0x%x\n", name, addr);
    print_name_by_dladdr(addr);
}

void print_name_by_dladdr(void *addr)
{
    Dl_info dli;
    if(!dladdr(addr, &dli)) {
        perror("dladdr()");
        exit(1);
    }
    (void)printf("  %s\n", dli.dli_sname);
}

Выход:

Getting name of function main() at 0x10714
  main
Getting name of function print_name() at 0x10778
  print_name
Getting name of function printf() at 0x209b8
  _PROCEDURE_LINKAGE_TABLE_

Это также работает правильно, если я напишу (например)

    print_name("main", (void *)&main + 4);

Вы говорите, что можете правильно решить против выхода nm таким образом, возможности кажутся ограниченными... вы уверены, что обратный адрес выводится или правильно передается вашей функции распознавателя? Я полагаю, вы используете для этого встроенные функции GCC? Я проверил __builtin_return_address(0) и это тоже хорошо работает для меня. Если вы используете встроенные функции GCC, вы звонили __builtin_extract_return_address() (подробности см. на странице выше, явно упоминается SPARC)? Вы можете опубликовать свой код?

Можете ли вы немного растянуть, чтобы "перечитать собственные двоичные / общие объектные файлы"? Если это так, то libelf может стать способом продвижения вперед. Это именно то, что используют некоторые из упомянутых вами утилит, например nm: http://cr.opensolaris.org/~devnull/6515400/usr/src/cmd/sgs/nm/common/nm.c.html

Эта вводная статья от sun.com может быть полезна (предупреждение: статье 10 лет).

Это не так хорошо, как делать нативный самоанализ, и странно, что dladdr(3C) не работает:(

Альтернативное промежуточное звено: вы пробовали RTLD_DL_SYMENT флаг для dladdr1(3C) (а потом возможно позаимствовать у nm.c как выше на возвращенном симе ELF)?

Немного поздно, но, возможно, все еще помогает: в эльфийских объектных файлах обычно есть две таблицы символов:.symtab и.dynsym nm по умолчанию читает.symtab, используйте nm -D для чтения таблицы.dynsym. dladdr (как и динамический загрузчик) использует таблицу.dynsym. таблица.symtab является более полной. Вы можете принудительно принудительно настроить все символы, находящиеся в таблице.dynsym, используя флаг -rdynamic linker. однако это значительно замедляет линковку (например, в моем текущем проекте приблизительно на 200 мс). (nb: сказанное выше относится к linux, но обработка символов работает в основном на sunos. Параметры командной строки могут отличаться)

Другие вопросы по тегам