gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 12:01:51 25 4
gpt4 key购买 nike

请告诉我什么是 _nocancel() 系统调用(例如 __pwrite_nocancel(),以及是否有办法创建 LD_PRELOAD 库来拦截这些调用。这里有一些背景知识:

我正在研究 Oracle 数据库的功能,并想使用 LD_PRELOAD 添加一个小填充层来捕获有关用户空间调用的信息。我知道使用系统点击捕获此信息的其他方法,但使用 LD_PRELOAD 是客户的硬性要求。 strace 显示这个特定进程重复调用 pwrite();同样,pstack 堆栈跟踪显示 __pwrite_nocancel() 作为堆栈中的最后一个条目被调用。我尝试重现我自己的 __libc_pwrite() 函数,并声明extern ssize_t pwrite(int fd, const void *buf, size_t numBytes, off_t offset)__attribute__((weak, alias ( "__libc_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 版本仅比 __pwrite 提前 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

感谢任何帮助。

最佳答案

pwrite_nocancel() 等不是 Linux 中的系统调用。它们是 C 库的内部函数,与 pthreads 和线程取消紧密耦合。

_nocancel() 版本的行为与原始函数完全相同,只是这些版本不是线程取消点。

大多数 I/O 函数都是取消点。也就是说,如果线程取消类型为deferred并且取消状态为enabled,并且进程中的另一个线程已经请求取消该线程,该线程将取消(退出) 输入取消点时。参见 man 3 pthread_cancel , man 3 pthread_setcancelstate , 和 man 3 pthread_setcanceltype了解更多详情。

不幸的是,pwrite_nocancel() 和其他 _nocancel() 函数是 pthreads 库的内部(本地)函数,因此很难插入;它们不是动态符号,因此动态链接器无法覆盖它们。在这一点上,我怀疑但不确定插入它们的方法是否涉及重写库代码的开头,直接跳转到您自己的代码。

如果它们是导出的(全局)函数,它们可以像任何其他库函数一样被插入(这些由 pthread 库 libpthread 提供),使用常规方法。 (在我自己的回答中,您可能会发现 thisthisthis 信息丰富。否则,只需搜索 LD_PRELOAD example。)

关于c - 什么是linux中的_nocancel()系统调用,有没有办法使用LD_PRELOAD来拦截它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32296818/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com