1 /*
2 * Copyright (c) 2022-2023 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 #include "backtrace_local_thread.h"
17
18 #include <sstream>
19
20 #include <link.h>
21 #include <unistd.h>
22 #include <mutex>
23 #include <pthread.h>
24 #include <libunwind.h>
25 #include <libunwind_i-ohos.h>
26 #include <securec.h>
27
28 #include "backtrace_local_context.h"
29 #include "dfx_define.h"
30 #include "dfx_util.h"
31 #include "procinfo.h"
32 #include "fp_unwinder.h"
33 #include "dwarf_unwinder.h"
34 #include "dfx_frame_format.h"
35
36 namespace OHOS {
37 namespace HiviewDFX {
38 namespace {
39 #undef LOG_DOMAIN
40 #undef LOG_TAG
41 #define LOG_DOMAIN 0xD002D11
42 #define LOG_TAG "DfxBacktraceLocal"
43 }
44
BacktraceLocalThread(int32_t tid)45 BacktraceLocalThread::BacktraceLocalThread(int32_t tid) : tid_(tid)
46 {
47 frames_.clear();
48 }
49
~BacktraceLocalThread()50 BacktraceLocalThread::~BacktraceLocalThread()
51 {
52 if (tid_ != BACKTRACE_CURRENT_THREAD) {
53 BacktraceLocalContext::GetInstance().CleanUp();
54 }
55 frames_.clear();
56 }
57
UnwindCurrentThread(unw_addr_space_t as,std::shared_ptr<DfxSymbols> symbol,size_t skipFrameNum,bool fast)58 bool BacktraceLocalThread::UnwindCurrentThread(unw_addr_space_t as, std::shared_ptr<DfxSymbols> symbol,
59 size_t skipFrameNum, bool fast)
60 {
61 bool ret = false;
62 unw_context_t context;
63 (void)memset_s(&context, sizeof(unw_context_t), 0, sizeof(unw_context_t));
64 unw_getcontext(&context);
65
66 if (fast) {
67 #ifdef __aarch64__
68 FpUnwinder unwinder;
69 ret = unwinder.UnwindWithContext(context, skipFrameNum + 1);
70 unwinder.UpdateFrameInfo();
71 frames_ = unwinder.GetFrames();
72 #endif
73 }
74 if (!ret) {
75 DwarfUnwinder unwinder;
76 ret = unwinder.UnwindWithContext(as, context, symbol, skipFrameNum + 1);
77 frames_ = unwinder.GetFrames();
78 }
79 return ret;
80 }
81
Unwind(unw_addr_space_t as,std::shared_ptr<DfxSymbols> symbol,size_t skipFrameNum,bool fast,bool releaseThread)82 bool BacktraceLocalThread::Unwind(unw_addr_space_t as, std::shared_ptr<DfxSymbols> symbol,
83 size_t skipFrameNum, bool fast, bool releaseThread)
84 {
85 static std::mutex mutex;
86 std::unique_lock<std::mutex> lock(mutex);
87 bool ret = false;
88
89 if (tid_ == BACKTRACE_CURRENT_THREAD) {
90 return UnwindCurrentThread(as, symbol, skipFrameNum + 1, fast);
91 } else if (tid_ < BACKTRACE_CURRENT_THREAD) {
92 return ret;
93 }
94
95 auto threadContext = BacktraceLocalContext::GetInstance().GetThreadContext(tid_);
96 if (threadContext == nullptr) {
97 return ret;
98 }
99
100 if (threadContext->ctx == nullptr) {
101 // should never happen
102 ReleaseThread();
103 return ret;
104 }
105
106 if (!ret) {
107 DwarfUnwinder unwinder;
108 ret = unwinder.UnwindWithContext(as, *(threadContext->ctx), symbol, skipFrameNum);
109 frames_ = unwinder.GetFrames();
110 }
111
112 if (releaseThread) {
113 ReleaseThread();
114 }
115 return ret;
116 }
117
GetFrames() const118 const std::vector<DfxFrame>& BacktraceLocalThread::GetFrames() const
119 {
120 return frames_;
121 }
122
ReleaseThread()123 void BacktraceLocalThread::ReleaseThread()
124 {
125 if (tid_ > BACKTRACE_CURRENT_THREAD) {
126 BacktraceLocalContext::GetInstance().ReleaseThread(tid_);
127 }
128 }
129
GetFormatedStr(bool withThreadName)130 std::string BacktraceLocalThread::GetFormatedStr(bool withThreadName)
131 {
132 if (frames_.empty()) {
133 return "";
134 }
135
136 std::ostringstream ss;
137 if (withThreadName && (tid_ > 0)) {
138 std::string threadName;
139 // Tid:1676, Name:IPC_3_1676
140 ReadThreadName(tid_, threadName);
141 ss << "Tid:" << tid_ << ", Name:" << threadName << std::endl;
142 }
143
144 ss << DfxFrameFormat::GetFramesStr(frames_);
145 return ss.str();
146 }
147 } // namespace HiviewDFX
148 } // namespace OHOS
149