summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-15 22:51:03 +0000
committerbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-15 22:51:03 +0000
commit5b0cd647c7afc0f9f99efcfc80b6e888c460f760 (patch)
treed6d39125de0a1b866e156d91158b3e0f3fdaeb1b /native_client_sdk
parentf8a5aec01f3489433363c2b34c9f8f6bcd8b79cb (diff)
downloadchromium_src-5b0cd647c7afc0f9f99efcfc80b6e888c460f760.zip
chromium_src-5b0cd647c7afc0f9f99efcfc80b6e888c460f760.tar.gz
chromium_src-5b0cd647c7afc0f9f99efcfc80b6e888c460f760.tar.bz2
[NaCl SDK] dlopen works from non-NMF source.
* Modify dlopen example to show this new behavior. * Add new MountPassthrough to nacl_io * Add nacl_io wrapping for mmap and open_resource functions. * Add more _real_* functions for passing through to the IRT. BUG=155086 TBR=noelallen@chromium.org NOTRY=true Review URL: https://chromiumcodereview.appspot.com/12253041 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182852 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/examples/dlopen/Makefile12
-rw-r--r--native_client_sdk/src/examples/dlopen/dlopen.cc146
-rw-r--r--native_client_sdk/src/examples/dlopen/eightball.cc4
-rw-r--r--native_client_sdk/src/examples/dlopen/eightball.h10
-rw-r--r--native_client_sdk/src/examples/dlopen/example.dsc7
-rw-r--r--native_client_sdk/src/examples/dlopen/example.js12
-rw-r--r--native_client_sdk/src/examples/dlopen/index.html2
-rw-r--r--native_client_sdk/src/examples/dlopen/reverse.cc16
-rw-r--r--native_client_sdk/src/examples/dlopen/reverse.h12
-rw-r--r--native_client_sdk/src/libraries/nacl_io/Makefile5
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc13
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.h4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.cc15
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.h11
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc116
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.h7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap.h3
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc110
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc71
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_real.h29
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc47
-rw-r--r--native_client_sdk/src/libraries/nacl_io/library.dsc4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount.h4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.cc8
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.cc29
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.h3
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc174
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.h30
-rw-r--r--native_client_sdk/src/libraries/nacl_io/nacl_io.h8
-rw-r--r--native_client_sdk/src/libraries/nacl_io/osmman.h27
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc115
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc9
-rw-r--r--native_client_sdk/src/tools/nacl_gcc.mk7
34 files changed, 981 insertions, 91 deletions
diff --git a/native_client_sdk/src/examples/dlopen/Makefile b/native_client_sdk/src/examples/dlopen/Makefile
index 29a08a8..8ddaf2c6 100644
--- a/native_client_sdk/src/examples/dlopen/Makefile
+++ b/native_client_sdk/src/examples/dlopen/Makefile
@@ -42,6 +42,7 @@ TARGET=dlopen
#
DLOPEN_SRCS=dlopen.cc
EIGHTBALL_SRCS=eightball.cc
+REVERSE_SRCS=reverse.cc
#
@@ -57,7 +58,7 @@ EIGHTBALL_SRCS=eightball.cc
# and the set we do not. This example does not havea any additional library
# dependencies.
#
-DEPS=
+DEPS=nacl_io
LIBS=$(DEPS) dl ppapi_cpp ppapi pthread
@@ -71,6 +72,14 @@ $(foreach dep,$(DEPS),$(eval $(call DEPEND_RULE,$(dep))))
#
$(foreach src,$(DLOPEN_SRCS),$(eval $(call COMPILE_RULE,$(src))))
$(foreach src,$(EIGHTBALL_SRCS),$(eval $(call COMPILE_RULE,$(src),-fPIC)))
+$(foreach src,$(REVERSE_SRCS),$(eval $(call COMPILE_RULE,$(src),-fPIC)))
+
+# NOTE: The 1 argument here builds libeightball, but prevents it from being
+# automatically included in the .nmf file (and therefore loaded at startup).
+# This is done to demonstrate that the shared library can be successfully
+# loaded from any location (in this example, the HTTP mount).
+$(eval $(call SO_RULE,libreverse,$(REVERSE_SRCS),,,1))
+
#
# Use the link macro for this target on the list of sources.
@@ -78,7 +87,6 @@ $(foreach src,$(EIGHTBALL_SRCS),$(eval $(call COMPILE_RULE,$(src),-fPIC)))
$(eval $(call SO_RULE,libeightball,$(EIGHTBALL_SRCS)))
$(eval $(call LINK_RULE,$(TARGET),$(DLOPEN_SRCS),$(LIBS),$(DEPS)))
-
#
# Specify the NMF to be created with no additional arugments.
#
diff --git a/native_client_sdk/src/examples/dlopen/dlopen.cc b/native_client_sdk/src/examples/dlopen/dlopen.cc
index 5a5487e..f77930a 100644
--- a/native_client_sdk/src/examples/dlopen/dlopen.cc
+++ b/native_client_sdk/src/examples/dlopen/dlopen.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Native Client Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,35 +16,32 @@
/// a blocking call, which is not alowed on the main thread.
#include <dlfcn.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
-#include <pthread.h>
+#include <string.h>
-#include <ppapi/cpp/module.h>
#include <ppapi/cpp/completion_callback.h>
-#include <ppapi/cpp/var.h>
#include <ppapi/cpp/instance.h>
+#include <ppapi/cpp/module.h>
+#include <ppapi/cpp/var.h>
#include "eightball.h"
+#include "nacl_io/nacl_io.h"
+#include "reverse.h"
-/// The Instance class. One of these exists for each instance of your NaCl
-/// module on the web page. The browser will ask the Module object to create
-/// a new Instance for each occurrence of the <embed> tag that has these
-/// attributes:
-/// <pre>
-/// type="application/x-nacl"
-/// nacl="dlopen.nmf"
-/// </pre>
-class dlOpenInstance : public pp::Instance {
+
+class DlopenInstance : public pp::Instance {
public:
- explicit dlOpenInstance(pp::Core *core, PP_Instance instance):
- pp::Instance(instance) {
- _dlhandle = NULL;
- _eightball = NULL;
- _core = core;
- _tid = 0;
- };
- virtual ~dlOpenInstance(){};
+ explicit DlopenInstance(PP_Instance instance)
+ : pp::Instance(instance),
+ eightball_so_(NULL),
+ reverse_so_(NULL),
+ eightball_(NULL),
+ reverse_(NULL),
+ tid_(NULL) {}
+
+ virtual ~DlopenInstance(){};
// Helper function to post a message back to the JS and stdout functions.
void logmsg(const char* pStr){
@@ -54,8 +51,14 @@ class dlOpenInstance : public pp::Instance {
// Initialize the module, staring a worker thread to load the shared object.
virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]){
+ nacl_io_init_ppapi(pp_instance(),
+ pp::Module::Get()->get_browser_interface());
+ // Mount a HTTP mount at /http. All reads from /http/* will read from the
+ // server.
+ mount("", "/http", "httpfs", 0, "");
+
logmsg("Spawning thread to cache .so files...");
- if (pthread_create(&_tid, NULL, LoadLibrariesOnWorker, this)) {
+ if (pthread_create(&tid_, NULL, LoadLibrariesOnWorker, this)) {
logmsg("ERROR; pthread_create() failed.\n");
return false;
}
@@ -65,57 +68,86 @@ class dlOpenInstance : public pp::Instance {
// This function is called on a worker thread, and will call dlopen to load
// the shared object. In addition, note that this function does NOT call
// dlclose, which would close the shared object and unload it from memory.
- void LoadLibrary()
- {
+ void LoadLibrary() {
const int32_t IMMEDIATELY = 0;
- _dlhandle = dlopen("libeightball.so", RTLD_LAZY);
+ eightball_so_ = dlopen("libeightball.so", RTLD_LAZY);
+ reverse_so_ = dlopen("/http/glibc/Debug/libreverse_x86_64.so", RTLD_LAZY);
pp::CompletionCallback cc(LoadDoneCB, this);
- _core->CallOnMainThread(IMMEDIATELY, cc , 0);
+ pp::Module::Get()->core()->CallOnMainThread(IMMEDIATELY, cc , 0);
}
// This function will run on the main thread and use the handle it stored by
// the worker thread, assuming it successfully loaded, to get a pointer to the
// message function in the shared object.
void UseLibrary() {
- _dlhandle = dlopen("libeightball.so", RTLD_LAZY);
- if(_dlhandle == NULL) {
- logmsg("libeightball.so did not load");
- } else {
- intptr_t offset = (intptr_t) dlsym(this->_dlhandle, "Magic8Ball");
- _eightball = (TYPE_eightball) offset;
- if (NULL == _eightball) {
- std::string ballmessage = "dlsym() returned NULL: ";
- ballmessage += dlerror();
- ballmessage += "\n";
- logmsg(ballmessage.c_str());
+ if (eightball_so_ != NULL) {
+ intptr_t offset = (intptr_t) dlsym(eightball_so_, "Magic8Ball");
+ eightball_ = (TYPE_eightball) offset;
+ if (NULL == eightball_) {
+ std::string message = "dlsym() returned NULL: ";
+ message += dlerror();
+ message += "\n";
+ logmsg(message.c_str());
+ return;
}
- else{
- logmsg("Eightball loaded!");
+
+ logmsg("Loaded libeightball.so");
+ } else {
+ logmsg("libeightball.so did not load");
+ }
+
+
+ if (reverse_so_ != NULL) {
+ intptr_t offset = (intptr_t) dlsym(reverse_so_, "Reverse");
+ reverse_ = (TYPE_reverse) offset;
+ if (NULL == reverse_) {
+ std::string message = "dlsym() returned NULL: ";
+ message += dlerror();
+ message += "\n";
+ logmsg(message.c_str());
+ return;
}
+ logmsg("Loaded libreverse.so");
+ } else {
+ logmsg("libreverse.so did not load");
}
}
// Called by the browser to handle the postMessage() call in Javascript.
virtual void HandleMessage(const pp::Var& var_message) {
- if(NULL == _eightball){
- logmsg("Eightball library not loaded");
- return;
- }
-
if (!var_message.is_string()) {
logmsg("Message is not a string.");
return;
}
std::string message = var_message.AsString();
- if (message == "query") {
- fprintf(stdout, "%s(%d) Got this far.\n", __FILE__, __LINE__);
+ if (message == "eightball") {
+ if (NULL == eightball_){
+ logmsg("Eightball library not loaded");
+ return;
+ }
+
std::string ballmessage = "The Magic 8-Ball says: ";
- ballmessage += this->_eightball();
+ ballmessage += eightball_();
ballmessage += "!";
logmsg(ballmessage.c_str());
- fprintf(stdout, "%s(%d) Got this far.\n", __FILE__, __LINE__);
+ } else if (message.find("reverse:") == 0) {
+ if (NULL == reverse_) {
+ logmsg("Reverse library not loaded");
+ return;
+ }
+
+ std::string s = message.substr(strlen("reverse:"));
+ char* result = reverse_(s.c_str());
+
+ std::string message = "Your string reversed: \"";
+ message += result;
+ message += "\"";
+
+ free(result);
+
+ logmsg(message.c_str());
} else {
std::string errormsg = "Unexpected message: ";
errormsg += message + "\n";
@@ -124,22 +156,22 @@ class dlOpenInstance : public pp::Instance {
}
static void* LoadLibrariesOnWorker(void *pInst) {
- dlOpenInstance *inst = static_cast<dlOpenInstance *>(pInst);
+ DlopenInstance *inst = static_cast<DlopenInstance *>(pInst);
inst->LoadLibrary();
return NULL;
}
static void LoadDoneCB(void *pInst, int32_t result) {
- dlOpenInstance *inst = static_cast<dlOpenInstance *>(pInst);
+ DlopenInstance *inst = static_cast<DlopenInstance *>(pInst);
inst->UseLibrary();
}
private:
- void *_dlhandle;
- TYPE_eightball _eightball;
- pp::Core *_core;
- pthread_t _tid;
-
+ void* eightball_so_;
+ void* reverse_so_;
+ TYPE_eightball eightball_;
+ TYPE_reverse reverse_;
+ pthread_t tid_;
};
// The Module class. The browser calls the CreateInstance() method to create
@@ -150,9 +182,9 @@ class dlOpenModule : public pp::Module {
dlOpenModule() : pp::Module() {}
virtual ~dlOpenModule() {}
- // Create and return a dlOpenInstance object.
+ // Create and return a DlopenInstance object.
virtual pp::Instance* CreateInstance(PP_Instance instance) {
- return new dlOpenInstance(core(), instance);
+ return new DlopenInstance(instance);
}
};
diff --git a/native_client_sdk/src/examples/dlopen/eightball.cc b/native_client_sdk/src/examples/dlopen/eightball.cc
index df2be2a..531f8a61 100644
--- a/native_client_sdk/src/examples/dlopen/eightball.cc
+++ b/native_client_sdk/src/examples/dlopen/eightball.cc
@@ -1,3 +1,7 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
#include <stdlib.h>
#include <stdio.h>
diff --git a/native_client_sdk/src/examples/dlopen/eightball.h b/native_client_sdk/src/examples/dlopen/eightball.h
index d0924d3..df3d997 100644
--- a/native_client_sdk/src/examples/dlopen/eightball.h
+++ b/native_client_sdk/src/examples/dlopen/eightball.h
@@ -1,9 +1,13 @@
-#ifndef __EIGHTBALL_H__
-#define __EIGHTBALL_H__
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EIGHTBALL_H_
+#define EIGHTBALL_H_
/* Return an answer. Question not required */
typedef char* (*TYPE_eightball)(void);
extern "C" const char* Magic8Ball();
-#endif /* __EIGHTBALL_H__ */
+#endif /* EIGHTBALL_H_ */
diff --git a/native_client_sdk/src/examples/dlopen/example.dsc b/native_client_sdk/src/examples/dlopen/example.dsc
index cd66e0c..09f0434 100644
--- a/native_client_sdk/src/examples/dlopen/example.dsc
+++ b/native_client_sdk/src/examples/dlopen/example.dsc
@@ -13,6 +13,13 @@
'SOURCES' : ['eightball.cc', 'eightball.h'],
'CXXFLAGS': ['-fPIC'],
'LIBS' : ['ppapi_cpp', 'ppapi', 'pthread']
+ },
+ {
+ 'NAME' : 'libreverse',
+ 'TYPE' : 'so',
+ 'SOURCES' : ['reverse.cc', 'reverse.h'],
+ 'CXXFLAGS': ['-fPIC'],
+ 'LIBS' : ['ppapi_cpp', 'ppapi', 'pthread']
}
],
'DATA': [
diff --git a/native_client_sdk/src/examples/dlopen/example.js b/native_client_sdk/src/examples/dlopen/example.js
index 580fbe8..bb658cd 100644
--- a/native_client_sdk/src/examples/dlopen/example.js
+++ b/native_client_sdk/src/examples/dlopen/example.js
@@ -5,6 +5,7 @@
// Called by the common.js module.
function attachListeners() {
document.querySelector('form').addEventListener('submit', askBall);
+ document.getElementById('reverse').addEventListener('click', reverseString);
}
// Called by the common.js module.
@@ -19,6 +20,15 @@ function askBall(event) {
var query = questionEl.value;
questionEl.value = '';
document.getElementById('log').innerHTML += 'You asked:' + query + '<br>';
- common.naclModule.postMessage('query');
+ common.naclModule.postMessage('eightball');
event.preventDefault();
}
+
+function reverseString(event) {
+ var questionEl = document.getElementById('question');
+ var query = questionEl.value;
+ questionEl.value = '';
+
+ document.getElementById('log').innerHTML += 'Reversing:' + query + '<br>';
+ common.naclModule.postMessage('reverse:' + query);
+}
diff --git a/native_client_sdk/src/examples/dlopen/index.html b/native_client_sdk/src/examples/dlopen/index.html
index 52be080..4ad4f54 100644
--- a/native_client_sdk/src/examples/dlopen/index.html
+++ b/native_client_sdk/src/examples/dlopen/index.html
@@ -21,6 +21,8 @@ found in the LICENSE file.
<input type="text" id="question" value="">
<input type="submit" value="ASK!">
</form>
+ <p>... or click this button to reverse the string.</p>
+ <button id="reverse">Reverse</button>
<!-- The NaCl plugin will be embedded inside the element with id "listener".
See common.js.-->
<div id="listener"></div>
diff --git a/native_client_sdk/src/examples/dlopen/reverse.cc b/native_client_sdk/src/examples/dlopen/reverse.cc
new file mode 100644
index 0000000..94eaaef
--- /dev/null
+++ b/native_client_sdk/src/examples/dlopen/reverse.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "reverse.h"
+#include <stdlib.h>
+#include <string.h>
+
+extern "C" char* Reverse(const char* s) {
+ size_t len = strlen(s);
+ char* reversed = static_cast<char*>(malloc(len + 1));
+ for (int i = len - 1; i >= 0; --i)
+ reversed[len - i - 1] = s[i];
+ reversed[len] = 0;
+ return reversed;
+}
diff --git a/native_client_sdk/src/examples/dlopen/reverse.h b/native_client_sdk/src/examples/dlopen/reverse.h
new file mode 100644
index 0000000..f0414ab
--- /dev/null
+++ b/native_client_sdk/src/examples/dlopen/reverse.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REVERSE_H_
+#define REVERSE_H_
+
+/* Allocate a new string that is the reverse of the given string. */
+typedef char* (*TYPE_reverse)(const char*);
+extern "C" char* Reverse(const char *);
+
+#endif /* REVERSE_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/Makefile b/native_client_sdk/src/libraries/nacl_io/Makefile
index e8c9bc9..7c5e8b4 100644
--- a/native_client_sdk/src/libraries/nacl_io/Makefile
+++ b/native_client_sdk/src/libraries/nacl_io/Makefile
@@ -43,8 +43,9 @@ TARGET=nacl_io
SOURCES:=kernel_handle.cc kernel_intercept.cc kernel_object.cc kernel_proxy.cc
SOURCES+=kernel_wrap_glibc.cc kernel_wrap_newlib.cc kernel_wrap_win.cc
SOURCES+=mount.cc mount_dev.cc mount_html5fs.cc mount_http.cc mount_mem.cc
-SOURCES+=mount_node.cc mount_node_dir.cc mount_node_html5fs.cc mount_node_mem.cc
-SOURCES+=nacl_io.cc path.cc pepper_interface.cc real_pepper_interface.cc
+SOURCES+=mount_node.cc mount_node_dir.cc mount_node_html5fs.cc
+SOURCES+=mount_node_mem.cc mount_passthrough.cc nacl_io.cc path.cc
+SOURCES+=pepper_interface.cc real_pepper_interface.cc
#
# Use the compile macro for each source.
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
index 9af208d..d42f118 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
@@ -155,3 +155,16 @@ int ki_link(const char* oldpath, const char* newpath) {
int ki_symlink(const char* oldpath, const char* newpath) {
return s_kp->symlink(oldpath, newpath);
}
+
+void* ki_mmap(void* addr, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ return s_kp->mmap(addr, length, prot, flags, fd, offset);
+}
+
+int ki_munmap(void* addr, size_t length) {
+ return s_kp->munmap(addr, length);
+}
+
+int ki_open_resource(const char* file) {
+ return s_kp->open_resource(file);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
index 8cec8ae..6de064d 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
@@ -51,6 +51,10 @@ int ki_unlink(const char* path);
int ki_access(const char* path, int amode);
int ki_link(const char* oldpath, const char* newpath);
int ki_symlink(const char* oldpath, const char* newpath);
+void* ki_mmap(void* addr, size_t length, int prot, int flags, int fd,
+ off_t offset);
+int ki_munmap(void* addr, size_t length);
+int ki_open_resource(const char* file);
EXTERN_C_END
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
index fca4041..95223f6 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
@@ -19,6 +19,19 @@
#include "nacl_io/mount_node.h"
#include "utils/auto_lock.h"
+KernelObject::MMapInfo::MMapInfo()
+ : addr(NULL),
+ length(0),
+ handle(NULL) {
+}
+
+KernelObject::MMapInfo::MMapInfo(void* addr, size_t length,
+ KernelHandle* handle)
+ : addr(addr),
+ length(length),
+ handle(handle) {
+}
+
KernelObject::KernelObject() {
pthread_mutex_init(&kernel_lock_, NULL);
pthread_mutex_init(&process_lock_, NULL);
@@ -161,8 +174,8 @@ void KernelObject::FreeFD(int fd) {
// Release the mount and handle since we no longer
// track them with this FD.
KernelHandle* handle = handle_map_[fd];
- handle->mount_->Release();
handle->Release();
+ handle->mount_->Release();
handle_map_[fd] = NULL;
free_fds_.push_back(fd);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.h b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
index f4c1b9e..d50aabc 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
@@ -21,8 +21,18 @@ class Mount;
// path resolution.
class KernelObject {
public:
+ struct MMapInfo {
+ MMapInfo();
+ MMapInfo(void* addr, size_t length, KernelHandle* handle);
+
+ void* addr;
+ size_t length;
+ KernelHandle* handle;
+ };
+
typedef std::vector<KernelHandle*> HandleMap_t;
typedef std::map<std::string, Mount*> MountMap_t;
+ typedef std::vector<MMapInfo> MMapInfoList_t;
KernelObject();
virtual ~KernelObject();
@@ -49,6 +59,7 @@ class KernelObject {
HandleMap_t handle_map_;
MountMap_t mounts_;
+ MMapInfoList_t mmap_info_list_;
// Kernel lock protects kernel wide resources such as the mount table...
pthread_mutex_t kernel_lock_;
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
index 71a0e65..745a680 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -9,15 +9,19 @@
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
+#include <iterator>
#include <string>
#include "nacl_io/kernel_handle.h"
+#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/mount.h"
#include "nacl_io/mount_dev.h"
#include "nacl_io/mount_html5fs.h"
#include "nacl_io/mount_http.h"
#include "nacl_io/mount_mem.h"
#include "nacl_io/mount_node.h"
+#include "nacl_io/mount_passthrough.h"
+#include "nacl_io/osmman.h"
#include "nacl_io/osstat.h"
#include "nacl_io/path.h"
#include "nacl_io/pepper_interface.h"
@@ -33,6 +37,7 @@
#define GRP_ID 1003
+
KernelProxy::KernelProxy()
: dev_(0),
ppapi_(NULL) {
@@ -51,10 +56,12 @@ void KernelProxy::Init(PepperInterface* ppapi) {
factories_["dev"] = MountDev::Create<MountDev>;
factories_["html5fs"] = MountHtml5Fs::Create<MountHtml5Fs>;
factories_["httpfs"] = MountHttp::Create<MountHttp>;
+ factories_["passthroughfs"] = MountPassthrough::Create<MountPassthrough>;
- // Create memory mount at root
+ // Create passthrough mount at root
StringMap_t smap;
- mounts_["/"] = MountMem::Create<MountMem>(dev_++, smap, ppapi_);
+ mounts_["/"] = MountPassthrough::Create<MountPassthrough>(
+ dev_++, smap, ppapi_);
mounts_["/dev"] = MountDev::Create<MountDev>(dev_++, smap, ppapi_);
// Open the first three in order to get STDIN, STDOUT, STDERR
@@ -428,3 +435,108 @@ int KernelProxy::symlink(const char* oldpath, const char* newpath) {
errno = EINVAL;
return -1;
}
+
+void* KernelProxy::mmap(void* addr, size_t length, int prot, int flags, int fd,
+ size_t offset) {
+ // We shouldn't be getting anonymous mmaps here.
+ assert((flags & MAP_ANONYMOUS) == 0);
+ assert(fd != -1);
+
+ KernelHandle* handle = AcquireHandle(fd);
+
+ if (NULL == handle)
+ return MAP_FAILED;
+
+ void* new_addr;
+ {
+ AutoLock lock(&handle->lock_);
+ new_addr = handle->node_->MMap(addr, length, prot, flags, offset);
+ if (new_addr == MAP_FAILED) {
+ ReleaseHandle(handle);
+ return MAP_FAILED;
+ }
+ }
+
+ // Don't release the KernelHandle, it is now owned by the MMapInfo.
+ AutoLock lock(&process_lock_);
+ mmap_info_list_.push_back(MMapInfo(new_addr, length, handle));
+
+ return new_addr;
+}
+
+int KernelProxy::munmap(void* addr, size_t length) {
+ if (addr == NULL || length == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ MMapInfoList_t unmap_list;
+ {
+ AutoLock lock(&process_lock_);
+ int mmap_list_end = mmap_info_list_.size();
+ void* addr_end = static_cast<char*>(addr) + length;
+
+ for (int i = 0; i < mmap_list_end;) {
+ const MMapInfo& mmap_info = mmap_info_list_[i];
+ if (addr < static_cast<char*>(mmap_info.addr) + mmap_info.length &&
+ mmap_info.addr < addr_end)
+ // This memory area should be unmapped; swap it with the last entry in
+ // our list.
+ std::swap(mmap_info_list_[i], mmap_info_list_[--mmap_list_end]);
+ else
+ ++i;
+ }
+
+ int num_to_unmap =- mmap_info_list_.size() - mmap_list_end;
+ if (!num_to_unmap) {
+ // From the Linux mmap man page: "It is not an error if the indicated
+ // range does not contain any mapped pages."
+ return 0;
+ }
+
+ std::copy(mmap_info_list_.begin() + mmap_list_end, mmap_info_list_.end(),
+ std::back_inserter(unmap_list));
+
+ mmap_info_list_.resize(mmap_list_end);
+ }
+
+ // Unmap everything past the new end of the list.
+ for (int i = 0; i < unmap_list.size(); ++i) {
+ const MMapInfo& mmap_info = unmap_list[i];
+ KernelHandle* handle = mmap_info.handle;
+ assert(handle != NULL);
+
+ // Ignore the results from individual munmaps.
+ handle->node_->Munmap(mmap_info.addr, mmap_info.length);
+ ReleaseHandle(handle);
+ }
+
+ return 0;
+}
+
+int KernelProxy::open_resource(const char* path) {
+ Path rel;
+
+ Mount* mnt = AcquireMountAndPath(path, &rel);
+ if (mnt == NULL) return -1;
+
+ MountNode* node = mnt->OpenResource(rel);
+ if (node == NULL) {
+ node = mnt->Open(rel, O_RDONLY);
+ if (node == NULL) {
+ ReleaseMount(mnt);
+ return -1;
+ }
+ }
+
+ // OpenResource failed, try Open().
+
+ KernelHandle* handle = new KernelHandle(mnt, node, O_RDONLY);
+ int fd = AllocateFD(handle);
+ mnt->AcquireNode(node);
+
+ ReleaseHandle(handle);
+ ReleaseMount(mnt);
+
+ return fd;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
index 904ef52..5ac7b9347 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
@@ -89,6 +89,13 @@ class KernelProxy : protected KernelObject {
virtual int link(const char* oldpath, const char* newpath);
virtual int symlink(const char* oldpath, const char* newpath);
+ virtual void* mmap(void* addr, size_t length, int prot, int flags, int fd,
+ size_t offset);
+ virtual int munmap(void* addr, size_t length);
+
+ // NaCl-only function to read resources specified in the NMF file.
+ virtual int open_resource(const char* file);
+
protected:
MountFactoryMap_t factories_;
int dev_;
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
index 7d88cfd..fa67be3 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
@@ -61,8 +61,11 @@ int _mkdir(const char* path);
#else
int mkdir(const char* path, mode_t mode) NOTHROW;
#endif
+void* mmap(void* addr, size_t length, int prot, int flags, int fd,
+ off_t offset) NOTHROW;
int mount(const char* source, const char* target, const char* filesystemtype,
unsigned long mountflags, const void* data) NOTHROW;
+int munmap(void* addr, size_t length) NOTHROW;
int NAME(open)(const char* path, int oflag, ...);
read_ssize_t NAME(read)(int fd, void* buf, size_t nbyte);
int remove(const char* path) NOTHROW;
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
index 67f1fc2..3c81474 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
@@ -17,6 +17,7 @@
#include <irt_syscalls.h>
#include <nacl_stat.h>
#include <string.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include "nacl_io/kernel_intercept.h"
@@ -117,6 +118,9 @@ DECLARE(rmdir)
DECLARE(seek)
DECLARE(stat)
DECLARE(write)
+DECLARE(mmap)
+DECLARE(munmap)
+DECLARE(open_resource)
int access(const char* path, int amode) NOTHROW {
return ki_access(path, amode);
@@ -223,16 +227,37 @@ int WRAP(mkdir) (const char* pathname, mode_t mode) {
return (ki_mkdir(pathname, mode)) ? errno : 0;
}
+int WRAP(mmap)(void** addr, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ if (flags & MAP_ANONYMOUS)
+ return REAL(mmap)(addr, length, prot, flags, fd, offset);
+
+ *addr = ki_mmap(*addr, length, prot, flags, fd, offset);
+ return *addr == (void*)-1 ? errno : 0;
+}
+
int mount(const char* source, const char* target, const char* filesystemtype,
unsigned long mountflags, const void* data) NOTHROW {
return ki_mount(source, target, filesystemtype, mountflags, data);
}
+int WRAP(munmap)(void* addr, size_t length) {
+ // Always let the real munmap run on the address range. It is not an error if
+ // there are no mapped pages in that range.
+ int result = ki_munmap(addr, length);
+ return REAL(munmap)(addr, length);
+}
+
int WRAP(open)(const char* pathname, int oflag, mode_t cmode, int* newfd) {
*newfd = ki_open(pathname, oflag);
return (*newfd < 0) ? errno : 0;
}
+int WRAP(open_resource)(const char* file, int* fd) {
+ *fd = ki_open_resource(file);
+ return (*fd < 0) ? errno : 0;
+}
+
int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) {
if (!ki_is_initialized())
return REAL(read)(fd, buf, count, nread);
@@ -290,20 +315,92 @@ int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) {
return (signed_nwrote < 0) ? errno : 0;
}
-int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
- return REAL(write)(fd, buf, count, nwrote);
+
+// "real" functions, i.e. the unwrapped original functions.
+
+int _real_close(int fd) {
+ return REAL(close)(fd);
+}
+
+int _real_fstat(int fd, struct stat *buf) {
+ struct nacl_abi_stat st;
+ int err = REAL(fstat)(fd, &st);
+ if (err) {
+ errno = err;
+ return -1;
+ }
+
+ nacl_stat_to_stat(&st, buf);
+ return 0;
+}
+
+int _real_getdents(int fd, void* buf, size_t count, size_t *nread) {
+ // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s).
+ // See WRAP(getdents) above.
+ char* nacl_buf = (char*)alloca(count);
+ size_t offset = 0;
+ size_t nacl_offset = 0;
+ size_t nacl_nread;
+ int err = REAL(getdents)(fd, (dirent*)nacl_buf, count, &nacl_nread);
+ if (err)
+ return err;
+
+ while (nacl_offset < nacl_nread) {
+ dirent* d = (dirent*)((char*)buf + offset);
+ nacl_abi_dirent* nacl_d = (nacl_abi_dirent*)(nacl_buf + nacl_offset);
+ d->d_ino = nacl_d->nacl_abi_d_ino;
+ d->d_off = nacl_d->nacl_abi_d_off;
+ d->d_reclen = nacl_d->nacl_abi_d_reclen + d_name_shift;
+ size_t d_name_len = nacl_d->nacl_abi_d_reclen -
+ offsetof(nacl_abi_dirent, nacl_abi_d_name);
+ memcpy(d->d_name, nacl_d->nacl_abi_d_name, d_name_len);
+
+ offset += d->d_reclen;
+ offset += nacl_d->nacl_abi_d_reclen;
+ }
+
+ *nread = offset;
+ return 0;
+}
+
+int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
+ return REAL(seek)(fd, offset, whence, new_offset);
+}
+
+int _real_mkdir(const char* pathname, mode_t mode) {
+ return REAL(mkdir)(pathname, mode);
+}
+
+int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ return REAL(mmap)(addr, length, prot, flags, fd, offset);
+}
+
+int _real_munmap(void* addr, size_t length) {
+ return REAL(munmap)(addr, length);
+}
+
+int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
+ return REAL(open)(pathname, oflag, cmode, newfd);
+}
+
+int _real_open_resource(const char* file, int* fd) {
+ return REAL(open_resource)(file, fd);
}
int _real_read(int fd, void *buf, size_t count, size_t *nread) {
return REAL(read)(fd, buf, count, nread);
}
-int _real_fstat(int fd, struct stat *buf) {
- struct nacl_abi_stat st;
- int ret = REAL(fstat)(fd, &st);
+int _real_rmdir(const char* pathname) {
+ return REAL(rmdir)(pathname);
+}
+int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
+ return REAL(write)(fd, buf, count, nwrote);
}
+
void kernel_wrap_init() {
static bool wrapped = false;
@@ -323,6 +420,9 @@ void kernel_wrap_init() {
DO_WRAP(seek);
DO_WRAP(stat);
DO_WRAP(write);
+ DO_WRAP(mmap);
+ DO_WRAP(munmap);
+ DO_WRAP(open_resource);
}
}
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
index f0c410e..37a58e5 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
@@ -13,6 +13,7 @@
#include <dirent.h>
#include <errno.h>
#include <irt.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include "nacl_io/kernel_intercept.h"
@@ -32,6 +33,7 @@ EXTERN_C_BEGIN
DECLARE_STRUCT(fdio)
DECLARE_STRUCT(filename)
+DECLARE_STRUCT(memory)
DECLARE(fdio, close)
DECLARE(fdio, dup)
@@ -43,6 +45,8 @@ DECLARE(fdio, seek)
DECLARE(fdio, write)
DECLARE(filename, open)
DECLARE(filename, stat)
+DECLARE(memory, mmap)
+DECLARE(memory, munmap)
int access(const char* path, int amode) {
@@ -107,11 +111,27 @@ int mkdir(const char* path, mode_t mode) {
return ki_mkdir(path, mode);
}
+int WRAP(mmap)(void** addr, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ if (flags & MAP_ANONYMOUS)
+ return REAL(mmap)(addr, length, prot, flags, fd, offset);
+
+ *addr = ki_mmap(*addr, length, prot, flags, fd, offset);
+ return *addr == (void*)-1 ? errno : 0;
+}
+
int mount(const char* source, const char* target, const char* filesystemtype,
unsigned long mountflags, const void* data) {
return ki_mount(source, target, filesystemtype, mountflags, data);
}
+int WRAP(munmap)(void* addr, size_t length) {
+ // Always let the real munmap run on the address range. It is not an error if
+ // there are no mapped pages in that range.
+ ki_munmap(addr, length);
+ return REAL(munmap)(addr, length);
+}
+
int WRAP(open)(const char* pathname, int oflag, mode_t cmode, int* newfd) {
*newfd = ki_open(pathname, oflag);
return (*newfd < 0) ? errno : 0;
@@ -164,18 +184,59 @@ int WRAP(write)(int fd, const void *buf, size_t count, size_t *nwrote) {
return (signed_nwrote < 0) ? errno : 0;
}
-int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
- return REAL(write)(fd, buf, count, nwrote);
+
+// "real" functions, i.e. the unwrapped original functions.
+
+int _real_close(int fd) {
+ return REAL(close)(fd);
+}
+
+int _real_fstat(int fd, struct stat *buf) {
+ return REAL(fstat)(fd, buf);
+}
+
+int _real_getdents(int fd, dirent* nacl_buf, size_t nacl_count, size_t *nread) {
+ return REAL(getdents)(fd, nacl_buf, nacl_count, nread);
+}
+
+int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
+ return REAL(seek)(fd, offset, whence, new_offset);
+}
+
+int _real_mkdir(const char* pathname, mode_t mode) {
+ return ENOSYS;
+}
+
+int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ return REAL(mmap)(addr, length, prot, flags, fd, offset);
+}
+
+int _real_munmap(void* addr, size_t length) {
+ return REAL(munmap)(addr, length);
+}
+
+int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
+ return REAL(open)(pathname, oflag, cmode, newfd);
+}
+
+int _real_open_resource(const char* file, int* fd) {
+ return ENOSYS;
}
int _real_read(int fd, void *buf, size_t count, size_t *nread) {
return REAL(read)(fd, buf, count, nread);
}
-int _real_fstat(int fd, struct stat *buf) {
- return REAL(fstat)(fd, buf);
+int _real_rmdir(const char* pathname) {
+ return ENOSYS;
+}
+
+int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
+ return REAL(write)(fd, buf, count, nwrote);
}
+
void kernel_wrap_init() {
static bool wrapped = false;
@@ -191,6 +252,8 @@ void kernel_wrap_init() {
DO_WRAP(fdio, write);
DO_WRAP(filename, open);
DO_WRAP(filename, stat);
+ DO_WRAP(memory, mmap);
+ DO_WRAP(memory, munmap);
}
}
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_real.h b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_real.h
new file mode 100644
index 0000000..7d7dd41
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_real.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef LIBRARIES_NACL_IO_KERNEL_WRAP_REAL_H_
+#define LIBRARIES_NACL_IO_KERNEL_WRAP_REAL_H_
+
+#include "nacl_io/ostypes.h"
+#include "utils/macros.h"
+
+EXTERN_C_BEGIN
+
+int _real_close(int fd);
+int _real_fstat(int fd, struct stat *buf);
+int _real_getdents(int fd, void* nacl_buf, size_t nacl_count, size_t *nread);
+int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset);
+int _real_mkdir(const char* pathname, mode_t mode);
+int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
+ off_t offset);
+int _real_munmap(void* addr, size_t length);
+int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd);
+int _real_open_resource(const char* file, int* fd);
+int _real_read(int fd, void *buf, size_t count, size_t *nread);
+int _real_rmdir(const char* pathname);
+int _real_write(int fd, const void *buf, size_t count, size_t *nwrote);
+
+EXTERN_C_END
+
+#endif // LIBRARIES_NACL_IO_KERNEL_WRAP_REAL_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc
index dd8f1ed..356bab7 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_win.cc
@@ -229,17 +229,58 @@ int _write(int fd, const void* buf, size_t nbyte) {
return ki_write(fd, buf, nbyte);
}
-int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
- *nwrote = count;
+
+// "real" functions, i.e. the unwrapped original functions. On Windows we don't
+// wrap, so the real functions aren't accessible. In most cases, we just fail.
+
+int _real_close(int fd) {
+ return ENOSYS;
+}
+
+int _real_fstat(int fd, struct stat *buf) {
return 0;
}
+int _real_getdents(int fd, void* nacl_buf, size_t nacl_count, size_t *nread) {
+ return ENOSYS;
+}
+
+int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
+ return ENOSYS;
+}
+
+int _real_mkdir(const char* pathname, mode_t mode) {
+ return ENOSYS;
+}
+
+int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
+ off_t offset) {
+ return ENOSYS;
+}
+
+int _real_munmap(void* addr, size_t length) {
+ return ENOSYS;
+}
+
+int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
+ return ENOSYS;
+}
+
+int _real_open_resource(const char* file, int* fd) {
+ return ENOSYS;
+}
+
int _real_read(int fd, void *buf, size_t count, size_t *nread) {
*nread = count;
return 0;
}
-int _real_fstat(int fd, struct stat *buf) {
+int _real_rmdir(const char* pathname) {
+ return ENOSYS;
+}
+
+int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
+ *nwrote = count;
return 0;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 6c7015b..d4749b2 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -28,6 +28,7 @@
"mount_node_dir.cc",
"mount_node_html5fs.cc",
"mount_node_mem.cc",
+ "mount_passthrough.cc",
"nacl_io.cc",
"path.cc",
"pepper_interface.cc",
@@ -44,6 +45,7 @@
"kernel_object.h",
"kernel_proxy.h",
"kernel_wrap.h",
+ "kernel_wrap_real.h",
"mount.h",
"mount_dev.h",
"mount_html5fs.h",
@@ -53,9 +55,11 @@
"mount_node.h",
"mount_node_html5fs.h",
"mount_node_mem.h",
+ "mount_passthrough.h",
"nacl_io.h",
"osdirent.h",
"osinttypes.h",
+ "osmman.h",
"osstat.h",
"ostypes.h",
"path.h",
diff --git a/native_client_sdk/src/libraries/nacl_io/mount.h b/native_client_sdk/src/libraries/nacl_io/mount.h
index dfc2e72..622dae0 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount.h
@@ -47,6 +47,10 @@ class Mount : public RefObject {
// MountNode is created with a ref count of 1.
virtual MountNode *Open(const Path& path, int o_flags) = 0;
+ // OpenResource is only used to read files from the NaCl NMF file. No mount
+ // except MountPassthrough should implement it.
+ virtual MountNode *OpenResource(const Path& path) { return NULL; }
+
// Unlink, Mkdir, Rmdir will affect the both the RefCount
// and the nlink number in the stat object.
virtual int Unlink(const Path& path) = 0;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
index 4fd3dba..83d2e55 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
@@ -9,6 +9,7 @@
#include <errno.h>
#include <fcntl.h>
#include <string.h>
+#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/mount_dev.h"
#include "nacl_io/mount_node.h"
#include "nacl_io/mount_node_dir.h"
@@ -22,13 +23,6 @@
#endif
-extern "C" {
-int _real_write(int fd, const void *buf, size_t count, size_t *nwrote);
-int _real_read(int fd, void *buf, size_t count, size_t *nread);
-int _real_fstat(int fd, struct stat *buf);
-};
-
-
namespace {
void ReleaseAndNullNode(MountNode** node) {
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.cc b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
index 47c142c..d31b99f 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
@@ -10,7 +10,9 @@
#include <sys/stat.h>
#include <string>
+#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/mount.h"
+#include "nacl_io/osmman.h"
#include "utils/auto_lock.h"
static const int USR_ID = 1001;
@@ -76,6 +78,33 @@ int MountNode::Write(size_t offs, const void* buf, size_t count) {
return -1;
}
+void* MountNode::MMap(void* addr, size_t length, int prot, int flags,
+ size_t offset) {
+ // This default mmap support is just enough to make dlopen work.
+ // This implementation just reads from the mount into the mmap'd memory area.
+ void* new_addr = addr;
+ int err = _real_mmap(&new_addr, length, prot | PROT_WRITE, flags |
+ MAP_ANONYMOUS, -1, 0);
+ if (addr == MAP_FAILED) {
+ _real_munmap(addr, length);
+ errno = err;
+ return MAP_FAILED;
+ }
+
+ ssize_t cnt = Read(offset, addr, length);
+ if (cnt == -1) {
+ _real_munmap(addr, length);
+ errno = ENOSYS;
+ return MAP_FAILED;
+ }
+
+ return new_addr;
+}
+
+int MountNode::Munmap(void* addr, size_t length) {
+ return _real_munmap(addr, length);
+}
+
int MountNode::GetLinks() {
return stat_.st_nlink;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.h b/native_client_sdk/src/libraries/nacl_io/mount_node.h
index aedc093..ced95b2 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.h
@@ -35,6 +35,9 @@ class MountNode : public RefObject {
virtual int Read(size_t offs, void* buf, size_t count);
virtual int Truncate(size_t size);
virtual int Write(size_t offs, const void* buf, size_t count);
+ virtual void* MMap(void* addr, size_t length, int prot, int flags,
+ size_t offset);
+ virtual int Munmap(void* addr, size_t length);
virtual int GetLinks();
virtual int GetMode();
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
new file mode 100644
index 0000000..7cb75b1
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
@@ -0,0 +1,174 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "nacl_io/mount_passthrough.h"
+#include <errno.h>
+#include "nacl_io/kernel_wrap_real.h"
+
+class MountNodePassthrough : public MountNode {
+ public:
+ explicit MountNodePassthrough(Mount* mount, int real_fd)
+ : MountNode(mount),
+ real_fd_(real_fd) {
+ }
+
+ protected:
+ virtual bool Init(int flags) {
+ return true;
+ }
+
+ virtual void Destroy() {
+ if (real_fd_)
+ _real_close(real_fd_);
+ real_fd_ = 0;
+ }
+
+ public:
+ // Normal read/write operations on a file
+ virtual int Read(size_t offs, void* buf, size_t count) {
+ off_t new_offset;
+ int err = _real_lseek(real_fd_, offs, 0, &new_offset);
+ if (err) {
+ errno = err;
+ return -1;
+ }
+
+ size_t nread;
+ err = _real_read(real_fd_, buf, count, &nread);
+ if (err) {
+ errno = err;
+ return -1;
+ }
+
+ return static_cast<int>(nread);
+ }
+
+ virtual int Write(size_t offs, const void* buf, size_t count) {
+ off_t new_offset;
+ int err = _real_lseek(real_fd_, offs, 0, &new_offset);
+ if (err) {
+ errno = err;
+ return -1;
+ }
+
+ size_t nwrote;
+ err = _real_write(real_fd_, buf, count, &nwrote);
+ if (err) {
+ errno = err;
+ return -1;
+ }
+
+ return static_cast<int>(nwrote);
+ }
+
+ virtual int Truncate(size_t size) {
+ // TODO(binji): what to do here?
+ return -1;
+ }
+
+ virtual int GetDents(size_t offs, struct dirent* pdir, size_t count) {
+ size_t nread;
+ int err = _real_getdents(real_fd_, pdir, count, &nread);
+ if (err) {
+ errno = err;
+ return -1;
+ }
+
+ return nread;
+ }
+
+ virtual int GetStat(struct stat* stat) {
+ int err = _real_fstat(real_fd_, stat);
+ if (err) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
+ }
+
+ void* MMap(void* addr, size_t length, int prot, int flags, size_t offset) {
+ void* new_addr = addr;
+ int err = _real_mmap(&new_addr, length, prot, flags, real_fd_, offset);
+ if (err) {
+ errno = err;
+ return (void*)-1;
+ }
+
+ return new_addr;
+ }
+
+ private:
+ friend class MountPassthrough;
+
+ int real_fd_;
+};
+
+MountPassthrough::MountPassthrough() {
+}
+
+bool MountPassthrough::Init(int dev, StringMap_t& args,
+ PepperInterface* ppapi) {
+ Mount::Init(dev, args, ppapi);
+ return true;
+}
+
+void MountPassthrough::Destroy() {
+}
+
+MountNode *MountPassthrough::Open(const Path& path, int mode) {
+ int real_fd;
+ int err = _real_open(path.Join().c_str(), mode, 0666, &real_fd);
+ if (err) {
+ errno = err;
+ return NULL;
+ }
+
+ MountNodePassthrough* node = new MountNodePassthrough(this, real_fd);
+ return node;
+}
+
+MountNode *MountPassthrough::OpenResource(const Path& path) {
+ int real_fd;
+ int err = _real_open_resource(path.Join().c_str(), &real_fd);
+ if (err) {
+ errno = err;
+ return NULL;
+ }
+
+ MountNodePassthrough* node = new MountNodePassthrough(this, real_fd);
+ return node;
+}
+
+int MountPassthrough::Unlink(const Path& path) {
+ // Not implemented by NaCl.
+ errno = ENOSYS;
+ return -1;
+}
+
+int MountPassthrough::Mkdir(const Path& path, int perm) {
+ int err = _real_mkdir(path.Join().c_str(), perm);
+ if (err) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
+}
+
+int MountPassthrough::Rmdir(const Path& path) {
+ int err = _real_rmdir(path.Join().c_str());
+ if (err) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
+}
+
+int MountPassthrough::Remove(const Path& path) {
+ // Not implemented by NaCl.
+ errno = ENOSYS;
+ return -1;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
new file mode 100644
index 0000000..00a0eec
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef LIBRARIES_NACL_IO_MOUNT_PASSTHROUGH_H_
+#define LIBRARIES_NACL_IO_MOUNT_PASSTHROUGH_H_
+
+#include "nacl_io/mount.h"
+
+class MountPassthrough : public Mount {
+ protected:
+ MountPassthrough();
+
+ virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual void Destroy();
+
+ public:
+ virtual MountNode *Open(const Path& path, int mode);
+ virtual MountNode *OpenResource(const Path& path);
+ virtual int Unlink(const Path& path);
+ virtual int Mkdir(const Path& path, int perm);
+ virtual int Rmdir(const Path& path);
+ virtual int Remove(const Path& path);
+
+private:
+ friend class Mount;
+ DISALLOW_COPY_AND_ASSIGN(MountPassthrough);
+};
+
+#endif // LIBRARIES_NACL_IO_MOUNT_PASSTHROUGH_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/nacl_io.h b/native_client_sdk/src/libraries/nacl_io/nacl_io.h
index 3a94057..f934353 100644
--- a/native_client_sdk/src/libraries/nacl_io/nacl_io.h
+++ b/native_client_sdk/src/libraries/nacl_io/nacl_io.h
@@ -39,7 +39,7 @@ void nacl_io_init();
* pp::Module::Get()->get_browser_interface()
*/
void nacl_io_init_ppapi(PP_Instance instance,
- PPB_GetInterface get_interface);
+ PPB_GetInterface get_interface);
/** Mount a new filesystem type.
@@ -94,6 +94,12 @@ void nacl_io_init_ppapi(PP_Instance instance,
* All other key/value pairs are assumed to be headers to use with
* HTTP requests.
*
+ * "passthroughfs": A filesystem that passes all requests through to the
+ * underlying NaCL calls. The primary use of this filesystem
+ * is to allow reading NMF resources.
+ * source: Unused.
+ * data: Unused.
+ *
*
* @param[in] source Depends on the filesystem type. See above.
* @param[in] target The absolute path to mount the filesystem.
diff --git a/native_client_sdk/src/libraries/nacl_io/osmman.h b/native_client_sdk/src/libraries/nacl_io/osmman.h
new file mode 100644
index 0000000..a652a09
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/osmman.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef LIBRARIES_NACL_IO_OSMMAN_H
+#define LIBRARIES_NACL_IO_OSMMAN_H
+
+#if defined(WIN32)
+
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+#define PROT_EXEC 0x4
+#define PROT_NONE 0x0
+
+#define MAP_SHARED 0x01
+#define MAP_PRIVATE 0x02
+#define MAP_FIXED 0x10
+#define MAP_ANONYMOUS 0x20
+#define MAP_FAILED (void*)-1
+
+#else
+
+#include <sys/mman.h>
+
+#endif
+
+#endif // LIBRARIES_NACL_IO_OSMMAN_H
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
index c2f7dc3..45caa4c 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
@@ -43,6 +43,8 @@ class KernelProxyMock : public KernelProxy {
MOCK_METHOD3(write, ssize_t(int, const void*, size_t));
MOCK_METHOD2(link, int(const char*, const char*));
MOCK_METHOD2(symlink, int(const char*, const char*));
+ MOCK_METHOD6(mmap, void*(void*, size_t, int, int, int, size_t));
+ MOCK_METHOD1(open_resource, int(const char*));
};
#endif // LIBRARIES_NACL_IO_TEST_KERNEL_PROXY_MOCK_H_
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
index f1e1e81..3c70ec7 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
@@ -16,6 +16,7 @@
#include "nacl_io/kernel_proxy.h"
#include "nacl_io/mount.h"
#include "nacl_io/mount_mem.h"
+#include "nacl_io/osmman.h"
#include "nacl_io/path.h"
#include "gtest/gtest.h"
@@ -26,6 +27,9 @@ class KernelProxyTest : public ::testing::Test {
KernelProxyTest()
: kp_(new KernelProxy) {
ki_init(kp_);
+ // Unmount the passthrough FS and mount a memfs.
+ EXPECT_EQ(0, kp_->umount("/"));
+ EXPECT_EQ(0, kp_->mount("", "/", "memfs", 0, NULL));
}
~KernelProxyTest() {
@@ -229,8 +233,6 @@ class KernelProxyMountTest : public ::testing::Test {
KernelProxy* kp_;
};
-
-
TEST_F(KernelProxyMountTest, MountInit) {
int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
@@ -242,3 +244,112 @@ TEST_F(KernelProxyMountTest, MountInit) {
EXPECT_NE(-1, res2);
EXPECT_EQ("y", g_StringMap["x"]);
}
+
+
+namespace {
+
+int g_MMapCount = 0;
+
+class MountNodeMockMMap : public MountNode {
+ public:
+ MountNodeMockMMap(Mount* mount)
+ : MountNode(mount),
+ node_mmap_count_(0) {
+ Init(0);
+ }
+
+ virtual void* MMap(void* addr, size_t length, int prot, int flags,
+ size_t offset) {
+ node_mmap_count_++;
+ switch (g_MMapCount++) {
+ case 0: return reinterpret_cast<void*>(0x1000);
+ case 1: return reinterpret_cast<void*>(0x2000);
+ case 2: return reinterpret_cast<void*>(0x3000);
+ default: return MAP_FAILED;
+ }
+ }
+
+ virtual int Munmap(void* addr, size_t length) {
+ EXPECT_GT(node_mmap_count_, 0);
+ --node_mmap_count_;
+ --g_MMapCount;
+ return 0;
+ }
+
+ private:
+ int node_mmap_count_;
+};
+
+class MountMockMMap : public Mount {
+ public:
+ virtual MountNode* Open(const Path& path, int mode) {
+ MountNodeMockMMap* node = new MountNodeMockMMap(this);
+ return node;
+ }
+
+ virtual MountNode* OpenResource(const Path& path) { return NULL; }
+ virtual int Unlink(const Path& path) { return -1; }
+ virtual int Mkdir(const Path& path, int permissions) { return -1; }
+ virtual int Rmdir(const Path& path) { return -1; }
+ virtual int Remove(const Path& path) { return -1; }
+};
+
+class KernelProxyMockMMap : public KernelProxy {
+ virtual void Init(PepperInterface* ppapi) {
+ KernelProxy::Init(NULL);
+ factories_["mmapfs"] = MountMockInit::Create<MountMockMMap>;
+ }
+};
+
+class KernelProxyMMapTest : public ::testing::Test {
+ public:
+ KernelProxyMMapTest()
+ : kp_(new KernelProxyMockMMap) {
+ ki_init(kp_);
+ }
+
+ ~KernelProxyMMapTest() {
+ ki_uninit();
+ delete kp_;
+ }
+
+ private:
+ KernelProxy* kp_;
+};
+
+} // namespace
+
+TEST_F(KernelProxyMMapTest, MMap) {
+ EXPECT_EQ(0, ki_umount("/"));
+ EXPECT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
+ int fd = ki_open("/file", O_RDWR | O_CREAT);
+ EXPECT_NE(-1, fd);
+
+ void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
+ EXPECT_EQ(reinterpret_cast<void*>(0x1000), addr1);
+ EXPECT_EQ(1, g_MMapCount);
+
+ void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
+ EXPECT_EQ(reinterpret_cast<void*>(0x2000), addr2);
+ EXPECT_EQ(2, g_MMapCount);
+
+ void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
+ EXPECT_EQ(reinterpret_cast<void*>(0x3000), addr3);
+ EXPECT_EQ(3, g_MMapCount);
+
+ // Unmap 0x2000 and 0x3000.
+ EXPECT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x2400), 0x1000));
+ EXPECT_EQ(1, g_MMapCount);
+
+ ki_close(fd);
+ EXPECT_EQ(1, g_MMapCount); // Closing the file doesn't unmap it.
+
+ // Open a new file, should have the same fd.
+ int fd2 = ki_open("/foo", O_RDWR | O_CREAT);
+ EXPECT_EQ(fd, fd2);
+
+ // Unmap 0x1000. This should unmap the old file, not the new file with the
+ // same fd.
+ EXPECT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x800));
+ EXPECT_EQ(0, g_MMapCount);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
index df7a784..0cf3bcb 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
@@ -11,8 +11,9 @@
#include "nacl_io/kernel_wrap.h"
#include "kernel_proxy_mock.h"
-using ::testing::StrEq;
using ::testing::_;
+using ::testing::Return;
+using ::testing::StrEq;
namespace {
@@ -75,6 +76,12 @@ void MakeDummyStatbuf(struct stat* statbuf) {
class KernelWrapTest : public ::testing::Test {
public:
KernelWrapTest() {
+ // Initializing the KernelProxy opens stdin/stdout/stderr.
+ EXPECT_CALL(mock, open(_, _))
+ .WillOnce(Return(0))
+ .WillOnce(Return(1))
+ .WillOnce(Return(2));
+
ki_init(&mock);
}
diff --git a/native_client_sdk/src/tools/nacl_gcc.mk b/native_client_sdk/src/tools/nacl_gcc.mk
index bde9115..59f2002 100644
--- a/native_client_sdk/src/tools/nacl_gcc.mk
+++ b/native_client_sdk/src/tools/nacl_gcc.mk
@@ -92,6 +92,9 @@ endef
#
# $1 = Target Name
# $2 = List of Sources
+# $3 = List of LIBS
+# $4 = List of DEPS
+# $5 = 1 => Don't add to NMF.
#
#
GLIBC_REMAP:=
@@ -104,9 +107,13 @@ NMF_TARGETS+=$(OUTDIR)/$(1)_x86_64.so
$(OUTDIR)/$(1)_x86_64.so : $(foreach src,$(2),$$(OUTDIR)/$(basename $(src))_x86_64.o) $(4)
$(call LOG,LINK,$$@,$(X86_32_LINK) -o $$@ $$(filter-out $(4),$$^) -shared -m64 $(LD_X86_64) $$(LD_FLAGS) $(foreach lib,$(3),-l$(lib)))
+ifneq (1,$(5))
GLIBC_SO_LIST+=$(OUTDIR)/$(1)_x86_32.so $(OUTDIR)/$(1)_x86_64.so
GLIBC_REMAP+=-n $(1)_x86_32.so,$(1).so
GLIBC_REMAP+=-n $(1)_x86_64.so,$(1).so
+else
+all: $(OUTDIR)/$(1)_x86_32.so $(OUTDIR)/$(1)_x86_64.so
+endif
endef