/* * Copyright (c) 2013-2020, Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "los_trace_pri.h" #include "ctype.h" #include "securec.h" #include "los_init.h" #include "los_task_pri.h" #include "los_typedef.h" #ifdef LOSCFG_SHELL #include "shcmd.h" #include "shell.h" #include "stdlib.h" #include "unistd.h" #endif #ifndef LOSCFG_KERNEL_TRACE UINT32 OsTraceInit(VOID) { return LOS_OK; } UINT32 LOS_TraceReg(TraceType traceType, WriteHook inHook, const CHAR *typeStr, TraceSwitch onOff) { (VOID)traceType; (VOID)inHook; (VOID)onOff; (VOID)typeStr; return LOS_OK; } UINT32 LOS_TraceUnreg(TraceType traceType) { (VOID)traceType; return LOS_OK; } VOID LOS_Trace(TraceType traceType, ...) { (VOID)traceType; return; } VOID LOS_TraceSwitch(TraceSwitch onOff) { (VOID)onOff; } UINT32 LOS_TraceTypeSwitch(TraceType traceType, TraceSwitch onOff) { (VOID)traceType; (VOID)onOff; return LOS_OK; } VOID LOS_TracePrint(VOID) { return; } INT32 LOS_Trace2File(const CHAR *filename) { (VOID)filename; return 0; } UINT8 *LOS_TraceBufDataGet(UINT32 *desLen, UINT32 *relLen) { (VOID)desLen; (VOID)relLen; return NULL; } #else SPIN_LOCK_INIT(g_traceSpin); #define TRACE_LOCK(state) LOS_SpinLockSave(&g_traceSpin, &(state)) #define TRACE_UNLOCK(state) LOS_SpinUnlockRestore(&g_traceSpin, (state)) #define TMP_DATALEN 128 STATIC UINT8 traceBufArray[LOS_TRACE_BUFFER_SIZE]; STATIC TraceBufferCtl traceBufCtl; STATIC TraceHook traceFunc[LOS_TRACE_TYPE_MAX + 1]; UINT32 OsTraceInit(VOID) { UINT32 intSave; /* Initialize the global variable. */ (VOID)memset_s((VOID *)traceBufArray, LOS_TRACE_BUFFER_SIZE, 0, LOS_TRACE_BUFFER_SIZE); (VOID)memset_s(&traceBufCtl, sizeof(traceBufCtl), 0, sizeof(traceBufCtl)); (VOID)memset_s((VOID *)traceFunc, sizeof(traceFunc), 0, sizeof(traceFunc)); TRACE_LOCK(intSave); /* Initialize trace contrl. */ traceBufCtl.bufLen = LOS_TRACE_BUFFER_SIZE; traceBufCtl.dataBuf = traceBufArray; traceBufCtl.onOff = LOS_TRACE_ENABLE; TRACE_UNLOCK(intSave); return LOS_OK; } UINT32 LOS_TraceReg(TraceType traceType, WriteHook inHook, const CHAR *typeStr, TraceSwitch onOff) { UINT32 intSave; INT32 i; if ((traceType < LOS_TRACE_TYPE_MIN) || (traceType > LOS_TRACE_TYPE_MAX)) { return LOS_ERRNO_TRACE_TYPE_INVALID; } if (inHook == NULL) { return LOS_ERRNO_TRACE_FUNCTION_NULL; } TRACE_LOCK(intSave); /* if inputHook is NULL,return failed. */ if (traceFunc[traceType].inputHook != NULL) { PRINT_ERR("Registered Failed!\n"); for (i = 0; i <= LOS_TRACE_TYPE_MAX; i++) { if (traceFunc[i].inputHook == NULL) { PRINTK("type:%d ", i); } } PRINTK("could be registered\n"); TRACE_UNLOCK(intSave); return LOS_ERRNO_TRACE_TYPE_EXISTED; } else { traceFunc[traceType].inputHook = inHook; traceFunc[traceType].onOff = onOff; traceFunc[traceType].typeStr = typeStr; } TRACE_UNLOCK(intSave); return LOS_OK; } UINT32 LOS_TraceUnreg(TraceType traceType) { UINT32 intSave; if ((traceType < LOS_TRACE_TYPE_MIN) || (traceType > LOS_TRACE_TYPE_MAX)) { return LOS_ERRNO_TRACE_TYPE_INVALID; } TRACE_LOCK(intSave); /* if inputHook is NULL,return failed. */ if (traceFunc[traceType].inputHook == NULL) { PRINT_ERR("Trace not exist!\n"); TRACE_UNLOCK(intSave); return LOS_ERRNO_TRACE_TYPE_NOT_EXISTED; } else { traceFunc[traceType].inputHook = NULL; traceFunc[traceType].onOff = LOS_TRACE_DISABLE; traceFunc[traceType].typeStr = NULL; } TRACE_UNLOCK(intSave); return LOS_OK; } VOID LOS_TraceSwitch(TraceSwitch onOff) { traceBufCtl.onOff = onOff; } UINT32 LOS_TraceTypeSwitch(TraceType traceType, TraceSwitch onOff) { UINT32 intSave; if (traceType < LOS_TRACE_TYPE_MIN || traceType > LOS_TRACE_TYPE_MAX) { return LOS_ERRNO_TRACE_TYPE_INVALID; } TRACE_LOCK(intSave); if (traceFunc[traceType].inputHook != NULL) { traceFunc[traceType].onOff = onOff; TRACE_UNLOCK(intSave); return LOS_OK; } TRACE_UNLOCK(intSave); return LOS_ERRNO_TRACE_TYPE_NOT_EXISTED; } STATIC UINT32 OsFindReadFrameHead(UINT32 readIndex, UINT32 dataSize) { UINT32 historySize = 0; UINT32 index = readIndex; while (historySize < dataSize) { historySize += ((FrameHead *)&(traceBufCtl.dataBuf[index]))->frameSize; index = readIndex + historySize; if (index >= traceBufCtl.bufLen) { index = index - traceBufCtl.bufLen; } } return index; } STATIC VOID OsAddData2Buf(UINT8 *buf, UINT32 dataSize) { UINT32 intSave; UINT32 ret; TRACE_LOCK(intSave); UINT32 desLen = traceBufCtl.bufLen; UINT32 writeIndex = traceBufCtl.writeIndex; UINT32 readIndex = traceBufCtl.readIndex; UINT32 writeRange = writeIndex + dataSize; UINT8 *des = traceBufCtl.dataBuf + writeIndex; /* update readIndex */ if ((readIndex > writeIndex) && (writeRange > readIndex)) { traceBufCtl.readIndex = OsFindReadFrameHead(readIndex, writeRange - readIndex); } else if ((readIndex <= writeIndex) && (writeRange > desLen + readIndex)) { traceBufCtl.readIndex = OsFindReadFrameHead(readIndex, writeRange - readIndex - desLen); } /* copy the data and update writeIndex */ UINT32 tmpLen = desLen - writeIndex; if (tmpLen >= dataSize) { ret = (UINT32)memcpy_s(des, tmpLen, buf, dataSize); if (ret != 0) { goto EXIT; } traceBufCtl.writeIndex = writeIndex + dataSize; } else { ret = (UINT32)memcpy_s(des, tmpLen, buf, tmpLen); /* tmpLen: The length of ringbuf that can be written */ if (ret != 0) { goto EXIT; } ret = (UINT32)memcpy_s(traceBufCtl.dataBuf, desLen, buf + tmpLen, dataSize - tmpLen); if (ret != 0) { goto EXIT; } traceBufCtl.writeIndex = dataSize - tmpLen; } EXIT: TRACE_UNLOCK(intSave); } VOID LOS_Trace(TraceType traceType, ...) { va_list ap; if ((traceType > LOS_TRACE_TYPE_MAX) || (traceType < LOS_TRACE_TYPE_MIN) || (traceFunc[traceType].inputHook == NULL)) { return; } if ((traceBufCtl.onOff == LOS_TRACE_DISABLE) || (traceFunc[traceType].onOff == LOS_TRACE_DISABLE)) { return; } /* Set the trace frame head */ UINT8 buf[TMP_DATALEN]; FrameHead *frameHead = (FrameHead *)buf; frameHead->type = traceType; frameHead->cpuID = ArchCurrCpuid(); frameHead->taskID = LOS_CurTaskIDGet(); frameHead->timestamp = HalClockGetCycles(); #ifdef LOSCFG_TRACE_LR /* Get the linkreg from stack fp and storage to frameHead */ LOS_RecordLR(frameHead->linkReg, LOSCFG_TRACE_LR_RECORD, LOSCFG_TRACE_LR_RECORD, LOSCFG_TRACE_LR_IGNOR); #endif /* Get the trace message */ va_start(ap, traceType); INT32 dataSize = (traceFunc[traceType].inputHook)(buf + sizeof(FrameHead), TMP_DATALEN - sizeof(FrameHead), ap); va_end(ap); if (dataSize <= 0) { return; } frameHead->frameSize = sizeof(FrameHead) + dataSize; OsAddData2Buf(buf, frameHead->frameSize); } UINT8 *LOS_TraceBufDataGet(UINT32 *desLen, UINT32 *relLen) { UINT32 traceSwitch = traceBufCtl.onOff; if (desLen == NULL || relLen == NULL) { return NULL; } if (traceSwitch != LOS_TRACE_DISABLE) { LOS_TraceSwitch(LOS_TRACE_DISABLE); } UINT32 writeIndex = traceBufCtl.writeIndex; UINT32 readIndex = traceBufCtl.readIndex; UINT32 srcLen = traceBufCtl.bufLen; UINT8 *des = (UINT8 *)malloc(srcLen * sizeof(UINT8)); if (des == NULL) { *desLen = 0; *relLen = 0; if (traceSwitch != LOS_TRACE_DISABLE) { LOS_TraceSwitch(LOS_TRACE_DISABLE); } return NULL; } *desLen = LOS_TRACE_BUFFER_SIZE; if (EOK != memset_s(des, srcLen * sizeof(UINT8), 0, LOS_TRACE_BUFFER_SIZE)) { *desLen = 0; *relLen = 0; free(des); return NULL; } if (writeIndex > readIndex) { *relLen = readIndex - writeIndex; (VOID)memcpy_s(des, *desLen, &(traceBufArray[readIndex]), *relLen); } else { UINT32 sumLen = srcLen - readIndex; (VOID)memcpy_s(des, *desLen, &(traceBufArray[readIndex]), sumLen); (VOID)memcpy_s(&(des[sumLen]), *desLen - sumLen, traceBufArray, writeIndex); *relLen = sumLen + writeIndex; } if (traceSwitch != LOS_TRACE_DISABLE) { LOS_TraceSwitch(LOS_TRACE_ENABLE); } return des; } #ifdef LOSCFG_FS_VFS INT32 LOS_Trace2File(const CHAR *filename) { INT32 ret; CHAR *fullpath = NULL; CHAR *shellWorkingDirectory = OsShellGetWorkingDirtectory(); UINT32 traceSwitch = traceBufCtl.onOff; ret = vfs_normalize_path(shellWorkingDirectory, filename, &fullpath); if (ret != 0) { return -1; } if (traceSwitch != LOS_TRACE_DISABLE) { LOS_TraceSwitch(LOS_TRACE_DISABLE); } INT32 fd = open(fullpath, O_CREAT | O_RDWR | O_APPEND, 0644); /* 0644:file right */ if (fd < 0) { return -1; } UINT32 writeIndex = traceBufCtl.writeIndex; UINT32 readIndex = traceBufCtl.readIndex; if (writeIndex > readIndex) { ret = write(fd, &(traceBufArray[readIndex]), writeIndex - readIndex); } else { ret = write(fd, &(traceBufArray[readIndex]), traceBufCtl.bufLen - readIndex); ret += write(fd, traceBufArray, writeIndex); } (VOID)close(fd); free(fullpath); if (traceSwitch != LOS_TRACE_DISABLE) { LOS_TraceSwitch(LOS_TRACE_ENABLE); } return ret; } #endif #ifdef LOSCFG_SHELL UINT32 OsShellCmdTraceNumSwitch(TraceType traceType, const CHAR *onOff) { UINT32 ret = LOS_NOK; if (strcmp("on", onOff) == 0) { ret = LOS_TraceTypeSwitch(traceType, LOS_TRACE_ENABLE); if (ret == LOS_OK) { PRINTK("trace %s on\n", traceFunc[traceType].typeStr); } else { PRINTK("trace %d is unregistered\n", traceType); } } else if (strcmp("off", onOff) == 0) { ret = LOS_TraceTypeSwitch(traceType, LOS_TRACE_DISABLE); if (ret == LOS_OK) { PRINTK("trace %s off\n", traceFunc[traceType].typeStr); } else { PRINTK("trace %d is unregistered\n", traceType); } } else { PRINTK("Unknown option: %s\n", onOff); } return ret; } UINT32 OsShellCmdTraceStrSwitch(const CHAR *typeStr, const CHAR *onOff) { UINT32 ret = LOS_NOK; UINT32 i; for (i = 0; i <= LOS_TRACE_TYPE_MAX; i++) { if (traceFunc[i].typeStr != NULL && !strcmp(typeStr, traceFunc[i].typeStr)) { ret = OsShellCmdTraceNumSwitch(i, onOff); if (ret != LOS_OK) { PRINTK("Unknown option: %s\n", onOff); } return ret; } } PRINTK("Unknown option: %s\n", typeStr); return ret; } UINT32 OsShellCmdTraceSwitch(INT32 argc, const CHAR **argv) { UINT32 ret; if (argc == 1) { if (strcmp("on", argv[0]) == 0) { LOS_TraceSwitch(LOS_TRACE_ENABLE); PRINTK("trace on\n"); } else if (strcmp("off", argv[0]) == 0) { LOS_TraceSwitch(LOS_TRACE_DISABLE); PRINTK("trace off\n"); } else { PRINTK("Unknown option: %s\n", argv[0]); goto TRACE_HELP; } } else if (argc == 2) { /* 2:argc number limited */ if (isdigit(argv[0][0]) != 0) { CHAR *endPtr = NULL; UINT32 traceType = strtoul(argv[0], &endPtr, 0); if ((endPtr == NULL) || (*endPtr != 0)) { PRINTK("Unknown option: %s\n", argv[0]); goto TRACE_HELP; } ret = OsShellCmdTraceNumSwitch(traceType, argv[1]); if (ret != LOS_OK) { goto TRACE_HELP; } } else { ret = OsShellCmdTraceStrSwitch(argv[0], argv[1]); if (ret != LOS_OK) { goto TRACE_HELP; } } } else { PRINTK("Argc is Incorrect!\n"); goto TRACE_HELP; } return LOS_OK; TRACE_HELP: PRINTK("Usage:trace [typeNum/typeName] on/off\n"); PRINTK(" typeNum range: [%d,%d]\n", LOS_TRACE_TYPE_MIN, LOS_TRACE_TYPE_MAX); return LOS_NOK; } #ifdef LOSCFG_FS_VFS UINT32 OsShellCmdTrace2File(INT32 argc, const CHAR **argv) { INT32 ret; if (argc == 1) { ret = LOS_Trace2File(argv[0]); if (ret == -1) { PRINTK("Trace to file failed: %s\n", argv[0]); } else { PRINTK("Trace to file successed: %s\n", argv[0]); } } else { PRINTK("Trace to file:wrong argc\n"); goto TRACE_HELP; } return LOS_OK; TRACE_HELP: PRINTK("usage:trace2file filename\n"); return LOS_NOK; } SHELLCMD_ENTRY(trace2file_shellcmd, CMD_TYPE_EX, "trace2file", 1, (CmdCallBackFunc)OsShellCmdTrace2File); #endif SHELLCMD_ENTRY(trace_shellcmd, CMD_TYPE_EX, "trace", 1, (CmdCallBackFunc)OsShellCmdTraceSwitch); #endif #endif LOS_MODULE_INIT(OsTraceInit, LOS_INIT_LEVEL_EARLIEST);