Как процесс 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. Параметры командной строки могут отличаться)