summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-07 00:02:13 +0000
committerbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-07 00:02:13 +0000
commit531e2a2678f1969150c0019e07e34825e2fe4bd9 (patch)
treee6ad15ce96663659fa12f49bc972e397c8108a4a /native_client_sdk
parent37f6454a0c30fce52459105db2f837da4f51e4d3 (diff)
downloadchromium_src-531e2a2678f1969150c0019e07e34825e2fe4bd9.zip
chromium_src-531e2a2678f1969150c0019e07e34825e2fe4bd9.tar.gz
chromium_src-531e2a2678f1969150c0019e07e34825e2fe4bd9.tar.bz2
[NaCl SDK] nacl-mounts example.
BUG=122229 NOTRY=true Review URL: https://chromiumcodereview.appspot.com/11190066 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166309 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rwxr-xr-xnative_client_sdk/src/build_tools/build_sdk.py1
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/example.dsc17
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/example.js164
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c464
-rw-r--r--native_client_sdk/src/examples/hello_nacl_mounts/index.html79
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc4
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.cc3
-rw-r--r--native_client_sdk/src/libraries/utils/macros.h19
9 files changed, 750 insertions, 2 deletions
diff --git a/native_client_sdk/src/build_tools/build_sdk.py b/native_client_sdk/src/build_tools/build_sdk.py
index e00b51e..9fd82f8 100755
--- a/native_client_sdk/src/build_tools/build_sdk.py
+++ b/native_client_sdk/src/build_tools/build_sdk.py
@@ -566,6 +566,7 @@ EXAMPLE_LIST = [
'fullscreen_tumbler',
'gamepad',
'geturl',
+ 'hello_nacl_mounts',
'hello_world_interactive',
'hello_world',
'hello_world_gles',
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc b/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc
new file mode 100644
index 0000000..41e5587
--- /dev/null
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/example.dsc
@@ -0,0 +1,17 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'win'],
+ 'TARGETS': [
+ {
+ 'NAME' : 'hello_nacl_mounts',
+ 'TYPE' : 'main',
+ 'SOURCES' : ['hello_nacl_mounts.c'],
+ 'LIBS': ['ppapi', 'pthread', 'nacl_mounts']
+ }
+ ],
+ 'DATA': [
+ 'example.js'
+ ],
+ 'DEST': 'examples',
+ 'NAME': 'hello_nacl_mounts',
+ 'TITLE': 'Hello, Nacl Mounts!',
+}
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/example.js b/native_client_sdk/src/examples/hello_nacl_mounts/example.js
new file mode 100644
index 0000000..3d1206b
--- /dev/null
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/example.js
@@ -0,0 +1,164 @@
+// 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.
+
+// Start up the paint timer when the NaCl module has loaded.
+function moduleDidLoad() {
+ common.hideModule();
+}
+
+// Called by the common.js module.
+function attachListeners() {
+ var radioEls = document.querySelectorAll('input[type="radio"]');
+ for (var i = 0; i < radioEls.length; ++i) {
+ radioEls[i].addEventListener('click', onRadioClicked);
+ }
+
+ document.getElementById('fopenExecute').addEventListener('click', fopen);
+ document.getElementById('fcloseExecute').addEventListener('click', fclose);
+ document.getElementById('freadExecute').addEventListener('click', fread);
+ document.getElementById('fwriteExecute').addEventListener('click', fwrite);
+ document.getElementById('fseekExecute').addEventListener('click', fseek);
+}
+
+function onRadioClicked(e) {
+ var divId = this.id.slice(5); // skip "radio"
+ var functionEls = document.querySelectorAll('.function');
+ for (var i = 0; i < functionEls.length; ++i) {
+ var visible = functionEls[i].id === divId;
+ if (functionEls[i].id === divId)
+ functionEls[i].removeAttribute('hidden');
+ else
+ functionEls[i].setAttribute('hidden');
+ }
+}
+
+function addFilenameToSelectElements(filehandle, filename) {
+ var text = '[' + filehandle + '] ' + filename;
+ var selectEls = document.querySelectorAll('select.file-handle');
+ for (var i = 0; i < selectEls.length; ++i) {
+ var optionEl = document.createElement('option');
+ optionEl.setAttribute('value', filehandle);
+ optionEl.appendChild(document.createTextNode(text));
+ selectEls[i].appendChild(optionEl);
+ }
+}
+
+function removeFilenameFromSelectElements(filehandle) {
+ var optionEls = document.querySelectorAll('select.file-handle > option');
+ for (var i = 0; i < optionEls.length; ++i) {
+ var optionEl = optionEls[i];
+ if (optionEl.value == filehandle) {
+ var selectEl = optionEl.parentNode;
+ selectEl.removeChild(optionEl);
+ }
+ }
+}
+
+var filehandle_map = {};
+
+function fopen(e) {
+ var filename = document.getElementById('fopenFilename').value;
+
+ var access = '';
+ if (document.getElementById('fopenWrite').checked)
+ access += 'w';
+ if (document.getElementById('fopenRead').checked)
+ access += 'r';
+
+ nacl_module.postMessage(makeCall('fopen', filename, access));
+}
+
+function fopen_result(filename, filehandle) {
+ filehandle_map[filehandle] = filename;
+
+ addFilenameToSelectElements(filehandle, filename)
+ logMessage('File ' + filename + ' opened successfully.');
+}
+
+function fclose(e) {
+ var filehandle = document.getElementById('fcloseHandle').value;
+ nacl_module.postMessage(makeCall('fclose', filehandle));
+}
+
+function fclose_result(filehandle) {
+ var filename = filehandle_map[filehandle];
+ removeFilenameFromSelectElements(filehandle, filename);
+ logMessage('File ' + filename + ' closed successfully.');
+}
+
+function fread(e) {
+ var filehandle = document.getElementById('freadHandle').value;
+ var numBytes = document.getElementById('freadBytes').value;
+ nacl_module.postMessage(makeCall('fread', filehandle, numBytes));
+}
+
+function fread_result(filehandle, data) {
+ var filename = filehandle_map[filehandle];
+ logMessage('Read "' + data + '" from file ' + filename + '.');
+}
+
+function fwrite(e) {
+ var filehandle = document.getElementById('fwriteHandle').value;
+ var data = document.getElementById('fwriteData').value;
+ nacl_module.postMessage(makeCall('fwrite', filehandle, data));
+}
+
+function fwrite_result(filehandle, bytes_written) {
+ var filename = filehandle_map[filehandle];
+ logMessage('Wrote ' + bytes_written + ' bytes to file ' + filename + '.');
+}
+
+function fseek(e) {
+ var filehandle = document.getElementById('fseekHandle').value;
+ var offset = document.getElementById('fseekOffset').value;
+ var whence = document.getElementById('fseekWhence').value;
+ nacl_module.postMessage(makeCall('fseek', filehandle, offset, whence));
+}
+
+/**
+ * Return true when |s| starts with the string |prefix|.
+ *
+ * @param {string} s The string to search.
+ * @param {string} prefix The prefix to search for in |s|.
+ */
+function startsWith(s, prefix) {
+ // indexOf would search the entire string, lastIndexOf(p, 0) only checks at
+ // the first index. See: http://stackoverflow.com/a/4579228
+ return s.lastIndexOf(prefix, 0) === 0;
+}
+
+function logMessage(msg) {
+ var logEl = document.getElementById('log');
+ logEl.innerHTML += msg + '<br>';
+}
+
+function makeCall(func) {
+ var message = func;
+ for (var i = 1; i < arguments.length; ++i) {
+ message += '\1' + arguments[i];
+ }
+
+ return message;
+}
+
+// Called by the common.js module.
+function handleMessage(message_event) {
+ var msg = message_event.data;
+ if (startsWith(msg, 'Error:')) {
+ logMessage(msg);
+ } else {
+ // Result from a function call.
+ var params = msg.split('\1');
+ var func_name = params[0];
+ var func_result_name = func_name + '_result';
+ var result_func = window[func_result_name];
+
+ if (!result_func) {
+ logMessage('Error: Bad message received from NaCl module.');
+ return;
+ }
+
+ result_func.apply(null, params.slice(1));
+ }
+}
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c b/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c
new file mode 100644
index 0000000..5536614
--- /dev/null
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/hello_nacl_mounts.c
@@ -0,0 +1,464 @@
+/* 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 <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_module.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/c/ppb.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_messaging.h"
+#include "ppapi/c/ppb_var.h"
+#include "ppapi/c/ppp.h"
+#include "ppapi/c/ppp_instance.h"
+#include "ppapi/c/ppp_messaging.h"
+#include "nacl_mounts/kernel_intercept.h"
+
+
+#define MAX_OPEN_FILES 10
+#define MAX_PARAMS 4
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#if defined(WIN32)
+#define va_copy(d, s) ((d) = (s))
+#endif
+
+
+typedef int (*HandleFunc)(int num_params, char** params, char** output);
+typedef struct {
+ const char* name;
+ HandleFunc function;
+} FuncNameMapping;
+
+
+int HandleFopen(int num_params, char** params, char** output);
+int HandleFwrite(int num_params, char** params, char** output);
+int HandleFread(int num_params, char** params, char** output);
+int HandleFseek(int num_params, char** params, char** output);
+int HandleFclose(int num_params, char** params, char** output);
+
+
+static PPB_Messaging* ppb_messaging_interface = NULL;
+static PPB_Var* ppb_var_interface = NULL;
+static FILE* g_OpenFiles[MAX_OPEN_FILES];
+static FuncNameMapping g_FunctionMap[] = {
+ { "fopen", HandleFopen },
+ { "fwrite", HandleFwrite },
+ { "fread", HandleFread },
+ { "fseek", HandleFseek },
+ { "fclose", HandleFclose },
+ { NULL, NULL },
+};
+
+
+static struct PP_Var CStrToVar(const char* str) {
+ if (ppb_var_interface != NULL) {
+ return ppb_var_interface->VarFromUtf8(str, strlen(str));
+ }
+ return PP_MakeUndefined();
+}
+
+static char* VprintfToNewString(const char* format, va_list args) {
+ va_list args_copy;
+ int length;
+ char* buffer;
+ int result;
+
+ va_copy(args_copy, args);
+ length = vsnprintf(NULL, 0, format, args);
+ buffer = (char*)malloc(length + 1); /* +1 for NULL-terminator. */
+ result = vsnprintf(&buffer[0], length + 1, format, args_copy);
+ assert(result == length);
+ return buffer;
+}
+
+static char* PrintfToNewString(const char* format, ...) {
+ va_list args;
+ char* result;
+ va_start(args, format);
+ result = VprintfToNewString(format, args);
+ va_end(args);
+ return result;
+}
+
+static struct PP_Var PrintfToVar(const char* format, ...) {
+ if (ppb_var_interface != NULL) {
+ char* string;
+ va_list args;
+ struct PP_Var var;
+
+ va_start(args, format);
+ string = VprintfToNewString(format, args);
+ va_end(args);
+
+ var = ppb_var_interface->VarFromUtf8(string, strlen(string));
+ free(string);
+
+ return var;
+ }
+
+ return PP_MakeUndefined();
+}
+
+static uint32_t VarToCStr(struct PP_Var var, char* buffer, uint32_t length) {
+ if (ppb_var_interface != NULL) {
+ uint32_t var_length;
+ const char* str = ppb_var_interface->VarToUtf8(var, &var_length);
+ /* str is NOT NULL-terminated. Copy using memcpy. */
+ uint32_t min_length = MIN(var_length, length - 1);
+ memcpy(buffer, str, min_length);
+ buffer[min_length] = 0;
+
+ return min_length;
+ }
+
+ return 0;
+}
+
+static int AddFileToMap(FILE* file) {
+ int i;
+ assert(file != NULL);
+ for (i = 0; i < MAX_OPEN_FILES; ++i) {
+ if (g_OpenFiles[i] == NULL) {
+ g_OpenFiles[i] = file;
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static void RemoveFileFromMap(int i) {
+ assert(i >= 0 && i < MAX_OPEN_FILES);
+ g_OpenFiles[i] = NULL;
+}
+
+static FILE* GetFileFromMap(int i) {
+ assert(i >= 0 && i < MAX_OPEN_FILES);
+ return g_OpenFiles[i];
+}
+
+static FILE* GetFileFromIndexString(const char* s, int* file_index) {
+ char* endptr;
+ int result = strtol(s, &endptr, 10);
+ if (endptr != s + strlen(s)) {
+ /* Garbage at the end of the number...? */
+ return NULL;
+ }
+
+ if (file_index)
+ *file_index = result;
+
+ return GetFileFromMap(result);
+}
+
+int HandleFopen(int num_params, char** params, char** output) {
+ FILE* file;
+ int file_index;
+ const char* filename;
+ const char* mode;
+
+ if (num_params != 2) {
+ *output = PrintfToNewString("Error: fopen takes 2 parameters.");
+ return 1;
+ }
+
+ filename = params[0];
+ mode = params[1];
+
+ file = fopen(filename, mode);
+ if (!file) {
+ *output = PrintfToNewString("Error: fopen returned a NULL FILE*.");
+ return 2;
+ }
+
+ file_index = AddFileToMap(file);
+ if (file_index == -1) {
+ *output = PrintfToNewString(
+ "Error: Example only allows %d open file handles.", MAX_OPEN_FILES);
+ return 3;
+ }
+
+ *output = PrintfToNewString("fopen\1%s\1%d", filename, file_index);
+ return 0;
+}
+
+int HandleFwrite(int num_params, char** params, char** output) {
+ FILE* file;
+ const char* file_index_string;
+ const char* data;
+ size_t data_len;
+ size_t bytes_written;
+
+ if (num_params != 2) {
+ *output = PrintfToNewString("Error: fwrite takes 2 parameters.");
+ return 1;
+ }
+
+ file_index_string = params[0];
+ file = GetFileFromIndexString(file_index_string, NULL);
+ data = params[1];
+ data_len = strlen(data);
+
+ if (!file) {
+ *output = PrintfToNewString("Error: Unknown file handle %s.",
+ file_index_string);
+ return 2;
+ }
+
+ bytes_written = fwrite(data, 1, data_len, file);
+
+ *output = PrintfToNewString("fwrite\1%s\1%d", file_index_string,
+ bytes_written);
+ return 0;
+}
+
+int HandleFread(int num_params, char** params, char** output) {
+ FILE* file;
+ const char* file_index_string;
+ char* buffer;
+ size_t data_len;
+ size_t bytes_read;
+
+ if (num_params != 2) {
+ *output = PrintfToNewString("Error: fread takes 2 parameters.");
+ return 1;
+ }
+
+ file_index_string = params[0];
+ file = GetFileFromIndexString(file_index_string, NULL);
+ data_len = strtol(params[1], NULL, 10);
+
+ if (!file) {
+ *output = PrintfToNewString("Error: Unknown file handle %s.",
+ file_index_string);
+ return 2;
+ }
+
+ buffer = (char*)malloc(data_len + 1);
+ bytes_read = fread(buffer, 1, data_len, file);
+ buffer[bytes_read] = 0;
+
+ *output = PrintfToNewString("fread\1%s\1%s", file_index_string, buffer);
+ free(buffer);
+ return 0;
+}
+
+int HandleFseek(int num_params, char** params, char** output) {
+ FILE* file;
+ const char* file_index_string;
+ long offset;
+ int whence;
+ int result;
+
+ if (num_params != 3) {
+ *output = PrintfToNewString("Error: fseek takes 3 parameters.");
+ return 1;
+ }
+
+ file_index_string = params[0];
+ file = GetFileFromIndexString(file_index_string, NULL);
+ offset = strtol(params[1], NULL, 10);
+ whence = strtol(params[2], NULL, 10);
+
+ if (!file) {
+ *output = PrintfToNewString("Error: Unknown file handle %s.",
+ file_index_string);
+ return 2;
+ }
+
+ result = fseek(file, offset, whence);
+ if (result) {
+ *output = PrintfToNewString("Error: fseek returned error %d.", result);
+ return 3;
+ }
+
+ *output = PrintfToNewString("fseek\1%d", file_index_string);
+ return 0;
+}
+
+int HandleFclose(int num_params, char** params, char** output) {
+ FILE* file;
+ int file_index;
+ const char* file_index_string;
+ int result;
+
+ if (num_params != 1) {
+ *output = PrintfToNewString("Error: fclose takes 1 parameters.");
+ return 1;
+ }
+
+ file_index_string = params[0];
+ file = GetFileFromIndexString(file_index_string, &file_index);
+ if (!file) {
+ *output = PrintfToNewString("Error: Unknown file handle %s.",
+ file_index_string);
+ return 2;
+ }
+
+ result = fclose(file);
+ if (result) {
+ *output = PrintfToNewString("Error: fclose returned error %d.", result);
+ return 3;
+ }
+
+ RemoveFileFromMap(file_index);
+
+ *output = PrintfToNewString("fclose\1%s", file_index_string);
+ return 0;
+}
+
+static size_t ParseMessage(char* message,
+ char** out_function,
+ char** out_params,
+ size_t max_params) {
+ char* separator;
+ char* param_start;
+ size_t num_params = 0;
+
+ /* Parse the message: function\1param1\1param2\1param3,... */
+ *out_function = &message[0];
+
+ separator = strchr(message, 1);
+ if (!separator) {
+ return num_params;
+ }
+
+ *separator = 0; /* NULL-terminate function. */
+
+ while (separator && num_params < max_params) {
+ param_start = separator + 1;
+ separator = strchr(param_start, 1);
+ if (separator) {
+ *separator = 0;
+ out_params[num_params++] = param_start;
+ }
+ }
+
+ out_params[num_params++] = param_start;
+
+ return num_params;
+}
+
+static HandleFunc GetFunctionByName(const char* function_name) {
+ FuncNameMapping* map_iter = g_FunctionMap;
+ for (; map_iter->name; ++map_iter) {
+ if (strcmp(map_iter->name, function_name) == 0) {
+ return map_iter->function;
+ }
+ }
+
+ return NULL;
+}
+
+
+static PP_Bool Instance_DidCreate(PP_Instance instance,
+ uint32_t argc,
+ const char* argn[],
+ const char* argv[]) {
+
+ ki_init(NULL);
+ return PP_TRUE;
+}
+
+
+static void Instance_DidDestroy(PP_Instance instance) {
+}
+
+static void Instance_DidChangeView(PP_Instance instance,
+ PP_Resource view_resource) {
+}
+
+static void Instance_DidChangeFocus(PP_Instance instance,
+ PP_Bool has_focus) {
+}
+
+static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
+ PP_Resource url_loader) {
+ /* NaCl modules do not need to handle the document load function. */
+ return PP_FALSE;
+}
+
+static void Messaging_HandleMessage(PP_Instance instance,
+ struct PP_Var message) {
+ char buffer[1024];
+ char* function_name;
+ char* params[MAX_PARAMS];
+ size_t num_params;
+ char* output = NULL;
+ int result;
+ HandleFunc function;
+
+ VarToCStr(message, &buffer[0], 1024);
+
+ num_params = ParseMessage(buffer, &function_name, &params[0], MAX_PARAMS);
+
+ function = GetFunctionByName(function_name);
+ if (!function) {
+ /* Function name wasn't found. Error. */
+ ppb_messaging_interface->PostMessage(
+ instance, PrintfToVar("Error: Unknown function \"%s\"", function));
+ }
+
+ result = (*function)(num_params, &params[0], &output);
+ if (result != 0) {
+ /* Error. */
+ struct PP_Var var;
+ if (output != NULL) {
+ var = PrintfToVar(
+ "Error: Function \"%s\" returned error %d. "
+ "Additional output: %s", function_name, result, output);
+ } else {
+ var = PrintfToVar("Error: Function \"%s\" returned error %d.",
+ function_name, result);
+ }
+
+ ppb_messaging_interface->PostMessage(instance, var);
+ return;
+ }
+
+ if (output != NULL) {
+ /* Function returned an output string. Send it to JavaScript. */
+ ppb_messaging_interface->PostMessage(instance, CStrToVar(output));
+ free(output);
+ }
+}
+
+PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
+ PPB_GetInterface get_browser) {
+ ppb_messaging_interface =
+ (PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE));
+ ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE));
+ return PP_OK;
+}
+
+
+PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
+ if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
+ static PPP_Instance instance_interface = {
+ &Instance_DidCreate,
+ &Instance_DidDestroy,
+ &Instance_DidChangeView,
+ &Instance_DidChangeFocus,
+ &Instance_HandleDocumentLoad,
+ };
+ return &instance_interface;
+ } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
+ static PPP_Messaging messaging_interface = {
+ &Messaging_HandleMessage,
+ };
+ return &messaging_interface;
+ }
+ return NULL;
+}
+
+
+PP_EXPORT void PPP_ShutdownModule() {
+}
diff --git a/native_client_sdk/src/examples/hello_nacl_mounts/index.html b/native_client_sdk/src/examples/hello_nacl_mounts/index.html
new file mode 100644
index 0000000..4116316
--- /dev/null
+++ b/native_client_sdk/src/examples/hello_nacl_mounts/index.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<!--
+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.
+-->
+<head>
+ <meta http-equiv="Pragma" content="no-cache">
+ <meta http-equiv="Expires" content="-1">
+ <title><TITLE></title>
+ <script type="text/javascript" src="common.js"></script>
+ <script type="text/javascript" src="example.js"></script>
+</head>
+<body data-name="<NAME>" data-tc="<tc>" data-path="<path>">
+ <h1><TITLE></h1>
+ <h2>Status: <code id="statusField">NO-STATUS</code></h2>
+ <div>
+ <span>
+ <input type="radio" id="radiofopen" name="group" checked="checked">fopen
+ <input type="radio" id="radiofclose" name="group">fclose
+ <input type="radio" id="radiofread" name="group">fread
+ <input type="radio" id="radiofwrite" name="group">fwrite
+ <input type="radio" id="radiofseek" name="group">fseek
+ </span>
+ </div>
+ <div class="function" id="fopen">
+ <span>
+ Filename:
+ <input type="text" id="fopenFilename">
+ Write:
+ <input type="checkbox" id="fopenWrite">
+ Read:
+ <input type="checkbox" id="fopenRead">
+ <button id="fopenExecute">fopen</button>
+ </span>
+ </div>
+ <div class="function" id="fclose" hidden>
+ <span>
+ <select class="file-handle" id="fcloseHandle"></select>
+ <button id="fcloseExecute">fclose</button>
+ </span>
+ </div>
+ <div class="function" id="fread" hidden>
+ <span>
+ <select class="file-handle" id="freadHandle"></select>
+ Count:
+ <input type="text" id="freadBytes">
+ <button id="freadExecute">fread</button>
+ </span>
+ </div>
+ <div class="function" id="fwrite" hidden>
+ <span>
+ <select class="file-handle" id="fwriteHandle"></select>
+ Data:
+ <input type="text" id="fwriteData">
+ <button id="fwriteExecute">fwrite</button>
+ </span>
+ </div>
+ <div class="function" id="fseek" hidden>
+ <span>
+ <select class="file-handle" id="fseekHandle"></select>
+ Offset:
+ <input type="text" id="fseekOffset">
+ Whence:
+ <select id="fseekWhence">
+ <option value="SEEK_SET">SEEK_SET</option>
+ <option value="SEEK_CUR">SEEK_CUR</option>
+ <option value="SEEK_END">SEEK_END</option>
+ </select>
+ <button id="fseekExecute">fseek</button>
+ </span>
+ </div>
+ <!-- The NaCl plugin will be embedded inside the element with id "listener".
+ See common.js.-->
+ <div id="listener"></div>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc
index f7af9e0..940f5b7 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.cc
@@ -3,8 +3,10 @@
* found in the LICENSE file.
*/
#include "nacl_mounts/kernel_intercept.h"
-
#include "nacl_mounts/kernel_proxy.h"
+#include "utils/macros.h"
+
+FORCE_LINK_THAT(kernel_wrap)
static KernelProxy* s_kp;
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h
index e4a472c..a966c4d 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_intercept.h
@@ -46,3 +46,4 @@ int ki_access(const char* path, int amode);
EXTERN_C_END
#endif // LIBRARIES_NACL_MOUNTS_KERNEL_INTERCEPT_H_
+
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.cc
index 0dd5021..c3d0581 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_wrap.cc
@@ -4,6 +4,9 @@
*/
#include <sys/types.h> // Include something that will define __GLIBC__.
+#include "utils/macros.h"
+
+FORCE_LINK_THIS(kernel_wrap)
#if defined(__native_client__)
# if defined(__GLIBC__)
diff --git a/native_client_sdk/src/libraries/utils/macros.h b/native_client_sdk/src/libraries/utils/macros.h
index 97602b3..8731e25 100644
--- a/native_client_sdk/src/libraries/utils/macros.h
+++ b/native_client_sdk/src/libraries/utils/macros.h
@@ -25,8 +25,25 @@
# define EXTERN_C_END }
#else
# define EXTERN_C_BEGIN
-# define EXEERN_C_END
+# define EXTERN_C_END
#endif /* __cplusplus */
+/**
+ * Macros to help force linkage of symbols that otherwise would not be
+ * included.
+ *
+ * // In a source file that you want to force linkage (file scope):
+ * FORCE_LINK_THIS(myfilename);
+ *
+ * // In a source file that you are sure will be linked (file scope):
+ * FORCE_LINK_THAT(myfilename)
+ *
+ */
+#define FORCE_LINK_THIS(x) int force_link_##x = 0;
+#define FORCE_LINK_THAT(x) \
+ void force_link_function_##x() { \
+ extern int force_link_##x; \
+ force_link_##x = 1; \
+ }
#endif /* LIBRARIES_UTILS_MACROS_H_ */