簡體   English   中英

如何判斷在vfork()處理過的過程中是否調用過函數?

[英]How to tell if a function is called within a vfork()'ed process?

我有一個用於C的插入器庫。無法插入vfork()因為vfork() (插入函數)在調用了真正的vfork()之后無法返回到調用函數。 但是我要插入_exit()因為我需要知道進程何時完成。 當然,我要插入exec*()函數。 我的問題是,當插入_exit() ,某些事情我想在正常進程調用_exit()時執行,但在該進程是受限制的vfork()進程時卻不希望執行。

我該如何在C程序中判斷我的進程是vfork()的進程,何時無法訪問vfork()返回的進程ID?

插入器庫:

/* COMPILE: gcc -shared -ldl -fPIC -o libso_interposer.so so_interposer.c -std=c99 */
/* RUN:     LD_PRELOAD=./libso_interposer.so so_interposer_test */
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <unistd.h>


static void (*_exit_R)(int) = (void *) 0;
static pid_t (*fork_R)(void) = (void *) 0;
static void teardown_interposer() {
    fprintf(stderr, "Destructing so_interposer.\n");
    /* Concurrency protected code to be executed only once
     * when the process finishes! */
    /* Must not be executed if/when vfork() process finishes. */
}

pid_t fork(void) {
    *(pid_t **) (&fork_R) = dlsym(RTLD_NEXT, "fork");
    /* Code to prepare for a new process.
    * More preparation in exec* interposing functions.*/
    pid_t pid = fork_R();
    return pid;
}
__attribute__((noreturn)) void _exit(int status) {
    *(void **) (&_exit_R) = dlsym(RTLD_NEXT, "_exit");
    fprintf(stderr, "Process '%lld' called _exit(%i).\n", (signed long long int) getpid(), status);
    teardown_interposer();
    _exit_R(status);
}

測試二進制文件:

/* COMPILE: gcc -std=c99 -D FORK=vfork -o so_interposer_test so_interposer_test.c */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#if !defined(FORK)
#error "Define FORK: 'fork' or 'vfork'!"
#endif
int main(void) {
    pid_t pid = FORK();
    if(pid == 0) {
        _exit(EXIT_SUCCESS);
    } else if(pid > 0) {
        _exit(EXIT_SUCCESS);
    }
    return EXIT_SUCCESS;
}

對於最新版本的gcc,您應該可以將vfork包裝為:

typedef pid_t (*vfork_t)(void);
extern vfork_t wrap_vfork();

pid_t vfork(void) {
    vfork_t f = wrap_vfork();
    return f();
}

其中wrap_vfork完成所有vfork包裝工作,並返回指向實際vfork的指針(不調用它)。 Gcc 6.3.0(-O3)編譯為:

    .globl  vfork
    .type   vfork, @function
vfork:
.LFB11:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    xorl    %eax, %eax
    call    wrap_vfork
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    jmp     *%rax
    .cfi_endproc
.LFE11:
    .size   vfork, .-vfork

需要注意的重要一點是,它直接跳轉到實際的vfork函數而不是調用它,因此它本身不需要返回(真正的vfork將直接返回給該函數的調用者)

如果您不滿意依靠編譯器為您執行尾調用優化,則可以直接在asm中而不是在C中編寫這個小例程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM