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