2

我目前正在尝试编写自己的程序来反映 pmap 命令,特别是在 Solaris 9 上。我无法解析库的名称和路径。来自 bash shell 的 Solaris 命令的输出如下所示:

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 并查看内存并以某种方式找到它们,但我还无法弄清楚它在哪里寻找或为什么。

4

1 回答 1

3

的 Solaris 实现pmap实际上可以通过 OpenSolaris 以源代码形式获得,pmap.c. 但这是非常复杂的东西;基础更容易实现。

Solaris 具有三个 /proc映射句柄:

  1. /proc/<PID>/map其中包含struct prmap反映“通常”工作集大小的数据
  2. /proc/<PID>/rmap除了虚拟集大小(VSZ)之外,它还包含struct prmap数据,即即使映射未提交,也反映映射的 VA 范围。
  3. /proc/<PID>/xmap其中包含struct prxmap数据,实际上是在地址空间中搜寻以识别内存驻留区域。

pmap当您不传递任何参数 ( map)、-r( rmap) 或-x( ) 时,该实用程序会查看这些内容xmap,但正如您发现的那样,它不仅仅是打开/读取 map proc 文件。这在很大程度上是使源代码难以解析的原因。

尽管如此,您可以通过以下代码构建一个简单的 Solaris [rx]map(当然struct prxmapstruct 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)在 any 之前使用read)。

享受实验!

编辑:

由于您已经下定决心要查找映射背后的路径名,因此这是非常困难的任务之一。pmap它本身不处理它,而是使用 的工具libproc来解析这些名称,正如您发现的那样truss,它可能会在进程地址空间中搜寻以提取这些名称,但还使用了一些其他技术。它本质上是执行此操作的“iter”函数libproc/Psymtab.c。Solaris 9 和更高版本之间也存在差异……不记得了,太久以前了……

于 2011-11-10T15:00:20.587 回答