• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stdint.h>
6 #include <sys/capability.h>
7 #include <sys/mount.h>
8 #include <sys/sysmacros.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 
12 #include <algorithm>
13 #include <map>
14 #include <set>
15 #include <string>
16 #include <vector>
17 
18 #include "base/logging.h"
19 
20 #include "compat/string.h"
21 #include "compat/test.h"
22 #include "compat/thread.h"
23 #include "dso_test_utils.h"
24 #include "perf_data_utils.h"
25 #include "perf_parser.h"
26 #include "perf_reader.h"
27 #include "perf_serializer.h"
28 #include "perf_test_files.h"
29 #include "scoped_temp_path.h"
30 #include "test_perf_data.h"
31 #include "test_utils.h"
32 
33 namespace quipper {
34 
35 using SampleEvent = PerfDataProto_SampleEvent;
36 using SampleInfo = PerfDataProto_SampleInfo;
37 using PerfEvent = PerfDataProto_PerfEvent;
38 
39 namespace {
40 
CheckChronologicalOrderOfEvents(const PerfReader & reader)41 void CheckChronologicalOrderOfEvents(const PerfReader &reader) {
42   if (reader.events().empty()) return;
43   const auto &events = reader.events();
44   uint64_t prev_time = GetTimeFromPerfEvent(events.Get(0));
45   for (int i = 1; i < events.size(); ++i) {
46     uint64_t new_time = GetTimeFromPerfEvent(events.Get(i));
47     CHECK_LE(prev_time, new_time);
48     prev_time = new_time;
49   }
50 }
51 
CheckNoDuplicates(const std::vector<string> & list)52 void CheckNoDuplicates(const std::vector<string> &list) {
53   std::set<string> list_as_set(list.begin(), list.end());
54   if (list.size() != list_as_set.size())
55     ADD_FAILURE() << "Given list has at least one duplicate";
56 }
57 
CreateFilenameToBuildIDMap(const std::vector<string> & filenames,unsigned int seed,std::map<string,string> * filenames_to_build_ids)58 void CreateFilenameToBuildIDMap(
59     const std::vector<string> &filenames, unsigned int seed,
60     std::map<string, string> *filenames_to_build_ids) {
61   srand(seed);
62   // Only use every other filename, so that half the filenames are unused.
63   for (size_t i = 0; i < filenames.size(); i += 2) {
64     u8 build_id[kBuildIDArraySize];
65     for (size_t j = 0; j < kBuildIDArraySize; ++j) build_id[j] = rand_r(&seed);
66 
67     (*filenames_to_build_ids)[filenames[i]] =
68         RawDataToHexString(build_id, kBuildIDArraySize);
69   }
70 }
71 
72 // Given a PerfReader that has already consumed an input perf data file, inject
73 // new build IDs for the MMAP'd files in the perf data and check that they have
74 // been correctly injected.
CheckFilenameAndBuildIDMethods(PerfReader * reader,const string & output_perf_data_prefix,unsigned int seed)75 void CheckFilenameAndBuildIDMethods(PerfReader *reader,
76                                     const string &output_perf_data_prefix,
77                                     unsigned int seed) {
78   // Check filenames.
79   std::vector<string> filenames;
80   reader->GetFilenames(&filenames);
81 
82   ASSERT_FALSE(filenames.empty());
83   CheckNoDuplicates(filenames);
84 
85   std::set<string> filename_set;
86   reader->GetFilenamesAsSet(&filename_set);
87 
88   // Make sure all MMAP filenames are in the set.
89   for (const auto &event : reader->events()) {
90     if (event.header().type() == PERF_RECORD_MMAP) {
91       EXPECT_TRUE(filename_set.find(event.mmap_event().filename()) !=
92                   filename_set.end())
93           << event.mmap_event().filename()
94           << " is not present in the filename set";
95     }
96   }
97 
98   std::map<string, string> expected_map;
99   reader->GetFilenamesToBuildIDs(&expected_map);
100 
101   // Inject some made up build ids.
102   std::map<string, string> filenames_to_build_ids;
103   CreateFilenameToBuildIDMap(filenames, seed, &filenames_to_build_ids);
104   ASSERT_TRUE(reader->InjectBuildIDs(filenames_to_build_ids));
105 
106   // Reader should now correctly populate the filenames to build ids map.
107   std::map<string, string>::const_iterator it;
108   for (it = filenames_to_build_ids.begin(); it != filenames_to_build_ids.end();
109        ++it) {
110     expected_map[it->first] = it->second;
111   }
112   std::map<string, string> reader_map;
113   reader->GetFilenamesToBuildIDs(&reader_map);
114   ASSERT_EQ(expected_map, reader_map);
115 
116   string output_perf_data1 = output_perf_data_prefix + ".parse.inject.out";
117   ASSERT_TRUE(reader->WriteFile(output_perf_data1));
118 
119   // Perf should find the same build ids.
120   std::map<string, string> perf_build_id_map;
121   ASSERT_TRUE(GetPerfBuildIDMap(output_perf_data1, &perf_build_id_map));
122   ASSERT_EQ(expected_map, perf_build_id_map);
123 
124   std::map<string, string> build_id_localizer;
125   // Only localize the first half of the files which have build ids.
126   for (size_t j = 0; j < filenames.size() / 2; ++j) {
127     string old_filename = filenames[j];
128     if (expected_map.find(old_filename) == expected_map.end()) continue;
129     string build_id = expected_map[old_filename];
130 
131     string new_filename = old_filename + ".local";
132     filenames[j] = new_filename;
133     build_id_localizer[build_id] = new_filename;
134     expected_map[new_filename] = build_id;
135     expected_map.erase(old_filename);
136   }
137   reader->Localize(build_id_localizer);
138 
139   // Filenames should be the same.
140   std::vector<string> new_filenames;
141   reader->GetFilenames(&new_filenames);
142   std::sort(filenames.begin(), filenames.end());
143   ASSERT_EQ(filenames, new_filenames);
144 
145   // Build ids should be updated.
146   reader_map.clear();
147   reader->GetFilenamesToBuildIDs(&reader_map);
148   ASSERT_EQ(expected_map, reader_map);
149 
150   string output_perf_data2 = output_perf_data_prefix + ".parse.localize.out";
151   ASSERT_TRUE(reader->WriteFile(output_perf_data2));
152 
153   perf_build_id_map.clear();
154   ASSERT_TRUE(GetPerfBuildIDMap(output_perf_data2, &perf_build_id_map));
155   EXPECT_EQ(expected_map, perf_build_id_map);
156 
157   std::map<string, string> filename_localizer;
158   // Only localize every third filename.
159   for (size_t j = 0; j < filenames.size(); j += 3) {
160     string old_filename = filenames[j];
161     string new_filename = old_filename + ".local2";
162     filenames[j] = new_filename;
163     filename_localizer[old_filename] = new_filename;
164 
165     if (expected_map.find(old_filename) != expected_map.end()) {
166       string build_id = expected_map[old_filename];
167       expected_map[new_filename] = build_id;
168       expected_map.erase(old_filename);
169     }
170   }
171   reader->LocalizeUsingFilenames(filename_localizer);
172 
173   // Filenames should be the same.
174   new_filenames.clear();
175   reader->GetFilenames(&new_filenames);
176   std::sort(filenames.begin(), filenames.end());
177   EXPECT_EQ(filenames, new_filenames);
178 
179   // Build ids should be updated.
180   reader_map.clear();
181   reader->GetFilenamesToBuildIDs(&reader_map);
182   EXPECT_EQ(expected_map, reader_map);
183 
184   string output_perf_data3 = output_perf_data_prefix + ".parse.localize2.out";
185   ASSERT_TRUE(reader->WriteFile(output_perf_data3));
186 
187   perf_build_id_map.clear();
188   ASSERT_TRUE(GetPerfBuildIDMap(output_perf_data3, &perf_build_id_map));
189   EXPECT_EQ(expected_map, perf_build_id_map);
190 }
191 
CopyActualEvents(const std::vector<ParsedEvent> & events,PerfDataProto * out)192 void CopyActualEvents(const std::vector<ParsedEvent> &events,
193                       PerfDataProto *out) {
194   for (const auto &ev : events) {
195     if (ev.event_ptr == nullptr) {
196       continue;
197     }
198     *out->add_events() = *ev.event_ptr;
199   }
200 }
201 
202 }  // namespace
203 
TEST(PerfParserTest,TestDSOAndOffsetConstructor)204 TEST(PerfParserTest, TestDSOAndOffsetConstructor) {
205   // DSOAndOffset contains a pointer to a dso info struct. Make sure this is
206   // initialized in a way such that DSOAndOffset::dso_name() executes without
207   // segfault and returns an empty string.
208   ParsedEvent::DSOAndOffset dso_and_offset;
209   EXPECT_TRUE(dso_and_offset.dso_name().empty());
210 }
211 
212 class PerfDataFiles : public ::testing::TestWithParam<const char *> {};
213 class PerfPipedDataFiles : public ::testing::TestWithParam<const char *> {};
214 
TEST_P(PerfDataFiles,NormalPerfData)215 TEST_P(PerfDataFiles, NormalPerfData) {
216   ScopedTempDir output_dir;
217   ASSERT_FALSE(output_dir.path().empty());
218   string output_path = output_dir.path();
219 
220   int seed = 0;
221   string test_file = GetParam();
222   string input_perf_data = GetTestInputFilePath(test_file);
223   LOG(INFO) << "Testing " << input_perf_data;
224 
225   PerfReader reader;
226   ASSERT_TRUE(reader.ReadFile(input_perf_data));
227 
228   // Test the PerfReader stage of the processing before continuing.
229   string pr_output_perf_data = output_path + test_file + ".pr.out";
230   ASSERT_TRUE(reader.WriteFile(pr_output_perf_data));
231   EXPECT_TRUE(CheckPerfDataAgainstBaseline(pr_output_perf_data));
232 
233   // Run it through PerfParser.
234   PerfParserOptions options = GetTestOptions();
235   options.sort_events_by_time = true;
236   PerfParser parser(&reader, options);
237   ASSERT_TRUE(parser.ParseRawEvents());
238 
239   CHECK_GT(parser.parsed_events().size(), 0U);
240   CheckChronologicalOrderOfEvents(reader);
241 
242   // Check perf event stats.
243   const PerfEventStats &stats = parser.stats();
244   EXPECT_GT(stats.num_sample_events, 0U);
245   EXPECT_GT(stats.num_mmap_events, 0U);
246   EXPECT_GT(stats.num_sample_events_mapped, 0U);
247   EXPECT_FALSE(stats.did_remap);
248 
249   string parsed_perf_data = output_path + test_file + ".parse.out";
250   ASSERT_TRUE(reader.WriteFile(parsed_perf_data));
251 
252   EXPECT_TRUE(CheckPerfDataAgainstBaseline(parsed_perf_data));
253   EXPECT_TRUE(ComparePerfBuildIDLists(input_perf_data, parsed_perf_data));
254 
255   // Run the event parsing again, this time with remapping.
256   options = PerfParserOptions();
257   options.do_remap = true;
258   parser.set_options(options);
259   ASSERT_TRUE(parser.ParseRawEvents());
260 
261   // Check perf event stats.
262   EXPECT_GT(stats.num_sample_events, 0U);
263   EXPECT_GT(stats.num_mmap_events, 0U);
264   EXPECT_GT(stats.num_sample_events_mapped, 0U);
265   EXPECT_TRUE(stats.did_remap);
266 
267   // Remapped addresses should not match the original addresses.
268   string remapped_perf_data = output_path + test_file + ".parse.remap.out";
269   ASSERT_TRUE(reader.WriteFile(remapped_perf_data));
270   EXPECT_TRUE(CheckPerfDataAgainstBaseline(remapped_perf_data));
271 
272   // Remapping again should produce the same addresses.
273   LOG(INFO) << "Reading in remapped data: " << remapped_perf_data;
274   PerfReader remap_reader;
275   ASSERT_TRUE(remap_reader.ReadFile(remapped_perf_data));
276 
277   PerfParser remap_parser(&remap_reader, options);
278   ASSERT_TRUE(remap_parser.ParseRawEvents());
279 
280   const PerfEventStats &remap_stats = remap_parser.stats();
281   EXPECT_GT(remap_stats.num_sample_events, 0U);
282   EXPECT_GT(remap_stats.num_mmap_events, 0U);
283   EXPECT_GT(remap_stats.num_sample_events_mapped, 0U);
284   EXPECT_TRUE(remap_stats.did_remap);
285 
286   ASSERT_EQ(stats.num_sample_events, remap_stats.num_sample_events);
287   ASSERT_EQ(stats.num_mmap_events, remap_stats.num_mmap_events);
288   ASSERT_EQ(stats.num_sample_events_mapped,
289             remap_stats.num_sample_events_mapped);
290 
291   string remapped_perf_data2 = output_path + test_file + ".parse.remap2.out";
292   ASSERT_TRUE(remap_reader.WriteFile(remapped_perf_data2));
293 
294   // No need to call CheckPerfDataAgainstBaseline again. Just compare
295   // ParsedEvents.
296   const auto &parser_events = parser.parsed_events();
297   const auto &remap_parser_events = remap_parser.parsed_events();
298   EXPECT_EQ(parser_events.size(), remap_parser_events.size());
299   EXPECT_TRUE(std::equal(parser_events.begin(), parser_events.end(),
300                          remap_parser_events.begin()));
301   EXPECT_TRUE(ComparePerfBuildIDLists(remapped_perf_data, remapped_perf_data2));
302 
303   // This must be called when |reader| is no longer going to be used, as it
304   // modifies the contents of |reader|.
305   CheckFilenameAndBuildIDMethods(&reader, output_path + test_file, seed);
306   ++seed;
307 }
308 
TEST_P(PerfPipedDataFiles,PipedModePerfData)309 TEST_P(PerfPipedDataFiles, PipedModePerfData) {
310   ScopedTempDir output_dir;
311   ASSERT_FALSE(output_dir.path().empty());
312   string output_path = output_dir.path();
313 
314   int seed = 0;
315   const string test_file = GetParam();
316   string input_perf_data = GetTestInputFilePath(test_file);
317   LOG(INFO) << "Testing " << input_perf_data;
318   string output_perf_data = output_path + test_file + ".pr.out";
319 
320   PerfReader reader;
321   ASSERT_TRUE(reader.ReadFile(input_perf_data));
322 
323   // Check results from the PerfReader stage.
324   ASSERT_TRUE(reader.WriteFile(output_perf_data));
325   EXPECT_TRUE(CheckPerfDataAgainstBaseline(output_perf_data));
326 
327   PerfParserOptions options = GetTestOptions();
328   options.do_remap = true;
329   options.sort_events_by_time = true;
330   PerfParser parser(&reader, options);
331   ASSERT_TRUE(parser.ParseRawEvents());
332 
333   EXPECT_GT(parser.stats().num_sample_events, 0U);
334   EXPECT_GT(parser.stats().num_mmap_events, 0U);
335   EXPECT_GT(parser.stats().num_sample_events_mapped, 0U);
336   EXPECT_TRUE(parser.stats().did_remap);
337 
338   // This must be called when |reader| is no longer going to be used, as it
339   // modifies the contents of |reader|.
340   CheckFilenameAndBuildIDMethods(&reader, output_path + test_file, seed);
341   ++seed;
342 }
343 
344 INSTANTIATE_TEST_CASE_P(
345     PerfParserTest, PerfDataFiles,
346     ::testing::ValuesIn(perf_test_files::GetPerfDataFiles()));
347 INSTANTIATE_TEST_CASE_P(
348     PerfParserTest, PerfPipedDataFiles,
349     ::testing::ValuesIn(perf_test_files::GetPerfPipedDataFiles()));
350 
TEST(PerfParserTest,MapsSampleEventIp)351 TEST(PerfParserTest, MapsSampleEventIp) {
352   std::stringstream input;
353 
354   // header
355   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
356 
357   // data
358 
359   // PERF_RECORD_HEADER_ATTR
360   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
361                                               true /*sample_id_all*/)
362       .WriteTo(&input);
363 
364   // PERF_RECORD_MMAP
365   testing::ExampleMmapEvent(1001, 0x1c1000, 0x1000, 0, "/usr/lib/foo.so",
366                             testing::SampleInfo().Tid(1001))
367       .WriteTo(&input);  // 0
368   // becomes: 0x0000, 0x1000, 0
369   testing::ExampleMmapEvent(1001, 0x1c3000, 0x2000, 0x2000, "/usr/lib/bar.so",
370                             testing::SampleInfo().Tid(1001))
371       .WriteTo(&input);  // 1
372   // becomes: 0x1000, 0x2000, 0
373 
374   // PERF_RECORD_MMAP2
375   testing::ExampleMmap2Event(1002, 0x2c1000, 0x2000, 0, "/usr/lib/baz.so",
376                              testing::SampleInfo().Tid(1002))
377       .WriteTo(&input);  // 2
378   // becomes: 0x0000, 0x2000, 0
379   testing::ExampleMmap2Event(1002, 0x2c3000, 0x1000, 0x3000, "/usr/lib/xyz.so",
380                              testing::SampleInfo().Tid(1002))
381       .WriteTo(&input);  // 3
382   // becomes: 0x1000, 0x1000, 0
383 
384   // PERF_RECORD_SAMPLE
385   testing::ExamplePerfSampleEvent(
386       testing::SampleInfo().Ip(0x00000000001c1000).Tid(1001))
387       .WriteTo(&input);  // 4
388   testing::ExamplePerfSampleEvent(
389       testing::SampleInfo().Ip(0x00000000001c100a).Tid(1001))
390       .WriteTo(&input);  // 5
391   testing::ExamplePerfSampleEvent(
392       testing::SampleInfo().Ip(0x00000000001c3fff).Tid(1001))
393       .WriteTo(&input);  // 6
394   testing::ExamplePerfSampleEvent(
395       testing::SampleInfo().Ip(0x00000000001c2bad).Tid(1001))
396       .WriteTo(&input);  // 7 (not mapped)
397   testing::ExamplePerfSampleEvent(
398       testing::SampleInfo().Ip(0x00000000002c100a).Tid(1002))
399       .WriteTo(&input);  // 8
400   testing::ExamplePerfSampleEvent(
401       testing::SampleInfo().Ip(0x00000000002c5bad).Tid(1002))
402       .WriteTo(&input);  // 9 (not mapped)
403   testing::ExamplePerfSampleEvent(
404       testing::SampleInfo().Ip(0x00000000002c300b).Tid(1002))
405       .WriteTo(&input);  // 10
406 
407   // not mapped yet:
408   testing::ExamplePerfSampleEvent(
409       testing::SampleInfo().Ip(0x00000000002c400b).Tid(1002))
410       .WriteTo(&input);  // 11
411   testing::ExampleMmap2Event(1002, 0x2c4000, 0x1000, 0, "/usr/lib/new.so",
412                              testing::SampleInfo().Tid(1002))
413       .WriteTo(&input);  // 12
414   testing::ExamplePerfSampleEvent(
415       testing::SampleInfo().Ip(0x00000000002c400b).Tid(1002))
416       .WriteTo(&input);  // 13
417 
418   //
419   // Parse input.
420   //
421 
422   PerfReader reader;
423   EXPECT_TRUE(reader.ReadFromString(input.str()));
424 
425   PerfParserOptions options;
426   options.sample_mapping_percentage_threshold = 0;
427   options.do_remap = true;
428   PerfParser parser(&reader, options);
429   EXPECT_TRUE(parser.ParseRawEvents());
430 
431   EXPECT_EQ(5, parser.stats().num_mmap_events);
432   EXPECT_EQ(9, parser.stats().num_sample_events);
433   EXPECT_EQ(6, parser.stats().num_sample_events_mapped);
434 
435   const std::vector<ParsedEvent> &events = parser.parsed_events();
436   ASSERT_EQ(14, events.size());
437 
438   // MMAPs
439 
440   EXPECT_EQ(PERF_RECORD_MMAP, events[0].event_ptr->header().type());
441   EXPECT_EQ("/usr/lib/foo.so", events[0].event_ptr->mmap_event().filename());
442   EXPECT_EQ(0x0000, events[0].event_ptr->mmap_event().start());
443   EXPECT_EQ(0x1000, events[0].event_ptr->mmap_event().len());
444   EXPECT_EQ(0, events[0].event_ptr->mmap_event().pgoff());
445 
446   EXPECT_EQ(PERF_RECORD_MMAP, events[1].event_ptr->header().type());
447   EXPECT_EQ("/usr/lib/bar.so", events[1].event_ptr->mmap_event().filename());
448   EXPECT_EQ(0x1000, events[1].event_ptr->mmap_event().start());
449   EXPECT_EQ(0x2000, events[1].event_ptr->mmap_event().len());
450   EXPECT_EQ(0x2000, events[1].event_ptr->mmap_event().pgoff());
451 
452   EXPECT_EQ(PERF_RECORD_MMAP2, events[2].event_ptr->header().type());
453   EXPECT_EQ("/usr/lib/baz.so", events[2].event_ptr->mmap_event().filename());
454   EXPECT_EQ(0x0000, events[2].event_ptr->mmap_event().start());
455   EXPECT_EQ(0x2000, events[2].event_ptr->mmap_event().len());
456   EXPECT_EQ(0, events[2].event_ptr->mmap_event().pgoff());
457 
458   EXPECT_EQ(PERF_RECORD_MMAP2, events[3].event_ptr->header().type());
459   EXPECT_EQ("/usr/lib/xyz.so", events[3].event_ptr->mmap_event().filename());
460   EXPECT_EQ(0x2000, events[3].event_ptr->mmap_event().start());
461   EXPECT_EQ(0x1000, events[3].event_ptr->mmap_event().len());
462   EXPECT_EQ(0x3000, events[3].event_ptr->mmap_event().pgoff());
463 
464   // SAMPLEs
465 
466   EXPECT_EQ(PERF_RECORD_SAMPLE, events[4].event_ptr->header().type());
467   EXPECT_EQ("/usr/lib/foo.so", events[4].dso_and_offset.dso_name());
468   EXPECT_EQ(0x0, events[4].dso_and_offset.offset());
469   EXPECT_EQ(0x0, events[4].event_ptr->sample_event().ip());
470 
471   EXPECT_EQ(PERF_RECORD_SAMPLE, events[5].event_ptr->header().type());
472   EXPECT_EQ("/usr/lib/foo.so", events[5].dso_and_offset.dso_name());
473   EXPECT_EQ(0xa, events[5].dso_and_offset.offset());
474   EXPECT_EQ(0xa, events[5].event_ptr->sample_event().ip());
475 
476   EXPECT_EQ(PERF_RECORD_SAMPLE, events[6].event_ptr->header().type());
477   EXPECT_EQ("/usr/lib/bar.so", events[6].dso_and_offset.dso_name());
478   EXPECT_EQ(0x2fff, events[6].dso_and_offset.offset());
479   EXPECT_EQ(0x1fff, events[6].event_ptr->sample_event().ip());
480 
481   EXPECT_EQ(PERF_RECORD_SAMPLE, events[7].event_ptr->header().type());
482   EXPECT_EQ(0x00000000001c2bad, events[7].event_ptr->sample_event().ip());
483 
484   EXPECT_EQ(PERF_RECORD_SAMPLE, events[8].event_ptr->header().type());
485   EXPECT_EQ("/usr/lib/baz.so", events[8].dso_and_offset.dso_name());
486   EXPECT_EQ(0xa, events[8].dso_and_offset.offset());
487   EXPECT_EQ(0xa, events[8].event_ptr->sample_event().ip());
488 
489   EXPECT_EQ(PERF_RECORD_SAMPLE, events[9].event_ptr->header().type());
490   EXPECT_EQ(0x00000000002c5bad, events[9].event_ptr->sample_event().ip());
491 
492   EXPECT_EQ(PERF_RECORD_SAMPLE, events[10].event_ptr->header().type());
493   EXPECT_EQ("/usr/lib/xyz.so", events[10].dso_and_offset.dso_name());
494   EXPECT_EQ(0x300b, events[10].dso_and_offset.offset());
495   EXPECT_EQ(0x200b, events[10].event_ptr->sample_event().ip());
496 
497   // not mapped yet:
498   EXPECT_EQ(PERF_RECORD_SAMPLE, events[11].event_ptr->header().type());
499   EXPECT_EQ(0x00000000002c400b, events[11].event_ptr->sample_event().ip());
500 
501   EXPECT_EQ(PERF_RECORD_MMAP2, events[12].event_ptr->header().type());
502   EXPECT_EQ("/usr/lib/new.so", events[12].event_ptr->mmap_event().filename());
503   EXPECT_EQ(0x3000, events[12].event_ptr->mmap_event().start());
504   EXPECT_EQ(0x1000, events[12].event_ptr->mmap_event().len());
505   EXPECT_EQ(0, events[12].event_ptr->mmap_event().pgoff());
506 
507   EXPECT_EQ(PERF_RECORD_SAMPLE, events[13].event_ptr->header().type());
508   EXPECT_EQ("/usr/lib/new.so", events[13].dso_and_offset.dso_name());
509   EXPECT_EQ(0xb, events[13].dso_and_offset.offset());
510   EXPECT_EQ(0x300b, events[13].event_ptr->sample_event().ip());
511 }
512 
TEST(PerfParserTest,DsoInfoHasBuildId)513 TEST(PerfParserTest, DsoInfoHasBuildId) {
514   std::stringstream input;
515 
516   // header
517   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
518 
519   // data
520 
521   // PERF_RECORD_HEADER_ATTR
522   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
523                                               true /*sample_id_all*/)
524       .WriteTo(&input);
525 
526   // PERF_RECORD_MMAP
527   testing::ExampleMmapEvent(1001, 0x1c1000, 0x1000, 0, "/usr/lib/foo.so",
528                             testing::SampleInfo().Tid(1001))
529       .WriteTo(&input);  // 0
530   // becomes: 0x0000, 0x1000, 0
531   testing::ExampleMmapEvent(1001, 0x1c3000, 0x2000, 0x2000, "/usr/lib/bar.so",
532                             testing::SampleInfo().Tid(1001))
533       .WriteTo(&input);  // 1
534   // becomes: 0x1000, 0x2000, 0
535 
536   // PERF_RECORD_HEADER_BUILDID                                // N/A
537   string build_id_filename("/usr/lib/foo.so\0", 2 * sizeof(u64));
538   ASSERT_EQ(0, build_id_filename.size() % sizeof(u64)) << "Sanity check";
539   const size_t event_size =
540       sizeof(struct build_id_event) + build_id_filename.size();
541   const struct build_id_event event = {
542       .header =
543           {
544               .type = PERF_RECORD_HEADER_BUILD_ID,
545               .misc = 0,
546               .size = static_cast<u16>(event_size),
547           },
548       .pid = -1,
549       .build_id = {0xde, 0xad, 0xf0, 0x0d},
550   };
551   input.write(reinterpret_cast<const char *>(&event), sizeof(event));
552   input.write(build_id_filename.data(), build_id_filename.size());
553 
554   // PERF_RECORD_SAMPLE
555   testing::ExamplePerfSampleEvent(
556       testing::SampleInfo().Ip(0x00000000001c1000).Tid(1001))
557       .WriteTo(&input);  // 2
558   testing::ExamplePerfSampleEvent(
559       testing::SampleInfo().Ip(0x00000000001c300a).Tid(1001))
560       .WriteTo(&input);  // 3
561 
562   //
563   // Parse input.
564   //
565 
566   PerfReader reader;
567   EXPECT_TRUE(reader.ReadFromString(input.str()));
568 
569   PerfParserOptions options;
570   options.sample_mapping_percentage_threshold = 0;
571   PerfParser parser(&reader, options);
572   EXPECT_TRUE(parser.ParseRawEvents());
573 
574   EXPECT_EQ(2, parser.stats().num_mmap_events);
575   EXPECT_EQ(2, parser.stats().num_sample_events);
576   EXPECT_EQ(2, parser.stats().num_sample_events_mapped);
577 
578   const std::vector<ParsedEvent> &events = parser.parsed_events();
579   ASSERT_EQ(4, events.size());
580 
581   EXPECT_EQ("/usr/lib/foo.so", events[2].dso_and_offset.dso_name());
582   EXPECT_EQ("deadf00d00000000000000000000000000000000",
583             events[2].dso_and_offset.build_id());
584   EXPECT_EQ("/usr/lib/bar.so", events[3].dso_and_offset.dso_name());
585   EXPECT_EQ("", events[3].dso_and_offset.build_id());
586 }
587 
588 // Check the process has a Linux capability. See libcap(3) and capabilities(7).
HaveCapability(cap_value_t capability)589 bool HaveCapability(cap_value_t capability) {
590   cap_t capabilities = cap_get_proc();
591   cap_flag_value_t value;
592   CHECK_EQ(cap_get_flag(capabilities, capability, CAP_EFFECTIVE, &value), 0);
593   cap_free(capabilities);
594   return value == CAP_SET;
595 }
596 
597 class RunInMountNamespaceThread : public quipper::Thread {
598  public:
RunInMountNamespaceThread(string tmpdir,string mntdir)599   explicit RunInMountNamespaceThread(string tmpdir, string mntdir)
600       : quipper::Thread("MntNamespace"),
601         tmpdir_(std::move(tmpdir)),
602         mntdir_(std::move(mntdir)) {}
603 
Start()604   void Start() override {
605     quipper::Thread::Start();
606     ready.Wait();
607   }
608 
Join()609   void Join() override {
610     exit.Notify();
611     quipper::Thread::Join();
612   }
613 
614  private:
Run()615   void Run() override {
616     CHECK_EQ(unshare(CLONE_NEWNS), 0);
617     CHECK_EQ(mount(tmpdir_.c_str(), mntdir_.c_str(), nullptr, MS_BIND, nullptr),
618              0);
619     ready.Notify();
620     exit.Wait();
621   }
622 
623   Notification ready;
624   Notification exit;
625   string tmpdir_;
626   string mntdir_;
627 };
628 
629 // Root task <pid>/<pid> Filesystem:
630 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
631 //   "/tmp/quipper_mnt.../file_in_namespace"  (Doesn't exist)
632 // Container task <pid>/<tid> Filesystem:
633 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
634 // * "/tmp/quipper_mnt.../file_in_namespace"  buildid: deadbeef  ino: X
635 // <path> = marked with *
636 // MMAP2: <pid+10>/<tid+1>, <path>, ino: X
637 // MMAP2: <pid>/<tid>, <path>, ino: X
638 // Reject (doesn't exist): /proc/<tid+10>/root/<path>
639 // Reject (doesn't exist): /proc/<pid+1>/root/<path>
640 // Accept:                 /proc/<tid>/root/<path>
641 // (Not tried):            /proc/<pid>/root/<path>
642 // (Not tried): /<path>
643 // Expected buildid for <path>: "deadbeef"
TEST(PerfParserTest,ReadsBuildidsInMountNamespace)644 TEST(PerfParserTest, ReadsBuildidsInMountNamespace) {
645   if (!HaveCapability(CAP_SYS_ADMIN)) return;  // Skip test.
646   ScopedTempDir tmpdir("/tmp/quipper_tmp.");
647   ScopedTempDir mntdir("/tmp/quipper_mnt.");
648   RunInMountNamespaceThread thread(tmpdir.path(), mntdir.path());
649   thread.Start();
650   const pid_t pid = getpid();
651   const pid_t tid = thread.tid();
652 
653   const string tmpfile = tmpdir.path() + "file_in_namespace";
654   const string tmpfile_in_ns = mntdir.path() + "file_in_namespace";
655   InitializeLibelf();
656   testing::WriteElfWithBuildid(tmpfile, ".note.gnu.build-id",
657                                "\xde\xad\xbe\xef");
658   struct stat tmp_stat;
659   ASSERT_NE(stat(tmpfile_in_ns.c_str(), &tmp_stat), 0);
660   ASSERT_EQ(stat(tmpfile.c_str(), &tmp_stat), 0);
661 
662   // Create perf.data
663   std::stringstream input;
664 
665   // header
666   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
667 
668   // data
669 
670   // PERF_RECORD_HEADER_ATTR
671   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
672                                               true /*sample_id_all*/)
673       .WriteTo(&input);
674 
675   // PERF_RECORD_MMAP2
676   // - mmap from a process and thread that doesn't exist
677   testing::ExampleMmap2Event(pid, tid, 0x1c1000, 0x1000, 0, tmpfile_in_ns,
678                              testing::SampleInfo().Tid(pid + 10, tid + 1))
679       .WithDeviceInfo(major(tmp_stat.st_dev), minor(tmp_stat.st_dev),
680                       tmp_stat.st_ino)
681       .WriteTo(&input);  // 0
682   // - mmap from a running thread
683   testing::ExampleMmap2Event(pid, tid, 0x1c2000, 0x1000, 0, tmpfile_in_ns,
684                              testing::SampleInfo().Tid(pid, tid))
685       .WithDeviceInfo(major(tmp_stat.st_dev), minor(tmp_stat.st_dev),
686                       tmp_stat.st_ino)
687       .WriteTo(&input);  // 1
688 
689   // PERF_RECORD_SAMPLE
690   testing::ExamplePerfSampleEvent(
691       testing::SampleInfo().Ip(0x00000000001c1000).Tid(pid, tid))
692       .WriteTo(&input);  // 2
693 
694   //
695   // Parse input.
696   //
697 
698   PerfReader reader;
699   EXPECT_TRUE(reader.ReadFromString(input.str()));
700 
701   PerfParserOptions options;
702   options.read_missing_buildids = true;
703   options.sample_mapping_percentage_threshold = 0;
704   PerfParser parser(&reader, options);
705   EXPECT_TRUE(parser.ParseRawEvents());
706 
707   EXPECT_EQ(2, parser.stats().num_mmap_events);
708   EXPECT_EQ(1, parser.stats().num_sample_events);
709   EXPECT_EQ(1, parser.stats().num_sample_events_mapped);
710 
711   const std::vector<ParsedEvent> &events = parser.parsed_events();
712   ASSERT_EQ(3, events.size());
713 
714   EXPECT_EQ(tmpfile_in_ns, events[2].dso_and_offset.dso_name());
715   EXPECT_EQ("deadbeef", events[2].dso_and_offset.build_id());
716 
717   thread.Join();
718 }
719 
720 class RunInMountNamespaceProcess {
721  public:
RunInMountNamespaceProcess(string tmpdir,string mntdir)722   RunInMountNamespaceProcess(string tmpdir, string mntdir)
723       : pid_(0), tmpdir_(std::move(tmpdir)), mntdir_(std::move(mntdir)) {}
724 
Start()725   void Start() {
726     int pipe_fd[2];
727     int nonce = 0;
728     CHECK_EQ(pipe(pipe_fd), 0) << "pipe: " << strerror(errno);
729 
730     pid_ = fork();
731     CHECK_NE(-1, pid_) << "fork: " << strerror(errno);
732     if (pid_ == 0) {  // child
733       close(pipe_fd[0]);
734       CHECK_EQ(unshare(CLONE_NEWNS), 0);
735       CHECK_EQ(
736           mount(tmpdir_.c_str(), mntdir_.c_str(), nullptr, MS_BIND, nullptr),
737           0);
738       // Tell parent mounting is done.
739       CHECK_EQ(write(pipe_fd[1], &nonce, sizeof(nonce)),
740                static_cast<ssize_t>(sizeof(nonce)));
741       close(pipe_fd[1]);
742       pause();  // Wait to be killed. (So morbid.)
743       std::_Exit(-1);
744     }
745     close(pipe_fd[1]);
746 
747     // Wait for child to tell us it has mounted the dir.
748     ssize_t sz = read(pipe_fd[0], &nonce, sizeof(nonce));
749     CHECK_EQ(sz, static_cast<ssize_t>(sizeof(nonce)))
750         << "read: " << strerror(errno);
751     close(pipe_fd[0]);
752   }
753 
Exit()754   void Exit() {
755     kill(pid_, SIGTERM);
756     waitpid(pid_, nullptr, 0);
757   }
758 
pid()759   pid_t pid() { return pid_; }
760 
761  private:
762   pid_t pid_;
763   string tmpdir_;
764   string mntdir_;
765 };
766 
767 // Root task <pid>/<pid> Filesystem:
768 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
769 // * "/tmp/quipper_mnt.../file_in_namespace"  buildid: baadf00d  ino: Y
770 // Container task <pid2>/<pid2> Filesystem:
771 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
772 // * "/tmp/quipper_mnt.../file_in_namespace"  buildid: deadbeef  ino: X
773 // <path> = marked with *
774 // MMAP2: <pid2>/<pid2+1>, <path>, ino: X
775 // Reject (doesn't exist): /proc/<pid2+1>/root/<path>
776 // Accept:                 /proc/<pid2>/root/<path>
777 // (Not tried): /<path>
778 // Expected buildid for <path>: "deadbeef"
TEST(PerfParserTest,ReadsBuildidsInMountNamespace_TriesOwningProcess)779 TEST(PerfParserTest, ReadsBuildidsInMountNamespace_TriesOwningProcess) {
780   if (!HaveCapability(CAP_SYS_ADMIN)) return;  // Skip test.
781   ScopedTempDir tmpdir("/tmp/quipper_tmp.");
782   ScopedTempDir mntdir("/tmp/quipper_mnt.");
783   RunInMountNamespaceProcess process(tmpdir.path(), mntdir.path());
784   process.Start();
785 
786   // Pretend we launched a thread in the other process, it mapped the file,
787   // and then exited. Let's make up a tid for it that's not likely to exist.
788   const pid_t pid = process.pid();
789   const pid_t tid = pid + 1;
790 
791   const string tmpfile = tmpdir.path() + "file_in_namespace";
792   const string tmpfile_in_ns = mntdir.path() + "file_in_namespace";
793   InitializeLibelf();
794   testing::WriteElfWithBuildid(tmpfile, ".note.gnu.build-id",
795                                "\xde\xad\xbe\xef");
796   // It's a trap! If "baadf00d" is seen, we read the wrong file.
797   testing::WriteElfWithBuildid(tmpfile_in_ns, ".note.gnu.build-id",
798                                "\xba\xad\xf0\x0d");
799   struct stat tmp_stat;
800   ASSERT_EQ(stat(tmpfile.c_str(), &tmp_stat), 0);
801 
802   // Create perf.data
803   std::stringstream input;
804 
805   // header
806   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
807 
808   // data
809 
810   // PERF_RECORD_HEADER_ATTR
811   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
812                                               true /*sample_id_all*/)
813       .WriteTo(&input);
814 
815   // PERF_RECORD_MMAP2
816   testing::ExampleMmap2Event(pid, tid, 0x1c1000, 0x1000, 0, tmpfile_in_ns,
817                              testing::SampleInfo().Tid(pid, tid))
818       .WithDeviceInfo(major(tmp_stat.st_dev), minor(tmp_stat.st_dev),
819                       tmp_stat.st_ino)
820       .WriteTo(&input);  // 0
821 
822   // PERF_RECORD_SAMPLE
823   testing::ExamplePerfSampleEvent(
824       testing::SampleInfo().Ip(0x00000000001c1000).Tid(pid, tid))
825       .WriteTo(&input);  // 1
826 
827   //
828   // Parse input.
829   //
830 
831   PerfReader reader;
832   EXPECT_TRUE(reader.ReadFromString(input.str()));
833 
834   PerfParserOptions options;
835   options.read_missing_buildids = true;
836   options.sample_mapping_percentage_threshold = 0;
837   PerfParser parser(&reader, options);
838   EXPECT_TRUE(parser.ParseRawEvents());
839 
840   EXPECT_EQ(1, parser.stats().num_mmap_events);
841   EXPECT_EQ(1, parser.stats().num_sample_events);
842   EXPECT_EQ(1, parser.stats().num_sample_events_mapped);
843 
844   const std::vector<ParsedEvent> &events = parser.parsed_events();
845   ASSERT_EQ(2, events.size());
846 
847   EXPECT_EQ(tmpfile_in_ns, events[1].dso_and_offset.dso_name());
848   EXPECT_EQ("deadbeef", events[1].dso_and_offset.build_id());
849 
850   process.Exit();
851 }
852 
853 // Root task <pid>/<pid> Filesystem:
854 // * "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
855 //   "/tmp/quipper_mnt.../file_in_namespace"  buildid: baadf00d  ino: Y
856 // Container task <pid>/<tid> Filesystem:
857 // * "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
858 //   "/tmp/quipper_mnt.../file_in_namespace"  buildid: deadbeef  ino: X
859 // <path> = marked with *
860 // MMAP2: <pid+10>/<tid+1>, <path>, ino: X
861 // Reject (doesn't exist): /proc/<tid+1>/root/<path>
862 // Reject (doesn't exist): /proc/<pid+10>/root/<path>
863 // Accept (same inode): /<path>
864 // Expected buildid for <path>: "deadbeef"
TEST(PerfParserTest,ReadsBuildidsInMountNamespace_TriesRootFs)865 TEST(PerfParserTest, ReadsBuildidsInMountNamespace_TriesRootFs) {
866   if (!HaveCapability(CAP_SYS_ADMIN)) return;  // Skip test.
867   ScopedTempDir tmpdir("/tmp/quipper_tmp.");
868   ScopedTempDir mntdir("/tmp/quipper_mnt.");
869   RunInMountNamespaceThread thread(tmpdir.path(), mntdir.path());
870   thread.Start();
871   const pid_t pid = getpid();
872   const pid_t tid = thread.tid();
873 
874   const string tmpfile = tmpdir.path() + "file_in_namespace";
875   const string tmpfile_in_ns = mntdir.path() + "file_in_namespace";
876   InitializeLibelf();
877   testing::WriteElfWithBuildid(tmpfile, ".note.gnu.build-id",
878                                "\xde\xad\xbe\xef");
879   // It's a trap! If "baadf00d" is seen, we read the wrong file.
880   testing::WriteElfWithBuildid(tmpfile_in_ns, ".note.gnu.build-id",
881                                "\xba\xad\xf0\x0d");
882   struct stat tmp_stat;
883   ASSERT_EQ(stat(tmpfile.c_str(), &tmp_stat), 0);
884 
885   // Create perf.data
886   std::stringstream input;
887 
888   // header
889   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
890 
891   // data
892 
893   // PERF_RECORD_HEADER_ATTR
894   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
895                                               true /*sample_id_all*/)
896       .WriteTo(&input);
897 
898   // PERF_RECORD_MMAP2
899   // - Process doesn't exist, but file exists in our own namespace.
900   testing::ExampleMmap2Event(pid, pid, 0x1c1000, 0x1000, 0, tmpfile,
901                              testing::SampleInfo().Tid(pid + 10, tid + 1))
902       .WithDeviceInfo(major(tmp_stat.st_dev), minor(tmp_stat.st_dev),
903                       tmp_stat.st_ino)
904       .WriteTo(&input);  // 0
905 
906   // PERF_RECORD_SAMPLE
907   testing::ExamplePerfSampleEvent(
908       testing::SampleInfo().Ip(0x00000000001c1000).Tid(pid))
909       .WriteTo(&input);  // 1
910 
911   //
912   // Parse input.
913   //
914 
915   PerfReader reader;
916   EXPECT_TRUE(reader.ReadFromString(input.str()));
917 
918   PerfParserOptions options;
919   options.read_missing_buildids = true;
920   options.sample_mapping_percentage_threshold = 0;
921   PerfParser parser(&reader, options);
922   EXPECT_TRUE(parser.ParseRawEvents());
923 
924   EXPECT_EQ(1, parser.stats().num_mmap_events);
925   EXPECT_EQ(1, parser.stats().num_sample_events);
926   EXPECT_EQ(1, parser.stats().num_sample_events_mapped);
927 
928   const std::vector<ParsedEvent> &events = parser.parsed_events();
929   ASSERT_EQ(2, events.size());
930 
931   EXPECT_EQ(tmpfile, events[1].dso_and_offset.dso_name());
932   // Finds file in root FS.
933   EXPECT_EQ("deadbeef", events[1].dso_and_offset.build_id());
934 
935   thread.Join();
936 }
937 
938 // Root task <pid>/<pid> Filesystem:
939 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
940 //   "/tmp/quipper_mnt.../file_in_namespace"  buildid: baadf00d  ino: Y
941 // Container task <pid>/<tid> Filesystem:
942 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
943 // * "/tmp/quipper_mnt.../file_in_namespace"  buildid: deadbeef  ino: X
944 // <path> = marked with *
945 // MMAP2: <pid>/<tid>, <path>, ino: X+1
946 // Reject (wrong inode): /proc/<tid>/root/<path>
947 // Reject (wrong inode): /proc/<pid>/root/<path>
948 // Reject (wrong inode): /<path>
949 // Expected buildid for <path>: ""
TEST(PerfParserTest,ReadsBuildidsInMountNamespace_TriesRootFsRejectsInode)950 TEST(PerfParserTest, ReadsBuildidsInMountNamespace_TriesRootFsRejectsInode) {
951   if (!HaveCapability(CAP_SYS_ADMIN)) return;  // Skip test.
952   ScopedTempDir tmpdir("/tmp/quipper_tmp.");
953   ScopedTempDir mntdir("/tmp/quipper_mnt.");
954   RunInMountNamespaceThread thread(tmpdir.path(), mntdir.path());
955   thread.Start();
956   const pid_t pid = getpid();
957   const pid_t tid = thread.tid();
958 
959   const string tmpfile = tmpdir.path() + "file_in_namespace";
960   const string tmpfile_in_ns = mntdir.path() + "file_in_namespace";
961   InitializeLibelf();
962   testing::WriteElfWithBuildid(tmpfile, ".note.gnu.build-id",
963                                "\xde\xad\xbe\xef");
964   // It's a trap! If "baadf00d" is seen, we read the wrong file.
965   testing::WriteElfWithBuildid(tmpfile_in_ns, ".note.gnu.build-id",
966                                "\xba\xad\xf0\x0d");
967   struct stat tmp_stat;
968   struct stat tmp_in_ns_stat;
969   ASSERT_EQ(stat(tmpfile.c_str(), &tmp_stat), 0);
970   ASSERT_EQ(stat(tmpfile_in_ns.c_str(), &tmp_in_ns_stat), 0);
971   // inodes are often issued sequentially, so go backwards rather than forwards.
972   const ino_t bad_ino = tmp_stat.st_ino - 1;
973   ASSERT_NE(bad_ino, tmp_in_ns_stat.st_ino);
974 
975   // Create perf.data
976   std::stringstream input;
977 
978   // header
979   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
980 
981   // data
982 
983   // PERF_RECORD_HEADER_ATTR
984   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
985                                               true /*sample_id_all*/)
986       .WriteTo(&input);
987 
988   // PERF_RECORD_MMAP2
989   // - Process doesn't exist, but file exists in our own namespace.
990   testing::ExampleMmap2Event(pid, pid, 0x1c1000, 0x1000, 0, tmpfile_in_ns,
991                              testing::SampleInfo().Tid(pid, tid))
992       .WithDeviceInfo(major(tmp_stat.st_dev), minor(tmp_stat.st_dev), bad_ino)
993       .WriteTo(&input);  // 0
994 
995   // PERF_RECORD_SAMPLE
996   testing::ExamplePerfSampleEvent(
997       testing::SampleInfo().Ip(0x00000000001c1000).Tid(pid))
998       .WriteTo(&input);  // 1
999 
1000   //
1001   // Parse input.
1002   //
1003 
1004   PerfReader reader;
1005   EXPECT_TRUE(reader.ReadFromString(input.str()));
1006 
1007   PerfParserOptions options;
1008   options.read_missing_buildids = true;
1009   options.sample_mapping_percentage_threshold = 0;
1010   PerfParser parser(&reader, options);
1011   EXPECT_TRUE(parser.ParseRawEvents());
1012 
1013   EXPECT_EQ(1, parser.stats().num_mmap_events);
1014   EXPECT_EQ(1, parser.stats().num_sample_events);
1015   EXPECT_EQ(1, parser.stats().num_sample_events_mapped);
1016 
1017   const std::vector<ParsedEvent> &events = parser.parsed_events();
1018   ASSERT_EQ(2, events.size());
1019 
1020   EXPECT_EQ(tmpfile_in_ns, events[1].dso_and_offset.dso_name());
1021   // Wrong inode, so rejects all candidates.
1022   EXPECT_EQ("", events[1].dso_and_offset.build_id());
1023 
1024   thread.Join();
1025 }
1026 
1027 // Root task <pid>/<pid> Filesystem:
1028 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
1029 // * "/tmp/quipper_mnt.../file_in_namespace"  buildid: baadf00d  ino: Y
1030 // Container task <pid>/<tid> Filesystem:
1031 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
1032 // * "/tmp/quipper_mnt.../file_in_namespace"  buildid: deadbeef  ino: X
1033 // <path> = marked with *
1034 // MMAP: <pid+10>/<tid+1>, <path>, ino: Not available
1035 // Reject (not found): /proc/<tid+1>/root/<path>
1036 // Reject (not found): /proc/<pid+10>/root/<path>
1037 // Accept (falsely): /<path>
1038 // Expected buildid for <path>: "baadf00d" (even though incorrect)
TEST(PerfParserTest,ReadsBuildidsInMountNamespace_TriesRootFsNoInodeToReject)1039 TEST(PerfParserTest, ReadsBuildidsInMountNamespace_TriesRootFsNoInodeToReject) {
1040   if (!HaveCapability(CAP_SYS_ADMIN)) return;  // Skip test.
1041   ScopedTempDir tmpdir("/tmp/quipper_tmp.");
1042   ScopedTempDir mntdir("/tmp/quipper_mnt.");
1043   RunInMountNamespaceThread thread(tmpdir.path(), mntdir.path());
1044   thread.Start();
1045   const pid_t pid = getpid();
1046   const pid_t tid = thread.tid();
1047 
1048   const string tmpfile = tmpdir.path() + "file_in_namespace";
1049   const string tmpfile_in_ns = mntdir.path() + "file_in_namespace";
1050   InitializeLibelf();
1051   testing::WriteElfWithBuildid(tmpfile, ".note.gnu.build-id",
1052                                "\xde\xad\xf0\x0d");
1053   // It's a trap! If "baadf00d" is seen, we read the wrong file.
1054   testing::WriteElfWithBuildid(tmpfile_in_ns, ".note.gnu.build-id",
1055                                "\xba\xad\xf0\x0d");
1056   struct stat tmp_stat;
1057   ASSERT_EQ(stat(tmpfile.c_str(), &tmp_stat), 0);
1058 
1059   // Create perf.data
1060   std::stringstream input;
1061 
1062   // header
1063   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1064 
1065   // data
1066 
1067   // PERF_RECORD_HEADER_ATTR
1068   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1069                                               true /*sample_id_all*/)
1070       .WriteTo(&input);
1071 
1072   // PERF_RECORD_MMAP
1073   // - Process & thread don't exist, but file exists in our own namespace.
1074   testing::ExampleMmapEvent(pid, 0x1c1000, 0x1000, 0, tmpfile_in_ns,
1075                             testing::SampleInfo().Tid(pid + 10, tid + 1))
1076       .WriteTo(&input);  // 0
1077 
1078   // PERF_RECORD_SAMPLE
1079   testing::ExamplePerfSampleEvent(
1080       testing::SampleInfo().Ip(0x00000000001c1000).Tid(pid))
1081       .WriteTo(&input);  // 1
1082 
1083   //
1084   // Parse input.
1085   //
1086 
1087   PerfReader reader;
1088   EXPECT_TRUE(reader.ReadFromString(input.str()));
1089 
1090   PerfParserOptions options;
1091   options.read_missing_buildids = true;
1092   options.sample_mapping_percentage_threshold = 0;
1093   PerfParser parser(&reader, options);
1094   EXPECT_TRUE(parser.ParseRawEvents());
1095 
1096   EXPECT_EQ(1, parser.stats().num_mmap_events);
1097   EXPECT_EQ(1, parser.stats().num_sample_events);
1098   EXPECT_EQ(1, parser.stats().num_sample_events_mapped);
1099 
1100   const std::vector<ParsedEvent> &events = parser.parsed_events();
1101   ASSERT_EQ(2, events.size());
1102 
1103   EXPECT_EQ(tmpfile_in_ns, events[1].dso_and_offset.dso_name());
1104   // We'll read the wrong file b/c we couldn't reject based on inode:
1105   EXPECT_EQ("baadf00d", events[1].dso_and_offset.build_id());
1106 
1107   thread.Join();
1108 }
1109 
1110 // Root task <pid>/<pid> Filesystem:
1111 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
1112 // * "/tmp/quipper_mnt.../file_in_namespace"  buildid: baadf00d  ino: Y
1113 // Container task <pid>/<tid> Filesystem:
1114 //   "/tmp/quipper_tmp.../file_in_namespace"  buildid: deadbeef  ino: X
1115 // * "/tmp/quipper_mnt.../file_in_namespace"  buildid: deadbeef  ino: X
1116 // <path> = marked with *
1117 // MMAP2(0): <pid>/<tid>, <path>, <maj+1>/<min>,  ino: X
1118 // MMAP2(1): <pid>/<tid>, <path>, <maj>/<min+1>,  ino: X
1119 // MMAP2(2): <pid>/<tid>, <path>, <maj>/<min>,    ino: X+1
1120 // SAMPLE(3): <pid>/<tid>, addr in MMAP2(0)
1121 // SAMPLE(4): <pid>/<tid>, addr in MMAP2(1)
1122 // SAMPLE(5): <pid>/<tid>, addr in MMAP2(2)
1123 // Expected buildid for <path>: ""
1124 //
1125 // with multiple device/ino numbers. This is really a shortcoming of perf--
1126 // it can only associate a buildid with a path. If the same path exists in
1127 // multiple containers but refers to different files (device/inode), then
1128 // it's hard to know what to do. Similarly, PerfParser associates a DSO name
1129 // (path) with a single DSOInfo and device/inode info therein, although it
1130 // tracks all threads the DSO name was seen in. This test is set up such that
1131 // all MMAPs should be rejected, but in truth PerfParser only compares the
1132 // device/inode of the file against the device/inode of one of the MMAPs.
1133 // A better thing to do might be to track a
1134 // map<tuple<maj,min,ino,path>, DSOInfo>, but even so, it will be impossible
1135 // to store unambiguously in perf.data.
TEST(PerfParserTest,ReadsBuildidsInMountNamespace_DifferentDevOrIno)1136 TEST(PerfParserTest, ReadsBuildidsInMountNamespace_DifferentDevOrIno) {
1137   if (!HaveCapability(CAP_SYS_ADMIN)) return;  // Skip test.
1138   ScopedTempDir tmpdir("/tmp/quipper_tmp.");
1139   ScopedTempDir mntdir("/tmp/quipper_mnt.");
1140   RunInMountNamespaceThread thread(tmpdir.path(), mntdir.path());
1141   thread.Start();
1142   const pid_t pid = getpid();
1143   const pid_t tid = thread.tid();
1144 
1145   const string tmpfile = tmpdir.path() + "file_in_namespace";
1146   const string tmpfile_in_ns = mntdir.path() + "file_in_namespace";
1147   InitializeLibelf();
1148   testing::WriteElfWithBuildid(tmpfile, ".note.gnu.build-id",
1149                                "\xde\xad\xf0\x0d");
1150   // It's a trap! If "baadf00d" is seen, we read the wrong file.
1151   testing::WriteElfWithBuildid(tmpfile_in_ns, ".note.gnu.build-id",
1152                                "\xba\xad\xf0\x0d");
1153   struct stat tmp_stat;
1154   struct stat tmp_in_ns_stat;
1155   ASSERT_EQ(stat(tmpfile.c_str(), &tmp_stat), 0);
1156   ASSERT_EQ(stat(tmpfile_in_ns.c_str(), &tmp_in_ns_stat), 0);
1157   // inodes are often issued sequentially, so go backwards rather than forwards.
1158   const ino_t bad_ino = tmp_stat.st_ino - 1;
1159   ASSERT_NE(bad_ino, tmp_in_ns_stat.st_ino);
1160 
1161   // Create perf.data
1162   std::stringstream input;
1163 
1164   // header
1165   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1166 
1167   // data
1168 
1169   // PERF_RECORD_HEADER_ATTR
1170   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1171                                               true /*sample_id_all*/)
1172       .WriteTo(&input);
1173 
1174   // PERF_RECORD_MMAP2
1175   // - Wrong major number
1176   testing::ExampleMmap2Event(pid, tid, 0x1c1000, 0x1000, 0, tmpfile_in_ns,
1177                              testing::SampleInfo().Tid(pid, tid))
1178       .WithDeviceInfo(major(tmp_stat.st_dev) + 1, minor(tmp_stat.st_dev),
1179                       tmp_stat.st_ino)
1180       .WriteTo(&input);  // 0
1181   // - Wrong minor number
1182   testing::ExampleMmap2Event(pid, tid, 0x1c2000, 0x1000, 0, tmpfile_in_ns,
1183                              testing::SampleInfo().Tid(pid, tid))
1184       .WithDeviceInfo(major(tmp_stat.st_dev), minor(tmp_stat.st_dev) + 1,
1185                       tmp_stat.st_ino)
1186       .WriteTo(&input);  // 1
1187   // - Wrong inode number
1188   testing::ExampleMmap2Event(pid, tid, 0x1c3000, 0x1000, 0, tmpfile_in_ns,
1189                              testing::SampleInfo().Tid(pid, tid))
1190       .WithDeviceInfo(major(tmp_stat.st_dev), minor(tmp_stat.st_dev),
1191                       bad_ino)
1192       .WriteTo(&input);  // 2
1193 
1194   // PERF_RECORD_SAMPLE
1195   testing::ExamplePerfSampleEvent(
1196       testing::SampleInfo().Ip(0x00000000001c1000).Tid(pid, tid))
1197       .WriteTo(&input);  // 3
1198   testing::ExamplePerfSampleEvent(
1199       testing::SampleInfo().Ip(0x00000000001c2000).Tid(pid, tid))
1200       .WriteTo(&input);  // 4
1201   testing::ExamplePerfSampleEvent(
1202       testing::SampleInfo().Ip(0x00000000001c3000).Tid(pid, tid))
1203       .WriteTo(&input);  // 5
1204 
1205   //
1206   // Parse input.
1207   //
1208 
1209   PerfReader reader;
1210   EXPECT_TRUE(reader.ReadFromString(input.str()));
1211 
1212   PerfParserOptions options;
1213   options.read_missing_buildids = true;
1214   options.sample_mapping_percentage_threshold = 0;
1215   PerfParser parser(&reader, options);
1216   EXPECT_TRUE(parser.ParseRawEvents());
1217 
1218   EXPECT_EQ(3, parser.stats().num_mmap_events);
1219   EXPECT_EQ(3, parser.stats().num_sample_events);
1220   EXPECT_EQ(3, parser.stats().num_sample_events_mapped);
1221 
1222   const std::vector<ParsedEvent> &events = parser.parsed_events();
1223   ASSERT_EQ(6, events.size());
1224 
1225   // Buildid should not be found for any of the samples.
1226   for (int i : {3, 4, 5}) {
1227     EXPECT_EQ(tmpfile_in_ns, events[i].dso_and_offset.dso_name());
1228     EXPECT_EQ("", events[i].dso_and_offset.build_id());
1229   }
1230 
1231   thread.Join();
1232 }
1233 
TEST(PerfParserTest,OverwriteBuildidIfAlreadyKnown)1234 TEST(PerfParserTest, OverwriteBuildidIfAlreadyKnown) {
1235   ScopedTempDir tmpdir("/tmp/quipper_tmp.");
1236   const string known_file = tmpdir.path() + "buildid_already_known";
1237   const string known_file_to_overwrite =
1238       tmpdir.path() + "buildid_already_known_overwrite";
1239   const string unknown_file = tmpdir.path() + "buildid_not_known";
1240   InitializeLibelf();
1241   testing::WriteElfWithBuildid(known_file_to_overwrite, ".note.gnu.build-id",
1242                                "\xf0\x01\x57\xea");
1243   testing::WriteElfWithBuildid(unknown_file, ".note.gnu.build-id",
1244                                "\xc0\x01\xd0\x0d");
1245 
1246   std::stringstream input;
1247 
1248   // header
1249   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1250 
1251   // data
1252 
1253   // PERF_RECORD_HEADER_ATTR
1254   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1255                                               true /*sample_id_all*/)
1256       .WriteTo(&input);
1257 
1258   // PERF_RECORD_MMAP
1259   testing::ExampleMmapEvent(1001, 0x1c1000, 0x1000, 0, known_file,
1260                             testing::SampleInfo().Tid(1001))
1261       .WriteTo(&input);  // 0
1262   // becomes: 0x0000, 0x1000, 0
1263   testing::ExampleMmapEvent(1001, 0x1c2000, 0x2000, 0, known_file_to_overwrite,
1264                             testing::SampleInfo().Tid(1001))
1265       .WriteTo(&input);  // 1
1266   // becomes: 0x1000, 0x2000, 0
1267   testing::ExampleMmapEvent(1001, 0x1c4000, 0x2000, 0x2000, unknown_file,
1268                             testing::SampleInfo().Tid(1001))
1269       .WriteTo(&input);  // 2
1270   // becomes: 0x3000, 0x2000, 0x2000
1271 
1272   // PERF_RECORD_HEADER_BUILDID                                // N/A
1273   {
1274     string build_id_filename(known_file);
1275     build_id_filename.resize(Align<u64>(known_file.size()));  // null-pad
1276     const size_t event_size =
1277         sizeof(struct build_id_event) + build_id_filename.size();
1278     const struct build_id_event event = {
1279         .header =
1280             {
1281                 .type = PERF_RECORD_HEADER_BUILD_ID,
1282                 .misc = 0,
1283                 .size = static_cast<u16>(event_size),
1284             },
1285         .pid = -1,
1286         .build_id = {0xde, 0xad, 0xbe, 0xef},
1287     };
1288     input.write(reinterpret_cast<const char *>(&event), sizeof(event));
1289     input.write(build_id_filename.data(), build_id_filename.size());
1290   }
1291 
1292   // PERF_RECORD_HEADER_BUILDID                                // N/A
1293   {
1294     string build_id_filename(known_file_to_overwrite);
1295     // null-pad
1296     build_id_filename.resize(Align<u64>(known_file_to_overwrite.size()));
1297     const size_t event_size =
1298         sizeof(struct build_id_event) + build_id_filename.size();
1299     const struct build_id_event event = {
1300         .header =
1301             {
1302                 .type = PERF_RECORD_HEADER_BUILD_ID,
1303                 .misc = 0,
1304                 .size = static_cast<u16>(event_size),
1305             },
1306         .pid = -1,
1307         .build_id = {0xca, 0xfe, 0xba, 0xbe},
1308     };
1309     input.write(reinterpret_cast<const char *>(&event), sizeof(event));
1310     input.write(build_id_filename.data(), build_id_filename.size());
1311   }
1312 
1313   // PERF_RECORD_SAMPLE
1314   testing::ExamplePerfSampleEvent(
1315       testing::SampleInfo().Ip(0x00000000001c100a).Tid(1001))
1316       .WriteTo(&input);  // 3
1317   testing::ExamplePerfSampleEvent(
1318       testing::SampleInfo().Ip(0x00000000001c300b).Tid(1001))
1319       .WriteTo(&input);  // 4
1320   testing::ExamplePerfSampleEvent(
1321       testing::SampleInfo().Ip(0x00000000001c400c).Tid(1001))
1322       .WriteTo(&input);  // 5
1323 
1324   //
1325   // Parse input.
1326   //
1327 
1328   PerfReader reader;
1329   EXPECT_TRUE(reader.ReadFromString(input.str()));
1330 
1331   PerfParserOptions options;
1332   options.read_missing_buildids = true;
1333   options.sample_mapping_percentage_threshold = 0;
1334   PerfParser parser(&reader, options);
1335   EXPECT_TRUE(parser.ParseRawEvents());
1336 
1337   EXPECT_EQ(3, parser.stats().num_mmap_events);
1338   EXPECT_EQ(3, parser.stats().num_sample_events);
1339   EXPECT_EQ(3, parser.stats().num_sample_events_mapped);
1340 
1341   const std::vector<ParsedEvent> &events = parser.parsed_events();
1342   ASSERT_EQ(6, events.size());
1343 
1344   EXPECT_EQ(known_file, events[3].dso_and_offset.dso_name());
1345   EXPECT_EQ("deadbeef00000000000000000000000000000000",
1346             events[3].dso_and_offset.build_id());
1347   EXPECT_EQ(known_file_to_overwrite, events[4].dso_and_offset.dso_name());
1348   EXPECT_EQ("f00157ea", events[4].dso_and_offset.build_id());
1349   EXPECT_EQ(unknown_file, events[5].dso_and_offset.dso_name());
1350   EXPECT_EQ("c001d00d", events[5].dso_and_offset.build_id());
1351 }
1352 
TEST(PerfParserTest,OnlyReadsBuildidIfSampled)1353 TEST(PerfParserTest, OnlyReadsBuildidIfSampled) {
1354   ScopedTempDir tmpdir("/tmp/quipper_tmp.");
1355   const string unknown_file = tmpdir.path() + "buildid_not_known";
1356   InitializeLibelf();
1357   testing::WriteElfWithBuildid(unknown_file, ".note.gnu.build-id",
1358                                "\xc0\x01\xd0\x0d");
1359 
1360   std::stringstream input;
1361 
1362   // header
1363   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1364 
1365   // data
1366 
1367   // PERF_RECORD_HEADER_ATTR
1368   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1369                                               true /*sample_id_all*/)
1370       .WriteTo(&input);
1371 
1372   // PERF_RECORD_MMAP
1373   testing::ExampleMmapEvent(1001, 0x1c1000, 0x1000, 0, unknown_file,
1374                             testing::SampleInfo().Tid(1001))
1375       .WriteTo(&input);  // 0
1376   // becomes: 0x0000, 0x1000, 0
1377 
1378   // PERF_RECORD_SAMPLE
1379   // - Sample outside mmap
1380   testing::ExamplePerfSampleEvent(
1381       testing::SampleInfo().Ip(0x00000000001c300a).Tid(1001))
1382       .WriteTo(&input);  // 1
1383 
1384   //
1385   // Parse input.
1386   //
1387 
1388   PerfReader reader;
1389   EXPECT_TRUE(reader.ReadFromString(input.str()));
1390 
1391   PerfParserOptions options;
1392   options.read_missing_buildids = true;
1393   options.sample_mapping_percentage_threshold = 0;
1394   PerfParser parser(&reader, options);
1395   EXPECT_TRUE(parser.ParseRawEvents());
1396 
1397   EXPECT_EQ(1, parser.stats().num_mmap_events);
1398   EXPECT_EQ(1, parser.stats().num_sample_events);
1399   EXPECT_EQ(0, parser.stats().num_sample_events_mapped);
1400 
1401   const std::vector<ParsedEvent> &events = parser.parsed_events();
1402   ASSERT_EQ(2, events.size());
1403 
1404   EXPECT_EQ("", events[1].dso_and_offset.dso_name());
1405   EXPECT_EQ("", events[1].dso_and_offset.build_id());
1406 
1407   std::map<string, string> filenames_to_build_ids;
1408   reader.GetFilenamesToBuildIDs(&filenames_to_build_ids);
1409   auto it = filenames_to_build_ids.find(unknown_file);
1410   EXPECT_EQ(filenames_to_build_ids.end(), it) << it->first << " " << it->second;
1411 }
1412 
TEST(PerfParserTest,HandlesFinishedRoundEventsAndSortsByTime)1413 TEST(PerfParserTest, HandlesFinishedRoundEventsAndSortsByTime) {
1414   // For now at least, we are ignoring PERF_RECORD_FINISHED_ROUND events.
1415 
1416   std::stringstream input;
1417 
1418   // header
1419   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1420 
1421   // data
1422 
1423   // PERF_RECORD_HEADER_ATTR
1424   testing::ExamplePerfEventAttrEvent_Hardware(
1425       PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME,
1426       true /*sample_id_all*/)
1427       .WriteTo(&input);
1428 
1429   // PERF_RECORD_MMAP
1430   testing::ExampleMmapEvent(1001, 0x1c1000, 0x1000, 0, "/usr/lib/foo.so",
1431                             testing::SampleInfo().Tid(1001).Time(12300010))
1432       .WriteTo(&input);
1433   // becomes: 0x0000, 0x1000, 0
1434 
1435   // PERF_RECORD_SAMPLE
1436   testing::ExamplePerfSampleEvent(
1437       testing::SampleInfo().Ip(0x00000000001c1000).Tid(1001).Time(12300020))
1438       .WriteTo(&input);  // 1
1439   testing::ExamplePerfSampleEvent(
1440       testing::SampleInfo().Ip(0x00000000001c1000).Tid(1001).Time(12300030))
1441       .WriteTo(&input);  // 2
1442   // PERF_RECORD_FINISHED_ROUND
1443   testing::FinishedRoundEvent().WriteTo(&input);  // N/A
1444 
1445   // PERF_RECORD_SAMPLE
1446   testing::ExamplePerfSampleEvent(
1447       testing::SampleInfo().Ip(0x00000000001c1000).Tid(1001).Time(12300050))
1448       .WriteTo(&input);  // 3
1449   testing::ExamplePerfSampleEvent(
1450       testing::SampleInfo().Ip(0x00000000001c1000).Tid(1001).Time(12300040))
1451       .WriteTo(&input);  // 4
1452   // PERF_RECORD_FINISHED_ROUND
1453   testing::FinishedRoundEvent().WriteTo(&input);  // N/A
1454 
1455   //
1456   // Parse input.
1457   //
1458 
1459   PerfReader reader;
1460   EXPECT_TRUE(reader.ReadFromString(input.str()));
1461 
1462   PerfParserOptions options;
1463   options.sample_mapping_percentage_threshold = 0;
1464   options.sort_events_by_time = true;
1465   PerfParser parser(&reader, options);
1466   EXPECT_TRUE(parser.ParseRawEvents());
1467 
1468   EXPECT_EQ(1, parser.stats().num_mmap_events);
1469   EXPECT_EQ(4, parser.stats().num_sample_events);
1470   EXPECT_EQ(4, parser.stats().num_sample_events_mapped);
1471 
1472   const std::vector<ParsedEvent> &events = parser.parsed_events();
1473   ASSERT_EQ(5, events.size());
1474 
1475   EXPECT_EQ(PERF_RECORD_MMAP, events[0].event_ptr->header().type());
1476   EXPECT_EQ(PERF_RECORD_SAMPLE, events[1].event_ptr->header().type());
1477   EXPECT_EQ(12300020, events[1].event_ptr->sample_event().sample_time_ns());
1478   EXPECT_EQ(PERF_RECORD_SAMPLE, events[2].event_ptr->header().type());
1479   EXPECT_EQ(12300030, events[2].event_ptr->sample_event().sample_time_ns());
1480   EXPECT_EQ(PERF_RECORD_SAMPLE, events[3].event_ptr->header().type());
1481   EXPECT_EQ(12300040, events[3].event_ptr->sample_event().sample_time_ns());
1482   EXPECT_EQ(PERF_RECORD_SAMPLE, events[4].event_ptr->header().type());
1483   EXPECT_EQ(12300050, events[4].event_ptr->sample_event().sample_time_ns());
1484 }
1485 
TEST(PerfParserTest,MmapCoversEntireAddressSpace)1486 TEST(PerfParserTest, MmapCoversEntireAddressSpace) {
1487   std::stringstream input;
1488 
1489   // header
1490   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1491 
1492   // PERF_RECORD_HEADER_ATTR
1493   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1494                                               true /*sample_id_all*/)
1495       .WriteTo(&input);
1496 
1497   // PERF_RECORD_MMAP, a kernel mapping that covers the whole space.
1498   const uint32_t kKernelMmapPid = UINT32_MAX;
1499   testing::ExampleMmapEvent(kKernelMmapPid, 0, UINT64_MAX, 0,
1500                             "[kernel.kallsyms]_text",
1501                             testing::SampleInfo().Tid(kKernelMmapPid, 0))
1502       .WriteTo(&input);
1503 
1504   // PERF_RECORD_MMAP, a shared object library.
1505   testing::ExampleMmapEvent(1234, 0x7f008e000000, 0x2000000, 0,
1506                             "/usr/lib/libfoo.so",
1507                             testing::SampleInfo().Tid(1234, 1234))
1508       .WriteTo(&input);
1509 
1510   // PERF_RECORD_SAMPLE, within library.
1511   testing::ExamplePerfSampleEvent(
1512       testing::SampleInfo().Ip(0x7f008e123456).Tid(1234, 1235))
1513       .WriteTo(&input);
1514   // PERF_RECORD_SAMPLE, within kernel.
1515   testing::ExamplePerfSampleEvent(
1516       testing::SampleInfo().Ip(0x8000819e).Tid(1234, 1235))
1517       .WriteTo(&input);
1518   // PERF_RECORD_SAMPLE, within library.
1519   testing::ExamplePerfSampleEvent(
1520       testing::SampleInfo().Ip(0x7f008fdeadbe).Tid(1234, 1235))
1521       .WriteTo(&input);
1522   // PERF_RECORD_SAMPLE, within kernel.
1523   testing::ExamplePerfSampleEvent(
1524       testing::SampleInfo().Ip(0xffffffff8100cafe).Tid(1234, 1235))
1525       .WriteTo(&input);
1526 
1527   //
1528   // Parse input.
1529   //
1530 
1531   PerfReader reader;
1532   EXPECT_TRUE(reader.ReadFromString(input.str()));
1533 
1534   PerfParserOptions options;
1535   options.do_remap = true;
1536   PerfParser parser(&reader, options);
1537   EXPECT_TRUE(parser.ParseRawEvents());
1538 
1539   EXPECT_EQ(2, parser.stats().num_mmap_events);
1540   EXPECT_EQ(4, parser.stats().num_sample_events);
1541   EXPECT_EQ(4, parser.stats().num_sample_events_mapped);
1542 
1543   const std::vector<ParsedEvent> &events = parser.parsed_events();
1544   ASSERT_EQ(6, events.size());
1545 
1546   EXPECT_EQ(PERF_RECORD_MMAP, events[0].event_ptr->header().type());
1547   EXPECT_EQ("[kernel.kallsyms]_text",
1548             events[0].event_ptr->mmap_event().filename());
1549   EXPECT_EQ(PERF_RECORD_MMAP, events[1].event_ptr->header().type());
1550   EXPECT_EQ("/usr/lib/libfoo.so", events[1].event_ptr->mmap_event().filename());
1551 
1552   // Sample from library.
1553   EXPECT_EQ(PERF_RECORD_SAMPLE, events[2].event_ptr->header().type());
1554   EXPECT_EQ("/usr/lib/libfoo.so", events[2].dso_and_offset.dso_name());
1555   EXPECT_EQ(0x123456, events[2].dso_and_offset.offset());
1556 
1557   // Sample from kernel.
1558   EXPECT_EQ(PERF_RECORD_SAMPLE, events[3].event_ptr->header().type());
1559   EXPECT_EQ("[kernel.kallsyms]_text", events[3].dso_and_offset.dso_name());
1560   EXPECT_EQ(0x8000819e, events[3].dso_and_offset.offset());
1561 
1562   // Sample from library.
1563   EXPECT_EQ(PERF_RECORD_SAMPLE, events[4].event_ptr->header().type());
1564   EXPECT_EQ("/usr/lib/libfoo.so", events[4].dso_and_offset.dso_name());
1565   EXPECT_EQ(0x1deadbe, events[4].dso_and_offset.offset());
1566 
1567   // Sample from kernel.
1568   EXPECT_EQ(PERF_RECORD_SAMPLE, events[5].event_ptr->header().type());
1569   EXPECT_EQ("[kernel.kallsyms]_text", events[5].dso_and_offset.dso_name());
1570   EXPECT_EQ(0xffffffff8100cafe, events[5].dso_and_offset.offset());
1571 }
1572 
TEST(PerfParserTest,HugePagesMappings)1573 TEST(PerfParserTest, HugePagesMappings) {
1574   std::stringstream input;
1575 
1576   // header
1577   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1578 
1579   // PERF_RECORD_HEADER_ATTR
1580   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1581                                               true /*sample_id_all*/)
1582       .WriteTo(&input);
1583 
1584   // PERF_RECORD_MMAP, a normal mapping.
1585   testing::ExampleMmapEvent(1234, 0x40000000, 0x18000, 0, "/usr/lib/libfoo.so",
1586                             testing::SampleInfo().Tid(1234, 1234))
1587       .WriteTo(&input);
1588 
1589   // PERF_RECORD_SAMPLE, within library.
1590   testing::ExamplePerfSampleEvent(
1591       testing::SampleInfo().Ip(0x40000100).Tid(1234, 1235))
1592       .WriteTo(&input);
1593 
1594   // Split Chrome mapping #1, with a huge pages section in the middle.
1595   testing::ExampleMmapEvent(1234, 0x40018000, 0x1e8000, 0,
1596                             "/opt/google/chrome/chrome",
1597                             testing::SampleInfo().Tid(1234, 1234))
1598       .WriteTo(&input);
1599   testing::ExampleMmapEvent(1234, 0x40200000, 0x1c00000, 0, "//anon",
1600                             testing::SampleInfo().Tid(1234, 1234))
1601       .WriteTo(&input);
1602   testing::ExampleMmapEvent(1234, 0x41e00000, 0x4000000, 0x1de8000,
1603                             "/opt/google/chrome/chrome",
1604                             testing::SampleInfo().Tid(1234, 1234))
1605       .WriteTo(&input);
1606 
1607   // Split Chrome mapping #2, starting with a huge pages section (no preceding
1608   // normal mapping).
1609   testing::ExampleMmapEvent(2345, 0x45e00000, 0x1e00000, 0, "//anon",
1610                             testing::SampleInfo().Tid(2345, 2346))
1611       .WriteTo(&input);
1612   testing::ExampleMmapEvent(2345, 0x47c00000, 0x4000000, 0x1e00000,
1613                             "/opt/google/chrome/chrome",
1614                             testing::SampleInfo().Tid(2345, 2346))
1615       .WriteTo(&input);
1616 
1617   // PERF_RECORD_SAMPLE, within Chrome #1 (before huge pages mapping).
1618   testing::ExamplePerfSampleEvent(
1619       testing::SampleInfo().Ip(0x40018300).Tid(1234, 1235))
1620       .WriteTo(&input);
1621   // PERF_RECORD_SAMPLE, within Chrome #1 (within huge pages mapping).
1622   testing::ExamplePerfSampleEvent(
1623       testing::SampleInfo().Ip(0x40020400).Tid(1234, 1235))
1624       .WriteTo(&input);
1625   // PERF_RECORD_SAMPLE, within Chrome #1 (after huge pages mapping).
1626   testing::ExamplePerfSampleEvent(
1627       testing::SampleInfo().Ip(0x41e20500).Tid(1234, 1235))
1628       .WriteTo(&input);
1629 
1630   // PERF_RECORD_SAMPLE, within library.
1631   testing::ExamplePerfSampleEvent(
1632       testing::SampleInfo().Ip(0x40000700).Tid(1234, 1235))
1633       .WriteTo(&input);
1634 
1635   // PERF_RECORD_SAMPLE, within Chrome #2 (within huge pages mapping).
1636   testing::ExamplePerfSampleEvent(
1637       testing::SampleInfo().Ip(0x45e01300).Tid(2345, 2346))
1638       .WriteTo(&input);
1639   // PERF_RECORD_SAMPLE, within Chrome #2 (after huge pages mapping).
1640   testing::ExamplePerfSampleEvent(
1641       testing::SampleInfo().Ip(0x45e02f00).Tid(2345, 2346))
1642       .WriteTo(&input);
1643 
1644   //
1645   // Parse input.
1646   //
1647 
1648   PerfReader reader;
1649   EXPECT_TRUE(reader.ReadFromString(input.str()));
1650 
1651   PerfParserOptions options;
1652   options.deduce_huge_page_mappings = true;
1653   options.combine_mappings = true;
1654   PerfParser parser(&reader, options);
1655   EXPECT_TRUE(parser.ParseRawEvents());
1656 
1657   EXPECT_EQ(3, parser.stats().num_mmap_events);
1658   EXPECT_EQ(7, parser.stats().num_sample_events);
1659   EXPECT_EQ(7, parser.stats().num_sample_events_mapped);
1660 
1661   const std::vector<ParsedEvent> &events = parser.parsed_events();
1662   ASSERT_EQ(10, events.size());
1663 
1664   EXPECT_EQ(PERF_RECORD_MMAP, events[0].event_ptr->header().type());
1665   EXPECT_EQ("/usr/lib/libfoo.so", events[0].event_ptr->mmap_event().filename());
1666   EXPECT_EQ(0x40000000, events[0].event_ptr->mmap_event().start());
1667   EXPECT_EQ(0x18000, events[0].event_ptr->mmap_event().len());
1668   EXPECT_EQ(0x0, events[0].event_ptr->mmap_event().pgoff());
1669 
1670   // Sample from library.
1671   EXPECT_EQ(PERF_RECORD_SAMPLE, events[1].event_ptr->header().type());
1672   EXPECT_EQ("/usr/lib/libfoo.so", events[1].dso_and_offset.dso_name());
1673   EXPECT_EQ(0x100, events[1].dso_and_offset.offset());
1674 
1675   // The split Chrome mappings should have been combined.
1676   EXPECT_EQ(PERF_RECORD_MMAP, events[2].event_ptr->header().type());
1677   EXPECT_EQ("/opt/google/chrome/chrome",
1678             events[2].event_ptr->mmap_event().filename());
1679   EXPECT_EQ(0x40018000, events[2].event_ptr->mmap_event().start());
1680   EXPECT_EQ(0x5de8000, events[2].event_ptr->mmap_event().len());
1681   EXPECT_EQ(0x0, events[2].event_ptr->mmap_event().pgoff());
1682 
1683   EXPECT_EQ(PERF_RECORD_MMAP, events[3].event_ptr->header().type());
1684   EXPECT_EQ("/opt/google/chrome/chrome",
1685             events[3].event_ptr->mmap_event().filename());
1686   EXPECT_EQ(0x45e00000, events[3].event_ptr->mmap_event().start());
1687   EXPECT_EQ(0x5e00000, events[3].event_ptr->mmap_event().len());
1688   EXPECT_EQ(0x0, events[3].event_ptr->mmap_event().pgoff());
1689 
1690   // Sample from Chrome (before huge pages mapping).
1691   EXPECT_EQ(PERF_RECORD_SAMPLE, events[4].event_ptr->header().type());
1692   EXPECT_EQ("/opt/google/chrome/chrome", events[4].dso_and_offset.dso_name());
1693   EXPECT_EQ(0x300, events[4].dso_and_offset.offset());
1694 
1695   // Sample from Chrome (within huge pages mapping).
1696   EXPECT_EQ(PERF_RECORD_SAMPLE, events[5].event_ptr->header().type());
1697   EXPECT_EQ("/opt/google/chrome/chrome", events[5].dso_and_offset.dso_name());
1698   EXPECT_EQ(0x8400, events[5].dso_and_offset.offset());
1699 
1700   // Sample from Chrome (after huge pages mapping).
1701   EXPECT_EQ(PERF_RECORD_SAMPLE, events[6].event_ptr->header().type());
1702   EXPECT_EQ("/opt/google/chrome/chrome", events[6].dso_and_offset.dso_name());
1703   EXPECT_EQ(0x1e08500, events[6].dso_and_offset.offset());
1704 
1705   // Sample from library.
1706   EXPECT_EQ(PERF_RECORD_SAMPLE, events[7].event_ptr->header().type());
1707   EXPECT_EQ("/usr/lib/libfoo.so", events[7].dso_and_offset.dso_name());
1708   EXPECT_EQ(0x700, events[7].dso_and_offset.offset());
1709 
1710   // Sample from Chrome #2 (within huge pages mapping).
1711   EXPECT_EQ(PERF_RECORD_SAMPLE, events[8].event_ptr->header().type());
1712   EXPECT_EQ("/opt/google/chrome/chrome", events[8].dso_and_offset.dso_name());
1713   EXPECT_EQ(0x1300, events[8].dso_and_offset.offset());
1714 
1715   // Sample from Chrome #2 (after huge pages mapping).
1716   EXPECT_EQ(PERF_RECORD_SAMPLE, events[9].event_ptr->header().type());
1717   EXPECT_EQ("/opt/google/chrome/chrome", events[9].dso_and_offset.dso_name());
1718   EXPECT_EQ(0x2f00, events[9].dso_and_offset.offset());
1719 }
1720 
TEST(PerfParserTest,Regression62446346)1721 TEST(PerfParserTest, Regression62446346) {
1722   std::stringstream input;
1723 
1724   // header
1725   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1726 
1727   // PERF_RECORD_HEADER_ATTR
1728   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1729                                               true /*sample_id_all*/)
1730       .WriteTo(&input);
1731 
1732   // Perf infers the filename is "file", but at offset 0 for
1733   // hugepage-backed, anonymous mappings.
1734   //
1735   // vaddr start   - vaddr end     vaddr-size    elf-offset
1736   // [0x55a685bfb000-55a685dfb000) (0x200000)   @ 0]:          file
1737   // [0x55a685dfb000-55a687c00000) (0x1e05000)  @ 0x200000]:   file
1738   // [0x55a687c00000-55a6a5200000) (0x1d600000) @ 0]:          file
1739   // [0x55a6a5200000-55a6a6400000) (0x1200000)  @ 0x1f605000]: file
1740   // [0x55a6a6400000-55a6a6600000) (0x200000)   @ 0]:          file
1741   // [0x55a6a6600000-55a6a8800000) (0x2200000)  @ 0x20a05000]: file
1742   // [0x55a6a8800000-55a6a8a00000) (0x200000)   @ 0]:          file
1743   // [0x55a6a8a00000-55a6a90ca000) (0x6ca000)   @ 0x22e05000]: file
1744   // [0x55a6a90ca000-55a6a90cb000) (0x1000)     @ 0x234cf000]: file
1745   testing::ExampleMmapEvent(1234, 0x55a685bfb000, 0x200000, 0, "file",
1746                             testing::SampleInfo().Tid(1234, 1234))
1747       .WriteTo(&input);
1748   testing::ExampleMmapEvent(1234, 0x55a685dfb000, 0x1e05000, 0x200000, "file",
1749                             testing::SampleInfo().Tid(1234, 1234))
1750       .WriteTo(&input);
1751   testing::ExampleMmapEvent(1234, 0x55a687c00000, 0x1d600000, 0, "file",
1752                             testing::SampleInfo().Tid(1234, 1234))
1753       .WriteTo(&input);
1754   testing::ExampleMmapEvent(1234, 0x55a6a5200000, 0x1200000, 0x1f605000, "file",
1755                             testing::SampleInfo().Tid(1234, 1234))
1756       .WriteTo(&input);
1757   testing::ExampleMmapEvent(1234, 0x55a6a6400000, 0x200000, 0, "file",
1758                             testing::SampleInfo().Tid(1234, 1234))
1759       .WriteTo(&input);
1760   testing::ExampleMmapEvent(1234, 0x55a6a6600000, 0x2200000, 0x20a05000, "file",
1761                             testing::SampleInfo().Tid(1234, 1234))
1762       .WriteTo(&input);
1763   testing::ExampleMmapEvent(1234, 0x55a6a8800000, 0x200000, 0, "file",
1764                             testing::SampleInfo().Tid(1234, 1234))
1765       .WriteTo(&input);
1766   testing::ExampleMmapEvent(1234, 0x55a6a8a00000, 0x6ca000, 0x22e05000, "file",
1767                             testing::SampleInfo().Tid(1234, 1234))
1768       .WriteTo(&input);
1769   testing::ExampleMmapEvent(1234, 0x55a6a90ca000, 0x1000, 0x234cf000, "file",
1770                             testing::SampleInfo().Tid(1234, 1234))
1771       .WriteTo(&input);
1772 
1773   //
1774   // Parse input.
1775   //
1776 
1777   PerfReader reader;
1778   EXPECT_TRUE(reader.ReadFromString(input.str()));
1779 
1780   PerfParserOptions options;
1781   options.deduce_huge_page_mappings = true;
1782   options.combine_mappings = true;
1783   PerfParser parser(&reader, options);
1784   EXPECT_TRUE(parser.ParseRawEvents());
1785 
1786   EXPECT_EQ(1, parser.stats().num_mmap_events);
1787   EXPECT_EQ(0, parser.stats().num_sample_events);
1788   EXPECT_EQ(0, parser.stats().num_sample_events_mapped);
1789 
1790   const std::vector<ParsedEvent> &events = parser.parsed_events();
1791 
1792   {
1793     PerfDataProto expected;
1794     {
1795       auto *ev = expected.add_events();
1796       ev->mutable_header()->set_type(PERF_RECORD_MMAP);
1797       ev->mutable_mmap_event()->set_filename("file");
1798       ev->mutable_mmap_event()->set_start(0x55a685bfb000);
1799       ev->mutable_mmap_event()->set_len(0x234d0000);
1800       ev->mutable_mmap_event()->set_pgoff(0x0);
1801     }
1802 
1803     PerfDataProto actual;
1804     for (const auto &ev : events) {
1805       if (ev.event_ptr == nullptr) {
1806         continue;
1807       }
1808 
1809       *actual.add_events() = *ev.event_ptr;
1810     }
1811 
1812     EXPECT_TRUE(PartiallyEqualsProto(actual, expected));
1813   }
1814   ASSERT_EQ(1, events.size());
1815 
1816   // Verify the header().size() entry is large enough to deserialize/serialize.
1817   for (const auto &ev : events) {
1818     malloced_unique_ptr<event_t> e(
1819         CallocMemoryForEvent(ev.event_ptr->header().size()));
1820 
1821     PerfSerializer serializer;
1822     ASSERT_TRUE(
1823         serializer.DeserializeMMapEvent(ev.event_ptr->mmap_event(), e.get()));
1824 
1825     PerfDataProto_MMapEvent roundtrip;
1826     ASSERT_TRUE(serializer.SerializeMMapEvent(*e, &roundtrip));
1827     // sample_info does not roundtrip through an event_t.
1828     EXPECT_TRUE(PartiallyEqualsProto(ev.event_ptr->mmap_event(), roundtrip));
1829   }
1830 }
1831 
TEST(PerfParserTest,Regression62446346_Perf3_12_0_11)1832 TEST(PerfParserTest, Regression62446346_Perf3_12_0_11) {
1833   std::stringstream input;
1834 
1835   // header
1836   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1837 
1838   // PERF_RECORD_HEADER_ATTR
1839   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1840                                               true /*sample_id_all*/)
1841       .WriteTo(&input);
1842 
1843   // Perf infers the filename is "file", but at offset 0 for
1844   // hugepage-backed, anonymous mappings.
1845   //
1846   // vaddr start   - vaddr end     vaddr-size    elf-offset
1847   // [0x55bd43879000-0x55bd45000000) (0x 1787000) @ 0x       0]: file
1848   // [0x55bd45000000-0x55bd58c00000) (0x13c00000) @ 0x       0]: file
1849   // [0x55bd58c00000-0x55bd59800000) (0x  c00000) @ 0x15387000]: file
1850   // [0x55bd59800000-0x55bd59a00000) (0x  200000) @ 0x       0]: file
1851   // [0x55bd59a00000-0x55bd5b600000) (0x 1c00000) @ 0x16187000]: file
1852   // [0x55bd5b600000-0x55bd5b800000) (0x  200000) @ 0x       0]: file
1853   // [0x55bd5b800000-0x55bd5bcb5000) (0x  4b5000) @ 0x17f87000]: file
1854 
1855   testing::ExampleMmapEvent(1234, 0x55bd43879000, 0x1787000, 0, "file",
1856                             testing::SampleInfo().Tid(1234, 1234))
1857       .WriteTo(&input);
1858   testing::ExampleMmapEvent(1234, 0x55bd45000000, 0x13c00000, 0, "file",
1859                             testing::SampleInfo().Tid(1234, 1234))
1860       .WriteTo(&input);
1861   testing::ExampleMmapEvent(1234, 0x55bd58c00000, 0xc00000, 0x15387000, "file",
1862                             testing::SampleInfo().Tid(1234, 1234))
1863       .WriteTo(&input);
1864   testing::ExampleMmapEvent(1234, 0x55bd59800000, 0x200000, 0, "file",
1865                             testing::SampleInfo().Tid(1234, 1234))
1866       .WriteTo(&input);
1867   testing::ExampleMmapEvent(1234, 0x55bd59a00000, 0x1c00000, 0x16187000, "file",
1868                             testing::SampleInfo().Tid(1234, 1234))
1869       .WriteTo(&input);
1870   testing::ExampleMmapEvent(1234, 0x55bd5b600000, 0x200000, 0, "file",
1871                             testing::SampleInfo().Tid(1234, 1234))
1872       .WriteTo(&input);
1873   testing::ExampleMmapEvent(1234, 0x55bd5b800000, 0x4b5000, 0x17f87000, "file",
1874                             testing::SampleInfo().Tid(1234, 1234))
1875       .WriteTo(&input);
1876 
1877   //
1878   // Parse input.
1879   //
1880 
1881   PerfReader reader;
1882   EXPECT_TRUE(reader.ReadFromString(input.str()));
1883 
1884   PerfParserOptions options;
1885   options.deduce_huge_page_mappings = true;
1886   options.combine_mappings = true;
1887   PerfParser parser(&reader, options);
1888   EXPECT_TRUE(parser.ParseRawEvents());
1889 
1890   EXPECT_EQ(1, parser.stats().num_mmap_events);
1891   EXPECT_EQ(0, parser.stats().num_sample_events);
1892   EXPECT_EQ(0, parser.stats().num_sample_events_mapped);
1893 
1894   PerfDataProto expected;
1895   {
1896     auto *ev = expected.add_events();
1897     ev->mutable_header()->set_type(PERF_RECORD_MMAP);
1898     ev->mutable_mmap_event()->set_filename("file");
1899     ev->mutable_mmap_event()->set_start(0x55bd43879000);
1900     ev->mutable_mmap_event()->set_len(0x55bd5bcb5000 - 0x55bd43879000);
1901     ev->mutable_mmap_event()->set_pgoff(0x0);
1902   }
1903 
1904   PerfDataProto actual;
1905   CopyActualEvents(parser.parsed_events(), &actual);
1906   EXPECT_TRUE(PartiallyEqualsProto(actual, expected));
1907   ASSERT_EQ(1, parser.parsed_events().size());
1908 }
1909 
TEST(PerfParserTest,Regression62446346_Perf3_12_0_14)1910 TEST(PerfParserTest, Regression62446346_Perf3_12_0_14) {
1911   std::stringstream input;
1912 
1913   // header
1914   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1915 
1916   // PERF_RECORD_HEADER_ATTR
1917   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1918                                               true /*sample_id_all*/)
1919       .WriteTo(&input);
1920 
1921   // Perf infers the filename is "file", but at offset 0 for
1922   // hugepage-backed, anonymous mappings.
1923   //
1924   // vaddr start   - vaddr end     vaddr-size    elf-offset
1925   // [0x55bd43879000-0x55bd45000000) (0x 1787000) @ 0x       0]: file
1926   // [0x55bd45000000-0x55bd58c00000) (0x13c00000) @ 0x 1787000]: file
1927   // [0x55bd58c00000-0x55bd59800000) (0x  c00000) @ 0x15387000]: file
1928   // [0x55bd59800000-0x55bd59a00000) (0x  200000) @ 0x15f87000]: file
1929   // [0x55bd59a00000-0x55bd5b600000) (0x 1c00000) @ 0x16187000]: file
1930   // [0x55bd5b600000-0x55bd5b800000) (0x  200000) @ 0x17d87000]: file
1931   // [0x55bd5b800000-0x55bd5bcb5000) (0x  4b5000) @ 0x17f87000]: file
1932 
1933   testing::ExampleMmapEvent(1234, 0x55bd43879000, 0x1787000, 0, "file",
1934                             testing::SampleInfo().Tid(1234, 1234))
1935       .WriteTo(&input);
1936   testing::ExampleMmapEvent(1234, 0x55bd45000000, 0x13c00000, 0x1787000, "file",
1937                             testing::SampleInfo().Tid(1234, 1234))
1938       .WriteTo(&input);
1939   testing::ExampleMmapEvent(1234, 0x55bd58c00000, 0xc00000, 0x15387000, "file",
1940                             testing::SampleInfo().Tid(1234, 1234))
1941       .WriteTo(&input);
1942   testing::ExampleMmapEvent(1234, 0x55bd59800000, 0x200000, 0x15f87000, "file",
1943                             testing::SampleInfo().Tid(1234, 1234))
1944       .WriteTo(&input);
1945   testing::ExampleMmapEvent(1234, 0x55bd59a00000, 0x1c00000, 0x16187000, "file",
1946                             testing::SampleInfo().Tid(1234, 1234))
1947       .WriteTo(&input);
1948   testing::ExampleMmapEvent(1234, 0x55bd5b600000, 0x200000, 0x17d87000, "file",
1949                             testing::SampleInfo().Tid(1234, 1234))
1950       .WriteTo(&input);
1951   testing::ExampleMmapEvent(1234, 0x55bd5b800000, 0x4b5000, 0x17f87000, "file",
1952                             testing::SampleInfo().Tid(1234, 1234))
1953       .WriteTo(&input);
1954 
1955   //
1956   // Parse input.
1957   //
1958 
1959   PerfReader reader;
1960   EXPECT_TRUE(reader.ReadFromString(input.str()));
1961 
1962   PerfParserOptions options;
1963   options.deduce_huge_page_mappings = true;
1964   options.combine_mappings = true;
1965   PerfParser parser(&reader, options);
1966   EXPECT_TRUE(parser.ParseRawEvents());
1967 
1968   EXPECT_EQ(1, parser.stats().num_mmap_events);
1969   EXPECT_EQ(0, parser.stats().num_sample_events);
1970   EXPECT_EQ(0, parser.stats().num_sample_events_mapped);
1971 
1972   PerfDataProto expected;
1973   {
1974     auto *ev = expected.add_events();
1975     ev->mutable_header()->set_type(PERF_RECORD_MMAP);
1976     ev->mutable_mmap_event()->set_filename("file");
1977     ev->mutable_mmap_event()->set_start(0x55bd43879000);
1978     ev->mutable_mmap_event()->set_len(0x55bd5bcb5000 - 0x55bd43879000);
1979     ev->mutable_mmap_event()->set_pgoff(0x0);
1980   }
1981 
1982   PerfDataProto actual;
1983   CopyActualEvents(parser.parsed_events(), &actual);
1984   EXPECT_TRUE(PartiallyEqualsProto(actual, expected));
1985   EXPECT_EQ(1, parser.parsed_events().size());
1986 }
1987 
TEST(PerfParserTest,DiscontiguousMappings)1988 TEST(PerfParserTest, DiscontiguousMappings) {
1989   std::stringstream input;
1990 
1991   // header
1992   testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
1993 
1994   // PERF_RECORD_HEADER_ATTR
1995   testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
1996                                               true /*sample_id_all*/)
1997       .WriteTo(&input);
1998 
1999   // vaddr start   - vaddr end     vaddr-size    elf-offset
2000   // [0x7f489000-0x80200000) (0xd77000)   @ 0]:          file
2001   // [0x80200000-0x80400000) (0x200000)   @ 0]:          file
2002   // [0x80400000-0x80474000) (0x47000)    @ 0x1a00000]:  file
2003   testing::ExampleMmapEvent(1234, 0x7f489000, 0xd77000, 0, "file",
2004                             testing::SampleInfo().Tid(1234, 1234))
2005       .WriteTo(&input);
2006   testing::ExampleMmapEvent(1234, 0x80200000, 0x200000, 0, "file",
2007                             testing::SampleInfo().Tid(1234, 1234))
2008       .WriteTo(&input);
2009   testing::ExampleMmapEvent(1234, 0x80400000, 0x47000, 0x1a00000, "file",
2010                             testing::SampleInfo().Tid(1234, 1234))
2011       .WriteTo(&input);
2012 
2013   //
2014   // Parse input.
2015   //
2016 
2017   PerfReader reader;
2018   EXPECT_TRUE(reader.ReadFromString(input.str()));
2019 
2020   PerfParserOptions options;
2021   options.deduce_huge_page_mappings = true;
2022   options.combine_mappings = true;
2023   PerfParser parser(&reader, options);
2024   EXPECT_TRUE(parser.ParseRawEvents());
2025 
2026   EXPECT_EQ(3, parser.stats().num_mmap_events);
2027   EXPECT_EQ(0, parser.stats().num_sample_events);
2028   EXPECT_EQ(0, parser.stats().num_sample_events_mapped);
2029 
2030   // The first two mappings should not combine, since we cannot know if the
2031   // middle one follows the first, or preceeds the last in the binary.
2032   PerfDataProto expected;
2033   {
2034     auto *ev = expected.add_events();
2035     ev->mutable_header()->set_type(PERF_RECORD_MMAP);
2036     ev->mutable_mmap_event()->set_filename("file");
2037     ev->mutable_mmap_event()->set_start(0x7f489000);
2038     ev->mutable_mmap_event()->set_len(0xd77000);
2039     ev->mutable_mmap_event()->set_pgoff(0x0);
2040   }
2041   {
2042     auto *ev = expected.add_events();
2043     ev->mutable_header()->set_type(PERF_RECORD_MMAP);
2044     ev->mutable_mmap_event()->set_filename("file");
2045     ev->mutable_mmap_event()->set_start(0x80200000);
2046     ev->mutable_mmap_event()->set_len(0x200000);
2047     ev->mutable_mmap_event()->set_pgoff(0x0);
2048   }
2049   {
2050     auto *ev = expected.add_events();
2051     ev->mutable_header()->set_type(PERF_RECORD_MMAP);
2052     ev->mutable_mmap_event()->set_filename("file");
2053     ev->mutable_mmap_event()->set_start(0x80400000);
2054     ev->mutable_mmap_event()->set_len(0x47000);
2055     ev->mutable_mmap_event()->set_pgoff(0x1a00000);
2056   }
2057 
2058   PerfDataProto actual;
2059   CopyActualEvents(parser.parsed_events(), &actual);
2060 
2061   EXPECT_TRUE(PartiallyEqualsProto(actual, expected));
2062   EXPECT_EQ(3, parser.parsed_events().size());
2063 }
2064 }  // namespace quipper
2065