1 /*
2 * Copyright (c) 2025 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 "fp_backtrace.h"
17
18 #if is_ohos && !is_mingw && __aarch64__
19 #include <mutex>
20 #include "dfx_ark.h"
21 #include "dfx_log.h"
22 #include "dfx_maps.h"
23 #include "dfx_symbols.h"
24 #include "dfx_util.h"
25 #include "memory_reader.h"
26 #include "smart_fd.h"
27 #include "stack_utils.h"
28 #include "unwinder.h"
29 #endif
30
31 namespace OHOS {
32 namespace HiviewDFX {
33
34 #if is_ohos && !is_mingw && __aarch64__
35 namespace {
36
37 #undef LOG_DOMAIN
38 #undef LOG_TAG
39 #define LOG_TAG "FpBacktrace"
40 #define LOG_DOMAIN 0xD002D11
41 }
42
ffrt_get_current_coroutine_stack(void ** stackAddr,size_t * size)43 extern "C" __attribute__((weak)) bool ffrt_get_current_coroutine_stack(void** stackAddr, size_t* size)
44 {
45 return false;
46 }
47
48 class FpBacktraceImpl : public FpBacktrace {
49 public:
50 bool Init();
51 uint32_t BacktraceFromFp(void* startFp, void** pcArray, uint32_t size) override;
52 DfxFrame* SymbolicAddress(void* pc) override;
53 private:
54 uint32_t BacktraceFromFp(void* startFp, void** pcArray, uint32_t size, MemoryReader& memoryReader) const;
55 bool GetCurrentThreadRange(uintptr_t startFp, uintptr_t& threadBegin, uintptr_t& threadEnd);
56 std::shared_ptr<DfxMaps> maps_ = nullptr;
57 Unwinder unwinder_{false};
58 uintptr_t mainStackBegin_{0};
59 uintptr_t mainStackEnd_{0};
60 std::map<void*, std::unique_ptr<DfxFrame>> cachedFrames_;
61 std::mutex mutex_;
62 };
63
Init()64 bool FpBacktraceImpl::Init()
65 {
66 static std::once_flag flag;
67 std::call_once(flag, []() {
68 void* stackBegin = 0;
69 size_t stackSize = 0;
70 ffrt_get_current_coroutine_stack(&stackBegin, &stackSize);
71 DfxArk::Instance().InitArkFunction(ArkFunction::STEP_ARK);
72 });
73 maps_ = DfxMaps::Create(0, false);
74 if (maps_ == nullptr) {
75 DFXLOGI("failed creat maps");
76 return false;
77 }
78 maps_->GetStackRange(mainStackBegin_, mainStackEnd_);
79 return true;
80 }
81
BacktraceFromFp(void * startFp,void ** pcArray,uint32_t size)82 uint32_t FpBacktraceImpl::BacktraceFromFp(void* startFp, void** pcArray, uint32_t size)
83 {
84 if (!maps_ || startFp == nullptr || pcArray == nullptr || size == 0) {
85 return 0;
86 }
87 uintptr_t stackBegin = 0;
88 uintptr_t stackEnd = 0;
89 if (GetCurrentThreadRange(reinterpret_cast<uintptr_t>(startFp), stackBegin, stackEnd)) {
90 ThreadMemoryReader memoryReader(stackBegin, stackEnd);
91 return BacktraceFromFp(startFp, pcArray, size, memoryReader);
92 }
93 ProcessMemoryReader memoryReader;
94 return BacktraceFromFp(startFp, pcArray, size, memoryReader);
95 }
96
BacktraceFromFp(void * startFp,void ** pcArray,uint32_t size,MemoryReader & memoryReader) const97 uint32_t FpBacktraceImpl::BacktraceFromFp(void* startFp, void** pcArray, uint32_t size,
98 MemoryReader& memoryReader) const
99 {
100 uint32_t index = 0;
101 bool isJsFrame = false;
102 uintptr_t registerState[] = {reinterpret_cast<uintptr_t>(startFp), 0};
103 uintptr_t sp = 0 ;
104 uintptr_t arkStubBegin{0};
105 uintptr_t arkStubEnd{0};
106 maps_->GetArkStackRange(arkStubBegin, arkStubEnd);
107 while (index < size) {
108 constexpr auto fpIndex = 0;
109 constexpr auto pcIndex = 1;
110 uintptr_t preFp = registerState[fpIndex] ;
111 if (isJsFrame || (registerState[pcIndex] < arkStubEnd && registerState[pcIndex] >= arkStubBegin)) {
112 ArkStepParam arkParam(®isterState[fpIndex], &sp, ®isterState[pcIndex], &isJsFrame);
113 DfxArk::Instance().StepArkFrame(&memoryReader, [](void* memoryReader, uintptr_t addr, uintptr_t* val) {
114 return reinterpret_cast<MemoryReader*>(memoryReader)->ReadMemory(addr, val, sizeof(uintptr_t));
115 }, &arkParam);
116 } else {
117 if (!memoryReader.ReadMemory(registerState[fpIndex], registerState, sizeof(registerState))) {
118 break;
119 }
120 }
121 constexpr auto pcBound = 0x1000;
122 if (registerState[pcIndex] <= pcBound) {
123 break;
124 }
125 auto realPc = reinterpret_cast<void *>(StripPac(registerState[pcIndex], 0));
126 if (realPc != nullptr) {
127 pcArray[index++] = realPc;
128 }
129 if (registerState[fpIndex] <= preFp || registerState[fpIndex] == 0) {
130 break;
131 }
132 }
133 return index;
134 }
135
GetCurrentThreadRange(uintptr_t startFp,uintptr_t & threadBegin,uintptr_t & threadEnd)136 bool FpBacktraceImpl::GetCurrentThreadRange(uintptr_t startFp, uintptr_t& threadBegin, uintptr_t& threadEnd)
137 {
138 if (getpid() == gettid() && startFp >= mainStackBegin_ && startFp < mainStackEnd_) {
139 threadBegin = mainStackBegin_;
140 threadEnd = mainStackEnd_;
141 return true;
142 }
143 if (StackUtils::GetSelfStackRange(threadBegin, threadEnd)) {
144 if (startFp >= threadBegin && startFp < threadEnd) {
145 return true;
146 }
147 }
148 size_t stackSize = 0;
149 if (ffrt_get_current_coroutine_stack(reinterpret_cast<void**>(&threadBegin), &stackSize)) {
150 if (startFp >= threadBegin && startFp < threadBegin + stackSize) {
151 threadEnd = threadBegin + stackSize;
152 return true;
153 }
154 }
155 return false;
156 }
157
SymbolicAddress(void * pc)158 DfxFrame* FpBacktraceImpl::SymbolicAddress(void* pc)
159 {
160 std::unique_lock<std::mutex> lock(mutex_);
161 auto cachedFrame = cachedFrames_.emplace(pc, nullptr);
162 auto& frame = cachedFrame.first->second;
163 if (!cachedFrame.second) {
164 return frame.get();
165 }
166 frame = std::unique_ptr<DfxFrame>(new (std::nothrow) DfxFrame());
167 if (!frame) {
168 return nullptr;
169 }
170 unwinder_.GetFrameByPc(reinterpret_cast<uintptr_t>(pc), maps_, *(frame));
171 if (frame->map == nullptr) {
172 frame = nullptr;
173 return nullptr;
174 }
175 frame->mapName = frame->map->GetElfName();
176 frame->relPc = frame->map->GetRelPc(frame->pc);
177 frame->mapOffset = frame->map->offset;
178 auto elf = frame->map->GetElf();
179 if (elf == nullptr) {
180 unwinder_.FillJsFrame(*frame);
181 if (!frame->funcName.empty()) {
182 return frame.get();
183 }
184 }
185 DfxSymbols::GetFuncNameAndOffsetByPc(frame->relPc, elf, frame->funcName, frame->funcOffset);
186 frame->buildId = elf->GetBuildId();
187 return frame.get();
188 }
189 #endif
190
CreateInstance()191 FpBacktrace* FpBacktrace::CreateInstance()
192 {
193 #if is_ohos && !is_mingw && __aarch64__
194 auto fpBacktraceImpl = new (std::nothrow) FpBacktraceImpl();
195 if (fpBacktraceImpl == nullptr) {
196 return nullptr;
197 }
198 if (fpBacktraceImpl->Init()) {
199 return fpBacktraceImpl;
200 }
201 delete fpBacktraceImpl;
202 #endif
203 return nullptr;
204 }
205 }
206 }
207