1/* 2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include "dfx_crash_local_handler.h" 16 17#include <securec.h> 18#include <csignal> 19#include <sys/time.h> 20#include <sys/ucontext.h> 21#include <cinttypes> 22#include <unistd.h> 23#include <pthread.h> 24#include <cerrno> 25#include "dfx_log.h" 26#include "dfx_cutil.h" 27#include "dfx_signalhandler_exception.h" 28#include "faultloggerd_client.h" 29#include "unwinder.h" 30 31#ifdef LOG_DOMAIN 32#undef LOG_DOMAIN 33#define LOG_DOMAIN 0xD002D11 34#endif 35 36#ifdef LOG_TAG 37#undef LOG_TAG 38#define LOG_TAG "DfxCrashLocalHandler" 39#endif 40 41#define MAX_FRAME 64 42#define BUF_SZ 512 43#define MAPINFO_SIZE 256 44#define TIME_DIV 1000 45#define BUF_SZ_SMALL 256 46 47static __attribute__((noinline)) int RequestOutputLogFile(const struct ProcessDumpRequest* request) 48{ 49 struct FaultLoggerdRequest faultloggerdRequest; 50 (void)memset_s(&faultloggerdRequest, sizeof(faultloggerdRequest), 0, sizeof(struct FaultLoggerdRequest)); 51 52 faultloggerdRequest.type = (int32_t)CPP_CRASH; 53 faultloggerdRequest.pid = request->pid; 54 faultloggerdRequest.tid = request->tid; 55 faultloggerdRequest.uid = request->uid; 56 faultloggerdRequest.time = request->timeStamp + 1; 57 return RequestFileDescriptorEx(&faultloggerdRequest); 58} 59 60static __attribute__((noinline)) void PrintLog(int fd, const char *format, ...) 61{ 62 char buf[BUF_SZ] = {0}; 63 va_list args; 64 va_start(args, format); 65 int size = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, args); 66 va_end(args); 67 if (size == -1) { 68 if (fd > 0) { 69 const char* error = "PrintLog vsnprintf_s fail\n"; 70 (void)OHOS_TEMP_FAILURE_RETRY(write(fd, error, strlen(error))); 71 } 72 return; 73 } 74 DFXLOGE("%{public}s", buf); 75 if (fd > 0) { 76 (void)OHOS_TEMP_FAILURE_RETRY(write(fd, buf, strlen(buf))); 77 } 78} 79 80__attribute__((noinline)) void CrashLocalUnwind(const int fd, const ucontext_t* uc) 81{ 82 if (uc == nullptr) { 83 return; 84 } 85 OHOS::HiviewDFX::Unwinder unwind; 86 unwind.UnwindLocalWithContext(*uc); 87 auto regs = OHOS::HiviewDFX::DfxRegs::CreateFromUcontext(*uc); 88 std::string logContext = unwind.GetFramesStr(unwind.GetFrames()) + regs->PrintRegs(); 89 logContext.append("\nMaps:\n"); 90 for (const auto &map : unwind.GetMaps()->GetMaps()) { 91 logContext.append(map->ToString()); 92 } 93 94 for (unsigned int i = 0; i < logContext.length(); i += BUF_SZ_SMALL) { 95 PrintLog(fd, "%s", logContext.substr(i, BUF_SZ_SMALL).c_str()); 96 } 97} 98 99// currently, only stacktrace is logged to faultloggerd 100void CrashLocalHandler(const struct ProcessDumpRequest* request) 101{ 102 int fd = RequestOutputLogFile(request); 103 CrashLocalHandlerFd(fd, request); 104 if (fd >= 0) { 105 close(fd); 106 } 107} 108 109static void PrintTimeStamp(const int fd) 110{ 111 uint64_t currentTime = GetTimeMilliseconds(); 112 char secBuf[BUF_SZ] = {0}; 113 char printBuf[BUF_SZ] = {0}; 114 time_t sec = static_cast<time_t>(currentTime / TIME_DIV); 115 uint64_t millisec = currentTime % TIME_DIV; 116 struct tm* t = localtime(&sec); 117 if (!t) { 118 return; 119 } 120 (void)strftime(secBuf, sizeof(secBuf) - 1, "%Y-%m-%d %H:%M:%S", t); 121 if (snprintf_s(printBuf, sizeof(printBuf), sizeof(printBuf) - 1, 122 "%s.%03" PRIx64 "\n", secBuf, millisec) < 0) { 123 DFXLOGE("snprintf timestamp fail"); 124 return; 125 } 126 PrintLog(fd, "Timestamp:%s", printBuf); 127} 128 129static void ReportToHiview(const char* logPath, const struct ProcessDumpRequest* request) 130{ 131 struct CrashDumpException exception; 132 (void)memset_s(&exception, sizeof(struct CrashDumpException), 0, sizeof(struct CrashDumpException)); 133 exception.pid = request->pid; 134 exception.uid = request->uid; 135 exception.error = CRASH_DUMP_LOCAL_REPORT; 136 exception.time = static_cast<int64_t>(GetTimeMilliseconds()); 137 if (strncpy_s(exception.message, sizeof(exception.message) - 1, logPath, strlen(logPath)) != 0) { 138 DFXLOGE("strcpy exception msg fail"); 139 return; 140 } 141 ReportException(exception); 142} 143 144void CrashLocalHandlerFd(const int fd, const struct ProcessDumpRequest* request) 145{ 146 if (request == nullptr) { 147 return; 148 } 149 PrintTimeStamp(fd); 150 PrintLog(fd, "Pid:%d\n", request->pid); 151 PrintLog(fd, "Uid:%d\n", request->uid); 152 PrintLog(fd, "Process name:%s\n", request->processName); 153#if defined(__LP64__) 154 PrintLog(fd, "Reason:Signal(%d)@%018p\n", request->siginfo.si_signo, request->siginfo.si_addr); 155#else 156 PrintLog(fd, "Reason:Signal(%d)@%010p\n", request->siginfo.si_signo, request->siginfo.si_addr); 157#endif 158 PrintLog(fd, "Fault thread info:\n"); 159 PrintLog(fd, "Tid:%d, Name:%s\n", request->tid, request->threadName); 160 CrashLocalUnwind(fd, &(request->context)); 161 char logFileName[BUF_SZ] = {0}; 162 if (snprintf_s(logFileName, sizeof(logFileName), sizeof(logFileName) - 1, 163 "/data/log/faultlog/temp/cppcrash-%d-%llu", request->pid, request->timeStamp + 1) < 0) { 164 DFXLOGE("snprintf logFileName fail"); 165 return; 166 } 167 ReportToHiview(logFileName, request); 168} 169