DL_ITERATE_PHDR(3)

ИМЯ
dl_iterate_phdr - обход списка общих объектов

ОБЗОР
#define _GNU_SOURCE         /* см. feature_test_macros(7) */
#include <link.h>
int dl_iterate_phdr(
          int (*callback) (struct dl_phdr_info *info,
                           size_t size, void *data),
          void *data);

ОПИСАНИЕ
Функция dl_iterate_phdr() позволяет приложению во время выполнения узнать, какие общие объекты были загружены. Функция dl_iterate_phdr() обходит список общих объектов приложения и однократно вызывает функцию callback для каждого объекта до тех пор, пока или все общие объекты не будут просмотрены, или функция callback не вернёт ненулевое значение. При каждом вызове в callback передаётся три параметра: info (указатель на структуру с информацией об общем объекте), size (размер структуры, на которую указывает info) и data (копия любого значения, переданного вызывающей программой во втором параметре (также называемом data) в вызов dl_iterate_phdr(). Параметр info представляет собой структуру следующего вида:
struct dl_phdr_info {
    ElfW(Addr)        dlpi_addr;  /* базовый адрес объекта */
    const char       *dlpi_name;  /* имя объекта
                                     (оканчивается Null) */
    const ElfW(Phdr) *dlpi_phdr;  /* указатель на массив
                                     программных заголовков ELF
                                     этого объекта */
    ElfW(Half)        dlpi_phnum; /* кол-во элементов в dlpi_phdr */
    /* Следующие поля были добавлены в glibc 2.4, после опубликования
       первой версии этой структуры. Из аргумента size,
       передавамом в dl_iterate_phdr, можно определить
       были ли добавлены новые члены. */
    unsigned long long int dlpi_adds;
                    /* увеличивается, когда мог быть
                       добавлен новый объект */
    unsigned long long int dlpi_subs;
                    /* увеличивается, когда мог быть
                       удалён новый объект */
    size_t dlpi_tls_modid;
                    /* если существует сегмент PT_TLS, это его
                       ID модуля, используемый в
                       перестановках TLS, иначе 0 */
    void  *dlpi_tls_data;
                    /* адрес экземпляра вызывающей нити
                       сегмента PT_TLS этого модуля, если он есть
                       и был выделен в вызывающей нити,
		       иначе указатель null */
};
(Макрос ElfW() преобразует свой аргумент в имя типа данных ELF, подходящее для аппаратной архитектуры. Например, на 32-битной платформе ElfW(Addr) вернёт имя типа данных Elf32_Addr. Дополнительную информацию можно найти в заголовочных файлах <elf.h> и <link.h>.) В поле dlpi_addr указывается базовый адрес общего объекта (т. е., разница между виртуальным адресом памяти общего объекта и смещением до этого объекта в файле, из которого он был загружен). Поле dlpi_name представляет собой строку с null на конце, определяющую путь, из которого был загружен общий объект. Чтобы понять назначение полей dlpi_phdr и dlpi_phnum, нам необходимо представлять, что общий объект ELF состоит из набора сегментов, каждый из которых имеет соответствующий программный заголовок, описывающий сегмент. Поле dlpi_phdr представляет собой указатель на массив программных заголовков этого общего объекта. В поле dlpi_phnum задаётся размер этого массива. Программные заголовки представляют собой структуры следующего вида:
typedef struct {
    Elf32_Word  p_type;    /* тип сегмента */
    Elf32_Off   p_offset;  /* смещение сегмента в файле */
    Elf32_Addr  p_vaddr;   /* виртуальный адрес сегмента */
    Elf32_Addr  p_paddr;   /* физический адрес сегмента */
    Elf32_Word  p_filesz;  /* размер сегмента в файле */
    Elf32_Word  p_memsz;   /* размер сегмента в памяти */
    Elf32_Word  p_flags;   /* флаги сегмента */
    Elf32_Word  p_align;   /* выравнивание сегмента */
} Elf32_Phdr;
Заметим, что мы можем вычислить расположение определённого программного заголовка x в виртуальной памяти по следующей формуле:
  addr == info->dlpi_addr + info->dlpi_phdr[x].p_vaddr;

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Функция dl_iterate_phdr() возвращает значение, которое было получено в результате последнего вызова callback.

ВЕРСИИ
Функция dl_iterate_phdr() доступна в glibc начиная с версии 2.2.4.

АТРИБУТЫ
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение
dl_iterate_phdr() | Безвредность в нитях | MT-Safe

СООТВЕТСТВИЕ СТАНДАРТАМ
Функция dl_iterate_phdr() не описана в каком-либо стандарте. Эта функция есть в некоторых других системах, при чём возвращаемая структура dl_phdr_info имеет другой формат. В BSD и Solaris, в структуре есть поля dlpi_addr, dlpi_name, dlpi_phdr и dlpi_phnum (помимо других внесённых реализацией полей).

ЗАМЕЧАНИЯ
В будущих версиях библиотеки C в структуре dl_phdr_info могут появиться дополнительные поля; для этого случая предусмотрен аргумент size, который предоставляет вызываемой функции механизм обнаружения того, что она работает в системе с добавленными полями. Первый объект, просматриваемый callback, это главная программа. У главной программы поле dlpi_name будет содержать пустую строку.

ПРИМЕР
Следующая программа выводит список путей общий объектов, из которых они были загружены. Для каждого общего объекта программа показывает виртуальный адрес, по которому загружены сегменты ELF объекта.
#define _GNU_SOURCE
#include <link.h>
#include <stdlib.h>
#include <stdio.h>
static int
callback(struct dl_phdr_info *info, size_t size, void *data)
{
    int j;
    printf("имя=%s (%d сегментов)\n", info->dlpi_name,
        info->dlpi_phnum);
    for (j = 0; j < info->dlpi_phnum; j++)
         printf("\t\t заголовок %2d: адрес=%10p\n", j,
             (void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr));
    return 0;
}
int
main(int argc, char *argv[])
{
    dl_iterate_phdr(callback, NULL);
    exit(EXIT_SUCCESS);
}

СМОТРИТЕ ТАКЖЕ
ldd(1), objdump(1), readelf(1), dladdr(3), dlopen(3), elf(5), ld.so(8) Executable and Linking Format Specification в веб.