往前冲队-合并请求 #37
|
|
@ -1,773 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openGauss is licensed under 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.
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* bbox_threads.cpp
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/gausskernel/cbb/bbox/bbox_threads.cpp
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include "bbox_syscall_support.h"
|
||||
#include "bbox_threads.h"
|
||||
#include "bbox_print.h"
|
||||
#include "bbox_atomic.h"
|
||||
#include "../../src/include/securec.h"
|
||||
#include "../../src/include/securec_check.h"
|
||||
|
||||
static const u32 iSyncSignals[] = {
|
||||
SIGABRT,
|
||||
SIGILL,
|
||||
SIGFPE,
|
||||
SIGSEGV,
|
||||
SIGBUS,
|
||||
SIGXCPU,
|
||||
SIGXFSZ,
|
||||
};
|
||||
|
||||
struct TASK_ATTACH_INFO {
|
||||
pid_t pid; /* pid */
|
||||
u8 cIsAttached; /* Whether the thread is ptraced */
|
||||
};
|
||||
|
||||
struct TASK_CHECK_RESUME_ARGS {
|
||||
struct TASK_ATTACH_INFO* pstTaskInfo; /* recover process information */
|
||||
s32 iThreadCount; /* thread count */
|
||||
GET_THREAD_TYPE enType; /* get thread type */
|
||||
};
|
||||
|
||||
struct BBOX_ListParams {
|
||||
s32 iResult; /* result */
|
||||
s32 iError; /* error code */
|
||||
u8* pAltStackMem; /* Execution stack information */
|
||||
BBOX_GetAllThreadsCallBack pCallBack; /* Executes the callback function exported by the thread */
|
||||
BBOX_GetAllThreadDone pDoneCallback; /* call back function after exporting the thread information */
|
||||
void* pDoneArgs; /* parameter of call back function pDoneCallback */
|
||||
GET_THREAD_TYPE enGetType; /* get data type */
|
||||
va_list ap; /* parameter list of function pCallBack */
|
||||
};
|
||||
|
||||
u8 g_szAltStackMem[BBOX_ALT_STACKSIZE]; /* independent thread stack memory */
|
||||
|
||||
BBOX_ATOMIC_STRU g_isBusy = BBOX_ATOMIC_INIT(0); /* whether deal with core file. */
|
||||
|
||||
/*
|
||||
function name: BBOX_ReserveZeroStack
|
||||
description: The function creat a empty stack, and its size depend on argument count.
|
||||
arguments: An integer of type s32, namely int, it destines the storage of stack.
|
||||
return value: void
|
||||
note: The stack this function creats is actually a character array.
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
void BBOX_ReserveZeroStack(s32 count)
|
||||
{
|
||||
char buff[count];
|
||||
|
||||
errno_t rc = memset_s(buff, count, 0, count);
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
|
||||
(void)sys_read(-1, buff, count);
|
||||
}
|
||||
|
||||
/*
|
||||
* clone the current process and runs the specified function
|
||||
* return 0 if seccess else err code
|
||||
*/
|
||||
s32 BBOX_CloneRun(u32 uFlags, s32 (*pFn)(void*), void* pArg, ...)
|
||||
{
|
||||
/* reserve 4K when calling and running a function to protect waitpid can exit correct. */
|
||||
/* CLONE_UNTRACED flag is must or gdb will debug new process which is cloned. */
|
||||
pid_t pid;
|
||||
if (pArg == NULL || pFn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = sys__clone(pFn, (((char*)(pArg)) - 4096), uFlags | CLONE_UNTRACED, pArg, 0, 0, 0);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_GetTaskNumber
|
||||
description: When get a path to specific process, this function will return count of threads below it.
|
||||
arguments: A pointer of type char*, including a path to specific process.
|
||||
return value: An integer that indicates the count of threads below specific process.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
s32 BBOX_GetTaskNumber(char* szTaskPath)
|
||||
{
|
||||
struct kernel_stat stProcSB = {0};
|
||||
s32 iProc = -1;
|
||||
|
||||
if (szTaskPath == NULL) {
|
||||
bbox_print(PRINT_ERR, "parameter szTaskPath is null.\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* open /proc */
|
||||
iProc = sys_open(szTaskPath, O_RDONLY | O_DIRECTORY, 0);
|
||||
if (iProc < 0) {
|
||||
bbox_print(PRINT_ERR, "open file %s failed, errno = %d\n", szTaskPath, errno);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get the number of first file nodes in the directory */
|
||||
if (sys_fstat(iProc, &stProcSB)) {
|
||||
bbox_print(PRINT_ERR, "Get file %s fstat, errno = %d, iProc = %d\n", szTaskPath, errno, iProc);
|
||||
|
||||
sys_close(iProc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sys_close(iProc);
|
||||
|
||||
return stProcSB.st_nlink;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_GetTaskId
|
||||
description: When get a path to specific process, this function will return count of threads below it.
|
||||
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
|
||||
we use it as a structure array to store requisite thread infomation, the next argument destines
|
||||
the max size of the array that the first argument destines. The last argument is a pointer of type
|
||||
char*, including a path to specific process.
|
||||
return value: An integer that indicates the count of threads stored in structure array.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
s32 BBOX_GetTaskId(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iSize, char* szTaskPath)
|
||||
{
|
||||
s32 iProc = -1;
|
||||
pid_t pid = 0;
|
||||
struct linux_dirent* pstEntry = NULL;
|
||||
char szBuff[PAGE_SIZE];
|
||||
ssize_t nBytes;
|
||||
const char* pszPtr = NULL;
|
||||
s32 iThreadCount = 0;
|
||||
|
||||
if (pstTaskInfo == NULL || szTaskPath == NULL) {
|
||||
bbox_print(PRINT_ERR,
|
||||
"parameter is invalid, pstTaskInfo or szTaskPath is NULL, iSize = %d \n",
|
||||
iSize);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
iProc = sys_open(szTaskPath, O_RDONLY | O_DIRECTORY, 0);
|
||||
if (iProc < 0) {
|
||||
bbox_print(PRINT_ERR, "open '%s' failed, errno = %d\n", szTaskPath, errno);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* traverse /proc/[pid]/task, get count of thread and pid. */
|
||||
for (; iThreadCount < iSize;) {
|
||||
/* get pointer to the directory structure */
|
||||
nBytes = sys_getdents(iProc, (struct linux_dirent*)szBuff, sizeof(szBuff));
|
||||
if (nBytes < 0) {
|
||||
bbox_print(PRINT_ERR, "Get dents '%s' failed, errno = %d\n", szTaskPath, errno);
|
||||
|
||||
goto errout;
|
||||
} else if (0 == nBytes) {
|
||||
sys_lseek(iProc, 0, SEEK_SET);
|
||||
break;
|
||||
}
|
||||
|
||||
/* recursively traversing the directory */
|
||||
for (pstEntry = (struct linux_dirent*)szBuff;
|
||||
(pstEntry < (struct linux_dirent*)&szBuff[nBytes]) && (iThreadCount < iSize);
|
||||
pstEntry = (struct linux_dirent*)((char*)pstEntry + pstEntry->d_reclen)) {
|
||||
if (pstEntry->d_ino == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pszPtr = pstEntry->d_name;
|
||||
bbox_print(PRINT_DBG, "dir: %s/%s\n", szTaskPath, pszPtr);
|
||||
|
||||
if (*pszPtr == '.') {
|
||||
pszPtr++;
|
||||
}
|
||||
|
||||
/* ignore directory that is not a proc. */
|
||||
if (*pszPtr < '0' || *pszPtr > '9') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get pid information */
|
||||
pid = bbox_atoi(pszPtr);
|
||||
|
||||
if (!pid || pid == sys_gettid()) {
|
||||
bbox_print(PRINT_ERR, "pid is invalid , pid = %d\n", pid);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* add thread information into a array. */
|
||||
pstTaskInfo[iThreadCount].pid = pid;
|
||||
pstTaskInfo[iThreadCount].cIsAttached = 0;
|
||||
iThreadCount++;
|
||||
}
|
||||
}
|
||||
|
||||
sys_close(iProc);
|
||||
return iThreadCount;
|
||||
errout:
|
||||
sys_close(iProc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_PtraceAttachPid
|
||||
description: The function is used to check the process whose id stored in structure array pstTaskInfo work normally.
|
||||
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
|
||||
it is used as a structure array that has stored requisite thread infomation, the next argument destines
|
||||
the size of the array that the first argument destines, namely how many elements the array has.
|
||||
The last argument is an integer to decide if need to check if the trace to destined process
|
||||
work normally, if normal, corresponding element of array pstTaskInfo's member variable cIsAttached
|
||||
will change from 0 to 1.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s32 iDoPtraceCheck)
|
||||
{
|
||||
u32 i;
|
||||
pid_t pid;
|
||||
unsigned long m = 0;
|
||||
unsigned long n = 0;
|
||||
|
||||
if (pstTaskInfo == NULL || iPidCount <= 0) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
for (i = 0; i < (u32)iPidCount; i++) {
|
||||
/* walk through all the threads and debug the trace. */
|
||||
pid = pstTaskInfo[i].pid;
|
||||
if (sys_ptrace(PTRACE_ATTACH, pid, (void*)0, (void*)0) < 0) {
|
||||
bbox_print(PRINT_ERR, "ptrace failed, pid = %d, errno = %d\n", pid, errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check that if the thread state is normal. */
|
||||
while (sys_waitpid(pid, (int*)0, __WALL) < 0) {
|
||||
if (errno != EINTR) {
|
||||
bbox_print(PRINT_ERR, "wait for %d failed, errno = %d\n", pid, errno);
|
||||
|
||||
sys_ptrace(PTRACE_DETACH, pid, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iDoPtraceCheck) {
|
||||
int ret = 0;
|
||||
ret = sys_ptrace(PTRACE_PEEKDATA, pid, &m, &n);
|
||||
/* check that if the trace is valid */
|
||||
if (ret || (m != n)) {
|
||||
bbox_print(PRINT_ERR,
|
||||
"ptrace peek data failed, pid = %d, ret = %d,m = %lu, n = %lu, errno = %d\n",
|
||||
pid, ret, m, n, errno);
|
||||
|
||||
sys_ptrace(PTRACE_DETACH, pid, 0, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bbox_print(PRINT_LOG, "ptrace attach %d\n", pid);
|
||||
pstTaskInfo[i].cIsAttached = 1;
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_DetachAllThread
|
||||
description: The function is used to cancel checking the process whose id stored in structure array pstTaskInfo
|
||||
work normally, "work normally" means in array pstTaskInfo corresponding element's member
|
||||
variable cIsAttached's value is 1.
|
||||
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
|
||||
it is used as a structure array that has stored requisite thread infomation, the next argument destines
|
||||
the size of the array that the first argument destines, namely how many elements the array has.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
void BBOX_DetachAllThread(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount)
|
||||
{
|
||||
u32 i;
|
||||
pid_t pid;
|
||||
|
||||
if (pstTaskInfo == NULL || iPidCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < (u32)iPidCount; i++) {
|
||||
pid = pstTaskInfo[i].pid;
|
||||
if (!pstTaskInfo[i].cIsAttached) {
|
||||
continue;
|
||||
}
|
||||
bbox_print(PRINT_LOG, "ptrace detach %d\n", pid);
|
||||
|
||||
/* cancel track. */
|
||||
sys_sched_yield();
|
||||
sys_ptrace(PTRACE_DETACH, pid, 0, 0);
|
||||
sys_kill(pid, SIGCONT);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* notification function after dump module have got all data, to recover a thread.
|
||||
*/
|
||||
void BBOX_CheckResumeThread(void* pArgs)
|
||||
{
|
||||
struct TASK_CHECK_RESUME_ARGS* pstTaskCheck = NULL;
|
||||
|
||||
if (pArgs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pstTaskCheck = (struct TASK_CHECK_RESUME_ARGS*)pArgs;
|
||||
|
||||
if (GET_TYPE_SNAP == pstTaskCheck->enType) {
|
||||
BBOX_DetachAllThread(pstTaskCheck->pstTaskInfo, pstTaskCheck->iThreadCount);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_PtraceAndRun
|
||||
description: When get a path to specific process, this function will trace the threads below it, and get the
|
||||
information for example how many threads work normally then store it in pstArgs.
|
||||
arguments: The first argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
|
||||
what matters is its member variable callback function pointer, the next argument destines
|
||||
the max count of the thread. The last argument is a pointer of type char*, including a path
|
||||
to specific process.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char* pszProcSelfTask)
|
||||
{
|
||||
struct TASK_ATTACH_INFO stTaskInfo[iMaxThreadCount];
|
||||
pid_t thread_pids[iMaxThreadCount];
|
||||
|
||||
struct TASK_CHECK_RESUME_ARGS stTaskCheck;
|
||||
s32 iThreadCount = 0;
|
||||
s32 iAttachCount = 0;
|
||||
s32 iRet = 0;
|
||||
s32 iDoPtraceCheck = 1;
|
||||
s32 i;
|
||||
|
||||
if (pstArgs == NULL || pszProcSelfTask == NULL || iMaxThreadCount <= 0) {
|
||||
|
||||
bbox_print(PRINT_ERR,
|
||||
"Parameter is invald, pstArgs or pszProcSelfTask is NULL, iMaxThreadCount = %d \n",
|
||||
iMaxThreadCount);
|
||||
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
errno_t rc = memset_s(stTaskInfo, sizeof(stTaskInfo), 0, sizeof(stTaskInfo));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
rc = memset_s(thread_pids, sizeof(thread_pids), 0, sizeof(thread_pids));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
rc = memset_s(&stTaskCheck, sizeof(stTaskCheck), 0, sizeof(stTaskCheck));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
|
||||
iThreadCount = BBOX_GetTaskId(stTaskInfo, iMaxThreadCount, pszProcSelfTask);
|
||||
if (iThreadCount <= 0) {
|
||||
bbox_print(PRINT_ERR, "Get task id failed.\n");
|
||||
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (GET_TYPE_DUMP != pstArgs->enGetType) {
|
||||
iDoPtraceCheck = 0;
|
||||
} else {
|
||||
iDoPtraceCheck = 1;
|
||||
}
|
||||
|
||||
iRet = BBOX_PtraceAttachPid(stTaskInfo, iThreadCount, iDoPtraceCheck);
|
||||
if (iRet != RET_OK) {
|
||||
bbox_print(PRINT_ERR, "Ptrace attache failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* copy information of thread that have been attaching. */
|
||||
for (i = 0; i < iThreadCount; i++) {
|
||||
if (!stTaskInfo[i].cIsAttached) {
|
||||
continue;
|
||||
}
|
||||
thread_pids[iAttachCount] = stTaskInfo[i].pid;
|
||||
iAttachCount++;
|
||||
}
|
||||
|
||||
stTaskCheck.pstTaskInfo = stTaskInfo;
|
||||
stTaskCheck.enType = pstArgs->enGetType;
|
||||
stTaskCheck.iThreadCount = iThreadCount;
|
||||
|
||||
/* run call back function. */
|
||||
bbox_print(PRINT_TIP, "Thread count :%d\n", iThreadCount);
|
||||
bbox_print(PRINT_TIP, "Ptraced thread count :%d\n", iAttachCount);
|
||||
bbox_print(PRINT_LOG, "Run callback: thread count = %d\n", iThreadCount);
|
||||
/* Callback to the thread information handler. */
|
||||
pstArgs->iResult = pstArgs->pCallBack(BBOX_CheckResumeThread, &stTaskCheck, iAttachCount, thread_pids, pstArgs->ap);
|
||||
pstArgs->iError = errno;
|
||||
|
||||
BBOX_DetachAllThread(stTaskInfo, iThreadCount);
|
||||
|
||||
return RET_OK;
|
||||
|
||||
errout:
|
||||
BBOX_DetachAllThread(stTaskInfo, iThreadCount);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_PrintFailedLog
|
||||
description: Write log infomation into specific file, if errors arise, print the infomation about errors.
|
||||
arguments: The only argument is a pointer of type const char* to a filename string, if this file doesn't
|
||||
exist, we will creat a new file named it.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
void BBOX_PrintFailedLog(const char* pFileName)
|
||||
{
|
||||
ssize_t iRet = 0;
|
||||
s32 iWriteSize = 0;
|
||||
s32 iBboxLogFd = -1;
|
||||
|
||||
iBboxLogFd = sys_open(pFileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (iBboxLogFd < 0) {
|
||||
|
||||
bbox_print(PRINT_ERR, "open failed, errno = %d\n", errno);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
iWriteSize = bbox_strnlen(g_acBBoxLog, BBOX_LOG_SIZE) + 1;
|
||||
iWriteSize = (iWriteSize > BBOX_LOG_SIZE) ? BBOX_LOG_SIZE : iWriteSize;
|
||||
iRet = sys_write(iBboxLogFd, g_acBBoxLog, iWriteSize);
|
||||
if (iRet < 0) {
|
||||
bbox_print(PRINT_ERR, "write failed, errno = %d\n", errno);
|
||||
|
||||
sys_close(iBboxLogFd);
|
||||
return;
|
||||
}
|
||||
|
||||
sys_close(iBboxLogFd);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_ListThread
|
||||
description: Export thread information.
|
||||
arguments: The only argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
|
||||
what matters is its member variable callback function pointer and thread infomation.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
void BBOX_ListThread(struct BBOX_ListParams* pstArgs)
|
||||
{
|
||||
pid_t ppid = 0;
|
||||
s32 iMaker = -1;
|
||||
s32 iMaxThreadCount = 0;
|
||||
s32 iRet = 0;
|
||||
|
||||
struct kernel_stat stMarkerSB;
|
||||
char szProcSelfTask[BBOX_PROC_PATH_LEN];
|
||||
char pszMarkPath[BBOX_PROC_PATH_LEN];
|
||||
stack_t altstack;
|
||||
errno_t rc = EOK;
|
||||
|
||||
if (pstArgs == NULL) {
|
||||
bbox_print(PRINT_ERR, "pstArgs is NULL.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ppid = sys_getppid();
|
||||
|
||||
iMaker = sys_socket(PF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (iMaker < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_socket error, errno = %d\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (sys_fcntl(iMaker, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_fcntl error, errno = %d\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (bbox_snprintf(szProcSelfTask, BBOX_PROC_PATH_LEN, "/proc/%d/task", ppid) <= 0) {
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (bbox_snprintf(pszMarkPath, BBOX_PROC_PATH_LEN, "/proc/%d/fd/%d", ppid, iMaker) <= 0) {
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
bbox_print(PRINT_TIP, "Get information for pid %d:\n", ppid);
|
||||
|
||||
rc = memset_s(&stMarkerSB, sizeof(stMarkerSB), 0, sizeof(stMarkerSB));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
|
||||
if (sys_stat(pszMarkPath, &stMarkerSB) < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_stat error, errno = %d, path = %s\n", errno, pszMarkPath);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* switch stack pointer */
|
||||
rc = memset_s(&altstack, sizeof(altstack), 0, sizeof(altstack));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
altstack.ss_sp = pstArgs->pAltStackMem;
|
||||
altstack.ss_flags = 0;
|
||||
altstack.ss_size = BBOX_ALT_STACKSIZE;
|
||||
sys_sigaltstack(&altstack, (const stack_t*)NULL);
|
||||
|
||||
/* get max count of task. */
|
||||
iMaxThreadCount = BBOX_GetTaskNumber(szProcSelfTask);
|
||||
if (iMaxThreadCount <= 0) {
|
||||
bbox_print(PRINT_ERR, "Get task number failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* ptrace and run thread. */
|
||||
iRet = BBOX_PtraceAndRun(pstArgs, iMaxThreadCount, szProcSelfTask);
|
||||
if (iRet != RET_OK) {
|
||||
bbox_print(PRINT_ERR, "ptrace task and run failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
bbox_print(PRINT_TIP, "Get information success.\n");
|
||||
|
||||
sys_close(iMaker);
|
||||
|
||||
if (RET_OK != pstArgs->iResult) {
|
||||
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
|
||||
}
|
||||
|
||||
if (pstArgs->pDoneCallback != NULL) {
|
||||
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
|
||||
}
|
||||
|
||||
sys_exit(0);
|
||||
errout:
|
||||
if (iMaker > 0) {
|
||||
sys_close(iMaker);
|
||||
}
|
||||
|
||||
bbox_print(PRINT_ERR, "Get information failed.\n");
|
||||
|
||||
pstArgs->iResult = -1;
|
||||
pstArgs->iError = errno;
|
||||
|
||||
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
|
||||
if (pstArgs->pDoneCallback != NULL) {
|
||||
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
|
||||
}
|
||||
|
||||
sys_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: BBOX_GetClonePidResult
|
||||
description: The function get the status of child process at first, then according to it assign pstArgs's
|
||||
member variables iError and iResult appropriate values.
|
||||
arguments: The first argument is a integer named iClonePid, it represents the pid of child process.
|
||||
The second argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
|
||||
what matters is its member variable callback function pointer and thread infomation.
|
||||
The third argument is a integer indicating error code.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32 iCloneErrno)
|
||||
{
|
||||
s32 iStatus = 0;
|
||||
s32 iRet = 0;
|
||||
|
||||
if (iClonePid < 0) {
|
||||
|
||||
bbox_print(PRINT_ERR, "Clone failed, can't create child process, errno = %d.\n", iCloneErrno);
|
||||
|
||||
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
|
||||
if (pstArgs->pDoneCallback != NULL) {
|
||||
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
|
||||
}
|
||||
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* wait child process exit. */
|
||||
while ((iRet = sys_waitpid(iClonePid, &iStatus, __WALL)) < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bbox_print(PRINT_LOG, "clone pid %d ret is %x, status = %x\n", iClonePid, iRet, WIFEXITED(iStatus));
|
||||
|
||||
if (iRet < 0) {
|
||||
pstArgs->iError = errno;
|
||||
pstArgs->iResult = -1;
|
||||
} else if (WIFEXITED(iStatus)) {
|
||||
switch (WEXITSTATUS(iStatus)) {
|
||||
case 0:
|
||||
break;
|
||||
case 2:
|
||||
pstArgs->iError = EFAULT;
|
||||
pstArgs->iResult = -1;
|
||||
break;
|
||||
case 3:
|
||||
pstArgs->iError = EPERM;
|
||||
pstArgs->iResult = 1;
|
||||
break;
|
||||
default:
|
||||
pstArgs->iError = ECHILD;
|
||||
pstArgs->iResult = -1;
|
||||
break;
|
||||
}
|
||||
} else if (!WIFEXITED(iStatus)) {
|
||||
pstArgs->iError = EFAULT;
|
||||
pstArgs->iResult = -1;
|
||||
bbox_print(PRINT_ERR, "WIFEXITED status failed");
|
||||
} else {
|
||||
pstArgs->iError = iCloneErrno;
|
||||
pstArgs->iResult = -1;
|
||||
bbox_print(PRINT_ERR, "WIFEXITED error, errno = %d\n", iCloneErrno);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* get all threads and run specify function
|
||||
*/
|
||||
s32 BBOX_GetAllThreads(
|
||||
GET_THREAD_TYPE enType, BBOX_GetAllThreadDone pDone, void* pDoneArgs, BBOX_GetAllThreadsCallBack pCallback, ...)
|
||||
{
|
||||
struct BBOX_ListParams stArgs;
|
||||
struct kernel_sigset_t stSigBlocked;
|
||||
struct kernel_sigset_t stSigOld;
|
||||
s32 iDumpable = 1;
|
||||
s32 iSigNo;
|
||||
s32 iCloneErrno;
|
||||
pid_t ClonePid;
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (BBOX_AtomicIncReturn(&g_isBusy) > 1) {
|
||||
BBOX_AtomicDec(&g_isBusy);
|
||||
|
||||
bbox_print(PRINT_ERR, "Dump task is running.\n");
|
||||
|
||||
errno = EALREADY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (enType >= GET_TYPE_BUTT || pCallback == NULL) {
|
||||
bbox_print(PRINT_ERR, "Parameter is invalid, enType = %d, and maybe pCallback is NULL", enType);
|
||||
BBOX_AtomicDec(&g_isBusy);
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno_t rc = memset_s(&stArgs, sizeof(stArgs), 0, sizeof(stArgs));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
rc = memset_s(&stSigBlocked, sizeof(stSigBlocked), 0, sizeof(stSigBlocked));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
rc = memset_s(&stSigOld, sizeof(stSigOld), 0, sizeof(stSigOld));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
|
||||
va_start(stArgs.ap, pCallback);
|
||||
|
||||
/* clear new stack */
|
||||
rc = memset_s(g_szAltStackMem, BBOX_ALT_STACKSIZE, 0, BBOX_ALT_STACKSIZE);
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
/* reserve 32K */
|
||||
BBOX_ReserveZeroStack(1024 * 32);
|
||||
|
||||
/* check and set dump flag. */
|
||||
iDumpable = sys_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
|
||||
if (!iDumpable) {
|
||||
sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* set start parameter of dump thread. */
|
||||
stArgs.iResult = -1;
|
||||
stArgs.iError = 0;
|
||||
stArgs.pAltStackMem = g_szAltStackMem;
|
||||
stArgs.pCallBack = pCallback;
|
||||
stArgs.pDoneCallback = pDone;
|
||||
stArgs.pDoneArgs = pDoneArgs;
|
||||
stArgs.enGetType = enType;
|
||||
|
||||
/* suspend all signals */
|
||||
sys_sigfillset(&stSigBlocked);
|
||||
for (iSigNo = 0; iSigNo < (s32)(sizeof(iSyncSignals) / sizeof(*iSyncSignals)); iSigNo++) {
|
||||
sys_sigdelset(&stSigBlocked, iSyncSignals[iSigNo]);
|
||||
}
|
||||
|
||||
/* block all signals */
|
||||
if (sys_sigprocmask(SIG_BLOCK, &stSigBlocked, &stSigOld)) {
|
||||
stArgs.iError = errno;
|
||||
stArgs.iResult = -1;
|
||||
bbox_print(PRINT_ERR, "sys_sigprocmask error, errno = %d\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* create child process and run function to export thread information. */
|
||||
if (GET_TYPE_DUMP == enType) {
|
||||
|
||||
ClonePid = BBOX_CloneRun(CLONE_VM | CLONE_FS | CLONE_FILES, (s32(*)(void*))BBOX_ListThread, &stArgs);
|
||||
} else {
|
||||
/* copy VMA if type is snapshoot. */
|
||||
ClonePid = BBOX_CloneRun(CLONE_FS | CLONE_FILES, (s32(*)(void*))BBOX_ListThread, &stArgs);
|
||||
}
|
||||
|
||||
iCloneErrno = errno;
|
||||
|
||||
/* restoring signal */
|
||||
sys_sigprocmask(SIG_SETMASK, &stSigOld, &stSigOld);
|
||||
|
||||
if (BBOX_GetClonePidResult(ClonePid, &stArgs, iCloneErrno) != RET_OK) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetClonePidResult error\n");
|
||||
}
|
||||
|
||||
errout:
|
||||
BBOX_AtomicDec(&g_isBusy);
|
||||
|
||||
if (!iDumpable) {
|
||||
sys_prctl(PR_SET_DUMPABLE, iDumpable, 0, 0, 0);
|
||||
}
|
||||
|
||||
va_end(stArgs.ap);
|
||||
|
||||
errno = stArgs.iError;
|
||||
return stArgs.iResult;
|
||||
}
|
||||
Loading…
Reference in New Issue