• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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