1 /*
2 * Copyright (c) 2024 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 "async_stack.h"
17
18 #include <pthread.h>
19 #include <securec.h>
20 #include <threads.h>
21
22 #include "dfx_frame_formatter.h"
23 #include "dfx_log.h"
24 #include "dfx_signal_handler.h"
25 #include "fp_backtrace.h"
26 #include "unique_stack_table.h"
27 #include "unwinder.h"
28
29 using namespace OHOS::HiviewDFX;
30 #if defined(__aarch64__)
31 static pthread_key_t g_stackidKey;
32 static bool g_init = false;
33 static OHOS::HiviewDFX::FpBacktrace* g_fpBacktrace = nullptr;
34
InitAsyncStackInner(void)35 static void InitAsyncStackInner(void)
36 {
37 // init unique stack table
38 if (!OHOS::HiviewDFX::UniqueStackTable::Instance()->Init()) {
39 DFXLOGE("failed to init unique stack table?.");
40 return;
41 }
42
43 if (pthread_key_create(&g_stackidKey, nullptr) == 0) {
44 g_init = true;
45 } else {
46 DFXLOGE("failed to create key for stackId.");
47 return;
48 }
49
50 // set callback for DfxSignalHandler to read stackId
51 DFX_SetAsyncStackCallback(GetStackId);
52 g_fpBacktrace = OHOS::HiviewDFX::FpBacktrace::CreateInstance();
53 }
54
InitAsyncStack(void)55 static bool InitAsyncStack(void)
56 {
57 static once_flag onceFlag = ONCE_FLAG_INIT;
58 call_once(&onceFlag, InitAsyncStackInner);
59 return g_init;
60 }
61 #endif
62
CollectAsyncStack(void)63 extern "C" uint64_t CollectAsyncStack(void)
64 {
65 #if defined(__aarch64__)
66 if (!InitAsyncStack()) {
67 return 0;
68 }
69 const uint32_t maxSize = 16;
70 void* pcArray[maxSize] = {0};
71 if (g_fpBacktrace == nullptr) {
72 return 0;
73 }
74 size_t size = g_fpBacktrace->BacktraceFromFp(__builtin_frame_address(0), pcArray, maxSize);
75 uint64_t stackId = 0;
76 auto stackIdPtr = reinterpret_cast<OHOS::HiviewDFX::StackId*>(&stackId);
77 uintptr_t* pcs = reinterpret_cast<uintptr_t*>(pcArray);
78 OHOS::HiviewDFX::UniqueStackTable::Instance()->PutPcsInTable(stackIdPtr, pcs, size);
79 return stackId;
80 #else
81 return 0;
82 #endif
83 }
84
SetStackId(uint64_t stackId)85 extern "C" void SetStackId(uint64_t stackId)
86 {
87 #if defined(__aarch64__)
88 if (!InitAsyncStack()) {
89 return;
90 }
91 pthread_setspecific(g_stackidKey, reinterpret_cast<void *>(stackId));
92 #else
93 return;
94 #endif
95 }
96
GetStackId()97 extern "C" uint64_t GetStackId()
98 {
99 #if defined(__aarch64__)
100 if (!InitAsyncStack()) {
101 return 0;
102 }
103 return reinterpret_cast<uint64_t>(pthread_getspecific(g_stackidKey));
104 #else
105 return 0;
106 #endif
107 }
108
DfxGetSubmitterStackLocal(char * stackTraceBuf,size_t bufferSize)109 extern "C" int DfxGetSubmitterStackLocal(char* stackTraceBuf, size_t bufferSize)
110 {
111 #if defined(__aarch64__)
112 uint64_t stackId = reinterpret_cast<uint64_t>(pthread_getspecific(g_stackidKey));
113 std::vector<uintptr_t> pcs;
114 StackId id;
115 id.value = stackId;
116 if (!OHOS::HiviewDFX::UniqueStackTable::Instance()->GetPcsByStackId(id, pcs)) {
117 DFXLOGW("Failed to get pcs by stackId");
118 return -1;
119 }
120 std::vector<DfxFrame> submitterFrames;
121 Unwinder unwinder;
122 std::string stackTrace;
123 unwinder.GetFramesByPcs(submitterFrames, pcs);
124 for (const auto& frame : submitterFrames) {
125 stackTrace += DfxFrameFormatter::GetFrameStr(frame);
126 }
127 auto result = strncpy_s(stackTraceBuf, bufferSize, stackTrace.c_str(), stackTrace.size());
128 if (result != EOK) {
129 DFXLOGE("strncpy failed, err = %{public}d.", result);
130 return -1;
131 }
132 return 0;
133 #else
134 return -1;
135 #endif
136 }