1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "pbreader_native_hook_parser.h"
16 #include "clock_filter_ex.h"
17 #include "process_filter.h"
18 #include "stat_filter.h"
19 namespace SysTuning {
20 namespace TraceStreamer {
21 constexpr static uint32_t MAX_PROTO_BUFFER_SIZE = 4 * 1024 * 1024;
22
PbreaderNativeHookParser(TraceDataCache * dataCache,const TraceStreamerFilters * ctx)23 PbreaderNativeHookParser::PbreaderNativeHookParser(TraceDataCache *dataCache, const TraceStreamerFilters *ctx)
24 : EventParserBase(dataCache, ctx), nativeHookFilter_(std::make_unique<NativeHookFilter>(dataCache, ctx))
25 {
26 }
27
~PbreaderNativeHookParser()28 PbreaderNativeHookParser::~PbreaderNativeHookParser()
29 {
30 TS_LOGI("native hook data ts MIN:%llu, MAX:%llu", static_cast<unsigned long long>(GetPluginStartTime()),
31 static_cast<unsigned long long>(GetPluginEndTime()));
32 TS_LOGI("native real ts MIN:%llu, MAX:%llu", static_cast<unsigned long long>(MinTs()),
33 static_cast<unsigned long long>(MaxTs()));
34 }
35
ParseStackMap(const ProtoReader::BytesView & bytesView)36 bool PbreaderNativeHookParser::ParseStackMap(const ProtoReader::BytesView &bytesView)
37 {
38 if (traceDataCache_->isSplitFile_) {
39 auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
40 StackMap *stackMap = hookData->mutable_stack_map();
41 stackMap->ParseFromArray(bytesView.Data(), bytesView.Size());
42 nativeHookFilter_->GetCommHookData().size += bytesView.Size();
43 return false;
44 }
45 ProtoReader::StackMap_Reader stackMapReader(bytesView);
46 bool parseError = false;
47 auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(stackMapReader.pid(), "");
48 // stores frames info. if offlineSymbolization is true, storing ips data, else storing FrameMap id.
49 std::vector<uint64_t> frames;
50 if (stackMapReader.has_frame_map_id()) {
51 auto itor = stackMapReader.frame_map_id(&parseError);
52 TS_CHECK_TRUE(!parseError, false, "Parse packed varInt in ParseStackMap function failed!!!");
53 while (itor) {
54 frames.emplace_back(*itor);
55 itor++;
56 }
57 } else if (stackMapReader.has_ip()) {
58 auto itor = stackMapReader.ip(&parseError);
59 TS_CHECK_TRUE(!parseError, false, "Parse packed varInt in ParseStackMap function failed!!!");
60 // OfflineSymbolization use ipidToStartAddrToMapsInfoMap_ Multi-process differentiation
61 while (itor) {
62 frames.emplace_back(*itor);
63 itor++;
64 }
65 }
66 nativeHookFilter_->AppendStackMaps(ipid, stackMapReader.id(), frames);
67 return true;
68 }
69
ParseFrameMap(std::unique_ptr<NativeHookMetaData> & nativeHookMetaData)70 void PbreaderNativeHookParser::ParseFrameMap(std::unique_ptr<NativeHookMetaData> &nativeHookMetaData)
71 {
72 segs_.emplace_back(nativeHookMetaData->seg_);
73 const ProtoReader::BytesView &frameMapByteView = nativeHookMetaData->reader_->frame_map();
74 if (traceDataCache_->isSplitFile_) {
75 auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
76 FrameMap *frameMap = hookData->mutable_frame_map();
77 frameMap->ParseFromArray(frameMapByteView.Data(), frameMapByteView.Size());
78 nativeHookFilter_->GetCommHookData().size += frameMapByteView.Size();
79 return;
80 }
81 ProtoReader::FrameMap_Reader frameMapReader(frameMapByteView);
82 auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(frameMapReader.pid(), "");
83 // when callstack is compressed, Frame message only has ip data area.
84 nativeHookFilter_->AppendFrameMaps(ipid, frameMapReader.id(), frameMapReader.frame());
85 }
ParseFileEvent(const ProtoReader::BytesView & bytesView)86 void PbreaderNativeHookParser::ParseFileEvent(const ProtoReader::BytesView &bytesView)
87 {
88 if (traceDataCache_->isSplitFile_) {
89 auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
90 FilePathMap *filePathMap = hookData->mutable_file_path();
91 filePathMap->ParseFromArray(bytesView.Data(), bytesView.Size());
92 nativeHookFilter_->GetCommHookData().size += bytesView.Size();
93 return;
94 }
95 ProtoReader::FilePathMap_Reader filePathMapReader(bytesView);
96 auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(filePathMapReader.pid(), "");
97 auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(filePathMapReader.name().ToStdString());
98 nativeHookFilter_->AppendFilePathMaps(ipid, filePathMapReader.id(), nameIndex);
99 }
ParseSymbolEvent(const ProtoReader::BytesView & bytesView)100 void PbreaderNativeHookParser::ParseSymbolEvent(const ProtoReader::BytesView &bytesView)
101 {
102 if (traceDataCache_->isSplitFile_) {
103 auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
104 SymbolMap *symbolMap = hookData->mutable_symbol_name();
105 symbolMap->ParseFromArray(bytesView.Data(), bytesView.Size());
106 nativeHookFilter_->GetCommHookData().size += bytesView.Size();
107 return;
108 }
109 ProtoReader::SymbolMap_Reader symbolMapReader(bytesView);
110 auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(symbolMapReader.pid(), "");
111 auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(symbolMapReader.name().ToStdString());
112 nativeHookFilter_->AppendSymbolMap(ipid, symbolMapReader.id(), nameIndex);
113 }
ParseThreadEvent(const ProtoReader::BytesView & bytesView)114 void PbreaderNativeHookParser::ParseThreadEvent(const ProtoReader::BytesView &bytesView)
115 {
116 if (traceDataCache_->isSplitFile_) {
117 auto hookData = nativeHookFilter_->GetCommHookData().datas->add_events();
118 ThreadNameMap *threadNameMap = hookData->mutable_thread_name_map();
119 threadNameMap->ParseFromArray(bytesView.Data(), bytesView.Size());
120 nativeHookFilter_->GetCommHookData().size += bytesView.Size();
121 return;
122 }
123 ProtoReader::ThreadNameMap_Reader threadNameMapReader(bytesView);
124 auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(threadNameMapReader.pid(), "");
125 auto nameIndex = traceDataCache_->GetDataIndex(threadNameMapReader.name().ToStdString());
126 nativeHookFilter_->AppendThreadNameMap(ipid, threadNameMapReader.id(), nameIndex);
127 }
128
ParseNativeHookAuxiliaryEvent(std::unique_ptr<NativeHookMetaData> & nativeHookMetaData)129 void PbreaderNativeHookParser::ParseNativeHookAuxiliaryEvent(std::unique_ptr<NativeHookMetaData> &nativeHookMetaData)
130 {
131 auto &reader = nativeHookMetaData->reader_;
132 if (reader->has_stack_map()) {
133 ParseStackMap(reader->stack_map());
134 } else if (reader->has_frame_map()) {
135 ParseFrameMap(nativeHookMetaData);
136 } else if (reader->has_file_path()) {
137 ParseFileEvent(reader->file_path());
138 } else if (reader->has_symbol_name()) {
139 ParseSymbolEvent(reader->symbol_name());
140 } else if (reader->has_thread_name_map()) {
141 ParseThreadEvent(reader->thread_name_map());
142 } else if (reader->has_maps_info()) {
143 nativeHookFilter_->ParseMapsEvent(nativeHookMetaData);
144 } else if (reader->has_symbol_tab()) {
145 nativeHookFilter_->ParseSymbolTableEvent(nativeHookMetaData);
146 } else if (reader->has_tag_event()) {
147 nativeHookFilter_->ParseTagEvent(reader->tag_event());
148 } else {
149 TS_LOGE("unsupported native_hook data!");
150 }
151 }
SplitHookData(std::unique_ptr<NativeHookMetaData> & nativeHookMetaData,bool & haveSplitSeg)152 void PbreaderNativeHookParser::SplitHookData(std::unique_ptr<NativeHookMetaData> &nativeHookMetaData,
153 bool &haveSplitSeg)
154 {
155 if (isCommData_ && hookBootTime_ <= traceDataCache_->SplitFileMinTime()) {
156 ParseNativeHookAuxiliaryEvent(nativeHookMetaData);
157 } else if (hookBootTime_ >= traceDataCache_->SplitFileMinTime() &&
158 hookBootTime_ <= traceDataCache_->SplitFileMaxTime()) {
159 haveSplitSeg = true;
160 }
161 }
162 // In order to improve the accuracy of data, it is necessary to sort the original data.
163 // Data sorting will be reduced by 5% to 10% Speed of parsing data.
Parse(PbreaderDataSegment & dataSeg,bool & haveSplitSeg)164 void PbreaderNativeHookParser::Parse(PbreaderDataSegment &dataSeg, bool &haveSplitSeg)
165 {
166 auto batchNativeHookDataReader = ProtoReader::BatchNativeHookData_Reader(dataSeg.protoData);
167 for (auto itor = batchNativeHookDataReader.events(); itor; itor++) {
168 auto nativeHookDataReader = std::make_unique<ProtoReader::NativeHookData_Reader>(itor->ToBytes());
169 auto nativeHookMetaData = std::make_unique<NativeHookMetaData>(dataSeg.seg, std::move(nativeHookDataReader));
170 isCommData_ =
171 !(nativeHookMetaData->reader_->has_alloc_event() || nativeHookMetaData->reader_->has_free_event() ||
172 nativeHookMetaData->reader_->has_mmap_event() || nativeHookMetaData->reader_->has_munmap_event() ||
173 nativeHookMetaData->reader_->has_statistics_event());
174 hookBootTime_ = 0;
175 if (!isCommData_ && (nativeHookMetaData->reader_->has_tv_sec() || nativeHookMetaData->reader_->has_tv_nsec())) {
176 auto timeStamp = nativeHookMetaData->reader_->tv_nsec() + nativeHookMetaData->reader_->tv_sec() * SEC_TO_NS;
177 hookBootTime_ = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, timeStamp);
178 auto timeRange = hookBootTime_ > statisticsInterval_ ? hookBootTime_ - statisticsInterval_ : 0;
179 UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp - statisticsInterval_, timeRange);
180 UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp, hookBootTime_);
181 }
182 if (haveSplitSeg) {
183 return;
184 } else if (traceDataCache_->isSplitFile_) {
185 SplitHookData(nativeHookMetaData, haveSplitSeg);
186 continue;
187 }
188 if (!isCommData_ || nativeHookMetaData->reader_->has_tag_event()) {
189 nativeHookFilter_->MaybeParseNativeHookMainEvent(hookBootTime_, std::move(nativeHookMetaData));
190 } else {
191 ParseNativeHookAuxiliaryEvent(nativeHookMetaData);
192 }
193 }
194 if (!traceDataCache_->isSplitFile_ || nativeHookFilter_->GetCommHookData().size < MAX_PROTO_BUFFER_SIZE) {
195 return;
196 }
197 nativeHookFilter_->SerializeHookCommDataToString();
198 }
ParseConfigInfo(PbreaderDataSegment & dataSeg)199 void PbreaderNativeHookParser::ParseConfigInfo(PbreaderDataSegment &dataSeg)
200 {
201 nativeHookFilter_->ParseConfigInfo(dataSeg.protoData, statisticsInterval_);
202 }
FinishSplitNativeHook()203 void PbreaderNativeHookParser::FinishSplitNativeHook()
204 {
205 nativeHookFilter_->SerializeHookCommDataToString();
206 }
FinishParseNativeHookData()207 void PbreaderNativeHookParser::FinishParseNativeHookData()
208 {
209 nativeHookFilter_->FinishParseNativeHookData();
210 }
Finish()211 void PbreaderNativeHookParser::Finish()
212 {
213 if (GetPluginStartTime() != GetPluginEndTime()) {
214 traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime());
215 } else {
216 traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginStartTime() + 1);
217 }
218 }
219 } // namespace TraceStreamer
220 } // namespace SysTuning
221