1 /* 2 * Copyright (c) 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 16 #ifndef THREAD_CONTEXT_H 17 #define THREAD_CONTEXT_H 18 19 #include <atomic> 20 #include <cstdint> 21 #include <condition_variable> 22 #include <csignal> 23 #include <mutex> 24 #include <nocopyable.h> 25 #include <string> 26 #include <vector> 27 28 #include "dfx_define.h" 29 #include "dfx_maps.h" 30 #include "dfx_regs.h" 31 32 namespace OHOS { 33 namespace HiviewDFX { 34 enum ThreadContextStatus : int32_t { 35 CONTEXT_UNUSED = -1, 36 CONTEXT_READY = -2, 37 }; 38 39 struct ThreadContext { 40 std::atomic<int32_t> tid {ThreadContextStatus::CONTEXT_UNUSED}; 41 // for protecting ctx, shared between threads 42 std::mutex mtx; 43 // the thread should be suspended while unwinding 44 // blocked in the signal handler of target thread 45 std::condition_variable cv; 46 // store unwind context 47 ucontext_t* ctx {nullptr}; 48 // stack range 49 uintptr_t stackBottom; 50 uintptr_t stackTop; 51 #if defined(__aarch64__) 52 // unwind in signal handler by fp 53 uintptr_t pcs[DEFAULT_MAX_LOCAL_FRAME_NUM] {0}; 54 #endif 55 std::atomic<size_t> frameSz {0}; 56 // first stack pointer 57 uintptr_t firstFrameSp; 58 ~ThreadContextThreadContext59 ~ThreadContext() 60 { 61 std::unique_lock<std::mutex> lock(mtx); 62 if (ctx != nullptr) { 63 delete ctx; 64 ctx = nullptr; 65 } 66 }; 67 }; 68 69 class LocalThreadContext { 70 public: 71 static LocalThreadContext& GetInstance(); 72 73 bool GetStackRange(int32_t tid, uintptr_t& stackBottom, uintptr_t& stackTop); 74 std::shared_ptr<ThreadContext> CollectThreadContext(int32_t tid); 75 std::shared_ptr<ThreadContext> GetThreadContext(int32_t tid); 76 void ReleaseThread(int32_t tid); 77 void CleanUp(); 78 79 private: 80 LocalThreadContext() = default; 81 DISALLOW_COPY_AND_MOVE(LocalThreadContext); 82 83 bool SignalRequestThread(int32_t tid, ThreadContext* ctx); 84 85 private: 86 std::mutex localMutex_; 87 }; 88 89 constexpr int STACK_BUFFER_SIZE = 64 * 1024; 90 enum SyncStatus : int32_t { 91 INIT = -1, 92 WAIT_CTX = 0, 93 COPY_START, 94 COPY_SUCCESS, 95 COPY_FAILED, 96 }; 97 98 class LocalThreadContextMix { 99 public: 100 LocalThreadContextMix(const LocalThreadContextMix&) = delete; 101 LocalThreadContextMix& operator=(const LocalThreadContextMix&) = delete; 102 static LocalThreadContextMix& GetInstance(); 103 void ReleaseCollectThreadContext(); 104 bool CollectThreadContext(int32_t tid); 105 bool CheckStatusValidate(int status, int32_t tid); 106 bool GetSelfStackRangeInSignal(); 107 void CopyRegister(void *context); 108 void CopyStackBuf(); 109 void SetRegister(std::shared_ptr<DfxRegs> regs); 110 void SetStackRang(uintptr_t stackTop, uintptr_t stackBottom); 111 int GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map) const; 112 int FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo) const; 113 int AccessMem(uintptr_t addr, uintptr_t *val); 114 std::shared_ptr<DfxMaps> GetMaps() const; 115 116 private: 117 LocalThreadContextMix() = default; 118 ~LocalThreadContextMix() = default; 119 bool SignalRequestThread(int32_t tid); 120 void StartCollectThreadContext(int32_t tid); 121 122 private: 123 std::mutex mtx_; 124 std::condition_variable cv_; 125 uintptr_t pc_ {0}; 126 uintptr_t sp_ {0}; 127 uintptr_t fp_ {0}; 128 uintptr_t lr_ {0}; 129 uintptr_t stackBottom_ {0}; 130 uintptr_t stackTop_ {0}; 131 std::vector<uint8_t> stackBuf_; 132 int32_t tid_ = -1; 133 int status_ = SyncStatus::INIT; 134 std::shared_ptr<DfxMaps> maps_ = nullptr; 135 }; 136 } // namespace Dfx 137 } // namespace OHOS 138 #endif 139