1 /*
2 * Copyright (C) 2023 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 "page_util.h"
18
19 #include "android-base/stringprintf.h"
20
21 namespace art {
22
23 using android::base::StringPrintf;
24
GetPageFlagsOrCount(art::File & kpage_file,uint64_t page_frame_number,uint64_t & page_flags_or_count,std::string & error_msg)25 bool GetPageFlagsOrCount(art::File& kpage_file,
26 uint64_t page_frame_number,
27 /*out*/ uint64_t& page_flags_or_count,
28 /*out*/ std::string& error_msg) {
29 return GetPageFlagsOrCounts(kpage_file,
30 ArrayRef<const uint64_t>(&page_frame_number, 1u),
31 ArrayRef<uint64_t>(&page_flags_or_count, 1u),
32 error_msg);
33 }
34
GetPageFlagsOrCounts(File & kpage_file,ArrayRef<const uint64_t> page_frame_numbers,ArrayRef<uint64_t> page_flags_or_counts,std::string & error_msg)35 bool GetPageFlagsOrCounts(File& kpage_file,
36 ArrayRef<const uint64_t> page_frame_numbers,
37 /*out*/ ArrayRef<uint64_t> page_flags_or_counts,
38 /*out*/ std::string& error_msg) {
39 static_assert(kPageFlagsEntrySize == kPageCountEntrySize, "entry size check");
40 CHECK_NE(page_frame_numbers.size(), 0u);
41 CHECK_EQ(page_flags_or_counts.size(), page_frame_numbers.size());
42 CHECK(page_frame_numbers.data() != nullptr);
43 CHECK(page_flags_or_counts.data() != nullptr);
44
45 size_t size = page_frame_numbers.size();
46 size_t i = 0;
47 while (i != size) {
48 size_t start = i;
49 ++i;
50 while (i != size && page_frame_numbers[i] - page_frame_numbers[start] == i - start) {
51 ++i;
52 }
53 // Read 64-bit entries from /proc/kpageflags or /proc/kpagecount.
54 if (!kpage_file.PreadFully(page_flags_or_counts.data() + start,
55 (i - start) * kPageMapEntrySize,
56 page_frame_numbers[start] * kPageFlagsEntrySize)) {
57 error_msg = StringPrintf("Failed to read the page flags or counts from %s, error: %s",
58 kpage_file.GetPath().c_str(),
59 strerror(errno));
60 return false;
61 }
62 }
63
64 return true;
65 }
66
GetPageFrameNumber(File & page_map_file,size_t virtual_page_index,uint64_t & page_frame_number,std::string & error_msg)67 bool GetPageFrameNumber(File& page_map_file,
68 size_t virtual_page_index,
69 /*out*/ uint64_t& page_frame_number,
70 /*out*/ std::string& error_msg) {
71 return GetPageFrameNumbers(
72 page_map_file, virtual_page_index, ArrayRef<uint64_t>(&page_frame_number, 1u), error_msg);
73 }
74
GetPageFrameNumbers(File & page_map_file,size_t virtual_page_index,ArrayRef<uint64_t> page_frame_numbers,std::string & error_msg)75 bool GetPageFrameNumbers(File& page_map_file,
76 size_t virtual_page_index,
77 /*out*/ ArrayRef<uint64_t> page_frame_numbers,
78 /*out*/ std::string& error_msg) {
79 CHECK_NE(page_frame_numbers.size(), 0u);
80 CHECK(page_frame_numbers.data() != nullptr);
81
82 // Read 64-bit entries from /proc/$pid/pagemap to get the physical page frame numbers.
83 if (!page_map_file.PreadFully(page_frame_numbers.data(),
84 page_frame_numbers.size() * kPageMapEntrySize,
85 virtual_page_index * kPageMapEntrySize)) {
86 error_msg = StringPrintf("Failed to read virtual page index entries from %s, error: %s",
87 page_map_file.GetPath().c_str(),
88 strerror(errno));
89 return false;
90 }
91
92 // Extract page frame numbers from pagemap entries.
93 for (uint64_t& page_frame_number : page_frame_numbers) {
94 page_frame_number &= kPageFrameNumberMask;
95 }
96
97 return true;
98 }
99
OpenFile(const char * file_name,File & file,std::string & error_msg)100 bool OpenFile(const char* file_name, /*out*/ File& file, /*out*/ std::string& error_msg) {
101 std::unique_ptr<File> file_ptr = std::unique_ptr<File>{OS::OpenFileForReading(file_name)};
102 if (file_ptr == nullptr) {
103 error_msg = StringPrintf("Failed to open file: %s", file_name);
104 return false;
105 }
106 file = std::move(*file_ptr);
107 return true;
108 }
109
OpenProcFiles(pid_t pid,ProcFiles & files,std::string & error_msg)110 bool OpenProcFiles(pid_t pid, /*out*/ ProcFiles& files, /*out*/ std::string& error_msg) {
111 if (!OpenFile("/proc/kpageflags", files.kpageflags, error_msg)) {
112 return false;
113 }
114 if (!OpenFile("/proc/kpagecount", files.kpagecount, error_msg)) {
115 return false;
116 }
117 std::string mem_file_name =
118 StringPrintf("/proc/%ld/mem", static_cast<long>(pid)); // NOLINT [runtime/int]
119 if (!OpenFile(mem_file_name.c_str(), files.mem, error_msg)) {
120 return false;
121 }
122 std::string pagemap_file_name =
123 StringPrintf("/proc/%ld/pagemap", static_cast<long>(pid)); // NOLINT [runtime/int]
124 if (!OpenFile(pagemap_file_name.c_str(), files.pagemap, error_msg)) {
125 return false;
126 }
127 return true;
128 }
129
130 } // namespace art
131