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