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 <iostream>
17 #include <vector>
18 #include <string>
19 #include <memory>
20 #include "hook_record.h"
21
22 namespace OHOS::Developtools::NativeDaemon {
23
GetType()24 uint16_t HookRecord::GetType()
25 {
26 return (IsValid()) ? rawStack_->stackContext->type : UNKNOWN;
27 }
28
Reset()29 void HookRecord::Reset()
30 {
31 if (rawStack_ != nullptr) {
32 rawStack_->Reset();
33 rawStack_ = nullptr;
34 }
35 }
36
GetAddr()37 uint64_t HookRecord::GetAddr()
38 {
39 return (IsValid()) ? reinterpret_cast<uint64_t>(rawStack_->stackContext->addr) : 0;
40 }
41
SetAddr(uint64_t addr)42 void HookRecord::SetAddr(uint64_t addr)
43 {
44 if (IsValid()) {
45 rawStack_->stackContext->addr = reinterpret_cast<void*>(addr);
46 }
47 }
48
IsValid()49 bool HookRecord::IsValid()
50 {
51 return (rawStack_ && rawStack_->stackContext);
52 }
53
54 template <typename T>
SetEventFrame(T * event,SerializeInfo & hookInfo)55 void HookRecord::SetEventFrame(T* event, SerializeInfo& hookInfo)
56 {
57 if (!(event && IsValid())) {
58 PROFILER_LOG_ERROR(LOG_CORE, "hookRecord SetEventFrame get nullptr");
59 return;
60 }
61 // ignore the first two frame if dwarf unwind
62 size_t idx = hookInfo.config->fp_unwind() ? 0 : FILTER_STACK_DEPTH;
63 event->set_pid(rawStack_->stackContext->pid);
64 event->set_tid(rawStack_->stackContext->tid);
65 event->set_addr(GetAddr());
66
67 if (hookInfo.config->callframe_compress() && hookInfo.stackMapId != 0) {
68 event->set_thread_name_id(rawStack_->stackContext->tid);
69 event->set_stack_id(hookInfo.stackMapId);
70 return;
71 }
72 for (; idx < (hookInfo.callFrames)->size(); ++idx) {
73 auto frame = event->add_frame_info();
74 SetFrameInfo(*frame, (*(hookInfo.callFrames))[idx], hookInfo.config);
75 }
76 event->set_thread_name_id(rawStack_->stackContext->tid);
77 }
78
79 template <typename T>
SetFrameInfo(T & frame,CallFrame & callFrame,NativeHookConfig * config)80 void HookRecord::SetFrameInfo(T& frame, CallFrame& callFrame, NativeHookConfig* config)
81 {
82 if (config == nullptr) {
83 PROFILER_LOG_ERROR(LOG_CORE, "hookRecord SetFrameInfo invalid config");
84 return;
85 }
86 frame.set_ip(callFrame.ip_);
87 if (config->offline_symbolization()) {
88 // when js mixes offline symbols, the js call stack is reported according to the online symbolization
89 if (callFrame.isJsFrame_ && callFrame.symbolNameId_ != 0 && callFrame.filePathId_ != 0) {
90 frame.set_sp(callFrame.sp_);
91 frame.set_offset(callFrame.offset_);
92 frame.set_symbol_offset(callFrame.symbolOffset_);
93 frame.set_symbol_name_id(callFrame.symbolNameId_);
94 frame.set_file_path_id(callFrame.filePathId_);
95 }
96 return;
97 }
98 frame.set_sp(callFrame.sp_);
99 if (!(callFrame.symbolNameId_ != 0 && callFrame.filePathId_ != 0)) {
100 frame.set_symbol_name(std::string(callFrame.symbolName_));
101 frame.set_file_path(std::string(callFrame.filePath_));
102 }
103 frame.set_offset(callFrame.offset_);
104 frame.set_symbol_offset(callFrame.symbolOffset_);
105 if (callFrame.symbolNameId_ != 0 && callFrame.filePathId_ != 0) {
106 frame.set_symbol_name_id(callFrame.symbolNameId_);
107 frame.set_file_path_id(callFrame.filePathId_);
108 }
109 }
110
111 template <typename T>
SetSize(T * event)112 void HookRecord::SetSize(T* event)
113 {
114 if (event == nullptr) {
115 PROFILER_LOG_ERROR(LOG_CORE, "hookRecord SetSize invalid event");
116 return;
117 }
118 auto size = static_cast<uint64_t>(rawStack_->stackContext->mallocSize);
119 #ifdef USE_JEMALLOC
120 if (GetType() != MEMORY_USING_MSG) {
121 size = static_cast<uint64_t>(ComputeAlign(size));
122 }
123 #endif
124 event->set_size(size);
125 }
126
SerializeData(NativeHookProto stackData,SerializeInfo & hookInfo)127 void FreeRecord::SerializeData(NativeHookProto stackData, SerializeInfo& hookInfo)
128 {
129 std::visit([this, &hookInfo](auto protoData) {
130 auto freeEvent = protoData->mutable_free_event();
131 HookRecord::SetEventFrame(freeEvent, hookInfo);
132 }, stackData);
133 }
134
SerializeData(NativeHookProto stackData,SerializeInfo & hookInfo)135 void MallocRecord::SerializeData(NativeHookProto stackData, SerializeInfo& hookInfo)
136 {
137 std::visit([this, &hookInfo](auto protoData) {
138 auto allocEvent = protoData->mutable_alloc_event();
139 HookRecord::SetSize(allocEvent);
140 HookRecord::SetEventFrame(allocEvent, hookInfo);
141 }, stackData);
142 }
143
SerializeData(NativeHookProto stackData,SerializeInfo & hookInfo)144 void MmapRecord::SerializeData(NativeHookProto stackData, SerializeInfo& hookInfo)
145 {
146 std::visit([this, &hookInfo](auto protoData) {
147 auto mmapEvent = protoData->mutable_mmap_event();
148 if (hookInfo.tagName != "") {
149 mmapEvent->set_type(hookInfo.tagName);
150 }
151 HookRecord::SetSize(mmapEvent);
152 HookRecord::SetEventFrame(mmapEvent, hookInfo);
153 }, stackData);
154 }
155
SerializeData(NativeHookProto stackData,SerializeInfo & hookInfo)156 void MmapFilePageRecord::SerializeData(NativeHookProto stackData, SerializeInfo& hookInfo)
157 {
158 std::visit([this, &hookInfo](auto protoData) {
159 auto mmapEvent = protoData->mutable_mmap_event();
160 if (hookInfo.tagName != "") {
161 mmapEvent->set_type(MMAP_FILE_PAGE_PREFIX + hookInfo.tagName);
162 }
163 HookRecord::SetSize(mmapEvent);
164 HookRecord::SetEventFrame(mmapEvent, hookInfo);
165 }, stackData);
166 }
167
SerializeData(NativeHookProto stackData,SerializeInfo & hookInfo)168 void MunmapRecord::SerializeData(NativeHookProto stackData, SerializeInfo& hookInfo)
169 {
170 std::visit([this, &hookInfo](auto protoData) {
171 auto munmapEvent = protoData->mutable_munmap_event();
172 HookRecord::SetSize(munmapEvent);
173 HookRecord::SetEventFrame(munmapEvent, hookInfo);
174 }, stackData);
175 }
176
SerializeData(NativeHookProto stackData,SerializeInfo & hookInfo)177 void PrSetVmaRecord::SerializeData(NativeHookProto stackData, SerializeInfo& hookInfo)
178 {
179 std::visit([this](auto protoData) {
180 auto tagEvent = protoData->mutable_tag_event();
181 std::string tagName(reinterpret_cast<char*>(rawStack_->data));
182 tagEvent->set_addr(reinterpret_cast<uint64_t>(rawStack_->stackContext->addr));
183 tagEvent->set_size(rawStack_->stackContext->mallocSize);
184 tagEvent->set_tag(PR_SET_VMA_PREFIX + tagName);
185 tagEvent->set_pid(rawStack_->stackContext->pid);
186 }, stackData);
187 }
188
SerializeData(NativeHookProto stackData,SerializeInfo & hookInfo)189 void MemoryUsingRecord::SerializeData(NativeHookProto stackData, SerializeInfo& hookInfo)
190 {
191 std::visit([this, &hookInfo](auto protoData) {
192 auto memUsingEvent = protoData->mutable_mmap_event();
193 if (hookInfo.tagName != "") {
194 memUsingEvent->set_type(hookInfo.tagName);
195 }
196 HookRecord::SetSize(memUsingEvent);
197 HookRecord::SetEventFrame(memUsingEvent, hookInfo);
198 }, stackData);
199 }
200
SerializeData(NativeHookProto stackData,SerializeInfo & hookInfo)201 void MemoryUnusingRecord::SerializeData(NativeHookProto stackData, SerializeInfo& hookInfo)
202 {
203 std::visit([this, &hookInfo](auto protoData) {
204 auto munmapEvent = protoData->mutable_munmap_event();
205 HookRecord::SetSize(munmapEvent);
206 HookRecord::SetEventFrame(munmapEvent, hookInfo);
207 }, stackData);
208 }
209 }