Программирование pmap в Solaris

В настоящее время я пытаюсь написать свою собственную программу, отражающую команду pmap, особенно в Solaris 9. У меня возникают проблемы с определением имен и путей к библиотекам. Вывод команды Solaris в оболочке bash выглядит примерно так:

bash-2.05# pmap $$
2427:   bash
00010000     496K r-x--  /usr/bin/bash
0009A000      80K rwx--  /usr/bin/bash
000AE000     120K rwx--    [ heap ]
FF100000     688K r-x--  /usr/lib/libc.so.1
FF1BC000      24K rwx--  /usr/lib/libc.so.1
FF1C2000       8K rwx--  /usr/lib/libc.so.1
FF200000     568K r-x--  /usr/lib/libnsl.so.1
FF29E000      32K rwx--  /usr/lib/libnsl.so.1
FF2A6000      32K rwx--  /usr/lib/libnsl.so.1
FF2F0000       8K rwx--    [ anon ]
FF300000      16K r-x--  /usr/lib/libmp.so.2
FF314000       8K rwx--  /usr/lib/libmp.so.2
FF320000       8K r-x--  /usr/platform/sun4u-us3/lib/libc_psr.so.1
FF330000      40K r-x--  /usr/lib/libsocket.so.1
FF34A000       8K rwx--  /usr/lib/libsocket.so.1
FF350000     168K r-x--  /usr/lib/libcurses.so.1
FF38A000      32K rwx--  /usr/lib/libcurses.so.1
FF392000       8K rwx--  /usr/lib/libcurses.so.1
FF3A0000       8K r-x--  /usr/lib/libdl.so.1
FF3B0000       8K rwx--    [ anon ]
FF3C0000     152K r-x--  /usr/lib/ld.so.1
FF3F6000       8K rwx--  /usr/lib/ld.so.1
FFBFC000      16K rw---    [ stack ]
 total      2536K

В основном я могу воспроизвести основные функции программы, прочитав /proc/$$/map, но осталось выяснить, как разрешать имена библиотек, показанные справа. /proc/$$/map дает только имена файлов в /proc/$$/object, которые являются просто общими именами. В Solaris 10 (ящик, который у меня есть) я, похоже, могу использовать /proc/$$/path, который содержит символические ссылки, но в ящике, над которым я работаю, их нет. Есть ли у кого-нибудь простые идеи о том, как получить эти имена библиотек? Когда я запускаю программу, кажется, что она открывает /proc/$$/as и просматривает память и каким-то образом находит их, но я пока не могу понять, где она ищет и почему.


person Dan Fego    schedule 02.11.2011    source источник
comment
Если вы погуглите «c pmap», вы найдете (старую) переработку pmap (для Solaris) одним человеком. Это не долго. Может быть, вы сможете найти там, где вы ошибаетесь (если код все еще действителен, учитывая его возраст).   -  person gnometorule    schedule 03.11.2011
comment
Тот, который я нашел, представляет собой реализацию pmap для Linux, которая, к сожалению, полностью отличается, поскольку Linux /proc/$$/maps — это текстовый файл, который в любом случае содержит все, что мне нужно. Вы видели что-то еще, что я пропустил?   -  person Dan Fego    schedule 03.11.2011
comment
Я снова проверил. Ты прав. Я не внимательно читал. Извинения. К сожалению, я работаю в Linux и поэтому не знаю, чем отличаются реализации двух диалектов.   -  person gnometorule    schedule 03.11.2011
comment
Я не знаю, на каком именно уровне это реализовано, но если повезет с hub.opensolaris .org/bin/view/Main/get   -  person gnometorule    schedule 03.11.2011
comment
К сожалению, версия OpenSolaris работает немного иначе, по крайней мере, насколько я могу судить. Он пытается использовать файл /proc/$$/path, которого нет в моем Solaris 9, и по умолчанию использует имена устройств/inode. Еще раз спасибо, что осмотрелись! :)   -  person Dan Fego    schedule 03.11.2011


Ответы (1)


Реализация Solaris pmap на самом деле доступна в виде исходного кода через OpenSolaris,pmap.c. Но это очень сложный материал; основы легче достичь.

В Solaris есть три /proc дескриптора для карт:

  1. /proc/<PID>/map, который содержит struct prmap данные, отражающие "обычный" размер рабочего набора
  2. /proc/<PID>/rmap, который также содержит данные struct prmap, но для размера виртуального набора (VSZ), т. е. отражает сопоставленные диапазоны VA, даже если сопоставление не зафиксировано.
  3. /proc/<PID>/xmap, который содержит struct prxmap данные, которые фактически просматривают адресное пространство для определения резидентных областей памяти.

Утилита pmap просматривает их, когда вы не передаете аргументы (map), -r (rmap) или -x (xmap), но, как вы обнаружили, она делает гораздо больше, чем просто открывает/читает файлы proc карты. Во многом это затрудняет разбор исходного кода.

Тем не менее, вы можете создать тривиальный синтаксический анализатор Solaris [rx]map (используйте struct prxmap вместо struct prmap, если вы, конечно, имеете доступ к xmap) с помощью кода, такого как:

char mappath[MAXPATHLEN];
sprintf(mappath, "/proc/%d/map", getpid());
int fd = open(mappath, O_RDONLY);
size_t nread;
size_t mapsz = (1 << 20);                 /* start at 1MB */
struct prmap *cur*mapbuf = malloc(mapsz);

while ((nread = pread(fd, mapbuf, mapsz, 0)) == mapsz) {
    free(mapbuf);
    mapsz *= 2;
    mapbuf = malloc(mapsz);
}
for (cur = mapbuf; nread; cur++, nread -= sizeof(*mapbuf))
    prettyprint(cur);
free(mapbuf);

Несколько советов:

  • не пытайтесь mmap() файл map, это не сработает (procfs этого не позволяет)
  • не пытайтесь последовательно читать его части; вышеприведенное (повторное чтение всего с начала в буфер с измененным размером) быстрее, чем выполнение непрерывной последовательности read(). Всегда читайте с начала (используйте pread, как в примере, или lseek(..., 0, SEEK_SET) перед любым read).

Наслаждайтесь экспериментами!

Изменить:

Поскольку вы решили найти пути, лежащие в основе отображений, это одна из действительно сложных задач. pmap не занимается этим сам по себе, но использует средства libproc для разрешения этих имен, которые, как вы обнаружили с помощью truss, могут прочесывать адресное пространство процесса для их извлечения, но также использует несколько других методов. По сути, это функции «iter» в libproc/Psymtab.c, которые делают это. Между Solaris 9 и более поздними версиями тоже есть различия ... не помню, слишком давно ...

person FrankH.    schedule 10.11.2011
comment
Спасибо за подробный ответ, а также за подсказку о том, что быстрее не выполнять кучу последовательных вызовов read(), поскольку именно это я и делал! - person Dan Fego; 10.11.2011
comment
Для небольших карт (несколько сотен записей) накладные расходы не поддаются измерению, но если у вас есть сотни тысяч сопоставлений, например, огромный 64-битный экземпляр JVM, и, возможно, также некоторая динамика, то это чертовски важно. . - person FrankH.; 10.11.2011
comment
Спасибо за отличный ответ. - person Artyom; 10.05.2017
comment
Есть способ получить пути, но он работает только для системных библиотек. Вы можете просмотреть структуры prmap_t в файле /proc/‹pid›/map и получить имена объектных файлов из /proc/‹pid›/objects. Затем можно разобрать эти объекты как файлы elf и получить имя библиотеки каждого файла, которое является именем системного файла .so из /usr/lib или /lib. Однако это не работает для пользовательских библиотек. Здесь единственный способ использовать libproc, но его интерфейс предполагается закрытым, поэтому вам следует использовать утилиту nm и надеяться, что интерфейс аналогичен тому, что описан в opensol. - person Artyom; 10.05.2017