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 <hilog/log.h>
19 #include <link.h>
20 #include <libunwind.h>
21 #include <libunwind_i-ohos.h>
22 #include <mutex>
23 #include <pthread.h>
24 #include <securec.h>
25 #include <sstream>
26 #include <unistd.h>
27
28 #include "backtrace_local_context.h"
29 #include "dfx_define.h"
30 #include "dfx_frame_format.h"
31 #include "dfx_util.h"
32 #include "dwarf_unwinder.h"
33 #include "fp_unwinder.h"
34 #include "procinfo.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 maxFrameNums_ = DEFAULT_MAX_FRAME_NUM;
48 frames_.clear();
49 }
50
~BacktraceLocalThread()51 BacktraceLocalThread::~BacktraceLocalThread()
52 {
53 if (tid_ != BACKTRACE_CURRENT_THREAD) {
54 BacktraceLocalContext::GetInstance().CleanUp();
55 }
56 frames_.clear();
57 }
58
UnwindCurrentThread(unw_addr_space_t as,std::shared_ptr<DfxSymbols> symbol,size_t skipFrameNum,bool fast)59 bool BacktraceLocalThread::UnwindCurrentThread(unw_addr_space_t as, std::shared_ptr<DfxSymbols> symbol,
60 size_t skipFrameNum, bool fast)
61 {
62 bool ret = false;
63 unw_context_t context;
64 (void)memset_s(&context, sizeof(unw_context_t), 0, sizeof(unw_context_t));
65 unw_getcontext(&context);
66
67 if (fast) {
68 #ifdef __aarch64__
69 FpUnwinder unwinder;
70 ret = unwinder.UnwindWithContext(context, skipFrameNum + 1, maxFrameNums_);
71 unwinder.UpdateFrameInfo();
72 frames_ = unwinder.GetFrames();
73 #endif
74 }
75 if (!ret) {
76 DwarfUnwinder unwinder;
77 ret = unwinder.UnwindWithContext(as, context, symbol, skipFrameNum + 1, maxFrameNums_);
78 frames_ = unwinder.GetFrames();
79 }
80 return ret;
81 }
82
Unwind(unw_addr_space_t as,std::shared_ptr<DfxSymbols> symbol,size_t skipFrameNum,bool fast,bool releaseThread)83 bool BacktraceLocalThread::Unwind(unw_addr_space_t as, std::shared_ptr<DfxSymbols> symbol,
84 size_t skipFrameNum, bool fast, bool releaseThread)
85 {
86 static std::mutex mutex;
87 std::unique_lock<std::mutex> lock(mutex);
88 bool ret = false;
89
90 if (tid_ == BACKTRACE_CURRENT_THREAD) {
91 return UnwindCurrentThread(as, symbol, skipFrameNum + 1, fast);
92 } else if (tid_ < BACKTRACE_CURRENT_THREAD) {
93 return ret;
94 }
95
96 auto threadContext = BacktraceLocalContext::GetInstance().CollectThreadContext(tid_);
97 if (threadContext == nullptr) {
98 HILOG_INFO(LOG_CORE, "failed to get context\n");
99 return ret;
100 }
101
102 if (threadContext->ctx == nullptr && (threadContext->frameSz == 0)) {
103 // should never happen
104 HILOG_INFO(LOG_CORE, "failed to get frameSz\n");
105 ReleaseThread();
106 return ret;
107 }
108
109 #if defined(__aarch64__)
110 if (threadContext->frameSz > 0) {
111 ret = true;
112 FpUnwinder fpUnwinder(threadContext->pcs, threadContext->frameSz);
113 fpUnwinder.UpdateFrameInfo();
114 frames_ = fpUnwinder.GetFrames();
115 }
116 #else
117 if (!ret) {
118 DwarfUnwinder unwinder;
119 std::unique_lock<std::mutex> mlock(threadContext->lock);
120 ret = unwinder.UnwindWithContext(as, *(threadContext->ctx), symbol, skipFrameNum, maxFrameNums_);
121 frames_ = unwinder.GetFrames();
122 }
123 #endif
124
125 if (releaseThread) {
126 ReleaseThread();
127 }
128 return ret;
129 }
130
GetFrames() const131 const std::vector<DfxFrame>& BacktraceLocalThread::GetFrames() const
132 {
133 return frames_;
134 }
135
ReleaseThread()136 void BacktraceLocalThread::ReleaseThread()
137 {
138 if (tid_ > BACKTRACE_CURRENT_THREAD) {
139 BacktraceLocalContext::GetInstance().ReleaseThread(tid_);
140 }
141 }
142
GetFormattedStr(bool withThreadName,bool isJson)143 std::string BacktraceLocalThread::GetFormattedStr(bool withThreadName, bool isJson)
144 {
145 if (frames_.empty()) {
146 return "";
147 }
148
149 std::ostringstream ss;
150 if (withThreadName && (tid_ > 0)) {
151 std::string threadName;
152 // Tid:1676, Name:IPC_3_1676
153 ReadThreadName(tid_, threadName);
154 ss << "Tid:" << tid_ << ", Name:" << threadName << std::endl;
155 }
156 if (isJson) {
157 #ifndef is_ohos_lite
158 ss << DfxFrameFormat::GetFramesJson(frames_);
159 #endif
160 } else {
161 ss << DfxFrameFormat::GetFramesStr(frames_);
162 }
163 return ss.str();
164 }
165
SetMaxFrameNums(size_t maxFrameNums)166 void BacktraceLocalThread::SetMaxFrameNums(size_t maxFrameNums)
167 {
168 maxFrameNums_ = maxFrameNums;
169 }
170 } // namespace HiviewDFX
171 } // namespace OHOS
172