9b55c997创建于 5月18日历史提交
/******************************************************************************

 * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.

 * libkperf licensed under the Mulan PSL v2.

 * You can use this software according to the terms and conditions of the Mulan PSL v2.

 * You may obtain a copy of Mulan PSL v2 at:

 *     http://license.coscl.org.cn/MulanPSL2

 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR

 * PURPOSE.

 * See the Mulan PSL v2 for more details.

 * Author: RicardoJDLi

 * Create: 2026-05-18

 * Description: Java attach process Interface

 ******************************************************************************/

#include <string.h>

#include <errno.h>

#include <unistd.h>

#include <signal.h>

#include <sys/socket.h>

#include <sys/stat.h>

#include <sys/un.h>

#include <fcntl.h>

#include <iostream>

#include <iostream>

#include <dlfcn.h>



#include "common.h"

#include "java_symbol.h"



const static char* TMP_SOCKET_PREFIX = "/tmp/.java_pid";

const static char* TMP_ATTACH_PREFIX = "/tmp/.attach_pid";

const static char* PROTOCOL = "1";

const static char* CMD = "load";

const static char* ABSOLUTE = "true";

const static char* KPERF_MAP_NAME = "libkperfmap.so";

const static char* LD_LIBRARY_PATH = "LD_LIBRARY_PATH";

const static char* KPERF_MAP_SYMBOL_NAME = "perf_map_open";

static std::string KPERF_MAP_LIB_PATH;



static inline bool FindSocketFile(int pid) {

    std::string path = TMP_ATTACH_PREFIX + std::to_string(pid);

    struct stat statbuf{};

    return stat(path.c_str(), &statbuf) == 0;

}



static inline int ConnectSocket(int fd, const char* path)

{

    struct sockaddr_un addr;

    int err = 0;



    addr.sun_family = AF_UNIX;

    strcpy(addr.sun_path, path);

    if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {

        err = errno;

    }

    return err;

}



static bool FindKperfMap() {

    char* libPath = getenv(LD_LIBRARY_PATH);

    if (libPath == nullptr) {

        return false;

    }

    std::vector<std::string> libList = SplitStringByDelimiter(libPath, ':');

    if (libList.empty()) {

        return false;

    }



    for (const auto&path  : libList) {

        std::string kperfPath = path + "/" + KPERF_MAP_NAME;

        if (ExistPath(kperfPath)) {

            KPERF_MAP_LIB_PATH = kperfPath;

            return true;

        }

    }

}



static bool CheckLib() {

    if (KPERF_MAP_LIB_PATH.empty()) {

        return false;

    }

    void* handle = dlopen(KPERF_MAP_LIB_PATH.c_str(), RTLD_LAZY | RTLD_NOLOAD);

    if (!handle) {

        handle = dlopen(KPERF_MAP_LIB_PATH.c_str(), RTLD_LAZY | RTLD_LOCAL);

        if (!handle) {

            return false;

        }

    }



    void* symbol = dlsym(handle, KPERF_MAP_SYMBOL_NAME);

    if (!symbol) {

        dlclose(handle);

        return false;

    }

    dlclose(handle);

    return true;

}



static inline void WriteDataToSocket(int fd, const std::string& data) {

    write(fd, data.c_str(), data.size());

    unsigned char zero[1] = {0};

    write(fd, zero, 1);

}



int attach_java_process(int pid) {

    if (KPERF_MAP_LIB_PATH.empty() && !FindKperfMap()) {

        return -1;

    }



    if (!CheckLib()) {

        return -1;

    }



    std::string socketPath = TMP_SOCKET_PREFIX + std::to_string(pid);

    if (!FindSocketFile(pid)) {

        std::string attachPath = TMP_ATTACH_PREFIX + std::to_string(pid);

        open(attachPath.c_str(), O_CREAT | O_EXCL, S_IWUSR | S_IRUSR);

        chown(attachPath.c_str(), geteuid(), getegid());

        kill((pid_t)pid, SIGQUIT);

        int i = 0; 

        long sleepTime = 200 * 1000;

        do {usleep(sleepTime);

            i++;

        } while(!FindSocketFile(pid) && i < 100);

    }



    int fd = socket(PF_UNIX, SOCK_STREAM, 0);

    if (fd <= 0) {

        return -1;

    }

    int err = ConnectSocket(fd, socketPath.c_str());

    if (err != 0) {

        return -1;

    }

    WriteDataToSocket(fd, PROTOCOL);

    WriteDataToSocket(fd, CMD);

    WriteDataToSocket(fd, KPERF_MAP_LIB_PATH);

    WriteDataToSocket(fd, ABSOLUTE);

    WriteDataToSocket(fd, "");

    unsigned char buf[128];

    size_t readLen = read(fd, buf, 1);

    if (readLen > 0) {

        if (buf[0] == '0') {

            return 0;

        }

    }

    return -1;

}