koffi 2.5.19 → 2.5.21-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@
4
4
 
5
5
  ### Koffi 2.5
6
6
 
7
+ #### Koffi 2.5.20 (2023-08-31)
8
+
9
+ - Fix possible crash with async registered callbacks introduced in Koffi 2.5.19
10
+ - Various documentation fixes and improvements
11
+
7
12
  #### Koffi 2.5.19 (2023-08-29)
8
13
 
9
14
  - Create thread-safe function broker lazily
@@ -332,7 +337,7 @@ Pre-built binaries don't work correctly in Koffi 2.5.13 to 2.5.15, skip those ve
332
337
  **Main changes:**
333
338
 
334
339
  - Add [koffi.as()](polymorphism.md#input-polymorphism) to support polymorphic APIs based on `void *` parameters
335
- - Add [endian-sensitive integer types](input.md#endian-sensitive-types): `intX_le_t`, `intX_be_t`, `uintX_le_t`, `uintX_be_t`
340
+ - Add [endian-sensitive integer types](input.md#endian-sensitive-integers): `intX_le_t`, `intX_be_t`, `uintX_le_t`, `uintX_be_t`
336
341
  - Accept typed arrays for `void *` parameters
337
342
  - Introduce `koffi.opaque()` to replace `koffi.handle()` (which remains supported until Koffi 3.0)
338
343
  - Support JS Array and TypedArray to fill struct and array pointer members
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/doc/callbacks.md CHANGED
@@ -88,7 +88,7 @@ console.log(ret);
88
88
 
89
89
  Use registered callbacks when the function needs to be called at a later time (e.g. log handler, event handler, `fopencookie/funopen`). Call `koffi.register(func, type)` to register a callback function, with two arguments: the JS function, and the callback type.
90
90
 
91
- When you are done, call `koffi.unregister()` (with the value returned by `koffi.register()`) to release the slot. A maximum of 1024 callbacks can exist at the same time. Failure to do so will leak the slot, and subsequent registrations may fail (with an exception) once all slots are used.
91
+ When you are done, call `koffi.unregister()` (with the value returned by `koffi.register()`) to release the slot. A maximum of 8192 callbacks can exist at the same time. Failure to do so will leak the slot, and subsequent registrations may fail (with an exception) once all slots are used.
92
92
 
93
93
  The example below shows how to register and unregister delayed callbacks.
94
94
 
package/doc/contribute.md CHANGED
@@ -14,7 +14,7 @@ Start by cloning the repository with [Git](https://git-scm.com/):
14
14
 
15
15
  ```sh
16
16
  git clone https://github.com/Koromix/rygel
17
- cd rygel/src/koffi
17
+ cd rygel
18
18
  ```
19
19
 
20
20
  As said before, this is a monorepository containg multiple projects, hence the name.
@@ -30,8 +30,8 @@ First, make sure the following dependencies are met:
30
30
  Once this is done, run this command _from the test or the benchmark directory_ (depending on what you want to build):
31
31
 
32
32
  ```sh
33
- cd koffi/test # or cd koffi/benchmark
34
- node ../../cnoke/cnoke.js
33
+ cd src/koffi
34
+ node ../cnoke/cnoke.js
35
35
  ```
36
36
 
37
37
  ### Other platforms
@@ -46,11 +46,31 @@ Make sure the following dependencies are met:
46
46
  Once this is done, run this command _from the test or the benchmark directory_ (depending on what you want to build):
47
47
 
48
48
  ```sh
49
- cd koffi/test # or cd koffi/benchmark
49
+ cd src/koffi
50
+ node ../cnoke/cnoke.js
51
+ ```
52
+
53
+ ## Run tests
54
+
55
+ ### On your machine
56
+
57
+ Once Koffi is built, you can build the tests and run them with the following commands:
58
+
59
+ ```sh
60
+ cd src/koffi/test
50
61
  node ../../cnoke/cnoke.js
62
+
63
+ node sync.js # Run synchronous unit tests
64
+ node async.js # Run asynchronous unit tests
65
+ node callbacks.js # Run callback unit tests
66
+ node union.js # Run union unit tests
67
+ node win32.js # Run Windows-specific unit tests (only on Windows)
68
+
69
+ node sqlite.js # Run SQLite integration tests
70
+ node raylib.js # Run Raylib integration tests
51
71
  ```
52
72
 
53
- ## Running tests
73
+ ### On virtual machines
54
74
 
55
75
  Koffi is tested on multiple architectures using emulated (accelerated when possible) QEMU machines. First, you need to install qemu packages, such as `qemu-system` (or even `qemu-system-gui`) on Ubuntu.
56
76
 
@@ -59,7 +79,7 @@ These machines are not included directly in this repository (for license and siz
59
79
  For example, if you want to run the tests on Debian ARM64, run the following commands:
60
80
 
61
81
  ```sh
62
- cd rygel/src/koffi/tools/
82
+ cd src/koffi/tools/
63
83
  wget -q -O- https://koromix.dev/files/machines/qemu_debian_arm64.tar.zst | zstd -d | tar xv
64
84
  sha256sum -c --ignore-missing registry/sha256sum.txt
65
85
  ```
@@ -107,6 +127,18 @@ Each machine is configured to run a VNC server available locally, which you can
107
127
  node qemu.js info debian_x64
108
128
  ```
109
129
 
130
+ ## Making a release
131
+
132
+ First, change the version numbers in `package.json`. Then publish a new release with the following commands:
133
+
134
+ ```sh
135
+ node qemu.js test
136
+ node qemu.js dist
137
+
138
+ cd build/dist
139
+ npm publish
140
+ ```
141
+
110
142
  ## Code style
111
143
 
112
144
  Koffi is programmed in a mix of C++ and assembly code (architecture-specific code). It uses [node-addon-api](https://github.com/nodejs/node-addon-api) (C++ N-API wrapper) to interact with Node.js.
package/doc/input.md CHANGED
@@ -56,26 +56,26 @@ let struct1 = koffi.struct({ dummy: 'long' });
56
56
  let struct2 = koffi.struct({ dummy: koffi.types.long });
57
57
  ```
58
58
 
59
- ### Endian-sensitive types
59
+ ### Endian-sensitive integers
60
60
 
61
61
  *New in Koffi 2.1*
62
62
 
63
63
  Koffi defines a bunch of endian-sensitive types, which can be used when dealing with binary data (network payloads, binary file formats, etc.).
64
64
 
65
- JS type | C type | Bytes | Signedness | Endianness
66
- ---------------- | ---------------------- | ----- | ---------- | -------------
67
- Number (integer) | int16_le, int16_le_t | 2 | Signed | Little Endian
68
- Number (integer) | int16_be, int16_be_t | 2 | Signed | Big Endian
69
- Number (integer) | uint16_le, uint16_le_t | 2 | Unsigned | Little Endian
70
- Number (integer) | uint16_be, uint16_be_t | 2 | Unsigned | Big Endian
71
- Number (integer) | int32_le, int32_le_t | 4 | Signed | Little Endian
72
- Number (integer) | int32_be, int32_be_t | 4 | Signed | Big Endian
73
- Number (integer) | uint32_le, uint32_le_t | 4 | Unsigned | Little Endian
74
- Number (integer) | uint32_be, uint32_be_t | 4 | Unsigned | Big Endian
75
- Number (integer) | int64_le, int64_le_t | 8 | Signed | Little Endian
76
- Number (integer) | int64_be, int64_be_t | 8 | Signed | Big Endian
77
- Number (integer) | uint64_le, uint64_le_t | 8 | Unsigned | Little Endian
78
- Number (integer) | uint64_be, uint64_be_t | 8 | Unsigned | Big Endian
65
+ C type | Bytes | Signedness | Endianness
66
+ ---------------------- | ----- | ---------- | -------------
67
+ int16_le, int16_le_t | 2 | Signed | Little Endian
68
+ int16_be, int16_be_t | 2 | Signed | Big Endian
69
+ uint16_le, uint16_le_t | 2 | Unsigned | Little Endian
70
+ uint16_be, uint16_be_t | 2 | Unsigned | Big Endian
71
+ int32_le, int32_le_t | 4 | Signed | Little Endian
72
+ int32_be, int32_be_t | 4 | Signed | Big Endian
73
+ uint32_le, uint32_le_t | 4 | Unsigned | Little Endian
74
+ uint32_be, uint32_be_t | 4 | Unsigned | Big Endian
75
+ int64_le, int64_le_t | 8 | Signed | Little Endian
76
+ int64_be, int64_be_t | 8 | Signed | Big Endian
77
+ uint64_le, uint64_le_t | 8 | Unsigned | Little Endian
78
+ uint64_be, uint64_be_t | 8 | Unsigned | Big Endian
79
79
 
80
80
  ## Struct types
81
81
 
package/doc/misc.md CHANGED
@@ -106,9 +106,9 @@ You can use `koffi.stats()` to get a few statistics related to Koffi.
106
106
 
107
107
  *New in Koffi 2.3.14*
108
108
 
109
- You can use `koffi.errno()` to the current errno value, and `koffi.errno(value)` to change it.
109
+ You can use `koffi.errno()` to get the current errno value, and `koffi.errno(value)` to change it.
110
110
 
111
- The standard POSIX error codes are available in `koffi.os.errno`, as in the example below:
111
+ The standard POSIX error codes are available in `koffi.os.errno`, as shown below:
112
112
 
113
113
  ```js
114
114
  const assert = require('assert');
@@ -138,5 +138,5 @@ You can use `koffi.reset()` to clear some Koffi internal state such as:
138
138
  This function is mainly intended for test code, when you execute the same code over and over and you need to reuse type names.
139
139
 
140
140
  ```{warning}
141
- Trying to use a function or a type defined before the reset is undefined behavior and will likely lead to a crash!
141
+ Trying to use a function or a type that was initially defined before the reset is undefined behavior and will likely lead to a crash!
142
142
  ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.5.19",
4
- "stable": "2.5.19",
3
+ "version": "2.5.21-beta.1",
4
+ "stable": "2.5.20",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
package/src/index.js CHANGED
@@ -378,8 +378,8 @@ var require_package = __commonJS({
378
378
  "build/dist/src/koffi/package.json"(exports2, module2) {
379
379
  module2.exports = {
380
380
  name: "koffi",
381
- version: "2.5.19",
382
- stable: "2.5.19",
381
+ version: "2.5.21-beta.1",
382
+ stable: "2.5.20",
383
383
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
384
384
  keywords: [
385
385
  "foreign",
@@ -413,6 +413,7 @@ var require_package = __commonJS({
413
413
  chalk: "^4.1.2",
414
414
  esbuild: "^0.19.2",
415
415
  "ffi-napi": "^4.0.3",
416
+ "ffi-rs": "^1.0.12",
416
417
  minimatch: "^5.0.1",
417
418
  "node-ssh": "^12.0.3",
418
419
  raylib: "^0.9.2",
@@ -66,6 +66,7 @@ set(KOFFI_SRC
66
66
  src/ffi.cc
67
67
  src/parser.cc
68
68
  src/util.cc
69
+ src/win32.cc
69
70
  ../../src/core/libcc/libcc.cc
70
71
  )
71
72
  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -1236,16 +1236,8 @@ void CallData::PopOutArguments()
1236
1236
 
1237
1237
  void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func)
1238
1238
  {
1239
- if (!instance->broker) {
1240
- if (napi_create_threadsafe_function(env, nullptr, nullptr,
1241
- Napi::String::New(env, "Koffi Async Callback Broker"),
1242
- 0, 1, nullptr, nullptr, nullptr,
1243
- CallData::RelayAsync, &instance->broker) != napi_ok) {
1244
- LogError("Failed to create async callback broker");
1245
- return nullptr;
1246
- }
1247
- napi_unref_threadsafe_function(env, instance->broker);
1248
- }
1239
+ if (!InitAsyncBroker(env, instance)) [[unlikely]]
1240
+ return nullptr;
1249
1241
 
1250
1242
  int16_t idx;
1251
1243
  {
@@ -1568,6 +1568,32 @@ static Napi::Value UnloadLibrary(const Napi::CallbackInfo &info)
1568
1568
  return env.Undefined();
1569
1569
  }
1570
1570
 
1571
+ #ifdef _WIN32
1572
+ static HANDLE LoadWindowsLibrary(Napi::Env env, const char16_t *filename)
1573
+ {
1574
+ HANDLE module = LoadLibraryW((LPCWSTR)filename);
1575
+
1576
+ if (!module) {
1577
+ if (GetLastError() == ERROR_BAD_EXE_FORMAT) {
1578
+ int process = GetSelfMachine();
1579
+ int dll = GetDllMachine(filename);
1580
+
1581
+ if (process >= 0 && dll >= 0 && dll != process) {
1582
+ ThrowError<Napi::Error>(env, "Cannot load '%1' DLL in '%2' process",
1583
+ WindowsMachineNames.FindValue(dll, "Unknown"),
1584
+ WindowsMachineNames.FindValue(process, "Unknown"));
1585
+ return nullptr;
1586
+ }
1587
+ }
1588
+
1589
+ ThrowError<Napi::Error>(env, "Failed to load shared library: %1", GetWin32ErrorString());
1590
+ return nullptr;
1591
+ }
1592
+
1593
+ return module;
1594
+ }
1595
+ #endif
1596
+
1571
1597
  static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1572
1598
  {
1573
1599
  Napi::Env env = info.Env();
@@ -1592,12 +1618,10 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1592
1618
  #ifdef _WIN32
1593
1619
  if (info[0].IsString()) {
1594
1620
  std::u16string filename = info[0].As<Napi::String>();
1595
- module = LoadLibraryW((LPCWSTR)filename.c_str());
1621
+ module = LoadWindowsLibrary(env, filename.c_str());
1596
1622
 
1597
- if (!module) {
1598
- ThrowError<Napi::Error>(env, "Failed to load shared library: %1", GetWin32ErrorString());
1623
+ if (!module)
1599
1624
  return env.Null();
1600
- }
1601
1625
  } else {
1602
1626
  module = GetModuleHandle(nullptr);
1603
1627
  RG_ASSERT(module);
@@ -1656,6 +1680,9 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1656
1680
  Napi::Env env = info.Env();
1657
1681
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1658
1682
 
1683
+ if (!InitAsyncBroker(env, instance)) [[unlikely]]
1684
+ return env.Null();
1685
+
1659
1686
  bool has_recv = (info.Length() >= 3 && info[1].IsFunction());
1660
1687
 
1661
1688
  if (info.Length() < 2u + has_recv) {
@@ -1937,6 +1964,22 @@ InstanceMemory::~InstanceMemory()
1937
1964
  #endif
1938
1965
  }
1939
1966
 
1967
+ bool InitAsyncBroker(Napi::Env env, InstanceData *instance)
1968
+ {
1969
+ if (!instance->broker) {
1970
+ if (napi_create_threadsafe_function(env, nullptr, nullptr,
1971
+ Napi::String::New(env, "Koffi Async Callback Broker"),
1972
+ 0, 1, nullptr, nullptr, nullptr,
1973
+ CallData::RelayAsync, &instance->broker) != napi_ok) {
1974
+ LogError("Failed to create async callback broker");
1975
+ return false;
1976
+ }
1977
+ napi_unref_threadsafe_function(env, instance->broker);
1978
+ }
1979
+
1980
+ return true;
1981
+ }
1982
+
1940
1983
  static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
1941
1984
  PrimitiveKind primitive, int32_t size, int16_t align, const char *ref = nullptr)
1942
1985
  {
@@ -341,4 +341,6 @@ Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info);
341
341
  Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info);
342
342
  Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info);
343
343
 
344
+ bool InitAsyncBroker(Napi::Env env, InstanceData *instance);
345
+
344
346
  }
@@ -0,0 +1,155 @@
1
+ // Copyright 2023 Niels Martignène <niels.martignene@protonmail.com>
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ // this software and associated documentation files (the “Software”), to deal in
5
+ // the Software without restriction, including without limitation the rights to use,
6
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
+ // Software, and to permit persons to whom the Software is furnished to do so,
8
+ // subject to the following conditions:
9
+ //
10
+ // The above copyright notice and this permission notice shall be included in all
11
+ // copies or substantial portions of the Software.
12
+ //
13
+ // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
+ // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
+ // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
+ // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
+ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
+ // OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ #ifdef _WIN32
23
+
24
+ #include "win32.hh"
25
+
26
+ #ifndef NOMINMAX
27
+ #define NOMINMAX
28
+ #endif
29
+ #ifndef WIN32_LEAN_AND_MEAN
30
+ #define WIN32_LEAN_AND_MEAN
31
+ #endif
32
+ #include <windows.h>
33
+ #include <ntsecapi.h>
34
+ #include <processthreadsapi.h>
35
+
36
+ namespace RG {
37
+
38
+ const HashMap<int, const char *> WindowsMachineNames = {
39
+ { 0x184, "Alpha AXP, 32-bit" },
40
+ { 0x284, "Alpha 64" },
41
+ { 0x1d3, "Matsushita AM33" },
42
+ { 0x8664, "AMD x64" },
43
+ { 0x1c0, "ARM little endian" },
44
+ { 0xaa64, "ARM64 little endian" },
45
+ { 0x1c4, "ARM Thumb-2 little endian" },
46
+ { 0x284, "AXP 64" },
47
+ { 0xebc, "EFI byte code" },
48
+ { 0x14c, "Intel 386+" },
49
+ { 0x200, "Intel Itanium" },
50
+ { 0x6232, "LoongArch 32-bit" },
51
+ { 0x6264, "LoongArch 64-bit" },
52
+ { 0x9041, "Mitsubishi M32R little endian" },
53
+ { 0x266, "MIPS16" },
54
+ { 0x366, "MIPS with FPU" },
55
+ { 0x466, "MIPS16 with FPU" },
56
+ { 0x1f0, "Power PC little endian" },
57
+ { 0x1f1, "Power PC with FP support" },
58
+ { 0x166, "MIPS little endian" },
59
+ { 0x5032, "RISC-V 32-bit" },
60
+ { 0x5064, "RISC-V 64-bit" },
61
+ { 0x5128, "RISC-V 128-bit" },
62
+ { 0x1a2, "Hitachi SH3" },
63
+ { 0x1a3, "Hitachi SH3 DSP" },
64
+ { 0x1a6, "Hitachi SH4" },
65
+ { 0x1a8, "Hitachi SH5" },
66
+ { 0x1c2, "Thumb" },
67
+ { 0x169, "MIPS little-endian WCE v2" }
68
+ };
69
+
70
+ // Fails silently on purpose
71
+ static bool ReadAt(HANDLE h, int32_t offset, void *buf, int len)
72
+ {
73
+ OVERLAPPED ov = {};
74
+ DWORD read;
75
+
76
+ ov.Offset = offset & 0x7FFFFFFFu;
77
+
78
+ if (offset < 0)
79
+ return false;
80
+ if (!ReadFile(h, buf, (DWORD)len, &read, &ov))
81
+ return false;
82
+ if (read != len)
83
+ return false;
84
+
85
+ return true;
86
+ }
87
+
88
+ static int GetFileMachine(HANDLE h, bool check_dll)
89
+ {
90
+ PE_DOS_HEADER dos = {};
91
+ PE_NT_HEADERS nt = {};
92
+
93
+ if (!ReadAt(h, 0, &dos, RG_SIZE(dos)))
94
+ goto generic;
95
+ if (!ReadAt(h, dos.e_lfanew, &nt, RG_SIZE(nt)))
96
+ goto generic;
97
+
98
+ if (dos.e_magic != 0x5A4D) // MZ
99
+ goto generic;
100
+ if (nt.Signature != 0x00004550) // PE\0\0
101
+ goto generic;
102
+ if (check_dll && !(nt.FileHeader.Characteristics & IMAGE_FILE_DLL))
103
+ goto generic;
104
+
105
+ return (int)nt.FileHeader.Machine;
106
+
107
+ generic:
108
+ LogError("Invalid or forbidden %1 file: %2", check_dll ? "DLL" : "executable", GetWin32ErrorString());
109
+ return -1;
110
+ }
111
+
112
+ int GetSelfMachine()
113
+ {
114
+ const char *filename = GetApplicationExecutable();
115
+
116
+ HANDLE h;
117
+ if (IsWin32Utf8()) {
118
+ h = CreateFileA(filename, GENERIC_READ,
119
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
120
+ nullptr, OPEN_EXISTING, 0, nullptr);
121
+ } else {
122
+ wchar_t filename_w[4096];
123
+ if (ConvertUtf8ToWin32Wide(filename, filename_w) < 0)
124
+ return -1;
125
+
126
+ h = CreateFileW(filename_w, GENERIC_READ,
127
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
128
+ nullptr, OPEN_EXISTING, 0, nullptr);
129
+ }
130
+ if (h == INVALID_HANDLE_VALUE) {
131
+ LogError("Cannot open '%1': %2", filename, GetWin32ErrorString());
132
+ return -1;
133
+ }
134
+ RG_DEFER { CloseHandle(h); };
135
+
136
+ return GetFileMachine(h, false);
137
+ }
138
+
139
+ int GetDllMachine(const char16_t *filename)
140
+ {
141
+ HANDLE h = CreateFileW((LPCWSTR)filename, GENERIC_READ,
142
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
143
+ nullptr, OPEN_EXISTING, 0, nullptr);
144
+ if (h == INVALID_HANDLE_VALUE) {
145
+ LogError("Cannot open '%1': %2", filename, GetWin32ErrorString());
146
+ return -1;
147
+ }
148
+ RG_DEFER { CloseHandle(h); };
149
+
150
+ return GetFileMachine(h, true);
151
+ }
152
+
153
+ }
154
+
155
+ #endif
@@ -27,6 +27,45 @@
27
27
 
28
28
  namespace RG {
29
29
 
30
+ struct PE_DOS_HEADER {
31
+ uint16_t e_magic;
32
+ uint16_t e_cblp;
33
+ uint16_t e_cp;
34
+ uint16_t e_crlc;
35
+ uint16_t e_cparhdr;
36
+ uint16_t e_minalloc;
37
+ uint16_t e_maxalloc;
38
+ uint16_t e_ss;
39
+ uint16_t e_sp;
40
+ uint16_t e_csum;
41
+ uint16_t e_ip;
42
+ uint16_t e_cs;
43
+ uint16_t e_lfarlc;
44
+ uint16_t e_ovno;
45
+ uint16_t e_res[4];
46
+ uint16_t e_oemid;
47
+ uint16_t e_oeminfo;
48
+ uint16_t e_res2[10];
49
+ uint32_t e_lfanew;
50
+ };
51
+
52
+ struct PE_FILE_HEADER {
53
+ uint16_t Machine;
54
+ uint16_t NumberOfSections;
55
+ uint32_t TimeDateStamp;
56
+ uint32_t PointerToSymbolTable;
57
+ uint32_t NumberOfSymbols;
58
+ uint16_t SizeOfOptionalHeader;
59
+ uint16_t Characteristics;
60
+ };
61
+
62
+ struct PE_NT_HEADERS {
63
+ uint32_t Signature;
64
+ PE_FILE_HEADER FileHeader;
65
+
66
+ // ... OptionalHeader;
67
+ };
68
+
30
69
  #if _WIN64
31
70
 
32
71
  struct TEB {
@@ -70,4 +109,9 @@ static inline TEB *GetTEB()
70
109
  return teb;
71
110
  }
72
111
 
112
+ extern const HashMap<int, const char *> WindowsMachineNames;
113
+
114
+ int GetSelfMachine();
115
+ int GetDllMachine(const char16_t *filename);
116
+
73
117
  }