1800b99b8Sopenharmony_ci/* 2800b99b8Sopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd. 3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License. 5800b99b8Sopenharmony_ci * You may obtain a copy of the License at 6800b99b8Sopenharmony_ci * 7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8800b99b8Sopenharmony_ci * 9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and 13800b99b8Sopenharmony_ci * limitations under the License. 14800b99b8Sopenharmony_ci */ 15800b99b8Sopenharmony_ci#include "dfx_crash_local_handler.h" 16800b99b8Sopenharmony_ci 17800b99b8Sopenharmony_ci#include <securec.h> 18800b99b8Sopenharmony_ci#include <csignal> 19800b99b8Sopenharmony_ci#include <sys/time.h> 20800b99b8Sopenharmony_ci#include <sys/ucontext.h> 21800b99b8Sopenharmony_ci#include <cinttypes> 22800b99b8Sopenharmony_ci#include <unistd.h> 23800b99b8Sopenharmony_ci#include <pthread.h> 24800b99b8Sopenharmony_ci#include <cerrno> 25800b99b8Sopenharmony_ci#include "dfx_log.h" 26800b99b8Sopenharmony_ci#include "dfx_cutil.h" 27800b99b8Sopenharmony_ci#include "dfx_signalhandler_exception.h" 28800b99b8Sopenharmony_ci#include "faultloggerd_client.h" 29800b99b8Sopenharmony_ci#include "unwinder.h" 30800b99b8Sopenharmony_ci 31800b99b8Sopenharmony_ci#ifdef LOG_DOMAIN 32800b99b8Sopenharmony_ci#undef LOG_DOMAIN 33800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11 34800b99b8Sopenharmony_ci#endif 35800b99b8Sopenharmony_ci 36800b99b8Sopenharmony_ci#ifdef LOG_TAG 37800b99b8Sopenharmony_ci#undef LOG_TAG 38800b99b8Sopenharmony_ci#define LOG_TAG "DfxCrashLocalHandler" 39800b99b8Sopenharmony_ci#endif 40800b99b8Sopenharmony_ci 41800b99b8Sopenharmony_ci#define MAX_FRAME 64 42800b99b8Sopenharmony_ci#define BUF_SZ 512 43800b99b8Sopenharmony_ci#define MAPINFO_SIZE 256 44800b99b8Sopenharmony_ci#define TIME_DIV 1000 45800b99b8Sopenharmony_ci#define BUF_SZ_SMALL 256 46800b99b8Sopenharmony_ci 47800b99b8Sopenharmony_cistatic __attribute__((noinline)) int RequestOutputLogFile(const struct ProcessDumpRequest* request) 48800b99b8Sopenharmony_ci{ 49800b99b8Sopenharmony_ci struct FaultLoggerdRequest faultloggerdRequest; 50800b99b8Sopenharmony_ci (void)memset_s(&faultloggerdRequest, sizeof(faultloggerdRequest), 0, sizeof(struct FaultLoggerdRequest)); 51800b99b8Sopenharmony_ci 52800b99b8Sopenharmony_ci faultloggerdRequest.type = (int32_t)CPP_CRASH; 53800b99b8Sopenharmony_ci faultloggerdRequest.pid = request->pid; 54800b99b8Sopenharmony_ci faultloggerdRequest.tid = request->tid; 55800b99b8Sopenharmony_ci faultloggerdRequest.uid = request->uid; 56800b99b8Sopenharmony_ci faultloggerdRequest.time = request->timeStamp + 1; 57800b99b8Sopenharmony_ci return RequestFileDescriptorEx(&faultloggerdRequest); 58800b99b8Sopenharmony_ci} 59800b99b8Sopenharmony_ci 60800b99b8Sopenharmony_cistatic __attribute__((noinline)) void PrintLog(int fd, const char *format, ...) 61800b99b8Sopenharmony_ci{ 62800b99b8Sopenharmony_ci char buf[BUF_SZ] = {0}; 63800b99b8Sopenharmony_ci va_list args; 64800b99b8Sopenharmony_ci va_start(args, format); 65800b99b8Sopenharmony_ci int size = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, args); 66800b99b8Sopenharmony_ci va_end(args); 67800b99b8Sopenharmony_ci if (size == -1) { 68800b99b8Sopenharmony_ci if (fd > 0) { 69800b99b8Sopenharmony_ci const char* error = "PrintLog vsnprintf_s fail\n"; 70800b99b8Sopenharmony_ci (void)OHOS_TEMP_FAILURE_RETRY(write(fd, error, strlen(error))); 71800b99b8Sopenharmony_ci } 72800b99b8Sopenharmony_ci return; 73800b99b8Sopenharmony_ci } 74800b99b8Sopenharmony_ci DFXLOGE("%{public}s", buf); 75800b99b8Sopenharmony_ci if (fd > 0) { 76800b99b8Sopenharmony_ci (void)OHOS_TEMP_FAILURE_RETRY(write(fd, buf, strlen(buf))); 77800b99b8Sopenharmony_ci } 78800b99b8Sopenharmony_ci} 79800b99b8Sopenharmony_ci 80800b99b8Sopenharmony_ci__attribute__((noinline)) void CrashLocalUnwind(const int fd, const ucontext_t* uc) 81800b99b8Sopenharmony_ci{ 82800b99b8Sopenharmony_ci if (uc == nullptr) { 83800b99b8Sopenharmony_ci return; 84800b99b8Sopenharmony_ci } 85800b99b8Sopenharmony_ci OHOS::HiviewDFX::Unwinder unwind; 86800b99b8Sopenharmony_ci unwind.UnwindLocalWithContext(*uc); 87800b99b8Sopenharmony_ci auto regs = OHOS::HiviewDFX::DfxRegs::CreateFromUcontext(*uc); 88800b99b8Sopenharmony_ci std::string logContext = unwind.GetFramesStr(unwind.GetFrames()) + regs->PrintRegs(); 89800b99b8Sopenharmony_ci logContext.append("\nMaps:\n"); 90800b99b8Sopenharmony_ci for (const auto &map : unwind.GetMaps()->GetMaps()) { 91800b99b8Sopenharmony_ci logContext.append(map->ToString()); 92800b99b8Sopenharmony_ci } 93800b99b8Sopenharmony_ci 94800b99b8Sopenharmony_ci for (unsigned int i = 0; i < logContext.length(); i += BUF_SZ_SMALL) { 95800b99b8Sopenharmony_ci PrintLog(fd, "%s", logContext.substr(i, BUF_SZ_SMALL).c_str()); 96800b99b8Sopenharmony_ci } 97800b99b8Sopenharmony_ci} 98800b99b8Sopenharmony_ci 99800b99b8Sopenharmony_ci// currently, only stacktrace is logged to faultloggerd 100800b99b8Sopenharmony_civoid CrashLocalHandler(const struct ProcessDumpRequest* request) 101800b99b8Sopenharmony_ci{ 102800b99b8Sopenharmony_ci int fd = RequestOutputLogFile(request); 103800b99b8Sopenharmony_ci CrashLocalHandlerFd(fd, request); 104800b99b8Sopenharmony_ci if (fd >= 0) { 105800b99b8Sopenharmony_ci close(fd); 106800b99b8Sopenharmony_ci } 107800b99b8Sopenharmony_ci} 108800b99b8Sopenharmony_ci 109800b99b8Sopenharmony_cistatic void PrintTimeStamp(const int fd) 110800b99b8Sopenharmony_ci{ 111800b99b8Sopenharmony_ci uint64_t currentTime = GetTimeMilliseconds(); 112800b99b8Sopenharmony_ci char secBuf[BUF_SZ] = {0}; 113800b99b8Sopenharmony_ci char printBuf[BUF_SZ] = {0}; 114800b99b8Sopenharmony_ci time_t sec = static_cast<time_t>(currentTime / TIME_DIV); 115800b99b8Sopenharmony_ci uint64_t millisec = currentTime % TIME_DIV; 116800b99b8Sopenharmony_ci struct tm* t = localtime(&sec); 117800b99b8Sopenharmony_ci if (!t) { 118800b99b8Sopenharmony_ci return; 119800b99b8Sopenharmony_ci } 120800b99b8Sopenharmony_ci (void)strftime(secBuf, sizeof(secBuf) - 1, "%Y-%m-%d %H:%M:%S", t); 121800b99b8Sopenharmony_ci if (snprintf_s(printBuf, sizeof(printBuf), sizeof(printBuf) - 1, 122800b99b8Sopenharmony_ci "%s.%03" PRIx64 "\n", secBuf, millisec) < 0) { 123800b99b8Sopenharmony_ci DFXLOGE("snprintf timestamp fail"); 124800b99b8Sopenharmony_ci return; 125800b99b8Sopenharmony_ci } 126800b99b8Sopenharmony_ci PrintLog(fd, "Timestamp:%s", printBuf); 127800b99b8Sopenharmony_ci} 128800b99b8Sopenharmony_ci 129800b99b8Sopenharmony_cistatic void ReportToHiview(const char* logPath, const struct ProcessDumpRequest* request) 130800b99b8Sopenharmony_ci{ 131800b99b8Sopenharmony_ci struct CrashDumpException exception; 132800b99b8Sopenharmony_ci (void)memset_s(&exception, sizeof(struct CrashDumpException), 0, sizeof(struct CrashDumpException)); 133800b99b8Sopenharmony_ci exception.pid = request->pid; 134800b99b8Sopenharmony_ci exception.uid = request->uid; 135800b99b8Sopenharmony_ci exception.error = CRASH_DUMP_LOCAL_REPORT; 136800b99b8Sopenharmony_ci exception.time = static_cast<int64_t>(GetTimeMilliseconds()); 137800b99b8Sopenharmony_ci if (strncpy_s(exception.message, sizeof(exception.message) - 1, logPath, strlen(logPath)) != 0) { 138800b99b8Sopenharmony_ci DFXLOGE("strcpy exception msg fail"); 139800b99b8Sopenharmony_ci return; 140800b99b8Sopenharmony_ci } 141800b99b8Sopenharmony_ci ReportException(exception); 142800b99b8Sopenharmony_ci} 143800b99b8Sopenharmony_ci 144800b99b8Sopenharmony_civoid CrashLocalHandlerFd(const int fd, const struct ProcessDumpRequest* request) 145800b99b8Sopenharmony_ci{ 146800b99b8Sopenharmony_ci if (request == nullptr) { 147800b99b8Sopenharmony_ci return; 148800b99b8Sopenharmony_ci } 149800b99b8Sopenharmony_ci PrintTimeStamp(fd); 150800b99b8Sopenharmony_ci PrintLog(fd, "Pid:%d\n", request->pid); 151800b99b8Sopenharmony_ci PrintLog(fd, "Uid:%d\n", request->uid); 152800b99b8Sopenharmony_ci PrintLog(fd, "Process name:%s\n", request->processName); 153800b99b8Sopenharmony_ci#if defined(__LP64__) 154800b99b8Sopenharmony_ci PrintLog(fd, "Reason:Signal(%d)@%018p\n", request->siginfo.si_signo, request->siginfo.si_addr); 155800b99b8Sopenharmony_ci#else 156800b99b8Sopenharmony_ci PrintLog(fd, "Reason:Signal(%d)@%010p\n", request->siginfo.si_signo, request->siginfo.si_addr); 157800b99b8Sopenharmony_ci#endif 158800b99b8Sopenharmony_ci PrintLog(fd, "Fault thread info:\n"); 159800b99b8Sopenharmony_ci PrintLog(fd, "Tid:%d, Name:%s\n", request->tid, request->threadName); 160800b99b8Sopenharmony_ci CrashLocalUnwind(fd, &(request->context)); 161800b99b8Sopenharmony_ci char logFileName[BUF_SZ] = {0}; 162800b99b8Sopenharmony_ci if (snprintf_s(logFileName, sizeof(logFileName), sizeof(logFileName) - 1, 163800b99b8Sopenharmony_ci "/data/log/faultlog/temp/cppcrash-%d-%llu", request->pid, request->timeStamp + 1) < 0) { 164800b99b8Sopenharmony_ci DFXLOGE("snprintf logFileName fail"); 165800b99b8Sopenharmony_ci return; 166800b99b8Sopenharmony_ci } 167800b99b8Sopenharmony_ci ReportToHiview(logFileName, request); 168800b99b8Sopenharmony_ci} 169