1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2024 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker *
8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker *
10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker */
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_mmap.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include <utility>
20*6dbdd20aSAndroid Build Coastguard Worker
21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/file_utils.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_file.h"
23*6dbdd20aSAndroid Build Coastguard Worker
24*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
25*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
26*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
27*6dbdd20aSAndroid Build Coastguard Worker #include <sys/mman.h>
28*6dbdd20aSAndroid Build Coastguard Worker #include <unistd.h>
29*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
30*6dbdd20aSAndroid Build Coastguard Worker #include <Windows.h>
31*6dbdd20aSAndroid Build Coastguard Worker #endif
32*6dbdd20aSAndroid Build Coastguard Worker
33*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto::base {
34*6dbdd20aSAndroid Build Coastguard Worker namespace {
35*6dbdd20aSAndroid Build Coastguard Worker
OpenFileForMmap(const char * fname)36*6dbdd20aSAndroid Build Coastguard Worker ScopedPlatformHandle OpenFileForMmap(const char* fname) {
37*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
38*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
39*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
40*6dbdd20aSAndroid Build Coastguard Worker return OpenFile(fname, O_RDONLY);
41*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
42*6dbdd20aSAndroid Build Coastguard Worker // This does not use base::OpenFile to avoid getting an exclusive lock.
43*6dbdd20aSAndroid Build Coastguard Worker return ScopedPlatformHandle(CreateFileA(fname, GENERIC_READ, FILE_SHARE_READ,
44*6dbdd20aSAndroid Build Coastguard Worker nullptr, OPEN_EXISTING,
45*6dbdd20aSAndroid Build Coastguard Worker FILE_ATTRIBUTE_NORMAL, nullptr));
46*6dbdd20aSAndroid Build Coastguard Worker #else
47*6dbdd20aSAndroid Build Coastguard Worker // mmap is not supported. Do not even open the file.
48*6dbdd20aSAndroid Build Coastguard Worker base::ignore_result(fname);
49*6dbdd20aSAndroid Build Coastguard Worker return ScopedPlatformHandle();
50*6dbdd20aSAndroid Build Coastguard Worker #endif
51*6dbdd20aSAndroid Build Coastguard Worker }
52*6dbdd20aSAndroid Build Coastguard Worker
53*6dbdd20aSAndroid Build Coastguard Worker } // namespace
54*6dbdd20aSAndroid Build Coastguard Worker
ScopedMmap(ScopedMmap && other)55*6dbdd20aSAndroid Build Coastguard Worker ScopedMmap::ScopedMmap(ScopedMmap&& other) noexcept {
56*6dbdd20aSAndroid Build Coastguard Worker *this = std::move(other);
57*6dbdd20aSAndroid Build Coastguard Worker }
58*6dbdd20aSAndroid Build Coastguard Worker
operator =(ScopedMmap && other)59*6dbdd20aSAndroid Build Coastguard Worker ScopedMmap& ScopedMmap::operator=(ScopedMmap&& other) noexcept {
60*6dbdd20aSAndroid Build Coastguard Worker if (this == &other) {
61*6dbdd20aSAndroid Build Coastguard Worker return *this;
62*6dbdd20aSAndroid Build Coastguard Worker }
63*6dbdd20aSAndroid Build Coastguard Worker reset();
64*6dbdd20aSAndroid Build Coastguard Worker std::swap(ptr_, other.ptr_);
65*6dbdd20aSAndroid Build Coastguard Worker std::swap(length_, other.length_);
66*6dbdd20aSAndroid Build Coastguard Worker std::swap(file_, other.file_);
67*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
68*6dbdd20aSAndroid Build Coastguard Worker std::swap(map_, other.map_);
69*6dbdd20aSAndroid Build Coastguard Worker #endif
70*6dbdd20aSAndroid Build Coastguard Worker return *this;
71*6dbdd20aSAndroid Build Coastguard Worker }
72*6dbdd20aSAndroid Build Coastguard Worker
~ScopedMmap()73*6dbdd20aSAndroid Build Coastguard Worker ScopedMmap::~ScopedMmap() {
74*6dbdd20aSAndroid Build Coastguard Worker reset();
75*6dbdd20aSAndroid Build Coastguard Worker }
76*6dbdd20aSAndroid Build Coastguard Worker
77*6dbdd20aSAndroid Build Coastguard Worker // static
FromHandle(base::ScopedPlatformHandle file,size_t length)78*6dbdd20aSAndroid Build Coastguard Worker ScopedMmap ScopedMmap::FromHandle(base::ScopedPlatformHandle file,
79*6dbdd20aSAndroid Build Coastguard Worker size_t length) {
80*6dbdd20aSAndroid Build Coastguard Worker ScopedMmap ret;
81*6dbdd20aSAndroid Build Coastguard Worker if (!file) {
82*6dbdd20aSAndroid Build Coastguard Worker return ret;
83*6dbdd20aSAndroid Build Coastguard Worker }
84*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
85*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
86*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
87*6dbdd20aSAndroid Build Coastguard Worker void* ptr = mmap(nullptr, length, PROT_READ, MAP_PRIVATE, *file, 0);
88*6dbdd20aSAndroid Build Coastguard Worker if (ptr != MAP_FAILED) {
89*6dbdd20aSAndroid Build Coastguard Worker ret.ptr_ = ptr;
90*6dbdd20aSAndroid Build Coastguard Worker ret.length_ = length;
91*6dbdd20aSAndroid Build Coastguard Worker ret.file_ = std::move(file);
92*6dbdd20aSAndroid Build Coastguard Worker }
93*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
94*6dbdd20aSAndroid Build Coastguard Worker ScopedPlatformHandle map(
95*6dbdd20aSAndroid Build Coastguard Worker CreateFileMapping(*file, nullptr, PAGE_READONLY, 0, 0, nullptr));
96*6dbdd20aSAndroid Build Coastguard Worker if (!map) {
97*6dbdd20aSAndroid Build Coastguard Worker return ret;
98*6dbdd20aSAndroid Build Coastguard Worker }
99*6dbdd20aSAndroid Build Coastguard Worker void* ptr = MapViewOfFile(*map, FILE_MAP_READ, 0, 0, length);
100*6dbdd20aSAndroid Build Coastguard Worker if (ptr != nullptr) {
101*6dbdd20aSAndroid Build Coastguard Worker ret.ptr_ = ptr;
102*6dbdd20aSAndroid Build Coastguard Worker ret.length_ = length;
103*6dbdd20aSAndroid Build Coastguard Worker ret.file_ = std::move(file);
104*6dbdd20aSAndroid Build Coastguard Worker ret.map_ = std::move(map);
105*6dbdd20aSAndroid Build Coastguard Worker }
106*6dbdd20aSAndroid Build Coastguard Worker #else
107*6dbdd20aSAndroid Build Coastguard Worker base::ignore_result(length);
108*6dbdd20aSAndroid Build Coastguard Worker #endif
109*6dbdd20aSAndroid Build Coastguard Worker return ret;
110*6dbdd20aSAndroid Build Coastguard Worker }
111*6dbdd20aSAndroid Build Coastguard Worker
reset()112*6dbdd20aSAndroid Build Coastguard Worker bool ScopedMmap::reset() noexcept {
113*6dbdd20aSAndroid Build Coastguard Worker bool ret = true;
114*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
115*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
116*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
117*6dbdd20aSAndroid Build Coastguard Worker if (ptr_ != nullptr) {
118*6dbdd20aSAndroid Build Coastguard Worker ret = munmap(ptr_, length_) == 0;
119*6dbdd20aSAndroid Build Coastguard Worker }
120*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
121*6dbdd20aSAndroid Build Coastguard Worker if (ptr_ != nullptr) {
122*6dbdd20aSAndroid Build Coastguard Worker ret = UnmapViewOfFile(ptr_);
123*6dbdd20aSAndroid Build Coastguard Worker }
124*6dbdd20aSAndroid Build Coastguard Worker map_.reset();
125*6dbdd20aSAndroid Build Coastguard Worker #endif
126*6dbdd20aSAndroid Build Coastguard Worker ptr_ = nullptr;
127*6dbdd20aSAndroid Build Coastguard Worker length_ = 0;
128*6dbdd20aSAndroid Build Coastguard Worker file_.reset();
129*6dbdd20aSAndroid Build Coastguard Worker return ret;
130*6dbdd20aSAndroid Build Coastguard Worker }
131*6dbdd20aSAndroid Build Coastguard Worker
132*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
133*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
134*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
135*6dbdd20aSAndroid Build Coastguard Worker // static
InheritMmappedRange(void * data,size_t size)136*6dbdd20aSAndroid Build Coastguard Worker ScopedMmap ScopedMmap::InheritMmappedRange(void* data, size_t size) {
137*6dbdd20aSAndroid Build Coastguard Worker ScopedMmap ret;
138*6dbdd20aSAndroid Build Coastguard Worker ret.ptr_ = data;
139*6dbdd20aSAndroid Build Coastguard Worker ret.length_ = size;
140*6dbdd20aSAndroid Build Coastguard Worker return ret;
141*6dbdd20aSAndroid Build Coastguard Worker }
142*6dbdd20aSAndroid Build Coastguard Worker #endif
143*6dbdd20aSAndroid Build Coastguard Worker
ReadMmapFilePart(const char * fname,size_t length)144*6dbdd20aSAndroid Build Coastguard Worker ScopedMmap ReadMmapFilePart(const char* fname, size_t length) {
145*6dbdd20aSAndroid Build Coastguard Worker return ScopedMmap::FromHandle(OpenFileForMmap(fname), length);
146*6dbdd20aSAndroid Build Coastguard Worker }
147*6dbdd20aSAndroid Build Coastguard Worker
ReadMmapWholeFile(const char * fname)148*6dbdd20aSAndroid Build Coastguard Worker ScopedMmap ReadMmapWholeFile(const char* fname) {
149*6dbdd20aSAndroid Build Coastguard Worker ScopedPlatformHandle file = OpenFileForMmap(fname);
150*6dbdd20aSAndroid Build Coastguard Worker if (!file) {
151*6dbdd20aSAndroid Build Coastguard Worker return ScopedMmap();
152*6dbdd20aSAndroid Build Coastguard Worker }
153*6dbdd20aSAndroid Build Coastguard Worker std::optional<uint64_t> file_size = GetFileSize(file.get());
154*6dbdd20aSAndroid Build Coastguard Worker if (!file_size.has_value()) {
155*6dbdd20aSAndroid Build Coastguard Worker return ScopedMmap();
156*6dbdd20aSAndroid Build Coastguard Worker }
157*6dbdd20aSAndroid Build Coastguard Worker size_t size = static_cast<size_t>(*file_size);
158*6dbdd20aSAndroid Build Coastguard Worker if (static_cast<uint64_t>(size) != *file_size) {
159*6dbdd20aSAndroid Build Coastguard Worker return ScopedMmap();
160*6dbdd20aSAndroid Build Coastguard Worker }
161*6dbdd20aSAndroid Build Coastguard Worker return ScopedMmap::FromHandle(std::move(file), size);
162*6dbdd20aSAndroid Build Coastguard Worker }
163*6dbdd20aSAndroid Build Coastguard Worker
164*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto::base
165