一种调试 glibc 函数的好方法是用您自己的版本覆盖所关注的函数。在没有 root 许可权和不必重新编译 libc 源代码的情况下就可以完成这个任务。想象一下编写您自己的 open() 版本该有多激动啊!
如果您没有应用程序的源代码并且由于 c 的 gnu 库(glibc)函数正将某些错误信息返回给该应用程序而使它失败,那么您该怎么办?因为 glibc 是开放源码,所以您当然可以获得其源代码、对它进行更改、重新构建和安装。然而,这不适合那些胆怯的人,因为虽然 api 有很好的文档说明,但 gnu c 库的内部组织却没有。查找正确的函数原型只是众多挑战中的第一个。它还是一个很大的包,所以第一次编译时,它将花一些时间(glibc 2.2.2 有 8552 个文件和 1775440 行代码,包括注释)。
更好的方法
比重新构建 glibc 更好的方法是选择性地覆盖一个函数。许多现代的 unix 都支持预装入用户定义库这一概念。这些库可以是完整的替代(即,glibc 的专用版本)也可以是子集 — 甚至是一个函数。首先,通过设置 ld_library_path 来包含库的专用版本,您可以使用 glibc 的专用版本。可通过使用 ld_preload 环境值来使用您编写的库例程的子集。ld_library_path 和 ld_preload 都是由动态 elf 链接器/装入器控制的。它使用第一个匹配来满足任何符号名。通过预装入您自己的库或函数版本,您“短路”了正常路径,这样就允许您覆盖它。
这里是一个示例 makefile,它覆盖 glibc 函数 setresgid():
覆盖 setresgid() 的 makefile
#
# makefile
#
all: libs setresgid-tester
#
# make a shared library
#
libs: libfuncs.c
gcc -shared -wl,-soname,libfuncs.so.1 -o libfuncs.so.1.0 libfuncs.c
ln -s libfuncs.so.1.0 libfuncs.so.1
ln -s libfuncs.so.1 libfuncs.so
#
# here is a program that calls setresgid() for testing
#
setresgid-tester: setresgid-tester.c
gcc -o setresgid-tester setresgid-tester.c
文件 libfuncs.c 包含我的 setresgid() 专用版本。实现它以支持与原始 setresgid() 相同的参数数目时要小心,并在其它方面完成与原始 setresgid() 相同的操作,尽管我的版本欺骗该应用程序并始终返回 0。
关注的第二个文件是 setresgid-tester.c。它通过调用 setresgid() 试验新函数。
这是动态库的源代码:
替换库
/*
put all the functions you want to override here
*/
#include
#include
#include
int errno;
int
setresgid(rgid, egid, sgid)
gid_t rgid,egid,sgid;
{
errno=1;
printf("it me the shim, hi there!\n");
return(0);
}
您还需要一个简单方法来测试您的 setresgid() 专用版本。可以使用 strace 或 ltrace 来监视进程运行。这是普通测试示例的源代码:
普通测试示例
/*
setresgid() system/library call tester
*/
#include
#include
main(){
setresgid(0,0,0);
}
现在,编译该库,设置 ld_preload shell 变量,然后运行测试应用程序。您可能还需要设置 ld_library_path。
运行测试应用程序
export ld_preload=libfuncs.so
export ld_library_path=.:$ld_library_path
./setresgid-tester
it's me the shim, hi there!
还可以通过使用 ldd 列出动态链接库来确认是否正在使用专用库:
确认专用库的使用
[jay@prion ld_preload]$ ldd setresgid-tester
libfuncs.so => libfuncs.so (0x40018000)
libc.so.6 => /lib/libc.so.6 (0x40022000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
结束语
编写 gnu c 库函数的专用版本是调试系统问题或进行快速修正的好方法。使用 ld_preload shell 变量,可以选择性地用您自己的专用版本来覆盖系统 c 库函数。这种技术可用于 linux 和 solaris 环境。
关于作者
jay allen 是 ibm linux for service providers lab(lspl)的程序员。可以通过 jaydallen@us.ibm.com 与 jay 联系。
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器