• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&registerState[fpIndex], &sp, &registerState[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