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

1 ответ

Решение

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

Солярис имеет три /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), но, как вы обнаружили, это намного больше, чем просто открытие / чтение файлов с картами. Это в значительной степени делает исходный код сложным для анализа.

Тем не менее, вы можете построить тривиальный солярис [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, может перетаскивать адресное пространство процесса, чтобы извлечь их, но также использует несколько других методов. Это по сути "итер" функции в libproc/Psymtab.c которые делают это. Также есть различия между Solaris 9 и более поздними версиями... не помню, слишком давно...

Другие вопросы по тегам