1 #include <cstdlib>
2 #include <node.h>
3 #include <v8.h>
4 #include <unistd.h>
5 #include <sys/syscall.h>
6 #include <errno.h>
7 
8 using namespace v8;
9 
10 #if NODE_MAJOR_VERSION == 0
11 #define ARRAY_BUFFER_DATA_OFFSET 23
12 #else
13 #define ARRAY_BUFFER_DATA_OFFSET 31
14 #endif
15 
toNative(Local<Value> value)16 intptr_t toNative(Local<Value> value) {
17   if (value.IsEmpty()) {
18     return 0;
19   }
20   if (value->IsArrayBufferView()) {
21     Local<ArrayBufferView> view = Local<ArrayBufferView>::Cast(value);
22     return *reinterpret_cast<intptr_t*>(*reinterpret_cast<char**>(*view->Buffer()) + ARRAY_BUFFER_DATA_OFFSET) + view->ByteOffset(); // ugly hack, because of https://codereview.chromium.org/25221002
23   }
24   if (value->IsArray()) {
25     Local<Array> array = Local<Array>::Cast(value);
26     intptr_t* native = reinterpret_cast<intptr_t*>(malloc(array->Length() * sizeof(intptr_t))); // TODO memory leak
27     for (uint32_t i = 0; i < array->Length(); i++) {
28       native[i] = toNative(array->Get(i));
29     }
30     return reinterpret_cast<intptr_t>(native);
31   }
32   return static_cast<intptr_t>(static_cast<int32_t>(value->ToInteger()->Value()));
33 }
34 
Syscall(const FunctionCallbackInfo<Value> & info)35 void Syscall(const FunctionCallbackInfo<Value>& info) {
36   int trap = info[0]->ToInteger()->Value();
37   int r1 = 0, r2 = 0;
38   switch (trap) {
39   case SYS_fork:
40     r1 = fork();
41     break;
42   case SYS_pipe:
43     int fd[2];
44     r1 = pipe(fd);
45     if (r1 == 0) {
46       r1 = fd[0];
47       r2 = fd[1];
48     }
49     break;
50   default:
51     r1 = syscall(
52       trap,
53       toNative(info[1]),
54       toNative(info[2]),
55       toNative(info[3])
56     );
57     break;
58   }
59   int err = 0;
60   if (r1 < 0) {
61     err = errno;
62   }
63   Isolate* isolate = info.GetIsolate();
64   Local<Array> res = Array::New(isolate, 3);
65   res->Set(0, Integer::New(isolate, r1));
66   res->Set(1, Integer::New(isolate, r2));
67   res->Set(2, Integer::New(isolate, err));
68   info.GetReturnValue().Set(res);
69 }
70 
Syscall6(const FunctionCallbackInfo<Value> & info)71 void Syscall6(const FunctionCallbackInfo<Value>& info) {
72   int r = syscall(
73     info[0]->ToInteger()->Value(),
74     toNative(info[1]),
75     toNative(info[2]),
76     toNative(info[3]),
77     toNative(info[4]),
78     toNative(info[5]),
79     toNative(info[6])
80   );
81   int err = 0;
82   if (r < 0) {
83     err = errno;
84   }
85   Isolate* isolate = info.GetIsolate();
86   Local<Array> res = Array::New(isolate, 3);
87   res->Set(0, Integer::New(isolate, r));
88   res->Set(1, Integer::New(isolate, 0));
89   res->Set(2, Integer::New(isolate, err));
90   info.GetReturnValue().Set(res);
91 }
92 
init(Handle<Object> target)93 void init(Handle<Object> target) {
94   NODE_SET_METHOD(target, "Syscall", Syscall);
95   NODE_SET_METHOD(target, "Syscall6", Syscall6);
96 }
97 
98 NODE_MODULE(syscall, init);
99