1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
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 "hook_record_factory.h"
17 #include <memory>
18 #include <string>
19 #include "hook_common.h"
20 #include "logging.h"
21
22 namespace OHOS::Developtools::NativeDaemon {
23
HookRecordFactory(NativeHookConfig hookConfig)24 HookRecordFactory::HookRecordFactory(NativeHookConfig hookConfig) : hookConfig_(hookConfig)
25 {
26 const bool isNoDataQueueMode = (hookConfig_.statistics_interval() > 0 && hookConfig_.fp_unwind() &&
27 hookConfig_.offline_symbolization());
28 int sharedMemCount = (hookConfig_.offline_symbolization()) ? SHARED_MEMORY_NUM : 1;
29 int rawDataCacheSize = isNoDataQueueMode ? sharedMemCount : RAW_DATA_CACHE_INIT_SIZE;
30 int hookRecordCacheSize = isNoDataQueueMode ? sharedMemCount : HOOK_RECORD_CACHE_INIT_SIZE;
31
32 for (int index = 0; index < rawDataCacheSize; ++index) {
33 rawStackCache_.emplace_back(std::make_shared<RawStack>());
34 }
35 for (int index = 0; index < hookRecordCacheSize; ++index) {
36 mallocRecordCache_.emplace_back(std::make_shared<MallocRecord>());
37 mmapRecordCache_.emplace_back(std::make_shared<MmapRecord>());
38 munmapRecordCache_.emplace_back(std::make_shared<MunmapRecord>());
39 jsRecordCache_.emplace_back(std::make_shared<JsRecord>());
40 if (hookConfig_.statistics_interval() > 0) {
41 freeRecordSimpCache_.emplace_back(std::make_shared<FreeRecordSimp>());
42 } else {
43 freeRecordCache_.emplace_back(std::make_shared<FreeRecord>());
44 }
45 }
46 }
47
CreateCacheItem(int16_t type)48 HookRecordPtr CreateCacheItem(int16_t type)
49 {
50 switch (type) {
51 case MALLOC_MSG:
52 return std::make_shared<MallocRecord>();
53 case FREE_MSG:
54 return std::make_shared<FreeRecord>();
55 case FREE_MSG_SIMP:
56 return std::make_shared<FreeRecordSimp>();
57 case MMAP_MSG:
58 return std::make_shared<MmapRecord>();
59 case MUNMAP_MSG:
60 return std::make_shared<MunmapRecord>();
61 case JS_STACK_MSG:
62 return std::make_shared<JsRecord>();
63 default:
64 PROFILER_LOG_ERROR(LOG_CORE, "CreateItem get unexpected type");
65 return nullptr;
66 }
67 }
68
69 template <typename T>
GetRecordFromCache(std::deque<std::shared_ptr<T>> & dataCache,int16_t type)70 std::shared_ptr<T> HookRecordFactory::GetRecordFromCache(std::deque<std::shared_ptr<T>>& dataCache, int16_t type)
71 {
72 std::unique_lock<std::mutex> lock(recordMutex_);
73 if (!dataCache.empty()) {
74 std::shared_ptr<T> cachedData = std::move(dataCache.back());
75 dataCache.pop_back();
76 return cachedData;
77 }
78 return CreateCacheItem(type);
79 }
80
GetRawStackFromCache()81 std::shared_ptr<RawStack> HookRecordFactory::GetRawStackFromCache()
82 {
83 std::unique_lock<std::mutex> lock(rawStackMutex_);
84 if (!rawStackCache_.empty()) {
85 std::shared_ptr<RawStack> cachedData = std::move(rawStackCache_.back());
86 rawStackCache_.pop_back();
87 return cachedData;
88 }
89 lock.unlock();
90 return std::make_shared<RawStack>();
91 }
92
SaveRawStack(RawStackPtr rawStack)93 void HookRecordFactory::SaveRawStack(RawStackPtr rawStack)
94 {
95 std::unique_lock<std::mutex> rawStackLock(rawStackMutex_);
96 if (rawStack && (rawStackCache_.size() <= RAW_DATA_CACHE_MAX_SIZE)) {
97 rawStackCache_.push_back(std::move(rawStack));
98 }
99 }
100
SaveRecordToCache(uint16_t type,HookRecordPtr hookRecord)101 void HookRecordFactory::SaveRecordToCache(uint16_t type, HookRecordPtr hookRecord)
102 {
103 switch (type) {
104 case FREE_MSG_SIMP:
105 if (freeRecordSimpCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
106 freeRecordSimpCache_.push_back(hookRecord);
107 }
108 break;
109 case FREE_MSG:
110 if (freeRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
111 freeRecordCache_.push_back(hookRecord);
112 }
113 break;
114 case MALLOC_MSG:
115 if (mallocRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
116 mallocRecordCache_.push_back(hookRecord);
117 }
118 break;
119 case MMAP_MSG:
120 if (mmapRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
121 mmapRecordCache_.push_back(hookRecord);
122 }
123 break;
124 case MUNMAP_MSG:
125 if (munmapRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
126 munmapRecordCache_.push_back(hookRecord);
127 }
128 break;
129 case JS_STACK_MSG:
130 if (jsRecordCache_.size() < HOOK_RECORD_CACHE_MAX_SIZE) {
131 jsRecordCache_.push_back(hookRecord);
132 }
133 break;
134 default:
135 break;
136 }
137 }
138
SaveHookRecord(HookRecordPtr hookRecord)139 void HookRecordFactory::SaveHookRecord(HookRecordPtr hookRecord)
140 {
141 if (hookRecord == nullptr) {
142 return;
143 }
144 auto rawStack = hookRecord->GetRawStack();
145 uint16_t type = hookRecord->GetType();
146 hookRecord->Reset();
147 SaveRawStack(std::move(rawStack));
148 std::unique_lock<std::mutex> lock(recordMutex_);
149 SaveRecordToCache(type, std::move(hookRecord));
150 }
151
CreateStackRecord(uint16_t type,RawStackPtr rawStack)152 std::shared_ptr<HookRecord> HookRecordFactory::CreateStackRecord(uint16_t type, RawStackPtr rawStack)
153 {
154 switch (type) {
155 case MMAP_FILE_PAGE_MSG:
156 return std::make_shared<MmapFilePageRecord>(rawStack);
157 case MUNMAP_MSG: {
158 auto munmapRecord = GetRecordFromCache(munmapRecordCache_, MUNMAP_MSG);
159 munmapRecord->rawStack_ = rawStack;
160 return munmapRecord;
161 }
162 case MEMORY_UNUSING_MSG:
163 return std::make_shared<MemoryUnusingRecord>(rawStack);
164 case MEMORY_USING_MSG:
165 return std::make_shared<MemoryUsingRecord>(rawStack);
166 case MMAP_FILE_TYPE:
167 return std::make_shared<TagRecord>(rawStack);
168 case MALLOC_MSG: {
169 auto mallocRecord = GetRecordFromCache(mallocRecordCache_, MALLOC_MSG);
170 mallocRecord->rawStack_ = rawStack;
171 return mallocRecord;
172 }
173 case MMAP_MSG: {
174 auto mmapRecord = GetRecordFromCache(mmapRecordCache_, MMAP_MSG);
175 mmapRecord->rawStack_ = rawStack;
176 return mmapRecord;
177 }
178 case FREE_MSG: {
179 auto freeRecord = GetRecordFromCache(freeRecordCache_, FREE_MSG);
180 freeRecord->rawStack_ = rawStack;
181 return freeRecord;
182 }
183 default:
184 PROFILER_LOG_ERROR(LOG_CORE, "GetHookRecord get unknown type");
185 return nullptr;
186 }
187 }
188
InitRawStack(RawStackPtr rawStack,const int8_t sharedMemData[],uint32_t size,bool storeData)189 void HookRecordFactory::InitRawStack(RawStackPtr rawStack, const int8_t sharedMemData[],
190 uint32_t size, bool storeData)
191 {
192 if (storeData) {
193 rawStack->baseStackData = std::make_unique<uint8_t[]>(size);
194 if (memcpy_s(rawStack->baseStackData.get(), size, sharedMemData, size) != EOK) {
195 PROFILER_LOG_ERROR(LOG_CORE, "HookRecordFactory memcpy_s raw data failed!");
196 return;
197 }
198 rawStack->stackContext = reinterpret_cast<BaseStackRawData*>(rawStack->baseStackData.get());
199 rawStack->data = rawStack->baseStackData.get() + sizeof(BaseStackRawData);
200 } else {
201 rawStack->stackContext = reinterpret_cast<BaseStackRawData*>(const_cast<int8_t*>(sharedMemData));
202 rawStack->data = reinterpret_cast<uint8_t*>(const_cast<int8_t*>(sharedMemData)) + sizeof(BaseStackRawData);
203 }
204 }
205
GetHookRecord(const int8_t sharedMemData[],uint32_t size,bool storeData)206 std::shared_ptr<HookRecord> HookRecordFactory::GetHookRecord(const int8_t sharedMemData[],
207 uint32_t size, bool storeData)
208 {
209 if (size == sizeof(void*)) {
210 uint64_t freeAddr = 0;
211 if (memcpy_s(&freeAddr, sizeof(freeAddr), sharedMemData, size) != EOK) {
212 PROFILER_LOG_ERROR(LOG_CORE, "GetHookRecord memcpy failed");
213 return nullptr;
214 }
215 auto freeRecord = GetRecordFromCache(freeRecordSimpCache_, FREE_MSG_SIMP);
216 freeRecord->SetAddr(freeAddr);
217 return freeRecord;
218 }
219 auto rawStack = GetRawStackFromCache();
220 InitRawStack(rawStack, sharedMemData, size, storeData);
221 uint16_t type = rawStack->stackContext->type;
222 switch (type) {
223 case NMD_MSG:
224 return std::make_shared<NmdRecord>(rawStack);
225 case END_MSG:
226 case MEMORY_TAG:
227 case THREAD_NAME_MSG:
228 return std::make_shared<TagRecord>(rawStack);
229 case PR_SET_VMA_MSG:
230 return std::make_shared<PrSetVmaRecord>(rawStack);
231 case JS_STACK_MSG: {
232 auto jsRecord = GetRecordFromCache(jsRecordCache_, JS_STACK_MSG);
233 jsRecord->rawStack_ = rawStack;
234 return jsRecord;
235 }
236 default:
237 break;
238 }
239
240 if (hookConfig_.fp_unwind()) {
241 rawStack->fpDepth = (size - sizeof(BaseStackRawData)) / sizeof(uint64_t);
242 } else {
243 size_t rawRealSize = sizeof(BaseStackRawData) + MAX_REG_SIZE * sizeof(char);
244 rawStack->stackSize = size - rawRealSize;
245 if (rawStack->stackSize > 0) {
246 rawStack->stackData = rawStack->baseStackData.get() + rawRealSize;
247 }
248 }
249 return CreateStackRecord(type, rawStack);
250 }
251 }