• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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