1800b99b8Sopenharmony_ci/* 2800b99b8Sopenharmony_ci * Copyright (c) 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 16800b99b8Sopenharmony_ci#include "thread_context.h" 17800b99b8Sopenharmony_ci 18800b99b8Sopenharmony_ci#include <chrono> 19800b99b8Sopenharmony_ci#include <csignal> 20800b99b8Sopenharmony_ci#include <map> 21800b99b8Sopenharmony_ci#include <memory> 22800b99b8Sopenharmony_ci#include <mutex> 23800b99b8Sopenharmony_ci#include <securec.h> 24800b99b8Sopenharmony_ci#include <sigchain.h> 25800b99b8Sopenharmony_ci#include <unistd.h> 26800b99b8Sopenharmony_ci 27800b99b8Sopenharmony_ci#include "dfx_define.h" 28800b99b8Sopenharmony_ci#include "dfx_log.h" 29800b99b8Sopenharmony_ci#include "fp_unwinder.h" 30800b99b8Sopenharmony_ci#if defined(__aarch64__) 31800b99b8Sopenharmony_ci#include "unwind_arm64_define.h" 32800b99b8Sopenharmony_ci#endif 33800b99b8Sopenharmony_ci 34800b99b8Sopenharmony_cinamespace OHOS { 35800b99b8Sopenharmony_cinamespace HiviewDFX { 36800b99b8Sopenharmony_cinamespace { 37800b99b8Sopenharmony_ci#undef LOG_DOMAIN 38800b99b8Sopenharmony_ci#undef LOG_TAG 39800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11 40800b99b8Sopenharmony_ci#define LOG_TAG "DfxThreadContext" 41800b99b8Sopenharmony_ci 42800b99b8Sopenharmony_cistd::mutex g_localMutex; 43800b99b8Sopenharmony_cistd::map<int32_t, std::shared_ptr<ThreadContext>> g_contextMap {}; 44800b99b8Sopenharmony_ciconst std::chrono::seconds g_timeOut = std::chrono::seconds(1); 45800b99b8Sopenharmony_ci 46800b99b8Sopenharmony_civoid CreateContext(std::shared_ptr<ThreadContext>& threadContext) 47800b99b8Sopenharmony_ci{ 48800b99b8Sopenharmony_ci#ifndef __aarch64__ 49800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lock(threadContext->mtx); 50800b99b8Sopenharmony_ci if (threadContext->ctx == nullptr) { 51800b99b8Sopenharmony_ci threadContext->ctx = new ucontext_t; 52800b99b8Sopenharmony_ci } 53800b99b8Sopenharmony_ci (void)memset_s(threadContext->ctx, sizeof(ucontext_t), 0, sizeof(ucontext_t)); 54800b99b8Sopenharmony_ci#endif 55800b99b8Sopenharmony_ci} 56800b99b8Sopenharmony_ci 57800b99b8Sopenharmony_civoid ReleaseContext(std::shared_ptr<ThreadContext> threadContext) 58800b99b8Sopenharmony_ci{ 59800b99b8Sopenharmony_ci#ifndef __aarch64__ 60800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lock(threadContext->mtx); 61800b99b8Sopenharmony_ci if (threadContext->ctx != nullptr) { 62800b99b8Sopenharmony_ci delete threadContext->ctx; 63800b99b8Sopenharmony_ci threadContext->ctx = nullptr; 64800b99b8Sopenharmony_ci } 65800b99b8Sopenharmony_ci#endif 66800b99b8Sopenharmony_ci} 67800b99b8Sopenharmony_ci 68800b99b8Sopenharmony_cistd::shared_ptr<ThreadContext> GetContextLocked(int32_t tid) 69800b99b8Sopenharmony_ci{ 70800b99b8Sopenharmony_ci auto it = g_contextMap.find(tid); 71800b99b8Sopenharmony_ci if (it == g_contextMap.end() || it->second == nullptr) { 72800b99b8Sopenharmony_ci auto threadContext = std::make_shared<ThreadContext>(); 73800b99b8Sopenharmony_ci threadContext->tid = tid; 74800b99b8Sopenharmony_ci threadContext->frameSz = 0; 75800b99b8Sopenharmony_ci CreateContext(threadContext); 76800b99b8Sopenharmony_ci g_contextMap[tid] = threadContext; 77800b99b8Sopenharmony_ci return threadContext; 78800b99b8Sopenharmony_ci } 79800b99b8Sopenharmony_ci 80800b99b8Sopenharmony_ci if (it->second->tid == ThreadContextStatus::CONTEXT_UNUSED) { 81800b99b8Sopenharmony_ci it->second->tid = tid; 82800b99b8Sopenharmony_ci it->second->frameSz = 0; 83800b99b8Sopenharmony_ci CreateContext(it->second); 84800b99b8Sopenharmony_ci return it->second; 85800b99b8Sopenharmony_ci } 86800b99b8Sopenharmony_ci DFXLOGE("GetContextLocked nullptr, tid: %{public}d", tid); 87800b99b8Sopenharmony_ci return nullptr; 88800b99b8Sopenharmony_ci} 89800b99b8Sopenharmony_ci 90800b99b8Sopenharmony_ciAT_UNUSED bool RemoveContextLocked(int32_t tid) 91800b99b8Sopenharmony_ci{ 92800b99b8Sopenharmony_ci auto it = g_contextMap.find(tid); 93800b99b8Sopenharmony_ci if (it == g_contextMap.end()) { 94800b99b8Sopenharmony_ci DFXLOGW("Context of tid(%{public}d) is already removed.", tid); 95800b99b8Sopenharmony_ci return true; 96800b99b8Sopenharmony_ci } 97800b99b8Sopenharmony_ci if (it->second == nullptr) { 98800b99b8Sopenharmony_ci g_contextMap.erase(it); 99800b99b8Sopenharmony_ci return true; 100800b99b8Sopenharmony_ci } 101800b99b8Sopenharmony_ci 102800b99b8Sopenharmony_ci // only release ucontext_t object 103800b99b8Sopenharmony_ci if (it->second->tid == ThreadContextStatus::CONTEXT_UNUSED) { 104800b99b8Sopenharmony_ci ReleaseContext(it->second); 105800b99b8Sopenharmony_ci return true; 106800b99b8Sopenharmony_ci } 107800b99b8Sopenharmony_ci 108800b99b8Sopenharmony_ci DFXLOGW("Failed to release context of tid(%{public}d), still using?", tid); 109800b99b8Sopenharmony_ci return false; 110800b99b8Sopenharmony_ci} 111800b99b8Sopenharmony_ci 112800b99b8Sopenharmony_cibool RemoveAllContextLocked() 113800b99b8Sopenharmony_ci{ 114800b99b8Sopenharmony_ci auto it = g_contextMap.begin(); 115800b99b8Sopenharmony_ci while (it != g_contextMap.end()) { 116800b99b8Sopenharmony_ci if (it->second == nullptr) { 117800b99b8Sopenharmony_ci it = g_contextMap.erase(it); 118800b99b8Sopenharmony_ci continue; 119800b99b8Sopenharmony_ci } 120800b99b8Sopenharmony_ci#ifndef __aarch64__ 121800b99b8Sopenharmony_ci if (it->second->tid == ThreadContextStatus::CONTEXT_UNUSED) { 122800b99b8Sopenharmony_ci ReleaseContext(it->second); 123800b99b8Sopenharmony_ci } 124800b99b8Sopenharmony_ci#endif 125800b99b8Sopenharmony_ci it++; 126800b99b8Sopenharmony_ci } 127800b99b8Sopenharmony_ci return true; 128800b99b8Sopenharmony_ci} 129800b99b8Sopenharmony_ci} 130800b99b8Sopenharmony_ci 131800b99b8Sopenharmony_ciLocalThreadContext& LocalThreadContext::GetInstance() 132800b99b8Sopenharmony_ci{ 133800b99b8Sopenharmony_ci static LocalThreadContext instance; 134800b99b8Sopenharmony_ci return instance; 135800b99b8Sopenharmony_ci} 136800b99b8Sopenharmony_ci 137800b99b8Sopenharmony_ciNO_SANITIZE std::shared_ptr<ThreadContext> LocalThreadContext::GetThreadContext(int32_t tid) 138800b99b8Sopenharmony_ci{ 139800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lock(localMutex_); 140800b99b8Sopenharmony_ci auto it = g_contextMap.find(tid); 141800b99b8Sopenharmony_ci if (it != g_contextMap.end()) { 142800b99b8Sopenharmony_ci return it->second; 143800b99b8Sopenharmony_ci } 144800b99b8Sopenharmony_ci DFXLOGW("Failed to get context of tid(%{public}d)", tid); 145800b99b8Sopenharmony_ci return nullptr; 146800b99b8Sopenharmony_ci} 147800b99b8Sopenharmony_ci 148800b99b8Sopenharmony_civoid LocalThreadContext::ReleaseThread(int32_t tid) 149800b99b8Sopenharmony_ci{ 150800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lock(localMutex_); 151800b99b8Sopenharmony_ci auto it = g_contextMap.find(tid); 152800b99b8Sopenharmony_ci if (it == g_contextMap.end() || it->second == nullptr) { 153800b99b8Sopenharmony_ci return; 154800b99b8Sopenharmony_ci } 155800b99b8Sopenharmony_ci it->second->cv.notify_all(); 156800b99b8Sopenharmony_ci} 157800b99b8Sopenharmony_ci 158800b99b8Sopenharmony_civoid LocalThreadContext::CleanUp() 159800b99b8Sopenharmony_ci{ 160800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lock(localMutex_); 161800b99b8Sopenharmony_ci RemoveAllContextLocked(); 162800b99b8Sopenharmony_ci} 163800b99b8Sopenharmony_ci 164800b99b8Sopenharmony_cistd::shared_ptr<ThreadContext> LocalThreadContext::CollectThreadContext(int32_t tid) 165800b99b8Sopenharmony_ci{ 166800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lock(localMutex_); 167800b99b8Sopenharmony_ci auto threadContext = GetContextLocked(tid); 168800b99b8Sopenharmony_ci if (threadContext == nullptr) { 169800b99b8Sopenharmony_ci DFXLOGW("Failed to get context of tid(%{public}d), still using?", tid); 170800b99b8Sopenharmony_ci return nullptr; 171800b99b8Sopenharmony_ci } 172800b99b8Sopenharmony_ci 173800b99b8Sopenharmony_ci InitSignalHandler(); 174800b99b8Sopenharmony_ci if (!SignalRequestThread(tid, threadContext.get())) { 175800b99b8Sopenharmony_ci return nullptr; 176800b99b8Sopenharmony_ci } 177800b99b8Sopenharmony_ci if (threadContext->cv.wait_for(lock, g_timeOut) == std::cv_status::timeout) { 178800b99b8Sopenharmony_ci DFXLOGE("wait_for timeout. tid = %{public}d", tid); 179800b99b8Sopenharmony_ci return nullptr; 180800b99b8Sopenharmony_ci } 181800b99b8Sopenharmony_ci return threadContext; 182800b99b8Sopenharmony_ci} 183800b99b8Sopenharmony_ci 184800b99b8Sopenharmony_ciNO_SANITIZE void LocalThreadContext::CopyContextAndWaitTimeout(int sig, siginfo_t *si, void *context) 185800b99b8Sopenharmony_ci{ 186800b99b8Sopenharmony_ci if (si == nullptr || si->si_code != DUMP_TYPE_LOCAL || si->si_value.sival_ptr == nullptr || context == nullptr) { 187800b99b8Sopenharmony_ci return; 188800b99b8Sopenharmony_ci } 189800b99b8Sopenharmony_ci 190800b99b8Sopenharmony_ci DFXLOGU("tid(%{public}d) recv sig(%{public}d)", gettid(), sig); 191800b99b8Sopenharmony_ci auto ctxPtr = static_cast<ThreadContext *>(si->si_value.sival_ptr); 192800b99b8Sopenharmony_ci#if defined(__aarch64__) 193800b99b8Sopenharmony_ci uintptr_t fp = reinterpret_cast<ucontext_t*>(context)->uc_mcontext.regs[REG_FP]; 194800b99b8Sopenharmony_ci uintptr_t pc = reinterpret_cast<ucontext_t*>(context)->uc_mcontext.pc; 195800b99b8Sopenharmony_ci ctxPtr->firstFrameSp = reinterpret_cast<ucontext_t*>(context)->uc_mcontext.sp; 196800b99b8Sopenharmony_ci ctxPtr->frameSz = FpUnwinder::GetPtr()->UnwindSafe(pc, fp, ctxPtr->pcs, DEFAULT_MAX_LOCAL_FRAME_NUM); 197800b99b8Sopenharmony_ci ctxPtr->cv.notify_all(); 198800b99b8Sopenharmony_ci ctxPtr->tid = static_cast<int32_t>(ThreadContextStatus::CONTEXT_UNUSED); 199800b99b8Sopenharmony_ci return; 200800b99b8Sopenharmony_ci#else 201800b99b8Sopenharmony_ci 202800b99b8Sopenharmony_ci std::unique_lock<std::mutex> lock(ctxPtr->mtx); 203800b99b8Sopenharmony_ci if (ctxPtr->ctx == nullptr) { 204800b99b8Sopenharmony_ci ctxPtr->tid = static_cast<int32_t>(ThreadContextStatus::CONTEXT_UNUSED); 205800b99b8Sopenharmony_ci return; 206800b99b8Sopenharmony_ci } 207800b99b8Sopenharmony_ci ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); 208800b99b8Sopenharmony_ci int tid = gettid(); 209800b99b8Sopenharmony_ci if (memcpy_s(&ctxPtr->ctx->uc_mcontext, sizeof(ucontext->uc_mcontext), 210800b99b8Sopenharmony_ci &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext)) != 0) { 211800b99b8Sopenharmony_ci DFXLOGW("Failed to copy local ucontext with tid(%{public}d)", tid); 212800b99b8Sopenharmony_ci } 213800b99b8Sopenharmony_ci 214800b99b8Sopenharmony_ci if (tid != getpid()) { 215800b99b8Sopenharmony_ci if (!GetSelfStackRange(ctxPtr->stackBottom, ctxPtr->stackTop)) { 216800b99b8Sopenharmony_ci DFXLOGW("Failed to get stack range with tid(%{public}d)", tid); 217800b99b8Sopenharmony_ci } 218800b99b8Sopenharmony_ci } 219800b99b8Sopenharmony_ci 220800b99b8Sopenharmony_ci ctxPtr->tid = static_cast<int32_t>(ThreadContextStatus::CONTEXT_READY); 221800b99b8Sopenharmony_ci ctxPtr->cv.notify_all(); 222800b99b8Sopenharmony_ci ctxPtr->cv.wait_for(lock, g_timeOut); 223800b99b8Sopenharmony_ci ctxPtr->tid = static_cast<int32_t>(ThreadContextStatus::CONTEXT_UNUSED); 224800b99b8Sopenharmony_ci#endif 225800b99b8Sopenharmony_ci} 226800b99b8Sopenharmony_ci 227800b99b8Sopenharmony_cibool LocalThreadContext::GetStackRange(int32_t tid, uintptr_t& stackBottom, uintptr_t& stackTop) 228800b99b8Sopenharmony_ci{ 229800b99b8Sopenharmony_ci auto ctxPtr = LocalThreadContext::GetInstance().GetThreadContext(tid); 230800b99b8Sopenharmony_ci if (ctxPtr == nullptr) { 231800b99b8Sopenharmony_ci return false; 232800b99b8Sopenharmony_ci } 233800b99b8Sopenharmony_ci stackBottom = ctxPtr->stackBottom; 234800b99b8Sopenharmony_ci stackTop = ctxPtr->stackTop; 235800b99b8Sopenharmony_ci return true; 236800b99b8Sopenharmony_ci} 237800b99b8Sopenharmony_ci 238800b99b8Sopenharmony_civoid LocalThreadContext::InitSignalHandler() 239800b99b8Sopenharmony_ci{ 240800b99b8Sopenharmony_ci static std::once_flag flag; 241800b99b8Sopenharmony_ci std::call_once(flag, [&]() { 242800b99b8Sopenharmony_ci FpUnwinder::GetPtr(); 243800b99b8Sopenharmony_ci struct sigaction action; 244800b99b8Sopenharmony_ci (void)memset_s(&action, sizeof(action), 0, sizeof(action)); 245800b99b8Sopenharmony_ci sigemptyset(&action.sa_mask); 246800b99b8Sopenharmony_ci sigaddset(&action.sa_mask, SIGLOCAL_DUMP); 247800b99b8Sopenharmony_ci action.sa_flags = SA_RESTART | SA_SIGINFO; 248800b99b8Sopenharmony_ci action.sa_sigaction = LocalThreadContext::CopyContextAndWaitTimeout; 249800b99b8Sopenharmony_ci DFXLOGU("Install local signal handler: %{public}d", SIGLOCAL_DUMP); 250800b99b8Sopenharmony_ci sigaction(SIGLOCAL_DUMP, &action, nullptr); 251800b99b8Sopenharmony_ci }); 252800b99b8Sopenharmony_ci} 253800b99b8Sopenharmony_ci 254800b99b8Sopenharmony_cibool LocalThreadContext::SignalRequestThread(int32_t tid, ThreadContext* threadContext) 255800b99b8Sopenharmony_ci{ 256800b99b8Sopenharmony_ci siginfo_t si {0}; 257800b99b8Sopenharmony_ci si.si_signo = SIGLOCAL_DUMP; 258800b99b8Sopenharmony_ci si.si_errno = 0; 259800b99b8Sopenharmony_ci si.si_code = DUMP_TYPE_LOCAL; 260800b99b8Sopenharmony_ci si.si_value.sival_ptr = reinterpret_cast<void *>(threadContext); 261800b99b8Sopenharmony_ci if (syscall(SYS_rt_tgsigqueueinfo, getpid(), tid, si.si_signo, &si) != 0) { 262800b99b8Sopenharmony_ci DFXLOGW("Failed to send signal(%{public}d) to tid(%{public}d), errno(%{public}d).", si.si_signo, tid, errno); 263800b99b8Sopenharmony_ci threadContext->tid = static_cast<int32_t>(ThreadContextStatus::CONTEXT_UNUSED); 264800b99b8Sopenharmony_ci return false; 265800b99b8Sopenharmony_ci } 266800b99b8Sopenharmony_ci return true; 267800b99b8Sopenharmony_ci} 268800b99b8Sopenharmony_ci} // namespace HiviewDFX 269800b99b8Sopenharmony_ci} // namespace OHOS 270