dl_iterate_phdr(3) обход списка общих объектов

ОБЗОР

#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 */
};

(Макрос 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, который предоставляет вызываемой функции механизм обнаружения того, что она работает в системе с добавленными полями.

ПРИМЕР

Следующая программа выводит список путей общий объектов, из которых они были загружены. Для каждого общего объекта программа показывает виртуальный адрес, по которому загружены сегменты 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);
}