Flutter Engine
 
Loading...
Searching...
No Matches
mapped_resource.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mapped_resource.h"
6
7#include <dlfcn.h>
8#include <fcntl.h>
9#include <fuchsia/io/cpp/fidl.h>
10#include <fuchsia/mem/cpp/fidl.h>
11#include <lib/fdio/directory.h>
12#include <lib/fdio/io.h>
13#include <lib/trace/event.h>
14#include <sys/mman.h>
15#include <sys/stat.h>
16#include <sys/types.h>
17#include <zircon/dlfcn.h>
18#include <zircon/status.h>
19
20#include "flutter/fml/logging.h"
21#include "third_party/dart/runtime/include/dart_api.h"
22
23#include "inlines.h"
24#include "vmo.h"
25
26namespace dart_utils {
27
28static bool OpenVmo(fuchsia::mem::Buffer* resource_vmo,
29 fdio_ns_t* namespc,
30 const std::string& path,
31 bool executable) {
32 TRACE_DURATION("dart", "LoadFromNamespace", "path", path);
33
34 if (namespc == nullptr) {
35 // Opening a file in the root namespace expects an absolute path.
36 FML_CHECK(path[0] == '/');
37 if (!VmoFromFilename(path, executable, resource_vmo)) {
38 return false;
39 }
40 } else {
41 // openat of a path with a leading '/' ignores the namespace fd.
42 // require a relative path.
43 FML_CHECK(path[0] != '/');
44
45 auto root_dir = fdio_ns_opendir(namespc);
46 if (root_dir < 0) {
47 FML_LOG(ERROR) << "Failed to open namespace directory";
48 return false;
49 }
50
51 bool result =
52 dart_utils::VmoFromFilenameAt(root_dir, path, executable, resource_vmo);
53 close(root_dir);
54 if (!result) {
55 return result;
56 }
57 }
58
59 return true;
60}
61
62bool MappedResource::LoadFromNamespace(fdio_ns_t* namespc,
63 const std::string& path,
64 MappedResource& resource,
65 bool executable) {
66 fuchsia::mem::Buffer resource_vmo;
67 return OpenVmo(&resource_vmo, namespc, path, executable) &&
68 LoadFromVmo(path, std::move(resource_vmo), resource, executable);
69}
70
71bool MappedResource::LoadFromVmo(const std::string& path,
72 fuchsia::mem::Buffer resource_vmo,
73 MappedResource& resource,
74 bool executable) {
75 if (resource_vmo.size == 0) {
76 return true;
77 }
78
79 uint32_t flags = ZX_VM_PERM_READ;
80 if (executable) {
81 flags |= ZX_VM_PERM_EXECUTE;
82 }
83 uintptr_t addr;
84 zx_status_t status = zx::vmar::root_self()->map(flags, 0, resource_vmo.vmo, 0,
85 resource_vmo.size, &addr);
86 if (status != ZX_OK) {
87 FML_LOG(ERROR) << "Failed to map: " << zx_status_get_string(status);
88 return false;
89 }
90
91 resource.address_ = reinterpret_cast<void*>(addr);
92 resource.size_ = resource_vmo.size;
93 return true;
94}
95
97 if (address_ != nullptr) {
98 zx::vmar::root_self()->unmap(reinterpret_cast<uintptr_t>(address_), size_);
99 address_ = nullptr;
100 size_ = 0;
101 }
102}
103
104static int OpenFdExec(const std::string& path, int dirfd) {
105 int fd = -1;
106 // fdio_open3_fd_at only allows relative paths
107 const char* path_ptr = path.c_str();
108 if (path_ptr && path_ptr[0] == '/') {
109 ++path_ptr;
110 }
111 zx_status_t result = fdio_open3_fd_at(
112 dirfd, path_ptr,
113 uint64_t{fuchsia::io::PERM_READABLE | fuchsia::io::PERM_EXECUTABLE}, &fd);
114 if (result != ZX_OK) {
115 FML_LOG(ERROR) << "fdio_open3_fd_at(" << path << ") "
116 << "failed: " << zx_status_get_string(result);
117 return -1;
118 }
119 return fd;
120}
121
122bool ElfSnapshot::Load(fdio_ns_t* namespc, const std::string& path) {
123 int root_dir = -1;
124 if (namespc == nullptr) {
125 root_dir = AT_FDCWD;
126 } else {
127 root_dir = fdio_ns_opendir(namespc);
128 if (root_dir < 0) {
129 FML_LOG(ERROR) << "Failed to open namespace directory";
130 return false;
131 }
132 }
133 return Load(root_dir, path);
134}
135
136bool ElfSnapshot::Load(int dirfd, const std::string& path) {
137 fml::UniqueFD fd(OpenFdExec(path, dirfd));
138 if (!fd.is_valid()) {
139 FML_LOG(ERROR) << "Failed to open VMO for " << path << " from dir.";
140 return false;
141 }
142 return Load(fd);
143}
144
145bool ElfSnapshot::Load(const fml::UniqueFD& fd) {
146 zx_handle_t vmo = ZX_HANDLE_INVALID;
147 zx_status_t status = fdio_get_vmo_exec(fd.get(), &vmo);
148 if (status != ZX_OK) {
149 FML_LOG(ERROR) << "Failed load ELF: " << zx_status_get_string(status);
150 return false;
151 }
152 handle_ = dlopen_vmo(vmo, RTLD_LAZY);
153 if (handle_ == nullptr) {
154 const char* error = dlerror();
155 FML_LOG(ERROR) << "Failed load ELF: " << error;
156 return false;
157 }
158
159 vm_data_ =
160 reinterpret_cast<const uint8_t*>(dlsym(handle_, kVmSnapshotDataCSymbol));
161 vm_instrs_ = reinterpret_cast<const uint8_t*>(
162 dlsym(handle_, kVmSnapshotInstructionsCSymbol));
163 isolate_data_ = reinterpret_cast<const uint8_t*>(
164 dlsym(handle_, kIsolateSnapshotDataCSymbol));
165 isolate_instrs_ = reinterpret_cast<const uint8_t*>(
166 dlsym(handle_, kIsolateSnapshotInstructionsCSymbol));
167 if (vm_data_ == nullptr || vm_instrs_ == nullptr ||
168 isolate_data_ == nullptr || isolate_instrs_ == nullptr) {
169 FML_LOG(ERROR) << "Failed to load ELF symbols";
170 return false;
171 }
172
173 return true;
174}
175
177 dlclose(handle_);
178}
179
180} // namespace dart_utils
bool Load(fdio_ns_t *namespc, const std::string &path)
static bool LoadFromNamespace(fdio_ns_t *namespc, const std::string &path, MappedResource &resource, bool executable=false)
static bool LoadFromVmo(const std::string &path, fuchsia::mem::Buffer resource_vmo, MappedResource &resource, bool executable=false)
bool is_valid() const
const T & get() const
const uint8_t uint32_t uint32_t GError ** error
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
bool VmoFromFilenameAt(int dirfd, const std::string &filename, bool executable, fuchsia::mem::Buffer *buffer)
Definition vmo.cc:63
static int OpenFdExec(const std::string &path, int dirfd)
bool VmoFromFilename(const std::string &filename, bool executable, fuchsia::mem::Buffer *buffer)
Definition vmo.cc:57
static bool OpenVmo(fuchsia::mem::Buffer *resource_vmo, fdio_ns_t *namespc, const std::string &path, bool executable)