1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include <string.h>
20
21 #include <memory>
22 #include <vector>
23
24 #include <android-base/file.h>
25
26 #include "environment.h"
27 #include "event_attr.h"
28 #include "event_type.h"
29 #include "record.h"
30 #include "record_file.h"
31 #include "utils.h"
32
33 #include "record_equal_test.h"
34
35 using namespace simpleperf;
36 using namespace simpleperf::PerfFileFormat;
37
38 class RecordFileTest : public ::testing::Test {
39 protected:
SetUp()40 void SetUp() override { close(tmpfile_.release()); }
41
AddEventType(const std::string & event_type_str)42 void AddEventType(const std::string& event_type_str) {
43 std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType(event_type_str);
44 ASSERT_TRUE(event_type_modifier != nullptr);
45 perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
46 attr.sample_id_all = 1;
47 attrs_.push_back(std::unique_ptr<perf_event_attr>(new perf_event_attr(attr)));
48 EventAttrWithId attr_id;
49 attr_id.attr = attrs_.back().get();
50 attr_id.ids.push_back(attrs_.size()); // Fake id.
51 attr_ids_.push_back(attr_id);
52 }
53
54 TemporaryFile tmpfile_;
55 std::vector<std::unique_ptr<perf_event_attr>> attrs_;
56 std::vector<EventAttrWithId> attr_ids_;
57 };
58
TEST_F(RecordFileTest,smoke)59 TEST_F(RecordFileTest, smoke) {
60 // Write to a record file.
61 std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
62 ASSERT_TRUE(writer != nullptr);
63
64 // Write attr section.
65 AddEventType("cpu-cycles");
66 ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
67
68 // Write data section.
69 MmapRecord mmap_record(*(attr_ids_[0].attr), true, 1, 1, 0x1000, 0x2000, 0x3000,
70 "mmap_record_example", attr_ids_[0].ids[0]);
71 ASSERT_TRUE(writer->WriteRecord(mmap_record));
72
73 // Write feature section.
74 ASSERT_TRUE(writer->BeginWriteFeatures(1));
75 char p[BuildId::Size()];
76 for (size_t i = 0; i < BuildId::Size(); ++i) {
77 p[i] = i;
78 }
79 BuildId build_id(p);
80 std::vector<BuildIdRecord> build_id_records;
81 build_id_records.push_back(BuildIdRecord(false, getpid(), build_id, "init"));
82 ASSERT_TRUE(writer->WriteBuildIdFeature(build_id_records));
83 ASSERT_TRUE(writer->EndWriteFeatures());
84 ASSERT_TRUE(writer->Close());
85
86 // Read from a record file.
87 std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
88 ASSERT_TRUE(reader != nullptr);
89 std::vector<EventAttrWithId> attrs = reader->AttrSection();
90 ASSERT_EQ(1u, attrs.size());
91 ASSERT_EQ(0, memcmp(attrs[0].attr, attr_ids_[0].attr, sizeof(perf_event_attr)));
92 ASSERT_EQ(attrs[0].ids, attr_ids_[0].ids);
93
94 // Read and check data section.
95 std::vector<std::unique_ptr<Record>> records = reader->DataSection();
96 ASSERT_EQ(1u, records.size());
97 CheckRecordEqual(mmap_record, *records[0]);
98
99 // Read and check feature section.
100 std::vector<BuildIdRecord> read_build_id_records = reader->ReadBuildIdFeature();
101 ASSERT_EQ(1u, read_build_id_records.size());
102 CheckRecordEqual(read_build_id_records[0], build_id_records[0]);
103
104 ASSERT_TRUE(reader->Close());
105 }
106
TEST_F(RecordFileTest,record_more_than_one_attr)107 TEST_F(RecordFileTest, record_more_than_one_attr) {
108 // Write to a record file.
109 std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
110 ASSERT_TRUE(writer != nullptr);
111
112 // Write attr section.
113 AddEventType("cpu-cycles");
114 AddEventType("cpu-clock");
115 AddEventType("task-clock");
116 ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
117
118 ASSERT_TRUE(writer->Close());
119
120 // Read from a record file.
121 std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
122 ASSERT_TRUE(reader != nullptr);
123 std::vector<EventAttrWithId> attrs = reader->AttrSection();
124 ASSERT_EQ(3u, attrs.size());
125 for (size_t i = 0; i < attrs.size(); ++i) {
126 ASSERT_EQ(0, memcmp(attrs[i].attr, attr_ids_[i].attr, sizeof(perf_event_attr)));
127 ASSERT_EQ(attrs[i].ids, attr_ids_[i].ids);
128 }
129 }
130
TEST_F(RecordFileTest,write_meta_info_feature_section)131 TEST_F(RecordFileTest, write_meta_info_feature_section) {
132 // Write to a record file.
133 std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
134 ASSERT_TRUE(writer != nullptr);
135 AddEventType("cpu-cycles");
136 ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
137
138 // Write meta_info feature section.
139 ASSERT_TRUE(writer->BeginWriteFeatures(1));
140 std::unordered_map<std::string, std::string> info_map;
141 for (int i = 0; i < 100; ++i) {
142 std::string s = std::to_string(i);
143 info_map[s] = s + s;
144 }
145 ASSERT_TRUE(writer->WriteMetaInfoFeature(info_map));
146 ASSERT_TRUE(writer->EndWriteFeatures());
147 ASSERT_TRUE(writer->Close());
148
149 // Read from a record file.
150 std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
151 ASSERT_TRUE(reader != nullptr);
152 ASSERT_EQ(reader->GetMetaInfoFeature(), info_map);
153 }
154
TEST_F(RecordFileTest,write_debug_unwind_feature_section)155 TEST_F(RecordFileTest, write_debug_unwind_feature_section) {
156 // Write to a record file.
157 std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
158 ASSERT_TRUE(writer != nullptr);
159 AddEventType("cpu-cycles");
160 ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
161
162 // Write debug_unwind feature section.
163 ASSERT_TRUE(writer->BeginWriteFeatures(1));
164 DebugUnwindFeature debug_unwind(2);
165 debug_unwind[0].path = "file1";
166 debug_unwind[0].size = 1000;
167 debug_unwind[1].path = "file2";
168 debug_unwind[1].size = 2000;
169 ASSERT_TRUE(writer->WriteDebugUnwindFeature(debug_unwind));
170 ASSERT_TRUE(writer->EndWriteFeatures());
171 ASSERT_TRUE(writer->Close());
172
173 // Read from a record file.
174 std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
175 ASSERT_TRUE(reader != nullptr);
176 std::optional<DebugUnwindFeature> opt_debug_unwind = reader->ReadDebugUnwindFeature();
177 ASSERT_TRUE(opt_debug_unwind.has_value());
178 ASSERT_EQ(opt_debug_unwind.value().size(), debug_unwind.size());
179 for (size_t i = 0; i < debug_unwind.size(); i++) {
180 ASSERT_EQ(opt_debug_unwind.value()[i].path, debug_unwind[i].path);
181 ASSERT_EQ(opt_debug_unwind.value()[i].size, debug_unwind[i].size);
182 }
183 }
184
TEST_F(RecordFileTest,write_file2_feature_section)185 TEST_F(RecordFileTest, write_file2_feature_section) {
186 // Write to a record file.
187 std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
188 ASSERT_TRUE(writer != nullptr);
189 AddEventType("cpu-cycles");
190 ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
191
192 // Write file2 feature section.
193 ASSERT_TRUE(writer->BeginWriteFeatures(1));
194 std::vector<FileFeature> files(3);
195 files[0].path = "fake_dex_file";
196 files[0].type = DSO_DEX_FILE;
197 files[0].min_vaddr = 0x1000;
198 files[0].symbols.emplace_back("dex_symbol", 0x1001, 0x1002);
199 files[0].dex_file_offsets.assign(0x1003, 0x1004);
200 files[1].path = "fake_elf_file";
201 files[1].type = DSO_ELF_FILE;
202 files[1].min_vaddr = 0x2000;
203 Symbol symbol("elf_symbol", 0x2001, 0x2002);
204 files[1].symbol_ptrs.emplace_back(&symbol);
205 files[1].file_offset_of_min_vaddr = 0x2003;
206 files[2].path = "fake_kernel_module";
207 files[2].type = DSO_KERNEL_MODULE;
208 files[2].min_vaddr = 0x3000;
209 files[2].symbols.emplace_back("kernel_module_symbol", 0x3001, 0x3002);
210 files[2].file_offset_of_min_vaddr = 0x3003;
211
212 for (const auto& file : files) {
213 ASSERT_TRUE(writer->WriteFileFeature(file));
214 }
215 ASSERT_TRUE(writer->EndWriteFeatures());
216 ASSERT_TRUE(writer->Close());
217
218 // Read from a record file.
219 std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
220 ASSERT_TRUE(reader != nullptr);
221 size_t read_pos = 0;
222 FileFeature file;
223
224 auto check_symbol = [](const Symbol& sym1, const Symbol& sym2) {
225 return sym1.addr == sym2.addr && sym1.len == sym2.len && strcmp(sym1.Name(), sym2.Name()) == 0;
226 };
227
228 size_t file_id = 0;
229 while (reader->ReadFileFeature(read_pos, &file)) {
230 ASSERT_LT(file_id, files.size());
231 const FileFeature& expected_file = files[file_id++];
232 ASSERT_EQ(file.path, expected_file.path);
233 ASSERT_EQ(file.type, expected_file.type);
234 ASSERT_EQ(file.min_vaddr, expected_file.min_vaddr);
235 if (!expected_file.symbols.empty()) {
236 ASSERT_EQ(file.symbols.size(), expected_file.symbols.size());
237 for (size_t i = 0; i < file.symbols.size(); i++) {
238 ASSERT_TRUE(check_symbol(file.symbols[i], expected_file.symbols[i]));
239 }
240 } else {
241 ASSERT_EQ(file.symbols.size(), expected_file.symbol_ptrs.size());
242 for (size_t i = 0; i < file.symbols.size(); i++) {
243 ASSERT_TRUE(check_symbol(file.symbols[i], *expected_file.symbol_ptrs[i]));
244 }
245 }
246 if (file.type == DSO_DEX_FILE) {
247 ASSERT_EQ(file.dex_file_offsets, expected_file.dex_file_offsets);
248 } else if (file.type == DSO_ELF_FILE) {
249 ASSERT_TRUE(file.dex_file_offsets.empty());
250 ASSERT_EQ(file.file_offset_of_min_vaddr, expected_file.file_offset_of_min_vaddr);
251 } else if (file.type == DSO_KERNEL_MODULE) {
252 ASSERT_TRUE(file.dex_file_offsets.empty());
253 ASSERT_EQ(file.file_offset_of_min_vaddr, expected_file.file_offset_of_min_vaddr);
254 }
255 }
256 ASSERT_EQ(file_id, files.size());
257 }