Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
linux中的_nocancel()系统调用是什么,有没有办法使用LD_PRELOAD拦截它们_C_Linux_System Calls - Fatal编程技术网

linux中的_nocancel()系统调用是什么,有没有办法使用LD_PRELOAD拦截它们

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

请告诉我什么是_nocancel()系统调用(例如u pwrite_nocancel()),以及是否有方法创建LD_预加载库来拦截这些调用。以下是一些背景信息:

我正在研究Oracle数据库的功能,并希望使用LD_PRELOAD添加一个小的填充层,以捕获用户空间中有关调用的信息。我知道使用system tap捕获此信息的其他方法,但使用LD_PRELOAD是客户的一个硬要求。 strace显示此特定进程正在重复调用pwrite();类似地,pstack堆栈跟踪显示uu pwrite_nocancel()正在作为堆栈上的最后一个条目被调用。我尝试重新生成自己的u libc_pwrite()函数,并声明
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重写库代码的开头