xref: /aosp_15_r20/external/perfetto/src/base/scoped_mmap.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 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 "perfetto/ext/base/scoped_mmap.h"
18 
19 #include <utility>
20 
21 #include "perfetto/ext/base/file_utils.h"
22 #include "perfetto/ext/base/scoped_file.h"
23 
24 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
25     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
26     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
27 #include <sys/mman.h>
28 #include <unistd.h>
29 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
30 #include <Windows.h>
31 #endif
32 
33 namespace perfetto::base {
34 namespace {
35 
OpenFileForMmap(const char * fname)36 ScopedPlatformHandle OpenFileForMmap(const char* fname) {
37 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
38     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
39     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
40   return OpenFile(fname, O_RDONLY);
41 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
42   // This does not use base::OpenFile to avoid getting an exclusive lock.
43   return ScopedPlatformHandle(CreateFileA(fname, GENERIC_READ, FILE_SHARE_READ,
44                                           nullptr, OPEN_EXISTING,
45                                           FILE_ATTRIBUTE_NORMAL, nullptr));
46 #else
47   // mmap is not supported. Do not even open the file.
48   base::ignore_result(fname);
49   return ScopedPlatformHandle();
50 #endif
51 }
52 
53 }  // namespace
54 
ScopedMmap(ScopedMmap && other)55 ScopedMmap::ScopedMmap(ScopedMmap&& other) noexcept {
56   *this = std::move(other);
57 }
58 
operator =(ScopedMmap && other)59 ScopedMmap& ScopedMmap::operator=(ScopedMmap&& other) noexcept {
60   if (this == &other) {
61     return *this;
62   }
63   reset();
64   std::swap(ptr_, other.ptr_);
65   std::swap(length_, other.length_);
66   std::swap(file_, other.file_);
67 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
68   std::swap(map_, other.map_);
69 #endif
70   return *this;
71 }
72 
~ScopedMmap()73 ScopedMmap::~ScopedMmap() {
74   reset();
75 }
76 
77 // static
FromHandle(base::ScopedPlatformHandle file,size_t length)78 ScopedMmap ScopedMmap::FromHandle(base::ScopedPlatformHandle file,
79                                   size_t length) {
80   ScopedMmap ret;
81   if (!file) {
82     return ret;
83   }
84 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
85     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
86     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
87   void* ptr = mmap(nullptr, length, PROT_READ, MAP_PRIVATE, *file, 0);
88   if (ptr != MAP_FAILED) {
89     ret.ptr_ = ptr;
90     ret.length_ = length;
91     ret.file_ = std::move(file);
92   }
93 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
94   ScopedPlatformHandle map(
95       CreateFileMapping(*file, nullptr, PAGE_READONLY, 0, 0, nullptr));
96   if (!map) {
97     return ret;
98   }
99   void* ptr = MapViewOfFile(*map, FILE_MAP_READ, 0, 0, length);
100   if (ptr != nullptr) {
101     ret.ptr_ = ptr;
102     ret.length_ = length;
103     ret.file_ = std::move(file);
104     ret.map_ = std::move(map);
105   }
106 #else
107   base::ignore_result(length);
108 #endif
109   return ret;
110 }
111 
reset()112 bool ScopedMmap::reset() noexcept {
113   bool ret = true;
114 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
115     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
116     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
117   if (ptr_ != nullptr) {
118     ret = munmap(ptr_, length_) == 0;
119   }
120 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
121   if (ptr_ != nullptr) {
122     ret = UnmapViewOfFile(ptr_);
123   }
124   map_.reset();
125 #endif
126   ptr_ = nullptr;
127   length_ = 0;
128   file_.reset();
129   return ret;
130 }
131 
132 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
133     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
134     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
135 // static
InheritMmappedRange(void * data,size_t size)136 ScopedMmap ScopedMmap::InheritMmappedRange(void* data, size_t size) {
137   ScopedMmap ret;
138   ret.ptr_ = data;
139   ret.length_ = size;
140   return ret;
141 }
142 #endif
143 
ReadMmapFilePart(const char * fname,size_t length)144 ScopedMmap ReadMmapFilePart(const char* fname, size_t length) {
145   return ScopedMmap::FromHandle(OpenFileForMmap(fname), length);
146 }
147 
ReadMmapWholeFile(const char * fname)148 ScopedMmap ReadMmapWholeFile(const char* fname) {
149   ScopedPlatformHandle file = OpenFileForMmap(fname);
150   if (!file) {
151     return ScopedMmap();
152   }
153   std::optional<uint64_t> file_size = GetFileSize(file.get());
154   if (!file_size.has_value()) {
155     return ScopedMmap();
156   }
157   size_t size = static_cast<size_t>(*file_size);
158   if (static_cast<uint64_t>(size) != *file_size) {
159     return ScopedMmap();
160   }
161   return ScopedMmap::FromHandle(std::move(file), size);
162 }
163 
164 }  // namespace perfetto::base
165