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 #include "htrace_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
HtraceNativeHookParser(TraceDataCache * dataCache,const TraceStreamerFilters * ctx)23 HtraceNativeHookParser::HtraceNativeHookParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx)
24 : EventParserBase(dataCache, ctx), nativeHookFilter_(std::make_unique<NativeHookFilter>(dataCache, ctx))
25 {
26 }
27
~HtraceNativeHookParser()28 HtraceNativeHookParser::~HtraceNativeHookParser()
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 HtraceNativeHookParser::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 HtraceNativeHookParser::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 HtraceNativeHookParser::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 HtraceNativeHookParser::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 HtraceNativeHookParser::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 HtraceNativeHookParser::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 HtraceNativeHookParser::SplitHookData(std::unique_ptr<NativeHookMetaData>& nativeHookMetaData, bool& haveSplitSeg)
153 {
154 if (isCommData_ && hookBootTime_ <= traceDataCache_->SplitFileMinTime()) {
155 ParseNativeHookAuxiliaryEvent(nativeHookMetaData);
156 } else if (hookBootTime_ >= traceDataCache_->SplitFileMinTime() &&
157 hookBootTime_ <= traceDataCache_->SplitFileMaxTime()) {
158 haveSplitSeg = true;
159 }
160 }
161 // In order to improve the accuracy of data, it is necessary to sort the original data.
162 // Data sorting will be reduced by 5% to 10% Speed of parsing data.
Parse(HtraceDataSegment & dataSeg,bool & haveSplitSeg)163 void HtraceNativeHookParser::Parse(HtraceDataSegment& dataSeg, bool& haveSplitSeg)
164 {
165 auto batchNativeHookDataReader = ProtoReader::BatchNativeHookData_Reader(dataSeg.protoData);
166 for (auto itor = batchNativeHookDataReader.events(); itor; itor++) {
167 auto nativeHookDataReader = std::make_unique<ProtoReader::NativeHookData_Reader>(itor->ToBytes());
168 auto nativeHookMetaData = std::make_unique<NativeHookMetaData>(dataSeg.seg, std::move(nativeHookDataReader));
169 isCommData_ =
170 !(nativeHookMetaData->reader_->has_alloc_event() || nativeHookMetaData->reader_->has_free_event() ||
171 nativeHookMetaData->reader_->has_mmap_event() || nativeHookMetaData->reader_->has_munmap_event() ||
172 nativeHookMetaData->reader_->has_statistics_event());
173 hookBootTime_ = 0;
174 if (nativeHookMetaData->reader_->has_tv_sec() || nativeHookMetaData->reader_->has_tv_nsec()) {
175 auto timeStamp = nativeHookMetaData->reader_->tv_nsec() + nativeHookMetaData->reader_->tv_sec() * SEC_TO_NS;
176 hookBootTime_ = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, timeStamp);
177 UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp, hookBootTime_);
178 }
179 if (haveSplitSeg) {
180 return;
181 } else if (traceDataCache_->isSplitFile_) {
182 SplitHookData(nativeHookMetaData, haveSplitSeg);
183 continue;
184 }
185 if (!isCommData_ || nativeHookMetaData->reader_->has_tag_event()) {
186 nativeHookFilter_->MaybeParseNativeHookMainEvent(hookBootTime_, std::move(nativeHookMetaData));
187 } else {
188 ParseNativeHookAuxiliaryEvent(nativeHookMetaData);
189 }
190 }
191 if (!traceDataCache_->isSplitFile_ || nativeHookFilter_->GetCommHookData().size < MAX_PROTO_BUFFER_SIZE) {
192 return;
193 }
194 nativeHookFilter_->SerializeHookCommDataToString();
195 }
ParseConfigInfo(HtraceDataSegment & dataSeg)196 void HtraceNativeHookParser::ParseConfigInfo(HtraceDataSegment& dataSeg)
197 {
198 nativeHookFilter_->ParseConfigInfo(dataSeg.protoData);
199 }
FinishSplitNativeHook()200 void HtraceNativeHookParser::FinishSplitNativeHook()
201 {
202 nativeHookFilter_->SerializeHookCommDataToString();
203 }
FinishParseNativeHookData()204 void HtraceNativeHookParser::FinishParseNativeHookData()
205 {
206 nativeHookFilter_->FinishParseNativeHookData();
207 }
Finish()208 void HtraceNativeHookParser::Finish()
209 {
210 if (GetPluginStartTime() != GetPluginEndTime()) {
211 traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime());
212 } else {
213 traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginStartTime() + 1);
214 }
215 }
216 } // namespace TraceStreamer
217 } // namespace SysTuning
218