1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. 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 "native_hook_filter.h"
17 #include "native_hook_config.pbreader.h"
18 #include <cstddef>
19 #include <cinttypes>
20 namespace SysTuning {
21 namespace TraceStreamer {
NativeHookFilter(TraceDataCache * dataCache,const TraceStreamerFilters * filter)22 NativeHookFilter::NativeHookFilter(TraceDataCache *dataCache, const TraceStreamerFilters *filter)
23 : OfflineSymbolizationFilter(dataCache, filter),
24 anonMmapData_(nullptr),
25 hookPluginData_(std::make_unique<ProfilerPluginData>()),
26 ipidToSymIdToSymIndex_(INVALID_UINT64),
27 ipidToFilePathIdToFileIndex_(INVALID_UINT64),
28 ipidToFrameIdToFrameBytes_(nullptr)
29 {
30 invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/libc++.so"));
31 invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib64/libc++.so"));
32 invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-aarch64.so.1"));
33 invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-arm.so.1"));
34 hookPluginData_->set_name("nativehook");
35 commHookData_.datas = std::make_unique<BatchNativeHookData>();
36 addrToAllocEventRow_ = traceDataCache_->GetNativeHookData()->GetAddrToAllocEventRow();
37 addrToMmapEventRow_ = traceDataCache_->GetNativeHookData()->GetAddrToMmapEventRow();
38 }
39
ParseConfigInfo(ProtoReader::BytesView & protoData)40 void NativeHookFilter::ParseConfigInfo(ProtoReader::BytesView &protoData)
41 {
42 auto configReader = ProtoReader::NativeHookConfig_Reader(protoData);
43 if (configReader.has_expand_pids() || (configReader.has_process_name() && configReader.has_pid())) {
44 isSingleProcData_ = false;
45 }
46 if (configReader.has_statistics_interval()) {
47 isStatisticMode_ = true;
48 isCallStackCompressedMode_ = true;
49 isStringCompressedMode_ = true;
50 }
51 if (configReader.has_response_library_mode() || configReader.has_offline_symbolization()) {
52 isOfflineSymbolizationMode_ = true;
53 isCallStackCompressedMode_ = true;
54 isStringCompressedMode_ = true;
55 return;
56 }
57 if (configReader.has_callframe_compress()) {
58 isCallStackCompressedMode_ = true;
59 isStringCompressedMode_ = true;
60 return;
61 }
62 if (configReader.has_string_compressed()) {
63 isStringCompressedMode_ = true;
64 return;
65 }
66 return;
67 }
AppendStackMaps(uint32_t ipid,uint32_t stackid,std::vector<uint64_t> & frames)68 void NativeHookFilter::AppendStackMaps(uint32_t ipid, uint32_t stackid, std::vector<uint64_t> &frames)
69 {
70 uint64_t ipidWithStackIdIndex = 0;
71 // the last element is ipid for this batch of frames/ips
72 if (isSingleProcData_) {
73 frames.emplace_back(SINGLE_PROC_IPID);
74 ipidWithStackIdIndex = stackid;
75 } else {
76 frames.emplace_back(ipid);
77 ipidWithStackIdIndex = traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" + std::to_string(stackid));
78 }
79 auto framesSharedPtr = std::make_shared<std::vector<uint64_t>>(frames);
80 stackIdToFramesMap_.emplace(std::make_pair(ipidWithStackIdIndex, framesSharedPtr));
81 // allStackIdToFramesMap_ save all offline symbolic call stack
82 if (isOfflineSymbolizationMode_) {
83 allStackIdToFramesMap_.emplace(std::make_pair(ipidWithStackIdIndex, framesSharedPtr));
84 }
85 }
AppendFrameMaps(uint32_t ipid,uint32_t frameMapId,const ProtoReader::BytesView & bytesView)86 void NativeHookFilter::AppendFrameMaps(uint32_t ipid, uint32_t frameMapId, const ProtoReader::BytesView &bytesView)
87 {
88 auto frames = std::make_shared<const ProtoReader::BytesView>(bytesView);
89 if (isSingleProcData_) {
90 ipidToFrameIdToFrameBytes_.Insert(SINGLE_PROC_IPID, frameMapId, frames);
91 } else {
92 ipidToFrameIdToFrameBytes_.Insert(ipid, frameMapId, frames);
93 }
94 }
AppendFilePathMaps(uint32_t ipid,uint32_t filePathId,uint64_t fileIndex)95 void NativeHookFilter::AppendFilePathMaps(uint32_t ipid, uint32_t filePathId, uint64_t fileIndex)
96 {
97 if (isSingleProcData_) {
98 ipidToFilePathIdToFileIndex_.Insert(SINGLE_PROC_IPID, filePathId, fileIndex);
99 } else {
100 ipidToFilePathIdToFileIndex_.Insert(ipid, filePathId, fileIndex);
101 }
102 }
AppendSymbolMap(uint32_t ipid,uint32_t symId,uint64_t symbolIndex)103 void NativeHookFilter::AppendSymbolMap(uint32_t ipid, uint32_t symId, uint64_t symbolIndex)
104 {
105 if (isSingleProcData_) {
106 ipidToSymIdToSymIndex_.Insert(SINGLE_PROC_IPID, symId, symbolIndex);
107 } else {
108 ipidToSymIdToSymIndex_.Insert(ipid, symId, symbolIndex);
109 }
110 }
AppendThreadNameMap(uint32_t ipid,uint32_t nameId,uint64_t threadNameIndex)111 void NativeHookFilter::AppendThreadNameMap(uint32_t ipid, uint32_t nameId, uint64_t threadNameIndex)
112 {
113 uint64_t ipidWithThreadNameIdIndex = 0;
114 if (isSingleProcData_) {
115 ipidWithThreadNameIdIndex = nameId;
116 } else {
117 ipidWithThreadNameIdIndex = traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" + std::to_string(nameId));
118 }
119 threadNameIdToThreadNameIndex_.emplace(ipidWithThreadNameIdIndex, threadNameIndex);
120 }
121
122 template <class T1, class T2>
UpdateMap(std::unordered_map<T1,T2> & sourceMap,T1 key,T2 value)123 void NativeHookFilter::UpdateMap(std::unordered_map<T1, T2> &sourceMap, T1 key, T2 value)
124 {
125 auto itor = sourceMap.find(key);
126 if (itor != sourceMap.end()) {
127 itor->second = value;
128 } else {
129 sourceMap.insert(std::make_pair(key, value));
130 }
131 }
ParseFrame(uint64_t row,const ProtoReader::DataArea & frame)132 std::unique_ptr<NativeHookFrameInfo> NativeHookFilter::ParseFrame(uint64_t row, const ProtoReader::DataArea &frame)
133 {
134 auto frameInfo = std::make_unique<NativeHookFrameInfo>();
135
136 ProtoReader::Frame_Reader reader(frame.Data(), frame.Size());
137 auto curCacheIpid = traceDataCache_->GetNativeHookData()->Ipids()[row];
138 if (isSingleProcData_) {
139 curCacheIpid = SINGLE_PROC_IPID;
140 }
141 if (isStringCompressedMode_) {
142 frameInfo->symbolIndex_ = ipidToSymIdToSymIndex_.Find(curCacheIpid, reader.symbol_name_id());
143 TS_CHECK_TRUE(frameInfo->symbolIndex_ != INVALID_UINT64, nullptr,
144 "Native hook ParseFrame find symbol id failed!!!");
145 frameInfo->filePathIndex_ = ipidToFilePathIdToFileIndex_.Find(curCacheIpid, reader.file_path_id());
146 TS_CHECK_TRUE(frameInfo->filePathIndex_ != INVALID_UINT64, nullptr,
147 "Native hook ParseFrame find file path id failed!!!");
148 } else {
149 frameInfo->symbolIndex_ = traceDataCache_->dataDict_.GetStringIndex(reader.symbol_name().ToStdString());
150 frameInfo->filePathIndex_ = traceDataCache_->dataDict_.GetStringIndex(reader.file_path().ToStdString());
151 }
152 // 0 is meaningful, but it is not displayed. Other data is still needed
153 if (reader.has_ip()) {
154 frameInfo->ip_ = reader.ip();
155 }
156 if (reader.has_offset()) {
157 frameInfo->offset_ = reader.offset();
158 }
159 if (reader.has_symbol_offset()) {
160 frameInfo->symbolOffset_ = reader.symbol_offset();
161 }
162 return frameInfo;
163 }
164
CompressStackAndFrames(uint64_t row,ProtoReader::RepeatedDataAreaIterator<ProtoReader::BytesView> frames)165 void NativeHookFilter::CompressStackAndFrames(uint64_t row,
166 ProtoReader::RepeatedDataAreaIterator<ProtoReader::BytesView> frames)
167 {
168 std::vector<uint64_t> framesHash;
169 std::string framesHashStr = "";
170 for (auto itor = frames; itor; itor++) {
171 std::string_view frameStr(reinterpret_cast<const char *>(itor->Data()), itor->Size());
172 auto frameHash = hashFun_(frameStr);
173 if (!frameHashToFrameInfoMap_.count(frameHash)) {
174 // the frame compression is completed and the frame is parsed.
175 auto frameInfo = ParseFrame(row, itor.GetDataArea());
176 if (!frameInfo) {
177 continue;
178 }
179 frameHashToFrameInfoMap_.emplace(std::make_pair(frameHash, std::move(frameInfo)));
180 }
181 framesHash.emplace_back(frameHash);
182 framesHashStr.append("+");
183 framesHashStr.append(std::to_string(frameHash));
184 }
185 auto stackHashValue = hashFun_(framesHashStr);
186 uint32_t callChainId = INVALID_UINT32;
187 if (!stackHashValueToCallChainIdMap_.count(stackHashValue)) {
188 callChainId = callChainIdToStackHashValueMap_.size() + 1;
189 callChainIdToStackHashValueMap_.emplace(std::make_pair(callChainId, stackHashValue));
190 stackHashValueToCallChainIdMap_.emplace(std::make_pair(stackHashValue, callChainId));
191 stackHashValueToFramesHashMap_.emplace(std::make_pair(stackHashValue, std::move(framesHash)));
192 } else {
193 callChainId = stackHashValueToCallChainIdMap_[stackHashValue];
194 }
195 // When compressing the call stack, update the callChainId of the nativeHook table
196 traceDataCache_->GetNativeHookData()->UpdateCallChainId(row, callChainId);
197 }
ParseStatisticEvent(uint64_t timeStamp,const ProtoReader::BytesView & bytesView)198 void NativeHookFilter::ParseStatisticEvent(uint64_t timeStamp, const ProtoReader::BytesView &bytesView)
199 {
200 ProtoReader::RecordStatisticsEvent_Reader reader(bytesView);
201 uint32_t callChainId = INVALID_UINT32;
202 uint64_t ipidWithCallChainIdIndex = INVALID_UINT64;
203 auto ipid = streamFilters_->processFilter_->GetOrCreateInternalPid(timeStamp, reader.pid());
204 if (isSingleProcData_) {
205 ipidWithCallChainIdIndex = reader.callstack_id();
206 } else {
207 ipidWithCallChainIdIndex =
208 traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" + std::to_string(reader.callstack_id()));
209 }
210 // When the stack id is zero, there is no matching call stack
211 if (isOfflineSymbolizationMode_ && reader.callstack_id()) {
212 // The same call stack may have different symbolic results due to changes in the symbol table
213 if (stackIdToCallChainIdMap_.count(ipidWithCallChainIdIndex)) {
214 callChainId = stackIdToCallChainIdMap_.at(ipidWithCallChainIdIndex);
215 } else {
216 TS_LOGE("invalid callChainId, can not find stack id : %u in stackIdToCallChainIdMap_!",
217 reader.callstack_id());
218 }
219 } else if (reader.callstack_id()) { // when isStatisticMode_ is true, isCallStackCompressedMode_ must be true.
220 // when isOfflineSymblolizationMode_ is false, the stack id is unique
221 callChainId = ipidWithCallChainIdIndex;
222 }
223
224 DataIndex memSubType = INVALID_UINT64;
225 if (reader.has_tag_name()) {
226 memSubType = traceDataCache_->GetDataIndex(reader.tag_name().ToStdString());
227 }
228 NativeHookStatisticRow nativeHookStatisticRow = {ipid,
229 timeStamp,
230 callChainId,
231 static_cast<uint32_t>(reader.type()),
232 memSubType,
233 reader.apply_count(),
234 reader.release_count(),
235 reader.apply_size(),
236 reader.release_size()};
237 traceDataCache_->GetNativeHookStatisticsData()->AppendNewNativeHookStatistic(nativeHookStatisticRow);
238 }
ParseAllocEvent(uint64_t timeStamp,const ProtoReader::BytesView & bytesView)239 void NativeHookFilter::ParseAllocEvent(uint64_t timeStamp, const ProtoReader::BytesView &bytesView)
240 {
241 ProtoReader::AllocEvent_Reader allocEventReader(bytesView);
242 uint32_t callChainId = INVALID_UINT32;
243 auto itid =
244 streamFilters_->processFilter_->GetOrCreateThreadWithPid(allocEventReader.tid(), allocEventReader.pid());
245 auto ipid = traceDataCache_->GetConstThreadData(itid).internalPid_;
246 uint64_t ipidWithStackIdIndex = INVALID_UINT64;
247 uint64_t ipidWithThreadNameIdIndex = INVALID_UINT64;
248 if (isSingleProcData_) {
249 ipidWithThreadNameIdIndex = allocEventReader.thread_name_id();
250 ipidWithStackIdIndex = allocEventReader.stack_id();
251 } else {
252 ipidWithThreadNameIdIndex = traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" +
253 std::to_string(allocEventReader.thread_name_id()));
254 ipidWithStackIdIndex =
255 traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" + std::to_string(allocEventReader.stack_id()));
256 }
257 // When the stack id is zero, there is no matching call stack
258 if (isOfflineSymbolizationMode_ && allocEventReader.stack_id()) {
259 // The same call stack may have different symbolic results due to changes in the symbol table
260 if (stackIdToCallChainIdMap_.count(ipidWithStackIdIndex)) {
261 callChainId = stackIdToCallChainIdMap_.at(ipidWithStackIdIndex);
262 } else {
263 TS_LOGE("invalid callChainId, can not find pid with stack id : %" PRIu64 " in stackIdToCallChainIdMap_!",
264 ipidWithStackIdIndex);
265 }
266 } else if (isCallStackCompressedMode_ && allocEventReader.stack_id()) {
267 // when isOfflineSymblolizationMode_ is false && isCallStackCompressedMode is true, the stack id is unique
268 callChainId = ipidWithStackIdIndex;
269 }
270
271 if (allocEventReader.has_thread_name_id()) {
272 UpdateMap(itidToThreadNameId_, itid, ipidWithThreadNameIdIndex);
273 }
274 NativeHookRow nativeHookRow = {callChainId,
275 ipid,
276 itid,
277 "AllocEvent",
278 INVALID_UINT64,
279 timeStamp,
280 0,
281 0,
282 allocEventReader.addr(),
283 static_cast<int64_t>(allocEventReader.size())};
284 auto row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData(nativeHookRow);
285 addrToAllocEventRow_->insert(std::make_pair(allocEventReader.addr(), static_cast<uint64_t>(row)));
286 if (allocEventReader.size() != 0) {
287 MaybeUpdateCurrentSizeDur(row, timeStamp, true);
288 }
289 // Uncompressed call stack
290 if (allocEventReader.has_frame_info()) {
291 CompressStackAndFrames(row, allocEventReader.frame_info());
292 }
293 }
294
SetFreeEventCallChainId(uint32_t & callChainId,uint32_t ipid,uint32_t itid,const ProtoReader::FreeEvent_Reader & freeEventReader)295 void NativeHookFilter::SetFreeEventCallChainId(uint32_t &callChainId,
296 uint32_t ipid,
297 uint32_t itid,
298 const ProtoReader::FreeEvent_Reader &freeEventReader)
299 {
300 uint64_t ipidWithStackIdIndex = INVALID_UINT64;
301 uint64_t ipidWithThreadNameIdIndex = INVALID_UINT64;
302 if (isSingleProcData_) {
303 ipidWithStackIdIndex = freeEventReader.stack_id();
304 ipidWithThreadNameIdIndex = freeEventReader.thread_name_id();
305 } else {
306 ipidWithThreadNameIdIndex = traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" +
307 std::to_string(freeEventReader.thread_name_id()));
308 ipidWithStackIdIndex =
309 traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" + std::to_string(freeEventReader.stack_id()));
310 }
311 // When the stack id is zero, there is no matching call stack
312 if (isOfflineSymbolizationMode_ && freeEventReader.stack_id()) {
313 // The same call stack may have different symbolic results due to changes in the symbol table
314 if (stackIdToCallChainIdMap_.count(ipidWithStackIdIndex)) {
315 callChainId = stackIdToCallChainIdMap_.at(ipidWithStackIdIndex);
316 } else {
317 TS_LOGE("invalid callChainId, can not find pid with stack id : %" PRIu64 " in stackIdToCallChainIdMap_!",
318 ipidWithStackIdIndex);
319 }
320 } else if (isCallStackCompressedMode_ && freeEventReader.stack_id()) {
321 // when isOfflineSymblolizationMode_ is false && isCallStackCompressedMode is true, the stack id is unique
322 callChainId = ipidWithStackIdIndex;
323 }
324 if (freeEventReader.thread_name_id() != 0) {
325 UpdateMap(itidToThreadNameId_, itid, ipidWithThreadNameIdIndex);
326 }
327 }
ParseFreeEvent(uint64_t timeStamp,const ProtoReader::BytesView & bytesView)328 void NativeHookFilter::ParseFreeEvent(uint64_t timeStamp, const ProtoReader::BytesView &bytesView)
329 {
330 ProtoReader::FreeEvent_Reader freeEventReader(bytesView);
331 uint32_t callChainId = INVALID_UINT32;
332 auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(freeEventReader.tid(), freeEventReader.pid());
333 auto ipid = traceDataCache_->GetConstThreadData(itid).internalPid_;
334 SetFreeEventCallChainId(callChainId, ipid, itid, freeEventReader);
335 int64_t freeHeapSize = 0;
336 // Find a matching malloc event, and if the matching fails, do not write to the database
337 uint64_t row = INVALID_UINT64;
338 if (addrToAllocEventRow_->count(freeEventReader.addr())) {
339 row = addrToAllocEventRow_->at(freeEventReader.addr());
340 }
341 if (row != INVALID_UINT64 && timeStamp > traceDataCache_->GetNativeHookData()->TimeStampData()[row]) {
342 addrToAllocEventRow_->erase(freeEventReader.addr());
343 traceDataCache_->GetNativeHookData()->UpdateEndTimeStampAndDuration(row, timeStamp);
344 freeHeapSize = traceDataCache_->GetNativeHookData()->MemSizes()[row];
345 } else {
346 TS_LOGD("func addr:%" PRIu64 " is empty", freeEventReader.addr());
347 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_DATA_INVALID);
348 return;
349 }
350 NativeHookRow nativeHookRow = {
351 callChainId, ipid, itid, "FreeEvent", INVALID_UINT64, timeStamp, 0, 0, freeEventReader.addr(), freeHeapSize};
352 row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData(nativeHookRow);
353 if (freeHeapSize != 0) {
354 MaybeUpdateCurrentSizeDur(row, timeStamp, true);
355 }
356 // Uncompressed call stack
357 if (freeEventReader.has_frame_info()) {
358 CompressStackAndFrames(row, freeEventReader.frame_info());
359 }
360 }
SetMmapEventCallChainId(uint32_t & callChainId,uint32_t ipid,uint32_t itid,const ProtoReader::MmapEvent_Reader & mMapEventReader)361 void NativeHookFilter::SetMmapEventCallChainId(uint32_t &callChainId,
362 uint32_t ipid,
363 uint32_t itid,
364 const ProtoReader::MmapEvent_Reader &mMapEventReader)
365 {
366 uint64_t ipidWithStackIdIndex = INVALID_UINT64;
367 uint64_t ipidWithThreadNameIdIndex = INVALID_UINT64;
368 if (isSingleProcData_) {
369 ipidWithStackIdIndex = mMapEventReader.stack_id();
370 ipidWithThreadNameIdIndex = mMapEventReader.thread_name_id();
371 } else {
372 ipidWithThreadNameIdIndex = traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" +
373 std::to_string(mMapEventReader.thread_name_id()));
374 ipidWithStackIdIndex =
375 traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" + std::to_string(mMapEventReader.stack_id()));
376 }
377 // When the stack id is zero, there is no matching call stack
378 if (isOfflineSymbolizationMode_ && mMapEventReader.stack_id()) {
379 // The same call stack may have different symbolic results due to changes in the symbol table
380 if (stackIdToCallChainIdMap_.count(ipidWithStackIdIndex)) {
381 callChainId = stackIdToCallChainIdMap_.at(ipidWithStackIdIndex);
382 } else {
383 TS_LOGE("invalid callChainId, can not find pid with stack id : %" PRIu64 " in stackIdToCallChainIdMap_!",
384 ipidWithStackIdIndex);
385 }
386 } else if (isCallStackCompressedMode_ && mMapEventReader.stack_id()) {
387 // when isOfflineSymblolizationMode_ is false && isCallStackCompressedMode is true, the stack id is unique
388 callChainId = ipidWithStackIdIndex;
389 }
390 // Update the mapping of tid to thread name id.
391 if (mMapEventReader.thread_name_id() != 0) {
392 UpdateMap(itidToThreadNameId_, itid, ipidWithThreadNameIdIndex);
393 }
394 }
ParseMmapEvent(uint64_t timeStamp,const ProtoReader::BytesView & bytesView)395 void NativeHookFilter::ParseMmapEvent(uint64_t timeStamp, const ProtoReader::BytesView &bytesView)
396 {
397 ProtoReader::MmapEvent_Reader mMapEventReader(bytesView);
398 uint32_t callChainId = INVALID_UINT32;
399 auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(mMapEventReader.tid(), mMapEventReader.pid());
400 auto ipid = traceDataCache_->GetConstThreadData(itid).internalPid_;
401 SetMmapEventCallChainId(callChainId, ipid, itid, mMapEventReader);
402 // Gets the index of the mmap event's label in the data dictionary
403 DataIndex subType = INVALID_UINT64;
404 auto mMapAddr = mMapEventReader.addr();
405 auto mMapSize = mMapEventReader.size();
406 if (mMapEventReader.has_type() && !mMapEventReader.type().ToStdString().empty()) {
407 subType = traceDataCache_->dataDict_.GetStringIndex(mMapEventReader.type().ToStdString());
408 // Establish a mapping of addr and size to the mmap tag index.
409 addrToMmapTag_[mMapAddr] = subType; // update addr to MemMapSubType
410 }
411 NativeHookRow nativeHookRow = {callChainId, ipid, itid, "MmapEvent", subType,
412 timeStamp, 0, 0, mMapAddr, static_cast<int64_t>(mMapSize)};
413 auto row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData(nativeHookRow);
414 if (subType == INVALID_UINT64) {
415 UpdateAnonMmapDataDbIndex(mMapAddr, mMapSize, static_cast<uint64_t>(row));
416 }
417 addrToMmapEventRow_->insert(std::make_pair(mMapAddr, static_cast<uint64_t>(row)));
418 // update currentSizeDur.
419 if (mMapSize) {
420 MaybeUpdateCurrentSizeDur(row, timeStamp, false);
421 }
422 // Uncompressed call stack
423 if (mMapEventReader.has_frame_info()) {
424 CompressStackAndFrames(row, mMapEventReader.frame_info());
425 }
426 }
SetMunmapEventCallChainId(uint32_t & callChainId,uint32_t ipid,uint32_t itid,const ProtoReader::MunmapEvent_Reader & mUnmapEventReader)427 void NativeHookFilter::SetMunmapEventCallChainId(uint32_t &callChainId,
428 uint32_t ipid,
429 uint32_t itid,
430 const ProtoReader::MunmapEvent_Reader &mUnmapEventReader)
431 {
432 uint64_t ipidWithStackIdIndex = INVALID_UINT64;
433 uint64_t ipidWithThreadNameIdIndex = INVALID_UINT64;
434 if (isSingleProcData_) {
435 ipidWithStackIdIndex = mUnmapEventReader.stack_id();
436 ipidWithThreadNameIdIndex = mUnmapEventReader.thread_name_id();
437 } else {
438 ipidWithThreadNameIdIndex = traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" +
439 std::to_string(mUnmapEventReader.thread_name_id()));
440 ipidWithStackIdIndex =
441 traceDataCache_->GetDataIndex(std::to_string(ipid) + "_" + std::to_string(mUnmapEventReader.stack_id()));
442 }
443 // When the stack id is zero, there is no matching call stack
444 if (isOfflineSymbolizationMode_) {
445 // The same call stack may have different symbolic results due to changes in the symbol table
446 if (stackIdToCallChainIdMap_.count(ipidWithStackIdIndex)) {
447 callChainId = stackIdToCallChainIdMap_.at(mUnmapEventReader.stack_id());
448 } else {
449 TS_LOGE("invalid callChainId, can not find pid with stack id : %" PRIu64 " in stackIdToCallChainIdMap_!",
450 ipidWithStackIdIndex);
451 }
452 } else if (isCallStackCompressedMode_) {
453 // when isOfflineSymblolizationMode_ is false && isCallStackCompressedMode is true, the stack id is unique
454 callChainId = ipidWithStackIdIndex;
455 }
456 if (mUnmapEventReader.thread_name_id() != 0) {
457 UpdateMap(itidToThreadNameId_, itid, ipidWithThreadNameIdIndex);
458 }
459 }
ParseMunmapEvent(uint64_t timeStamp,const ProtoReader::BytesView & bytesView)460 void NativeHookFilter::ParseMunmapEvent(uint64_t timeStamp, const ProtoReader::BytesView &bytesView)
461 {
462 ProtoReader::MunmapEvent_Reader mUnmapEventReader(bytesView);
463 uint32_t callChainId = INVALID_UINT32;
464 auto itid =
465 streamFilters_->processFilter_->GetOrCreateThreadWithPid(mUnmapEventReader.tid(), mUnmapEventReader.pid());
466 auto ipid = traceDataCache_->GetConstThreadData(itid).internalPid_;
467 SetMunmapEventCallChainId(callChainId, ipid, itid, mUnmapEventReader);
468 // Query for MMAP events that match the current data. If there are no matching MMAP events, the current data is not
469 // written to the database.
470 uint64_t row = INVALID_UINT64;
471 if (addrToMmapEventRow_->count(mUnmapEventReader.addr())) {
472 row = addrToMmapEventRow_->at(mUnmapEventReader.addr());
473 }
474 if (row != INVALID_UINT64 && timeStamp > traceDataCache_->GetNativeHookData()->TimeStampData()[row]) {
475 addrToMmapEventRow_->erase(mUnmapEventReader.addr());
476 traceDataCache_->GetNativeHookData()->UpdateEndTimeStampAndDuration(row, timeStamp);
477 } else {
478 TS_LOGD("func addr:%" PRIu64 " is empty", mUnmapEventReader.addr());
479 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_DATA_INVALID);
480 return;
481 }
482 NativeHookRow nativeHookRow = {callChainId,
483 ipid,
484 itid,
485 "MunmapEvent",
486 GetMemMapSubTypeWithAddr(mUnmapEventReader.addr()),
487 timeStamp,
488 0,
489 0,
490 mUnmapEventReader.addr(),
491 static_cast<int64_t>(mUnmapEventReader.size())};
492 row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData(nativeHookRow);
493 addrToMmapTag_.erase(mUnmapEventReader.addr()); // earse MemMapSubType with addr
494 if (mUnmapEventReader.size() != 0) {
495 MaybeUpdateCurrentSizeDur(row, timeStamp, false);
496 }
497 // Uncompressed call stack
498 if (mUnmapEventReader.has_frame_info()) {
499 CompressStackAndFrames(row, mUnmapEventReader.frame_info());
500 }
501 }
ParseTagEvent(const ProtoReader::BytesView & bytesView)502 void NativeHookFilter::ParseTagEvent(const ProtoReader::BytesView &bytesView)
503 {
504 ProtoReader::MemTagEvent_Reader memTagEventReader(bytesView);
505 auto addr = memTagEventReader.addr();
506 auto size = memTagEventReader.size();
507 if (traceDataCache_->isSplitFile_) {
508 auto hookData = commHookData_.datas->add_events();
509 MemTagEvent *memTagEvent = hookData->mutable_tag_event();
510 memTagEvent->ParseFromArray(bytesView.Data(), bytesView.Size());
511 commHookData_.size += bytesView.Size();
512 return;
513 }
514 auto tagIndex = traceDataCache_->dataDict_.GetStringIndex(memTagEventReader.tag().ToStdString());
515 NativeHook *nativeHookPtr = traceDataCache_->GetNativeHookData();
516 std::shared_ptr<std::set<uint64_t>> indexSetPtr = anonMmapData_.Find(addr, size); // get anonMmapData dbIndex
517 if (indexSetPtr != nullptr) {
518 for (auto rowIter = indexSetPtr->begin(); rowIter != indexSetPtr->end(); rowIter++) {
519 nativeHookPtr->UpdateMemMapSubType(*rowIter, tagIndex);
520 }
521 indexSetPtr->clear(); // clear annoMmapData dbIndex
522 addrToMmapTag_[addr] = tagIndex; // update addr to MemMapSubType
523 }
524 }
GetMemMapSubTypeWithAddr(uint64_t addr)525 inline uint64_t NativeHookFilter::GetMemMapSubTypeWithAddr(uint64_t addr)
526 {
527 auto iter = addrToMmapTag_.find(addr);
528 if (iter != addrToMmapTag_.end()) {
529 return iter->second; // subType
530 } else {
531 return INVALID_UINT64;
532 }
533 }
UpdateAnonMmapDataDbIndex(uint64_t addr,uint64_t size,uint64_t row)534 inline void NativeHookFilter::UpdateAnonMmapDataDbIndex(uint64_t addr, uint64_t size, uint64_t row)
535 {
536 auto indexPtr = anonMmapData_.Find(addr, size);
537 if (indexPtr == nullptr) {
538 std::shared_ptr<std::set<uint64_t>> rowPtr_ = std::make_shared<std::set<uint64_t>>();
539 rowPtr_->insert(row);
540 anonMmapData_.Insert(addr, size, std::move(rowPtr_));
541 } else {
542 indexPtr->insert(row);
543 }
544 }
FilterNativeHookMainEvent(size_t num)545 void NativeHookFilter::FilterNativeHookMainEvent(size_t num)
546 {
547 auto itor = tsToMainEventsMap_.begin();
548 for (; itor != tsToMainEventsMap_.end() && num; num--, itor++) {
549 auto nativeHookDataReader = itor->second->reader_.get();
550 auto timeStamp = itor->first;
551 if (nativeHookDataReader->has_alloc_event()) {
552 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED);
553 ParseAllocEvent(timeStamp, nativeHookDataReader->alloc_event());
554 } else if (nativeHookDataReader->has_free_event()) {
555 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED);
556 ParseFreeEvent(timeStamp, nativeHookDataReader->free_event());
557 } else if (nativeHookDataReader->has_mmap_event()) {
558 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED);
559 ParseMmapEvent(timeStamp, nativeHookDataReader->mmap_event());
560 } else if (nativeHookDataReader->has_munmap_event()) {
561 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED);
562 ParseMunmapEvent(timeStamp, nativeHookDataReader->munmap_event());
563 } else if (nativeHookDataReader->has_statistics_event()) {
564 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_RECORD_STATISTICS, STAT_EVENT_RECEIVED);
565 ParseStatisticEvent(timeStamp, nativeHookDataReader->statistics_event());
566 } else if (nativeHookDataReader->has_tag_event()) {
567 streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MEMTAG, STAT_EVENT_RECEIVED);
568 ParseTagEvent(nativeHookDataReader->tag_event());
569 }
570 }
571 tsToMainEventsMap_.erase(tsToMainEventsMap_.begin(), itor);
572 }
573
MaybeParseNativeHookMainEvent(uint64_t timeStamp,std::unique_ptr<NativeHookMetaData> nativeHookMetaData)574 void NativeHookFilter::MaybeParseNativeHookMainEvent(uint64_t timeStamp,
575 std::unique_ptr<NativeHookMetaData> nativeHookMetaData)
576 {
577 tsToMainEventsMap_.insert(std::make_pair(timeStamp, std::move(nativeHookMetaData)));
578 if (tsToMainEventsMap_.size() > MAX_CACHE_SIZE) {
579 if (isOfflineSymbolizationMode_) {
580 ParseFramesInOfflineSymbolizationMode();
581 ReparseStacksWithDifferentMeans();
582 }
583 FilterNativeHookMainEvent(tsToMainEventsMap_.size() - MAX_CACHE_SIZE);
584 }
585 }
586
587 // Returns the address range of memMaps that conflict with start Addr and endAddr, as [start, end).
GetNeedUpdateProcessMapsAddrRange(uint32_t ipid,uint64_t startAddr,uint64_t endAddr)588 std::tuple<uint64_t, uint64_t> NativeHookFilter::GetNeedUpdateProcessMapsAddrRange(uint32_t ipid,
589 uint64_t startAddr,
590 uint64_t endAddr)
591 {
592 uint64_t start = INVALID_UINT64;
593 uint64_t end = INVALID_UINT64;
594 auto startAddrToMapsInfoMapPtr = ipidToStartAddrToMapsInfoMap_.Find(ipid);
595 if (startAddr >= endAddr || startAddrToMapsInfoMapPtr == nullptr) {
596 return std::make_tuple(start, end);
597 }
598 // Find first item in startAddrToMapsInfoMapPtr,
599 // that startItor->second()->start <= startAddr && startItor->second()->end > startAddr.
600 auto startItor = startAddrToMapsInfoMapPtr->upper_bound(startAddr);
601 if (startAddrToMapsInfoMapPtr->begin() != startItor) {
602 --startItor;
603 // Follow the rules of front closing and rear opening, [start, end)
604 if (startItor != startAddrToMapsInfoMapPtr->end() && startAddr >= startItor->second->end()) {
605 ++startItor;
606 }
607 }
608 // Forward query for the last item with filePathId == startItor ->filePathId()
609 if (startItor != startAddrToMapsInfoMapPtr->end()) {
610 auto startFilePathId = startItor->second->file_path_id();
611 while (startAddrToMapsInfoMapPtr->begin() != startItor) {
612 --startItor;
613 if (startFilePathId != startItor->second->file_path_id()) {
614 ++startItor;
615 break;
616 }
617 }
618 start = startItor->first;
619 }
620
621 // Find first item in startAddrToMapsInfoMapPtr, that endItor->second()->start > endAddr
622 auto endItor = startAddrToMapsInfoMapPtr->upper_bound(endAddr);
623 if (endItor == startAddrToMapsInfoMapPtr->end()) {
624 return std::make_tuple(start, end);
625 }
626 if (endItor == startAddrToMapsInfoMapPtr->begin()) {
627 start = INVALID_UINT64;
628 return std::make_tuple(start, end);
629 }
630 // Backward query for the last item with filePathId == endItor ->filePathId()
631 --endItor;
632 auto endFilePathId = endItor->second->file_path_id();
633 ++endItor;
634 while (endItor != startAddrToMapsInfoMapPtr->end()) {
635 if (endFilePathId != endItor->second->file_path_id()) {
636 end = endItor->second->start();
637 break;
638 }
639 endItor++;
640 }
641 return std::make_tuple(start, end);
642 }
643
ParseArktsOfflineSymbolization(uint64_t ipid,uint64_t arktsIp)644 std::shared_ptr<FrameInfo> NativeHookFilter::ParseArktsOfflineSymbolization(uint64_t ipid, uint64_t arktsIp)
645 {
646 auto arktsFrameInfo = std::make_shared<FrameInfo>();
647 // Under offline symbolization, there is no need to symbolize js data
648 uint64_t arktsFrame = arktsIp & (~JS_IP_MASK);
649 auto arktsReaderFrameInfo = ipidToFrameIdToFrameBytes_.Find(ipid, arktsFrame);
650 if (arktsReaderFrameInfo == nullptr) {
651 TS_LOGE("Can not to find Frame_map.id for js(arkts)!!!");
652 return nullptr;
653 }
654 ProtoReader::Frame_Reader reader(*arktsReaderFrameInfo);
655 // 0 is meaningful, but it is not displayed. Other data is still needed
656 // For js, the last 5 bytes of stack.ip and the outgoing frame member IP are reserved
657 if (reader.has_ip()) {
658 arktsFrameInfo->ip_ = reader.ip();
659 }
660 if (reader.has_symbol_name_id()) {
661 arktsFrameInfo->symbolIndex_ = ipidToSymIdToSymIndex_.Find(ipid, reader.symbol_name_id());
662 }
663 if (reader.has_file_path_id()) {
664 arktsFrameInfo->filePathId_ = reader.file_path_id();
665 }
666 if (reader.has_offset()) {
667 arktsFrameInfo->offset_ = reader.offset();
668 }
669 // Unchanged data is the default value
670 return arktsFrameInfo;
671 }
672
OfflineSymbolization(const std::shared_ptr<std::vector<uint64_t>> ips)673 std::shared_ptr<std::vector<std::shared_ptr<FrameInfo>>> NativeHookFilter::OfflineSymbolization(
674 const std::shared_ptr<std::vector<uint64_t>> ips)
675 {
676 auto ipid = ips->back();
677 auto result = std::make_shared<std::vector<std::shared_ptr<FrameInfo>>>();
678 for (auto itor = ips->begin(); (itor + 1) != ips->end(); itor++) {
679 if (JS_IP_MASK == (*itor & ALLOC_IP_MASK)) {
680 auto arktsFrameInfo = ParseArktsOfflineSymbolization(ipid, *itor);
681 if (!arktsFrameInfo) {
682 break;
683 }
684 result->emplace_back(arktsFrameInfo);
685 continue;
686 }
687 auto frameInfo = OfflineSymbolizationByIp(ipid, *itor);
688 // If the IP in the middle of the call stack cannot be symbolized, the remaining IP is discarded
689 if (!frameInfo) {
690 break;
691 }
692 result->emplace_back(frameInfo);
693 }
694 return result;
695 }
FillOfflineSymbolizationFrames(std::map<uint64_t,std::shared_ptr<std::vector<uint64_t>>>::iterator mapItor)696 void NativeHookFilter::FillOfflineSymbolizationFrames(
697 std::map<uint64_t, std::shared_ptr<std::vector<uint64_t>>>::iterator mapItor)
698 {
699 auto curCacheIpid = mapItor->second->back();
700 stackIdToCallChainIdMap_.insert(std::make_pair(mapItor->first, ++callChainId_));
701 auto framesInfo = OfflineSymbolization(mapItor->second);
702 uint16_t depth = 0;
703 if (isSingleProcData_) {
704 curCacheIpid = SINGLE_PROC_IPID;
705 }
706 uint64_t filePathIndex = INVALID_UINT64;
707 for (auto itor = framesInfo->rbegin(); itor != framesInfo->rend(); itor++) {
708 // Note that the filePathId here is provided for the end side. Not a true TS internal index dictionary.
709 auto frameInfo = itor->get();
710 filePathIndex = ipidToFilePathIdToFileIndex_.Find(curCacheIpid, frameInfo->filePathId_);
711 std::string vaddr = base::Uint64ToHexText(frameInfo->symVaddr_);
712 NativeHookFrameVaddrRow nativeHookFrameVaddrRow = {callChainId_,
713 depth++,
714 frameInfo->ip_,
715 frameInfo->symbolIndex_,
716 filePathIndex,
717 frameInfo->offset_,
718 frameInfo->symbolOffset_,
719 vaddr};
720 auto row = traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame(nativeHookFrameVaddrRow);
721 UpdateFilePathIndexToCallStackRowMap(row, filePathIndex);
722 }
723 }
724
ReparseStacksWithDifferentMeans()725 void NativeHookFilter::ReparseStacksWithDifferentMeans()
726 {
727 for (auto itor = reparseStackIdToFramesMap_.begin(); itor != reparseStackIdToFramesMap_.end(); itor++) {
728 // Items with key equal to stack id should not be retained in stackIdToCallChainIdMap_
729 if (stackIdToCallChainIdMap_.count(itor->first)) {
730 TS_LOGE("error! The mapping of ambiguous call stack id and callChainId has not been deleted!");
731 }
732 FillOfflineSymbolizationFrames(itor);
733 }
734 reparseStackIdToFramesMap_.clear();
735 }
736
UpdateReparseStack(uint64_t stackId,std::shared_ptr<std::vector<uint64_t>> frames)737 void NativeHookFilter::UpdateReparseStack(uint64_t stackId, std::shared_ptr<std::vector<uint64_t>> frames)
738 {
739 // delete the stack ids whitch should be parsed again
740 if (stackIdToCallChainIdMap_.count(stackId)) {
741 stackIdToCallChainIdMap_.erase(stackId);
742 }
743 /* update reparseStackIdToFramesMap_. The reparseStackIdToFramesMap_ cannot be parsed immediately.
744 Wait until the relevant memmaps and symbolTable updates are completed. After the main event is
745 updated and before the main event is about to be parsed, parse reparseStackIdToFramesMap_ first. */
746 if (!stackIdToFramesMap_.count(stackId)) {
747 reparseStackIdToFramesMap_.emplace(std::make_pair(stackId, frames));
748 }
749 }
ReparseStacksWithAddrRange(uint64_t start,uint64_t end)750 inline void NativeHookFilter::ReparseStacksWithAddrRange(uint64_t start, uint64_t end)
751 {
752 // Get the list of call stack ids that should be parsed again
753 for (auto itor = allStackIdToFramesMap_.begin(); itor != allStackIdToFramesMap_.end(); itor++) {
754 auto ips = itor->second;
755 for (auto ipsItor = ips->begin(); ipsItor != ips->end(); ipsItor++) {
756 if (*ipsItor >= start && *ipsItor < end) {
757 UpdateReparseStack(itor->first, itor->second);
758 break;
759 }
760 }
761 }
762 }
763
764 // Only called in offline symbolization mode.
ParseMapsEvent(std::unique_ptr<NativeHookMetaData> & nativeHookMetaData)765 void NativeHookFilter::ParseMapsEvent(std::unique_ptr<NativeHookMetaData> &nativeHookMetaData)
766 {
767 segs_.emplace_back(nativeHookMetaData->seg_);
768 const ProtoReader::BytesView &mapsInfoByteView = nativeHookMetaData->reader_->maps_info();
769 if (traceDataCache_->isSplitFile_) {
770 auto hookData = commHookData_.datas->add_events();
771 MapsInfo *mapsInfo = hookData->mutable_maps_info();
772 mapsInfo->ParseFromArray(mapsInfoByteView.Data(), mapsInfoByteView.Size());
773 commHookData_.size += mapsInfoByteView.Size();
774 return;
775 }
776 auto reader = std::make_shared<ProtoReader::MapsInfo_Reader>(mapsInfoByteView);
777
778 // The temporary variable startAddr here is to solve the problem of parsing errors under the window platform
779 auto startAddr = reader->start();
780 auto endAddr = reader->end();
781 uint64_t start = INVALID_UINT64;
782 uint64_t end = INVALID_UINT64;
783 auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(reader->pid(), "");
784 if (isSingleProcData_) {
785 ipid = SINGLE_PROC_IPID;
786 }
787 // Get [start, end) of ips addr range which need to update
788 std::tie(start, end) = GetNeedUpdateProcessMapsAddrRange(ipid, startAddr, endAddr);
789 if (start != INVALID_UINT64 && start != end) { // Conflicting
790 /* First parse the updated call stacks, then parse the main events, and finally update Maps or SymbolTable
791 Note that when tsToMainEventsMap_.size() > MAX_CACHE_SIZE and main events need to be resolved, this logic
792 should also be followed. */
793 ParseFramesInOfflineSymbolizationMode();
794 // When a main event is updated, the call stack that needs to be parsed again is parsed.
795 if (tsToMainEventsMap_.size()) {
796 ReparseStacksWithDifferentMeans();
797 FilterNativeHookMainEvent(tsToMainEventsMap_.size());
798 }
799
800 // Delete IP symbolization results within the conflict range.
801 auto ipToFrameInfoPtr = const_cast<IpToFrameInfoType *>(ipidToIpToFrameInfo_.Find(ipid));
802 if (ipToFrameInfoPtr != nullptr) {
803 auto ipToFrameInfoItor = ipToFrameInfoPtr->lower_bound(start);
804 while (ipToFrameInfoItor != ipToFrameInfoPtr->end() && ipToFrameInfoItor->first < end) {
805 ipToFrameInfoItor = ipToFrameInfoPtr->erase(ipToFrameInfoItor);
806 }
807 }
808 // Delete MapsInfo within the conflict range
809 auto startAddrToMapsInfoMapPtr =
810 const_cast<StartAddrToMapsInfoType *>(ipidToStartAddrToMapsInfoMap_.Find(ipid));
811 if (startAddrToMapsInfoMapPtr != nullptr) {
812 auto itor = startAddrToMapsInfoMapPtr->lower_bound(start);
813 while (itor != startAddrToMapsInfoMapPtr->end() && itor->first < end) {
814 itor = startAddrToMapsInfoMapPtr->erase(itor);
815 }
816 }
817 ReparseStacksWithAddrRange(start, end);
818 }
819 ipidToStartAddrToMapsInfoMap_.Insert(ipid, startAddr, std::move(reader));
820 }
821 template <class T>
UpdateSymbolTablePtrAndStValueToSymAddrMap(T * firstSymbolAddr,const int size,std::shared_ptr<ProtoReader::SymbolTable_Reader> reader)822 void NativeHookFilter::UpdateSymbolTablePtrAndStValueToSymAddrMap(
823 T *firstSymbolAddr,
824 const int size,
825 std::shared_ptr<ProtoReader::SymbolTable_Reader> reader)
826 {
827 for (auto i = 0; i < size; i++) {
828 auto symAddr = firstSymbolAddr + i;
829 if ((symAddr->st_info & STT_FUNC) && symAddr->st_value) {
830 symbolTablePtrAndStValueToSymAddr_.Insert(reader, symAddr->st_value,
831 reinterpret_cast<const uint8_t *>(symAddr));
832 }
833 }
834 }
GetIpRangeByIpidAndFilePathId(uint32_t ipid,uint32_t filePathId)835 std::tuple<uint64_t, uint64_t> NativeHookFilter::GetIpRangeByIpidAndFilePathId(uint32_t ipid, uint32_t filePathId)
836 {
837 uint64_t start = INVALID_UINT32;
838 uint64_t end = 0;
839 auto startAddrToMapsInfoMapPtr = ipidToStartAddrToMapsInfoMap_.Find(ipid);
840 if (startAddrToMapsInfoMapPtr != nullptr) {
841 for (auto itor = startAddrToMapsInfoMapPtr->begin(); itor != startAddrToMapsInfoMapPtr->end(); itor++) {
842 if (itor->second->file_path_id() == filePathId) {
843 start = std::min(itor->first, start);
844 end = std::max(itor->second->end(), end);
845 } else if (start != INVALID_UINT32) {
846 break;
847 }
848 }
849 }
850 return std::make_tuple(start, end);
851 }
DeleteFrameInfoWhichNeedsReparse(uint32_t ipid,uint32_t filePathId)852 void NativeHookFilter::DeleteFrameInfoWhichNeedsReparse(uint32_t ipid, uint32_t filePathId)
853 {
854 // Delete symbolic results with the same filePathId
855 auto ipToFrameInfoPtr = const_cast<IpToFrameInfoType *>(ipidToIpToFrameInfo_.Find(ipid));
856 if (ipToFrameInfoPtr != nullptr) {
857 for (auto itor = ipToFrameInfoPtr->begin(); itor != ipToFrameInfoPtr->end();) {
858 if (itor->second->filePathId_ == filePathId) {
859 itor = ipToFrameInfoPtr->erase(itor);
860 continue;
861 }
862 itor++;
863 }
864 }
865 }
ProcSymbolTable(uint32_t ipid,uint32_t filePathId,std::shared_ptr<ProtoReader::SymbolTable_Reader> reader)866 void NativeHookFilter::ProcSymbolTable(uint32_t ipid,
867 uint32_t filePathId,
868 std::shared_ptr<ProtoReader::SymbolTable_Reader> reader)
869 {
870 auto symbolTablePtr = ipidTofilePathIdToSymbolTableMap_.Find(ipid, filePathId);
871 if (symbolTablePtr != nullptr) { // SymbolTable already exists.
872 /* First parse the updated call stacks, then parse the main events, and finally update Maps or SymbolTable
873 Note that when tsToMainEventsMap_.size() > MAX_CACHE_SIZE and main events need to be resolved, this logic
874 should also be followed. */
875 ParseFramesInOfflineSymbolizationMode();
876 // When a main event is updated, the call stack that needs to be parsed again is parsed.
877 if (tsToMainEventsMap_.size()) {
878 ReparseStacksWithDifferentMeans();
879 FilterNativeHookMainEvent(tsToMainEventsMap_.size());
880 }
881 DeleteFrameInfoWhichNeedsReparse(ipid, filePathId);
882 uint64_t start = INVALID_UINT32;
883 uint64_t end = 0;
884 std::tie(start, end) = GetIpRangeByIpidAndFilePathId(ipid, filePathId);
885 ReparseStacksWithAddrRange(start, end);
886 symbolTablePtr = reader;
887 } else {
888 ipidTofilePathIdToSymbolTableMap_.Insert(ipid, filePathId, reader);
889 }
890 }
891 // Only called in offline symbolization mode.
ParseSymbolTableEvent(std::unique_ptr<NativeHookMetaData> & nativeHookMetaData)892 void NativeHookFilter::ParseSymbolTableEvent(std::unique_ptr<NativeHookMetaData> &nativeHookMetaData)
893 {
894 segs_.emplace_back(nativeHookMetaData->seg_);
895 const ProtoReader::BytesView &symbolTableByteView = nativeHookMetaData->reader_->symbol_tab();
896 if (traceDataCache_->isSplitFile_) {
897 auto hookData = commHookData_.datas->add_events();
898 SymbolTable *symbolTable = hookData->mutable_symbol_tab();
899 symbolTable->ParseFromArray(symbolTableByteView.Data(), symbolTableByteView.Size());
900 commHookData_.size += symbolTableByteView.Size();
901 return;
902 }
903 auto reader = std::make_shared<ProtoReader::SymbolTable_Reader>(symbolTableByteView);
904 auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(reader->pid(), "");
905 if (isSingleProcData_) {
906 ipid = SINGLE_PROC_IPID;
907 }
908 ProcSymbolTable(ipid, reader->file_path_id(), reader);
909 auto symEntrySize = reader->sym_entry_size();
910 auto symTable = reader->sym_table();
911 if (symEntrySize == 0) {
912 return;
913 }
914 auto size = symTable.Size() / symEntrySize;
915 if (symEntrySize == ELF32_SYM) {
916 UpdateSymbolTablePtrAndStValueToSymAddrMap(reinterpret_cast<const Elf32_Sym *>(symTable.Data()), size, reader);
917 } else {
918 UpdateSymbolTablePtrAndStValueToSymAddrMap(reinterpret_cast<const Elf64_Sym *>(symTable.Data()), size, reader);
919 }
920 }
921
MaybeUpdateCurrentSizeDur(uint64_t row,uint64_t timeStamp,bool isMalloc)922 void NativeHookFilter::MaybeUpdateCurrentSizeDur(uint64_t row, uint64_t timeStamp, bool isMalloc)
923 {
924 auto &lastAnyEventRaw = isMalloc ? traceDataCache_->GetNativeHookData()->GetLastMallocEventRaw()
925 : traceDataCache_->GetNativeHookData()->GetLastMmapEventRaw();
926 if (lastAnyEventRaw != INVALID_UINT64) {
927 traceDataCache_->GetNativeHookData()->UpdateCurrentSizeDur(lastAnyEventRaw, timeStamp);
928 }
929 lastAnyEventRaw = row;
930 }
931
932 // when symbolization failed, use filePath + vaddr as symbol name
UpdateSymbolIdsForSymbolizationFailed()933 void NativeHookFilter::UpdateSymbolIdsForSymbolizationFailed()
934 {
935 auto size = traceDataCache_->GetNativeHookFrameData()->Size();
936 for (size_t i = 0; i < size; ++i) {
937 auto symbolNameIndex = traceDataCache_->GetNativeHookFrameData()->SymbolNames()[i];
938 if (symbolNameIndex != INVALID_UINT64) {
939 continue;
940 }
941 auto filePathIndex = traceDataCache_->GetNativeHookFrameData()->FilePaths()[i];
942 if (filePathIndex != INVALID_UINT64) {
943 auto filePathStr = traceDataCache_->dataDict_.GetDataFromDict(filePathIndex);
944 auto vaddrStr = traceDataCache_->GetNativeHookFrameData()->Vaddrs()[i];
945 traceDataCache_->GetNativeHookFrameData()->UpdateSymbolId(
946 i, traceDataCache_->dataDict_.GetStringIndex(filePathStr + "+" + vaddrStr));
947 } else {
948 // when symbolization failed,filePath and symbolNameIndex invalid
949 auto ip = traceDataCache_->GetNativeHookFrameData()->Ips()[i];
950 // Distinguish whether it is the last layer call stack using the first 3 bytes
951 if (ALLOC_IP_MASK == (ip & ALLOC_IP_MASK)) {
952 // Take the last five bytes from the IP address
953 uint64_t ipBitOperation = ip & IP_BIT_OPERATION;
954 std::ostringstream newSymbol;
955 // alloc size (IP(Decimal))bytes 0xIP(hexadecimal conversion)
956 newSymbol << "alloc size(" << base::number(ipBitOperation, base::INTEGER_RADIX_TYPE_DEC) << "bytes)"
957 << "0x" << base::number(ip, base::INTEGER_RADIX_TYPE_HEX);
958 traceDataCache_->GetNativeHookFrameData()->UpdateSymbolId(
959 i, traceDataCache_->dataDict_.GetStringIndex(newSymbol.str()));
960 } else {
961 // If the current callChainId is same,unknow 0x ip(Convert IP to hexadecimal)
962 traceDataCache_->GetNativeHookFrameData()->UpdateSymbolId(
963 i, traceDataCache_->dataDict_.GetStringIndex("unknown 0x" +
964 base::number(ip, base::INTEGER_RADIX_TYPE_HEX)));
965 }
966 }
967 }
968 }
ParseFramesInOfflineSymbolizationMode()969 void NativeHookFilter::ParseFramesInOfflineSymbolizationMode()
970 {
971 for (auto stackIdToFramesItor = stackIdToFramesMap_.begin(); stackIdToFramesItor != stackIdToFramesMap_.end();
972 stackIdToFramesItor++) {
973 FillOfflineSymbolizationFrames(stackIdToFramesItor);
974 }
975 // In offline symbolization scenarios, The updated call stack information is saved in stackIdToFramesMap_.
976 // After each parsing is completed, it needs to be cleared to avoid repeated parsing.
977 stackIdToFramesMap_.clear();
978 }
979
GetNativeHookFrameVaddrs()980 void NativeHookFilter::GetNativeHookFrameVaddrs()
981 {
982 vaddrs_.clear();
983 auto size = traceDataCache_->GetNativeHookFrameData()->Size();
984 // Traverse every piece of native_hook frame data
985 for (size_t i = 0; i < size; i++) {
986 auto symbolOffset = traceDataCache_->GetNativeHookFrameData()->SymbolOffsets()[i];
987 auto fileOffset = traceDataCache_->GetNativeHookFrameData()->Offsets()[i];
988 // When the symbol offset not is INVALID_UINT64, vaddr=offset+symbol offset
989 if (symbolOffset != INVALID_UINT64 && fileOffset != INVALID_UINT64) {
990 auto vaddr = base::Uint64ToHexText(fileOffset + symbolOffset);
991 vaddrs_.emplace_back(vaddr);
992 continue;
993 }
994 // When the symbol offset is 0, vaddr takes the string after the plus sign in the function name
995 auto functionNameIndex = traceDataCache_->GetNativeHookFrameData()->SymbolNames()[i];
996 std::string vaddr = "";
997 auto itor = functionNameIndexToVaddr_.find(functionNameIndex);
998 if (itor == functionNameIndexToVaddr_.end()) {
999 auto functionName = traceDataCache_->dataDict_.GetDataFromDict(functionNameIndex);
1000 auto pos = functionName.rfind("+");
1001 if (pos != functionName.npos && pos != functionName.length() - 1) {
1002 vaddr = functionName.substr(++pos);
1003 }
1004 // Vaddr keeps "" when lookup failed
1005 functionNameIndexToVaddr_.emplace(std::make_pair(functionNameIndex, vaddr));
1006 } else {
1007 vaddr = itor->second;
1008 }
1009 vaddrs_.emplace_back(vaddr);
1010 }
1011 }
1012 // Called When isCallStackCompressedMode_ is true && isOfflineSymbolizationMode_ is false.
ParseFramesInCallStackCompressedMode()1013 void NativeHookFilter::ParseFramesInCallStackCompressedMode()
1014 {
1015 for (auto stackIdToFramesItor = stackIdToFramesMap_.begin(); stackIdToFramesItor != stackIdToFramesMap_.end();
1016 stackIdToFramesItor++) {
1017 auto frameIds = stackIdToFramesItor->second;
1018 uint16_t depth = 0;
1019 auto curCacheIpid = frameIds->back();
1020 if (isSingleProcData_) {
1021 curCacheIpid = SINGLE_PROC_IPID;
1022 }
1023 for (auto frameIdsItor = frameIds->crbegin() + 1; frameIdsItor != frameIds->crend(); frameIdsItor++) {
1024 auto frameBytesPtr = ipidToFrameIdToFrameBytes_.Find(curCacheIpid, *frameIdsItor);
1025 if (frameBytesPtr == nullptr) {
1026 TS_LOGE("Can not find Frame by frame_map_id!!!");
1027 continue;
1028 }
1029 ProtoReader::Frame_Reader reader(*frameBytesPtr);
1030 if (!reader.has_file_path_id() or !reader.has_symbol_name_id()) {
1031 TS_LOGE("Data exception, frames should has fil_path_id and symbol_name_id");
1032 continue;
1033 }
1034 auto filePathIndex = ipidToFilePathIdToFileIndex_.Find(curCacheIpid, reader.file_path_id());
1035 if (filePathIndex == INVALID_UINT64) {
1036 TS_LOGE("Data exception, can not find fil_path_id(%u)!!!", reader.file_path_id());
1037 continue;
1038 }
1039 auto symbolIndex = ipidToSymIdToSymIndex_.Find(curCacheIpid, reader.symbol_name_id());
1040 if (symbolIndex == INVALID_UINT64) {
1041 TS_LOGE("Data exception, can not find symbol_name_id!!!");
1042 continue;
1043 }
1044 // IP may not exist
1045 // 0 is meaningful, but it is not displayed. Other data is still needed
1046 auto frameIp = reader.has_ip() ? reader.ip() : INVALID_UINT64;
1047 auto frameOffset = reader.has_offset() ? reader.offset() : INVALID_UINT64;
1048 auto frameSymbolOffset = reader.has_symbol_offset() ? reader.symbol_offset() : INVALID_UINT64;
1049 NativeHookFrameRow nativeHookFrameRow = {static_cast<uint32_t>(stackIdToFramesItor->first),
1050 depth++,
1051 frameIp,
1052 symbolIndex,
1053 filePathIndex,
1054 frameOffset,
1055 frameSymbolOffset};
1056 auto row = traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame(nativeHookFrameRow);
1057 UpdateFilePathIndexToCallStackRowMap(row, filePathIndex);
1058 }
1059 }
1060 }
1061 // Called When isCallStackCompressedMode_ is false
ParseFramesWithOutCallStackCompressedMode()1062 void NativeHookFilter::ParseFramesWithOutCallStackCompressedMode()
1063 {
1064 for (auto itor = callChainIdToStackHashValueMap_.begin(); itor != callChainIdToStackHashValueMap_.end(); itor++) {
1065 auto callChainId = itor->first;
1066 if (!stackHashValueToFramesHashMap_.count(itor->second)) {
1067 continue;
1068 }
1069 auto &framesHash = stackHashValueToFramesHashMap_.at(itor->second);
1070 uint16_t depth = 0;
1071 for (auto frameHashValueVectorItor = framesHash.crbegin(); frameHashValueVectorItor != framesHash.crend();
1072 frameHashValueVectorItor++) {
1073 if (!frameHashToFrameInfoMap_.count(*frameHashValueVectorItor)) {
1074 TS_LOGE("find matching frameInfo failed!!!!");
1075 return;
1076 }
1077 auto &frameInfo = frameHashToFrameInfoMap_.at(*frameHashValueVectorItor);
1078 NativeHookFrameRow nativeHookFrameRow = {callChainId,
1079 depth++,
1080 frameInfo->ip_,
1081 frameInfo->symbolIndex_,
1082 frameInfo->filePathIndex_,
1083 frameInfo->offset_,
1084 frameInfo->symbolOffset_};
1085 auto row = traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame(nativeHookFrameRow);
1086 UpdateFilePathIndexToCallStackRowMap(row, frameInfo->filePathIndex_);
1087 }
1088 }
1089 }
ParseSymbolizedNativeHookFrame()1090 void NativeHookFilter::ParseSymbolizedNativeHookFrame()
1091 {
1092 // isOfflineSymbolizationMode is false, but isCallStackCompressedMode is true.
1093 if (isCallStackCompressedMode_) {
1094 ParseFramesInCallStackCompressedMode();
1095 } else {
1096 ParseFramesWithOutCallStackCompressedMode();
1097 }
1098 GetNativeHookFrameVaddrs();
1099 traceDataCache_->GetNativeHookFrameData()->UpdateVaddrs(vaddrs_);
1100 return;
1101 }
UpdateThreadNameWithNativeHookData() const1102 void NativeHookFilter::UpdateThreadNameWithNativeHookData() const
1103 {
1104 if (itidToThreadNameId_.empty() || threadNameIdToThreadNameIndex_.empty()) {
1105 return;
1106 }
1107 for (auto itor = itidToThreadNameId_.begin(); itor != itidToThreadNameId_.end(); ++itor) {
1108 auto thread = traceDataCache_->GetThreadData(itor->first);
1109 if (!thread->nameIndex_) {
1110 auto threadNameMapItor = threadNameIdToThreadNameIndex_.find(itor->second);
1111 if (threadNameMapItor != threadNameIdToThreadNameIndex_.end()) {
1112 thread->nameIndex_ = threadNameMapItor->second;
1113 }
1114 }
1115 }
1116 }
FinishParseNativeHookData()1117 void NativeHookFilter::FinishParseNativeHookData()
1118 {
1119 // In offline symbolization mode Parse all NativeHook main events depends on updated stackIdToCallChainIdMap_
1120 // during execute ParseSymbolizedNativeHookFrame or ReparseStacksWithDifferentMeans , So first parse the call
1121 // stack data and then parse the main event.
1122 if (isOfflineSymbolizationMode_) {
1123 ParseFramesInOfflineSymbolizationMode();
1124 ReparseStacksWithDifferentMeans();
1125 UpdateSymbolIdsForSymbolizationFailed();
1126 }
1127 FilterNativeHookMainEvent(tsToMainEventsMap_.size());
1128 // In online symbolization mode and callstack is not compressed mode parse stack should after parse main event
1129 // In online symbolization mode and callstack is compressed mode, there is no need worry about the order
1130 if (!isOfflineSymbolizationMode_) {
1131 ParseSymbolizedNativeHookFrame();
1132 }
1133
1134 // update last lib id
1135 UpdateLastCallerPathAndSymbolIndexs();
1136 UpdateThreadNameWithNativeHookData();
1137 }
UpdateLastCallerPathAndSymbolIndexs()1138 void NativeHookFilter::UpdateLastCallerPathAndSymbolIndexs()
1139 {
1140 GetCallIdToLastLibId();
1141 if (isStatisticMode_) {
1142 traceDataCache_->GetNativeHookStatisticsData()->UpdateLastCallerPathAndSymbolIndexs(
1143 callIdToLastCallerPathIndex_);
1144 } else {
1145 traceDataCache_->GetNativeHookData()->UpdateLastCallerPathAndSymbolIndexs(callIdToLastCallerPathIndex_);
1146 }
1147 }
GetCallIdToLastLibId()1148 void NativeHookFilter::GetCallIdToLastLibId()
1149 {
1150 callIdToLastCallerPathIndex_.clear();
1151 auto size = static_cast<int64_t>(traceDataCache_->GetNativeHookFrameData()->Size());
1152 uint32_t lastCallChainId = INVALID_UINT32;
1153 bool foundLast = false;
1154 for (auto i = size - 1; i > -1; i--) {
1155 auto callChainId = traceDataCache_->GetNativeHookFrameData()->CallChainIds()[i];
1156 if (callChainId == lastCallChainId) {
1157 if (foundLast) {
1158 continue;
1159 }
1160 }
1161 if (callChainId != lastCallChainId) {
1162 lastCallChainId = callChainId;
1163 foundLast = false;
1164 }
1165 auto filePathIndex = traceDataCache_->GetNativeHookFrameData()->FilePaths()[i];
1166 if (filePathIndex == INVALID_UINT64) {
1167 continue;
1168 }
1169 auto symbolIndex = traceDataCache_->GetNativeHookFrameData()->SymbolNames()[i];
1170 if (!traceDataCache_->GetNativeHookFrameData()->Depths()[i]) {
1171 callIdToLastCallerPathIndex_.insert({callChainId, std::make_tuple(filePathIndex, symbolIndex)});
1172 foundLast = true;
1173 continue;
1174 }
1175
1176 auto lower = std::lower_bound(invalidLibPathIndexs_.begin(), invalidLibPathIndexs_.end(), filePathIndex);
1177 if (lower == invalidLibPathIndexs_.end() || *lower != filePathIndex) { // found
1178 auto filePath = traceDataCache_->dataDict_.GetDataFromDict(filePathIndex);
1179 auto ret = filePath.find("libc++_shared.so");
1180 if (ret == filePath.npos) {
1181 callIdToLastCallerPathIndex_.insert({callChainId, std::make_tuple(filePathIndex, symbolIndex)});
1182 foundLast = true;
1183 }
1184 }
1185 }
1186 }
1187
1188 template <class T>
UpdateFilePathIdAndStValueToSymAddrMap(T * firstSymbolAddr,const int size,uint32_t filePathId)1189 void NativeHookFilter::UpdateFilePathIdAndStValueToSymAddrMap(T *firstSymbolAddr, const int size, uint32_t filePathId)
1190 {
1191 for (auto i = 0; i < size; i++) {
1192 auto symAddr = firstSymbolAddr + i;
1193 if ((symAddr->st_info & STT_FUNC) && (symAddr->st_value)) {
1194 filePathIdAndStValueToSymAddr_.Insert(filePathId, symAddr->st_value,
1195 reinterpret_cast<const uint8_t *>(symAddr));
1196 }
1197 }
1198 }
1199
NativeHookReloadElfSymbolTable(const std::vector<std::unique_ptr<SymbolsFile>> & symbolsFiles)1200 void NativeHookFilter::NativeHookReloadElfSymbolTable(const std::vector<std::unique_ptr<SymbolsFile>> &symbolsFiles)
1201 {
1202 auto nativeHookFrame = traceDataCache_->GetNativeHookFrameData();
1203 auto size = nativeHookFrame->Size();
1204 auto filePathIndexs = nativeHookFrame->FilePaths();
1205 auto vaddrs = nativeHookFrame->Vaddrs();
1206 for (const auto &symbolsFile : symbolsFiles) {
1207 std::shared_ptr<std::set<size_t>> frameRows = nullptr;
1208 for (const auto &item : filePathIndexToFrameTableRowMap_) {
1209 auto filePath = traceDataCache_->GetDataFromDict(item.first);
1210 if (base::EndWith(filePath, symbolsFile->filePath_)) {
1211 frameRows = item.second;
1212 break;
1213 }
1214 }
1215 if (frameRows == nullptr) {
1216 continue;
1217 }
1218 for (auto row : *frameRows) {
1219 auto symVaddr = base::StrToInt<uint32_t>(vaddrs[row], base::INTEGER_RADIX_TYPE_HEX);
1220 if (!symVaddr.has_value()) {
1221 continue;
1222 }
1223 auto dfxSymbol = symbolsFile->GetSymbolWithVaddr(symVaddr.value());
1224 if (dfxSymbol.IsValid()) {
1225 auto newSymbolIndex = traceDataCache_->GetDataIndex(dfxSymbol.GetName());
1226 nativeHookFrame->UpdateSymbolId(row, newSymbolIndex);
1227 }
1228 }
1229 }
1230 UpdateLastCallerPathAndSymbolIndexs();
1231 }
UpdateFilePathIndexToCallStackRowMap(size_t row,DataIndex filePathIndex)1232 void NativeHookFilter::UpdateFilePathIndexToCallStackRowMap(size_t row, DataIndex filePathIndex)
1233 {
1234 if (filePathIndex != INVALID_UINT64) {
1235 if (filePathIndexToFrameTableRowMap_.count(filePathIndex) == 0) {
1236 auto rows = std::make_shared<std::set<size_t>>();
1237 rows->insert(row);
1238 filePathIndexToFrameTableRowMap_[filePathIndex] = rows;
1239 } else {
1240 filePathIndexToFrameTableRowMap_[filePathIndex]->insert(row);
1241 }
1242 }
1243 }
GetCommHookData()1244 CommHookData &NativeHookFilter::GetCommHookData()
1245 {
1246 return commHookData_;
1247 }
GetHookPluginData()1248 ProfilerPluginData *NativeHookFilter::GetHookPluginData()
1249 {
1250 return hookPluginData_.get();
1251 }
SerializeHookCommDataToString()1252 void NativeHookFilter::SerializeHookCommDataToString()
1253 {
1254 if (commHookData_.size == 0) {
1255 return;
1256 }
1257 std::string hookBuffer;
1258 commHookData_.datas->SerializeToString(&hookBuffer);
1259 hookPluginData_->set_data(hookBuffer);
1260 std::unique_ptr<std::string> pluginBuffer = std::make_unique<std::string>();
1261 hookPluginData_->SerializeToString(pluginBuffer.get());
1262 traceDataCache_->HookCommProtos().push_back(std::move(pluginBuffer));
1263 hookPluginData_->Clear();
1264 commHookData_.datas->Clear();
1265 commHookData_.size = 0;
1266 hookPluginData_->set_name("nativehook");
1267 }
1268 } // namespace TraceStreamer
1269 } // namespace SysTuning
1270