1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
13 #include "mozilla/Assertions.h"
14 #include "mozilla/NullPtr.h"
16 #include "PlatformMacros.h"
17 #include "AutoObjectMapper.h"
19 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
21 # include "mozilla/Types.h"
22 // FIXME move these out of mozglue/linker/ElfLoader.h into their
23 // own header, so as to avoid conflicts arising from two definitions
27 __dl_get_mappable_length(void *handle
);
29 __dl_mmap(void *handle
, void *addr
, size_t length
, off_t offset
);
31 __dl_munmap(void *handle
, void *addr
, size_t length
);
33 // The following are for get_installation_lib_dir()
34 # include "nsString.h"
35 # include "nsDirectoryServiceUtils.h"
36 # include "nsDirectoryServiceDefs.h"
40 // A helper function for creating failure error messages in
41 // AutoObjectMapper*::Map.
43 failedToMessage(void(*aLog
)(const char*),
44 const char* aHowFailed
, std::string aFileName
)
47 snprintf(buf
, sizeof(buf
), "AutoObjectMapper::Map: Failed to %s \'%s\'",
48 aHowFailed
, aFileName
.c_str());
49 buf
[sizeof(buf
)-1] = 0;
54 AutoObjectMapperPOSIX::AutoObjectMapperPOSIX(void(*aLog
)(const char*))
61 AutoObjectMapperPOSIX::~AutoObjectMapperPOSIX() {
63 // There's nothing to do.
65 MOZ_ASSERT(mSize
== 0);
68 MOZ_ASSERT(mSize
> 0);
69 // The following assertion doesn't necessarily have to be true,
70 // but we assume (reasonably enough) that no mmap facility would
71 // be crazy enough to map anything at page zero.
73 munmap(mImage
, mSize
);
76 bool AutoObjectMapperPOSIX::Map(/*OUT*/void** start
, /*OUT*/size_t* length
,
79 MOZ_ASSERT(!mIsMapped
);
81 int fd
= open(fileName
.c_str(), O_RDONLY
);
83 failedToMessage(mLog
, "open", fileName
);
88 int err
= fstat(fd
, &st
);
89 size_t sz
= (err
== 0) ? st
.st_size
: 0;
90 if (err
!= 0 || sz
== 0) {
91 failedToMessage(mLog
, "fstat", fileName
);
96 void* image
= mmap(nullptr, sz
, PROT_READ
, MAP_SHARED
, fd
, 0);
97 if (image
== MAP_FAILED
) {
98 failedToMessage(mLog
, "mmap", fileName
);
105 mImage
= *start
= image
;
106 mSize
= *length
= sz
;
111 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
112 // A helper function for AutoObjectMapperFaultyLib::Map. Finds out
113 // where the installation's lib directory is, since we'll have to look
114 // in there to get hold of libmozglue.so. Returned C string is heap
115 // allocated and the caller must deallocate it.
117 get_installation_lib_dir()
119 nsCOMPtr
<nsIProperties
>
120 directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
));
121 if (!directoryService
) {
124 nsCOMPtr
<nsIFile
> greDir
;
125 nsresult rv
= directoryService
->Get(NS_GRE_DIR
, NS_GET_IID(nsIFile
),
126 getter_AddRefs(greDir
));
127 if (NS_FAILED(rv
)) return nullptr;
129 rv
= greDir
->GetNativePath(path
);
133 return strdup(path
.get());
136 AutoObjectMapperFaultyLib::AutoObjectMapperFaultyLib(void(*aLog
)(const char*))
137 : AutoObjectMapperPOSIX(aLog
)
141 AutoObjectMapperFaultyLib::~AutoObjectMapperFaultyLib() {
143 // We've got an object mapped by faulty.lib. Unmap it via faulty.lib.
144 MOZ_ASSERT(mSize
> 0);
145 // Assert on the basis that no valid mapping would start at page zero.
147 __dl_munmap(mHdl
, mImage
, mSize
);
149 // Stop assertions in ~AutoObjectMapperPOSIX from failing.
153 // At this point the parent class destructor, ~AutoObjectMapperPOSIX,
154 // gets called. If that has something mapped in the normal way, it
155 // will unmap it in the normal way. Unfortunately there's no
156 // obvious way to enforce the requirement that the object is mapped
157 // either by faulty.lib or by the parent class, but not by both.
160 bool AutoObjectMapperFaultyLib::Map(/*OUT*/void** start
, /*OUT*/size_t* length
,
161 std::string fileName
)
165 if (fileName
== "libmozglue.so") {
167 // Do (2) in the comment above.
168 char* libdir
= get_installation_lib_dir();
170 fileName
= std::string(libdir
) + "/lib/" + fileName
;
173 // Hand the problem off to the standard mapper.
174 return AutoObjectMapperPOSIX::Map(start
, length
, fileName
);
178 // Do cases (1) and (3) in the comment above. We have to
179 // grapple with faulty.lib directly.
180 void* hdl
= dlopen(fileName
.c_str(), RTLD_GLOBAL
| RTLD_LAZY
);
182 failedToMessage(mLog
, "get handle for ELF file", fileName
);
186 size_t sz
= __dl_get_mappable_length(hdl
);
189 failedToMessage(mLog
, "get size for ELF file", fileName
);
193 void* image
= __dl_mmap(hdl
, nullptr, sz
, 0);
194 if (image
== MAP_FAILED
) {
196 failedToMessage(mLog
, "mmap ELF file", fileName
);
201 mImage
= *start
= image
;
202 mSize
= *length
= sz
;
207 #endif // defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)