• 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 
100 }  // namespace art
101