Как процесс Solaris может читать свою собственную таблицу символов? - PullRequest
7 голосов
/ 11 августа 2011

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

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

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

Я работаю на Solaris10 / SPARC и использую gcc 4.2.х.

Спасибо!

Ответы [ 2 ]

4 голосов
/ 12 августа 2011

Я пробовал простой тест с использованием 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 может быть полезна (предупреждение: article is 10лет).

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

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

3 голосов
/ 15 сентября 2011

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

...