linux中的_nocancel()系统调用是什么,有没有办法使用LD_PRELOAD拦截它们
请告诉我什么是_nocancel()系统调用(例如u pwrite_nocancel()),以及是否有方法创建LD_预加载库来拦截这些调用。以下是一些背景信息: 我正在研究Oracle数据库的功能,并希望使用LD_PRELOAD添加一个小的填充层,以捕获用户空间中有关调用的信息。我知道使用system tap捕获此信息的其他方法,但使用LD_PRELOAD是客户的一个硬要求。 strace显示此特定进程正在重复调用pwrite();类似地,pstack堆栈跟踪显示uu pwrite_nocancel()正在作为堆栈上的最后一个条目被调用。我尝试重新生成自己的u libc_pwrite()函数,并声明linux中的_nocancel()系统调用是什么,有没有办法使用LD_PRELOAD拦截它们,c,linux,system-calls,C,Linux,System Calls,请告诉我什么是_nocancel()系统调用(例如u pwrite_nocancel()),以及是否有方法创建LD_预加载库来拦截这些调用。以下是一些背景信息: 我正在研究Oracle数据库的功能,并希望使用LD_PRELOAD添加一个小的填充层,以捕获用户空间中有关调用的信息。我知道使用system tap捕获此信息的其他方法,但使用LD_PRELOAD是客户的一个硬要求。 strace显示此特定进程正在重复调用pwrite();类似地,pstack堆栈跟踪显示uu pwrite_nocanc
extern ssize\u t pwrite(intfd,const void*buf,size\u t numBytes,off\u t offset)\u属性(弱,别名(“\u libc\u pwrite”));
但当我链接库并运行nm-a | grep pwrite时,我得到了以下结果:
000000000006c190 T __libc_pwrite
000000000006c190 W pwrite
相反,nm-a/lib64/libpthread.so.0 | grep pwrite提供了以下内容:
000000000000eaf0 t __libc_pwrite
000000000000eaf0 t __libc_pwrite64
000000000000eaf0 W pwrite
000000000000eaf0 t __pwrite
000000000000eaf0 W pwrite64
000000000000eaf0 W __pwrite64
0000000000000000 a pwrite64.c
000000000000eaf9 t __pwrite_nocancel
我注意到,nocancel版本只比写入文件早9个字节,但看看源代码,我不确定它是在哪里创建的:
/* Copyright (C) 1997, 1998, 2000, 2002, 2003, 2004, 2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <endian.h>
#include <sysdep-cancel.h>
#include <sys/syscall.h>
#include <bp-checks.h>
#include <kernel-features.h>
#ifdef __NR_pwrite64 /* Newer kernels renamed but it's the same. */
# ifdef __NR_pwrite
# error "__NR_pwrite and __NR_pwrite64 both defined???"
# endif
# define __NR_pwrite __NR_pwrite64
#endif
#if defined __NR_pwrite || __ASSUME_PWRITE_SYSCALL > 0
# if __ASSUME_PWRITE_SYSCALL == 0
static ssize_t __emulate_pwrite (int fd, const void *buf, size_t count,
off_t offset) internal_function;
# endif
ssize_t
__libc_pwrite (fd, buf, count, offset)
int fd;
const void *buf;
size_t count;
off_t offset;
{
ssize_t result;
if (SINGLE_THREAD_P)
{
/* First try the syscall. */
result = INLINE_SYSCALL (pwrite, 6, fd, CHECK_N (buf, count), count, 0,
__LONG_LONG_PAIR (offset >> 31, offset));
# if __ASSUME_PWRITE_SYSCALL == 0
if (result == -1 && errno == ENOSYS)
/* No system call available. Use the emulation. */
result = __emulate_pwrite (fd, buf, count, offset);
# endif
return result;
}
int oldtype = LIBC_CANCEL_ASYNC ();
/* First try the syscall. */
result = INLINE_SYSCALL (pwrite, 6, fd, CHECK_N (buf, count), count, 0,
__LONG_LONG_PAIR (offset >> 31, offset));
# if __ASSUME_PWRITE_SYSCALL == 0
if (result == -1 && errno == ENOSYS)
/* No system call available. Use the emulation. */
result = __emulate_pwrite (fd, buf, count, offset);
# endif
LIBC_CANCEL_RESET (oldtype);
return result;
}
strong_alias (__libc_pwrite, __pwrite)
weak_alias (__libc_pwrite, pwrite)
# define __libc_pwrite(fd, buf, count, offset) \
static internal_function __emulate_pwrite (fd, buf, count, offset)
#endif
#if __ASSUME_PWRITE_SYSCALL == 0
# include <sysdeps/posix/pwrite.c>
#endif
/*版权所有(C)1997、1998、2000、2002、2003、2004、2006
自由软件基金会
此文件是GNUC库的一部分。
由Ulrich Drepper提供,1997年。
GNUC库是自由软件;您可以重新发布它和/或
根据GNU小公众的条款对其进行修改
自由软件基金会发布的许可证;
许可证的2.1版,或(由您选择)任何更高版本。
分发GNU C库是希望它会有用,
但没有任何保证;甚至没有对
适销性或适合某一特定目的。参见GNU
有关更多详细信息,请参阅较低的通用公共许可证。
您应该已经收到GNU Lesser General Public的副本
许可证以及GNU C库;如果没有,请参阅
. */
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#ifdef _NR_pwrite64/*更新的内核重命名,但它是相同的*/
#ifdef_uu_unr_upwrite
#错误“\uuuunr\upWrite和\uuuunr\upWrite64都已定义???”
#恩迪夫
#定义_NR_pwrite _NR_pwrite 64
#恩迪夫
#如果已定义uuu NR_upwrite | | uuu假设u pwrite_SYSCALL>0
#如果uu假设PWRITE SYSCALL==0
静态ssize_t______模拟_pwrite(int fd,const void*buf,size_t count,
off_t offset)内部函数;
#恩迪夫
ssize\u t
__自由写入(fd、buf、计数、偏移)
int-fd;
const void*buf;
大小/数量;
偏移量;
{
对结果进行量化;
if(单螺纹)
{
/*首先尝试系统调用*/
结果=内联系统调用(pwrite,6,fd,CHECK,N(buf,count),count,0,
__长对(偏移量>>31,偏移量));
#如果uu假设PWRITE SYSCALL==0
如果(结果==-1&&errno==ENOSYS)
/*没有可用的系统调用。请使用模拟*/
结果=\模拟\写入(fd、buf、计数、偏移量);
#恩迪夫
返回结果;
}
int oldtype=LIBC_CANCEL_ASYNC();
/*首先尝试系统调用*/
结果=内联系统调用(pwrite,6,fd,CHECK,N(buf,count),count,0,
__长对(偏移量>>31,偏移量));
#如果uu假设PWRITE SYSCALL==0
如果(结果==-1&&errno==ENOSYS)
/*没有可用的系统调用。请使用模拟*/
结果=\模拟\写入(fd、buf、计数、偏移量);
#恩迪夫
LIBC\u取消\u重置(旧类型);
返回结果;
}
强别名(uuu libc_pwrite,uuu pwrite)
弱别名(uuu libc_pwrite,pwrite)
#定义自由写入(fd、buf、计数、偏移)\
静态内部函数模拟写入(fd、buf、计数、偏移)
#恩迪夫
#如果uu假设PWRITE SYSCALL==0
#包括
#恩迪夫
非常感谢您的帮助。如果您想通过
LD_PRELOAD
插入,您需要查看rtld使用的相同符号。因此,使用objdump-T
而不是nm-a
。如果您想要的符号未列出,则无法插入。所有导出的glibc符号都有一个“版本”通过rtld进行比较并允许具有同一符号的多个版本的字符串(这就是为什么即使nm-D
也没有用处——它不显示版本)。要插入某些内容,您应该具有相同的版本字符串。这可以使用版本脚本来完成(请参见info ld
),asm指令或调用该指令的宏。请注意,在libc的任何新版本中,具有“私有”版本的符号可能会更改,并且在任何新版本中,其他符号可能会被新符号取代(符号仍然有效,但根据新版本编译的应用程序不再使用它们)
\u nocancel()
版本的行为与原始函数完全相同,只是这些版本不是线程取消点
大多数I/O函数都是取消点。也就是说,如果线程取消类型为“延迟”且取消状态为“启用”,并且进程中的另一个线程已请求取消该线程,则该线程将在进入取消点时取消(退出)。有关详细信息,请参阅和
不幸的是,pwrite\u nocancel()
和其他\u nocancel()
函数是内部(本地)函数到pthreads库,因此很难插入;它们不是动态符号,因此动态链接器无法覆盖它们。在这一点上,我怀疑,但不确定,插入它们的方法将涉及使用直接jum重写库代码的开头